go.mod: bump github.com/getkin/kin-openapi to v0.131.0
As deepmap/oapi-codegen didn't work with this newer version, upgrade to oapi-codegen/oapi-codegen v2. Mitigating CVE-2025-30153
This commit is contained in:
parent
c5cb0d0618
commit
b2700903ae
403 changed files with 44758 additions and 16347 deletions
202
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/apply.go
generated
vendored
Normal file
202
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/apply.go
generated
vendored
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/vmware-labs/yaml-jsonpath/pkg/yamlpath"
|
||||
"gopkg.in/yaml.v3"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ApplyTo will take an overlay and apply its changes to the given YAML
|
||||
// document.
|
||||
func (o *Overlay) ApplyTo(root *yaml.Node) error {
|
||||
for _, action := range o.Actions {
|
||||
var err error
|
||||
if action.Remove {
|
||||
err = applyRemoveAction(root, action)
|
||||
} else {
|
||||
err = applyUpdateAction(root, action, &[]string{})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Overlay) ApplyToStrict(root *yaml.Node) (error, []string) {
|
||||
multiError := []string{}
|
||||
warnings := []string{}
|
||||
for i, action := range o.Actions {
|
||||
err := validateSelectorHasAtLeastOneTarget(root, action)
|
||||
if err != nil {
|
||||
multiError = append(multiError, err.Error())
|
||||
}
|
||||
if action.Remove {
|
||||
err = applyRemoveAction(root, action)
|
||||
} else {
|
||||
actionWarnings := []string{}
|
||||
err = applyUpdateAction(root, action, &actionWarnings)
|
||||
for _, warning := range actionWarnings {
|
||||
warnings = append(warnings, fmt.Sprintf("update action (%v / %v) target=%s: %s", i+1, len(o.Actions), action.Target, warning))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(multiError) > 0 {
|
||||
return fmt.Errorf("error applying overlay (strict): %v", strings.Join(multiError, ",")), warnings
|
||||
}
|
||||
return nil, warnings
|
||||
}
|
||||
|
||||
func validateSelectorHasAtLeastOneTarget(root *yaml.Node, action Action) error {
|
||||
if action.Target == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
p, err := yamlpath.NewPath(action.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := p.Find(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(nodes) == 0 {
|
||||
return fmt.Errorf("selector %q did not match any targets", action.Target)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyRemoveAction(root *yaml.Node, action Action) error {
|
||||
if action.Target == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
idx := newParentIndex(root)
|
||||
|
||||
p, err := yamlpath.NewPath(action.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := p.Find(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
removeNode(idx, node)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeNode(idx parentIndex, node *yaml.Node) {
|
||||
parent := idx.getParent(node)
|
||||
if parent == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i, child := range parent.Content {
|
||||
if child == node {
|
||||
switch parent.Kind {
|
||||
case yaml.MappingNode:
|
||||
// we have to delete the key too
|
||||
parent.Content = append(parent.Content[:i-1], parent.Content[i+1:]...)
|
||||
return
|
||||
case yaml.SequenceNode:
|
||||
parent.Content = append(parent.Content[:i], parent.Content[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func applyUpdateAction(root *yaml.Node, action Action, warnings *[]string) error {
|
||||
if action.Target == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if action.Update.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
p, err := yamlpath.NewPath(action.Target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodes, err := p.Find(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prior, err := yaml.Marshal(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
if err := updateNode(node, action.Update); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
post, err := yaml.Marshal(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if warnings != nil && string(prior) == string(post) {
|
||||
*warnings = append(*warnings, "does nothing")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateNode(node *yaml.Node, updateNode yaml.Node) error {
|
||||
mergeNode(node, updateNode)
|
||||
return nil
|
||||
}
|
||||
|
||||
func mergeNode(node *yaml.Node, merge yaml.Node) {
|
||||
if node.Kind != merge.Kind {
|
||||
*node = merge
|
||||
return
|
||||
}
|
||||
switch node.Kind {
|
||||
default:
|
||||
node.Value = merge.Value
|
||||
case yaml.MappingNode:
|
||||
mergeMappingNode(node, merge)
|
||||
case yaml.SequenceNode:
|
||||
mergeSequenceNode(node, merge)
|
||||
}
|
||||
}
|
||||
|
||||
// mergeMappingNode will perform a shallow merge of the merge node into the main
|
||||
// node.
|
||||
func mergeMappingNode(node *yaml.Node, merge yaml.Node) {
|
||||
NextKey:
|
||||
for i := 0; i < len(merge.Content); i += 2 {
|
||||
mergeKey := merge.Content[i].Value
|
||||
mergeValue := merge.Content[i+1]
|
||||
|
||||
for j := 0; j < len(node.Content); j += 2 {
|
||||
nodeKey := node.Content[j].Value
|
||||
if nodeKey == mergeKey {
|
||||
mergeNode(node.Content[j+1], *mergeValue)
|
||||
continue NextKey
|
||||
}
|
||||
}
|
||||
|
||||
node.Content = append(node.Content, merge.Content[i], mergeValue)
|
||||
}
|
||||
}
|
||||
|
||||
// mergeSequenceNode will append the merge node's content to the original node.
|
||||
func mergeSequenceNode(node *yaml.Node, merge yaml.Node) {
|
||||
node.Content = append(node.Content, merge.Content...)
|
||||
}
|
||||
260
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/compare.go
generated
vendored
Normal file
260
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/compare.go
generated
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Compare compares input specifications from two files and returns an overlay
|
||||
// that will convert the first into the second.
|
||||
func Compare(title string, y1 *yaml.Node, y2 yaml.Node) (*Overlay, error) {
|
||||
actions, err := walkTreesAndCollectActions(simplePath{}, y1, y2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Overlay{
|
||||
Version: "1.0.0",
|
||||
Info: Info{
|
||||
Title: title,
|
||||
Version: "0.0.0",
|
||||
},
|
||||
Actions: actions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type simplePart struct {
|
||||
isKey bool
|
||||
key string
|
||||
index int
|
||||
}
|
||||
|
||||
func intPart(index int) simplePart {
|
||||
return simplePart{
|
||||
index: index,
|
||||
}
|
||||
}
|
||||
|
||||
func keyPart(key string) simplePart {
|
||||
return simplePart{
|
||||
isKey: true,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
func (p simplePart) String() string {
|
||||
if p.isKey {
|
||||
return fmt.Sprintf("[%q]", p.key)
|
||||
}
|
||||
return fmt.Sprintf("[%d]", p.index)
|
||||
}
|
||||
|
||||
func (p simplePart) KeyString() string {
|
||||
if p.isKey {
|
||||
return p.key
|
||||
}
|
||||
panic("FIXME: Bug detected in overlay comparison algorithm: attempt to use non key part as key")
|
||||
}
|
||||
|
||||
type simplePath []simplePart
|
||||
|
||||
func (p simplePath) WithIndex(index int) simplePath {
|
||||
return append(p, intPart(index))
|
||||
}
|
||||
|
||||
func (p simplePath) WithKey(key string) simplePath {
|
||||
return append(p, keyPart(key))
|
||||
}
|
||||
|
||||
func (p simplePath) ToJSONPath() string {
|
||||
out := &strings.Builder{}
|
||||
out.WriteString("$")
|
||||
for _, part := range p {
|
||||
out.WriteString(part.String())
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
func (p simplePath) Dir() simplePath {
|
||||
return p[:len(p)-1]
|
||||
}
|
||||
|
||||
func (p simplePath) Base() simplePart {
|
||||
return p[len(p)-1]
|
||||
}
|
||||
|
||||
func walkTreesAndCollectActions(path simplePath, y1 *yaml.Node, y2 yaml.Node) ([]Action, error) {
|
||||
if y1 == nil {
|
||||
return []Action{{
|
||||
Target: path.Dir().ToJSONPath(),
|
||||
Update: y2,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
if y2.IsZero() {
|
||||
return []Action{{
|
||||
Target: path.ToJSONPath(),
|
||||
Remove: true,
|
||||
}}, nil
|
||||
}
|
||||
if y1.Kind != y2.Kind {
|
||||
return []Action{{
|
||||
Target: path.ToJSONPath(),
|
||||
Update: y2,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
switch y1.Kind {
|
||||
case yaml.DocumentNode:
|
||||
return walkTreesAndCollectActions(path, y1.Content[0], *y2.Content[0])
|
||||
case yaml.SequenceNode:
|
||||
if len(y2.Content) == len(y1.Content) {
|
||||
return walkSequenceNode(path, y1, y2)
|
||||
}
|
||||
|
||||
if len(y2.Content) == len(y1.Content)+1 &&
|
||||
yamlEquals(y2.Content[:len(y1.Content)], y1.Content) {
|
||||
return []Action{{
|
||||
Target: path.ToJSONPath(),
|
||||
Update: yaml.Node{
|
||||
Kind: y1.Kind,
|
||||
Content: []*yaml.Node{y2.Content[len(y1.Content)]},
|
||||
},
|
||||
}}, nil
|
||||
}
|
||||
|
||||
return []Action{{
|
||||
Target: path.ToJSONPath() + "[*]", // target all elements
|
||||
Remove: true,
|
||||
}, {
|
||||
Target: path.ToJSONPath(),
|
||||
Update: yaml.Node{
|
||||
Kind: y1.Kind,
|
||||
Content: y2.Content,
|
||||
},
|
||||
}}, nil
|
||||
case yaml.MappingNode:
|
||||
return walkMappingNode(path, y1, y2)
|
||||
case yaml.ScalarNode:
|
||||
if y1.Value != y2.Value {
|
||||
return []Action{{
|
||||
Target: path.ToJSONPath(),
|
||||
Update: y2,
|
||||
}}, nil
|
||||
}
|
||||
case yaml.AliasNode:
|
||||
log.Println("YAML alias nodes are not yet supported for compare.")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func yamlEquals(nodes []*yaml.Node, content []*yaml.Node) bool {
|
||||
for i := range nodes {
|
||||
bufA := &bytes.Buffer{}
|
||||
bufB := &bytes.Buffer{}
|
||||
decodeA := yaml.NewEncoder(bufA)
|
||||
decodeB := yaml.NewEncoder(bufB)
|
||||
err := decodeA.Encode(nodes[i])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
err = decodeB.Encode(content[i])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if bufA.String() != bufB.String() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func walkSequenceNode(path simplePath, y1 *yaml.Node, y2 yaml.Node) ([]Action, error) {
|
||||
nodeLen := max(len(y1.Content), len(y2.Content))
|
||||
var actions []Action
|
||||
for i := 0; i < nodeLen; i++ {
|
||||
var c1, c2 *yaml.Node
|
||||
if i < len(y1.Content) {
|
||||
c1 = y1.Content[i]
|
||||
}
|
||||
if i < len(y2.Content) {
|
||||
c2 = y2.Content[i]
|
||||
}
|
||||
|
||||
newActions, err := walkTreesAndCollectActions(
|
||||
path.WithIndex(i),
|
||||
c1, *c2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actions = append(actions, newActions...)
|
||||
}
|
||||
|
||||
return actions, nil
|
||||
}
|
||||
|
||||
func walkMappingNode(path simplePath, y1 *yaml.Node, y2 yaml.Node) ([]Action, error) {
|
||||
var actions []Action
|
||||
foundKeys := map[string]struct{}{}
|
||||
|
||||
// Add or update keys in y2 that differ/missing from y1
|
||||
Outer:
|
||||
for i := 0; i < len(y2.Content); i += 2 {
|
||||
k2 := y2.Content[i]
|
||||
v2 := y2.Content[i+1]
|
||||
|
||||
foundKeys[k2.Value] = struct{}{}
|
||||
|
||||
// find keys in y1 to update
|
||||
for j := 0; j < len(y1.Content); j += 2 {
|
||||
k1 := y1.Content[j]
|
||||
v1 := y1.Content[j+1]
|
||||
|
||||
if k1.Value == k2.Value {
|
||||
newActions, err := walkTreesAndCollectActions(
|
||||
path.WithKey(k2.Value),
|
||||
v1, *v2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actions = append(actions, newActions...)
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
|
||||
// key not found in y1, so add it
|
||||
newActions, err := walkTreesAndCollectActions(
|
||||
path.WithKey(k2.Value),
|
||||
nil, yaml.Node{
|
||||
Kind: y1.Kind,
|
||||
Content: []*yaml.Node{k2, v2},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actions = append(actions, newActions...)
|
||||
}
|
||||
|
||||
// look for keys in y1 that are not in y2: remove them
|
||||
for i := 0; i < len(y1.Content); i += 2 {
|
||||
k1 := y1.Content[i]
|
||||
|
||||
if _, alreadySeen := foundKeys[k1.Value]; alreadySeen {
|
||||
continue
|
||||
}
|
||||
|
||||
actions = append(actions, Action{
|
||||
Target: path.WithKey(k1.Value).ToJSONPath(),
|
||||
Remove: true,
|
||||
})
|
||||
}
|
||||
|
||||
return actions, nil
|
||||
}
|
||||
23
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/parents.go
generated
vendored
Normal file
23
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/parents.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package overlay
|
||||
|
||||
import "gopkg.in/yaml.v3"
|
||||
|
||||
type parentIndex map[*yaml.Node]*yaml.Node
|
||||
|
||||
// newParentIndex returns a new parentIndex, populated for the given root node.
|
||||
func newParentIndex(root *yaml.Node) parentIndex {
|
||||
index := parentIndex{}
|
||||
index.indexNodeRecursively(root)
|
||||
return index
|
||||
}
|
||||
|
||||
func (index parentIndex) indexNodeRecursively(parent *yaml.Node) {
|
||||
for _, child := range parent.Content {
|
||||
index[child] = parent
|
||||
index.indexNodeRecursively(child)
|
||||
}
|
||||
}
|
||||
|
||||
func (index parentIndex) getParent(child *yaml.Node) *yaml.Node {
|
||||
return index[child]
|
||||
}
|
||||
58
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/parse.go
generated
vendored
Normal file
58
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/parse.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Parse will parse the given reader as an overlay file.
|
||||
func Parse(path string) (*Overlay, error) {
|
||||
filePath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get absolute path for %q: %w", path, err)
|
||||
}
|
||||
|
||||
ro, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open overlay file at path %q: %w", path, err)
|
||||
}
|
||||
defer ro.Close()
|
||||
|
||||
var overlay Overlay
|
||||
dec := yaml.NewDecoder(ro)
|
||||
|
||||
err = dec.Decode(&overlay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &overlay, err
|
||||
}
|
||||
|
||||
// Format will validate reformat the given file
|
||||
func Format(path string) error {
|
||||
overlay, err := Parse(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filePath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open overlay file at path %q: %w", path, err)
|
||||
}
|
||||
formatted, err := overlay.ToString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(filePath, []byte(formatted), 0644)
|
||||
}
|
||||
|
||||
// Format writes the file back out as YAML.
|
||||
func (o *Overlay) Format(w io.Writer) error {
|
||||
enc := yaml.NewEncoder(w)
|
||||
enc.SetIndent(2)
|
||||
return enc.Encode(o)
|
||||
}
|
||||
64
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/schema.go
generated
vendored
Normal file
64
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/schema.go
generated
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Extensible provides a place for extensions to be added to components of the
|
||||
// Overlay configuration. These are a map from x-* extension fields to their values.
|
||||
type Extensions map[string]any
|
||||
|
||||
// Overlay is the top-level configuration for an OpenAPI overlay.
|
||||
type Overlay struct {
|
||||
Extensions `yaml:"-,inline"`
|
||||
|
||||
// Version is the version of the overlay configuration. As the RFC was never
|
||||
// really ratifies, this value does not mean much.
|
||||
Version string `yaml:"overlay"`
|
||||
|
||||
// Info describes the metadata for the overlay.
|
||||
Info Info `yaml:"info"`
|
||||
|
||||
// Extends is a URL to the OpenAPI specification this overlay applies to.
|
||||
Extends string `yaml:"extends,omitempty"`
|
||||
|
||||
// Actions is the list of actions to perform to apply the overlay.
|
||||
Actions []Action `yaml:"actions"`
|
||||
}
|
||||
|
||||
func (o *Overlay) ToString() (string, error) {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
decoder := yaml.NewEncoder(buf)
|
||||
decoder.SetIndent(2)
|
||||
err := decoder.Encode(o)
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
// Info describes the metadata for the overlay.
|
||||
type Info struct {
|
||||
Extensions `yaml:"-,inline"`
|
||||
|
||||
// Title is the title of the overlay.
|
||||
Title string `yaml:"title"`
|
||||
|
||||
// Version is the version of the overlay.
|
||||
Version string `yaml:"version"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
Extensions `yaml:"-,inline"`
|
||||
|
||||
// Target is the JSONPath to the target of the action.
|
||||
Target string `yaml:"target"`
|
||||
|
||||
// Description is a description of the action.
|
||||
Description string `yaml:"description,omitempty"`
|
||||
|
||||
// Update is the sub-document to use to merge or replace in the target. This is
|
||||
// ignored if Remove is set.
|
||||
Update yaml.Node `yaml:"update,omitempty"`
|
||||
|
||||
// Remove marks the target node for removal rather than update.
|
||||
Remove bool `yaml:"remove,omitempty"`
|
||||
}
|
||||
19
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/utils.go
generated
vendored
Normal file
19
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/utils.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func NewTargetSelector(path, method string) string {
|
||||
return fmt.Sprintf(`$["paths"]["%s"]["%s"]`, path, method)
|
||||
}
|
||||
|
||||
func NewUpdateAction(path, method string, update yaml.Node) Action {
|
||||
target := NewTargetSelector(path, method)
|
||||
|
||||
return Action{
|
||||
Target: target,
|
||||
Update: update,
|
||||
}
|
||||
}
|
||||
61
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/validate.go
generated
vendored
Normal file
61
vendor/github.com/speakeasy-api/openapi-overlay/pkg/overlay/validate.go
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package overlay
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ValidationErrors []error
|
||||
|
||||
func (v ValidationErrors) Error() string {
|
||||
msgs := make([]string, len(v))
|
||||
for i, err := range v {
|
||||
msgs[i] = err.Error()
|
||||
}
|
||||
return strings.Join(msgs, "\n")
|
||||
}
|
||||
|
||||
func (v ValidationErrors) Return() error {
|
||||
if len(v) > 0 {
|
||||
return v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *Overlay) Validate() error {
|
||||
errs := make(ValidationErrors, 0)
|
||||
if o.Version != "1.0.0" {
|
||||
errs = append(errs, fmt.Errorf("overlay version must be 1.0.0"))
|
||||
}
|
||||
|
||||
if o.Info.Title == "" {
|
||||
errs = append(errs, fmt.Errorf("overlay info title must be defined"))
|
||||
}
|
||||
if o.Info.Version == "" {
|
||||
errs = append(errs, fmt.Errorf("overlay info version must be defined"))
|
||||
}
|
||||
|
||||
if o.Extends != "" {
|
||||
_, err := url.Parse(o.Extends)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("overlay extends must be a valid URL"))
|
||||
}
|
||||
}
|
||||
|
||||
if len(o.Actions) == 0 {
|
||||
errs = append(errs, fmt.Errorf("overlay must define at least one action"))
|
||||
} else {
|
||||
for i, action := range o.Actions {
|
||||
if action.Target == "" {
|
||||
errs = append(errs, fmt.Errorf("overlay action at index %d target must be defined", i))
|
||||
}
|
||||
|
||||
if action.Remove && !action.Update.IsZero() {
|
||||
errs = append(errs, fmt.Errorf("overlay action at index %d should not both set remove and define update", i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs.Return()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue