mirror of
https://github.com/containers/podman.git
synced 2025-05-24 02:27:00 +08:00
update c/{buildah,common,image,storage} to latest main
Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
188
vendor/github.com/go-openapi/validate/spec.go
generated
vendored
188
vendor/github.com/go-openapi/validate/spec.go
generated
vendored
@ -15,6 +15,8 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
@ -26,23 +28,23 @@ import (
|
||||
"github.com/go-openapi/loads"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/swag"
|
||||
)
|
||||
|
||||
// Spec validates an OpenAPI 2.0 specification document.
|
||||
//
|
||||
// Returns an error flattening in a single standard error, all validation messages.
|
||||
//
|
||||
// - TODO: $ref should not have siblings
|
||||
// - TODO: make sure documentation reflects all checks and warnings
|
||||
// - TODO: check on discriminators
|
||||
// - TODO: explicit message on unsupported keywords (better than "forbidden property"...)
|
||||
// - TODO: full list of unresolved refs
|
||||
// - TODO: validate numeric constraints (issue#581): this should be handled like defaults and examples
|
||||
// - TODO: option to determine if we validate for go-swagger or in a more general context
|
||||
// - TODO: check on required properties to support anyOf, allOf, oneOf
|
||||
// - TODO: $ref should not have siblings
|
||||
// - TODO: make sure documentation reflects all checks and warnings
|
||||
// - TODO: check on discriminators
|
||||
// - TODO: explicit message on unsupported keywords (better than "forbidden property"...)
|
||||
// - TODO: full list of unresolved refs
|
||||
// - TODO: validate numeric constraints (issue#581): this should be handled like defaults and examples
|
||||
// - TODO: option to determine if we validate for go-swagger or in a more general context
|
||||
// - TODO: check on required properties to support anyOf, allOf, oneOf
|
||||
//
|
||||
// NOTE: SecurityScopes are maps: no need to check uniqueness
|
||||
//
|
||||
func Spec(doc *loads.Document, formats strfmt.Registry) error {
|
||||
errs, _ /*warns*/ := NewSpecValidator(doc.Schema(), formats).Validate(doc)
|
||||
if errs.HasErrors() {
|
||||
@ -53,25 +55,38 @@ func Spec(doc *loads.Document, formats strfmt.Registry) error {
|
||||
|
||||
// SpecValidator validates a swagger 2.0 spec
|
||||
type SpecValidator struct {
|
||||
schema *spec.Schema // swagger 2.0 schema
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
expanded *loads.Document
|
||||
KnownFormats strfmt.Registry
|
||||
Options Opts // validation options
|
||||
schema *spec.Schema // swagger 2.0 schema
|
||||
spec *loads.Document
|
||||
analyzer *analysis.Spec
|
||||
expanded *loads.Document
|
||||
KnownFormats strfmt.Registry
|
||||
Options Opts // validation options
|
||||
schemaOptions *SchemaValidatorOptions
|
||||
}
|
||||
|
||||
// NewSpecValidator creates a new swagger spec validator instance
|
||||
func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidator {
|
||||
// schema options that apply to all called validators
|
||||
schemaOptions := new(SchemaValidatorOptions)
|
||||
for _, o := range []Option{
|
||||
SwaggerSchema(true),
|
||||
WithRecycleValidators(true),
|
||||
// withRecycleResults(true),
|
||||
} {
|
||||
o(schemaOptions)
|
||||
}
|
||||
|
||||
return &SpecValidator{
|
||||
schema: schema,
|
||||
KnownFormats: formats,
|
||||
Options: defaultOpts,
|
||||
schema: schema,
|
||||
KnownFormats: formats,
|
||||
Options: defaultOpts,
|
||||
schemaOptions: schemaOptions,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the swagger spec
|
||||
func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
|
||||
s.schemaOptions.skipSchemataResult = s.Options.SkipSchemataResult
|
||||
var sd *loads.Document
|
||||
errs, warnings := new(Result), new(Result)
|
||||
|
||||
@ -85,11 +100,8 @@ func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
|
||||
s.spec = sd
|
||||
s.analyzer = analysis.New(sd.Spec())
|
||||
|
||||
// Swagger schema validator
|
||||
schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats, SwaggerSchema(true))
|
||||
var obj interface{}
|
||||
|
||||
// Raw spec unmarshalling errors
|
||||
var obj interface{}
|
||||
if err := json.Unmarshal(sd.Raw(), &obj); err != nil {
|
||||
// NOTE: under normal conditions, the *load.Document has been already unmarshalled
|
||||
// So this one is just a paranoid check on the behavior of the spec package
|
||||
@ -103,6 +115,8 @@ func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
|
||||
warnings.AddErrors(errs.Warnings...)
|
||||
}()
|
||||
|
||||
// Swagger schema validator
|
||||
schv := newSchemaValidator(s.schema, nil, "", s.KnownFormats, s.schemaOptions)
|
||||
errs.Merge(schv.Validate(obj)) // error -
|
||||
// There may be a point in continuing to try and determine more accurate errors
|
||||
if !s.Options.ContinueOnErrors && errs.HasErrors() {
|
||||
@ -130,13 +144,13 @@ func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
|
||||
}
|
||||
|
||||
// Values provided as default MUST validate their schema
|
||||
df := &defaultValidator{SpecValidator: s}
|
||||
df := &defaultValidator{SpecValidator: s, schemaOptions: s.schemaOptions}
|
||||
errs.Merge(df.Validate())
|
||||
|
||||
// Values provided as examples MUST validate their schema
|
||||
// Value provided as examples in a response without schema generate a warning
|
||||
// Known limitations: examples in responses for mime type not application/json are ignored (warning)
|
||||
ex := &exampleValidator{SpecValidator: s}
|
||||
ex := &exampleValidator{SpecValidator: s, schemaOptions: s.schemaOptions}
|
||||
errs.Merge(ex.Validate())
|
||||
|
||||
errs.Merge(s.validateNonEmptyPathParamNames())
|
||||
@ -148,22 +162,27 @@ func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateNonEmptyPathParamNames() *Result {
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
if s.spec.Spec().Paths == nil {
|
||||
// There is no Paths object: error
|
||||
res.AddErrors(noValidPathMsg())
|
||||
} else {
|
||||
if s.spec.Spec().Paths.Paths == nil {
|
||||
// Paths may be empty: warning
|
||||
res.AddWarnings(noValidPathMsg())
|
||||
} else {
|
||||
for k := range s.spec.Spec().Paths.Paths {
|
||||
if strings.Contains(k, "{}") {
|
||||
res.AddErrors(emptyPathParameterMsg(k))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
if s.spec.Spec().Paths.Paths == nil {
|
||||
// Paths may be empty: warning
|
||||
res.AddWarnings(noValidPathMsg())
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
for k := range s.spec.Spec().Paths.Paths {
|
||||
if strings.Contains(k, "{}") {
|
||||
res.AddErrors(emptyPathParameterMsg(k))
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
@ -177,7 +196,7 @@ func (s *SpecValidator) validateDuplicateOperationIDs() *Result {
|
||||
// fallback on possible incomplete picture because of previous errors
|
||||
analyzer = s.analyzer
|
||||
}
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
known := make(map[string]int)
|
||||
for _, v := range analyzer.OperationIDs() {
|
||||
if v != "" {
|
||||
@ -199,7 +218,7 @@ type dupProp struct {
|
||||
|
||||
func (s *SpecValidator) validateDuplicatePropertyNames() *Result {
|
||||
// definition can't declare a property that's already defined by one of its ancestors
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
for k, sch := range s.spec.Spec().Definitions {
|
||||
if len(sch.AllOf) == 0 {
|
||||
continue
|
||||
@ -248,7 +267,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema,
|
||||
|
||||
schn := nm
|
||||
schc := &sch
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
|
||||
for schc.Ref.String() != "" {
|
||||
// gather property names
|
||||
@ -285,7 +304,7 @@ func (s *SpecValidator) validateSchemaPropertyNames(nm string, sch spec.Schema,
|
||||
}
|
||||
|
||||
func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, knowns map[string]struct{}) ([]string, *Result) {
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
|
||||
if sch.Ref.String() == "" && len(sch.AllOf) == 0 { // Safeguard. We should not be able to actually get there
|
||||
return nil, res
|
||||
@ -335,7 +354,7 @@ func (s *SpecValidator) validateCircularAncestry(nm string, sch spec.Schema, kno
|
||||
|
||||
func (s *SpecValidator) validateItems() *Result {
|
||||
// validate parameter, items, schema and response objects for presence of item if type is array
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
|
||||
for method, pi := range s.analyzer.Operations() {
|
||||
for path, op := range pi {
|
||||
@ -394,7 +413,7 @@ func (s *SpecValidator) validateItems() *Result {
|
||||
|
||||
// Verifies constraints on array type
|
||||
func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) *Result {
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
if !schema.Type.Contains(arrayType) {
|
||||
return res
|
||||
}
|
||||
@ -418,7 +437,7 @@ func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID str
|
||||
func (s *SpecValidator) validatePathParamPresence(path string, fromPath, fromOperation []string) *Result {
|
||||
// Each defined operation path parameters must correspond to a named element in the API's path pattern.
|
||||
// (For example, you cannot have a path parameter named id for the following path /pets/{petId} but you must have a path parameter named petId.)
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
for _, l := range fromPath {
|
||||
var matched bool
|
||||
for _, r := range fromOperation {
|
||||
@ -456,7 +475,6 @@ func (s *SpecValidator) validateReferenced() *Result {
|
||||
return &res
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func (s *SpecValidator) validateReferencedParameters() *Result {
|
||||
// Each referenceable definition should have references.
|
||||
params := s.spec.Spec().Parameters
|
||||
@ -475,14 +493,13 @@ func (s *SpecValidator) validateReferencedParameters() *Result {
|
||||
if len(expected) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := new(Result)
|
||||
result := pools.poolOfResults.BorrowResult()
|
||||
for k := range expected {
|
||||
result.AddWarnings(unusedParamMsg(k))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func (s *SpecValidator) validateReferencedResponses() *Result {
|
||||
// Each referenceable definition should have references.
|
||||
responses := s.spec.Spec().Responses
|
||||
@ -501,14 +518,13 @@ func (s *SpecValidator) validateReferencedResponses() *Result {
|
||||
if len(expected) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := new(Result)
|
||||
result := pools.poolOfResults.BorrowResult()
|
||||
for k := range expected {
|
||||
result.AddWarnings(unusedResponseMsg(k))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// nolint: dupl
|
||||
func (s *SpecValidator) validateReferencedDefinitions() *Result {
|
||||
// Each referenceable definition must have references.
|
||||
defs := s.spec.Spec().Definitions
|
||||
@ -537,7 +553,7 @@ func (s *SpecValidator) validateReferencedDefinitions() *Result {
|
||||
|
||||
func (s *SpecValidator) validateRequiredDefinitions() *Result {
|
||||
// Each property listed in the required array must be defined in the properties of the model
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
|
||||
DEFINITIONS:
|
||||
for d, schema := range s.spec.Spec().Definitions {
|
||||
@ -556,7 +572,7 @@ DEFINITIONS:
|
||||
|
||||
func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Schema) *Result {
|
||||
// Takes care of recursive property definitions, which may be nested in additionalProperties schemas
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
propertyMatch := false
|
||||
patternMatch := false
|
||||
additionalPropertiesMatch := false
|
||||
@ -615,40 +631,42 @@ func (s *SpecValidator) validateRequiredProperties(path, in string, v *spec.Sche
|
||||
func (s *SpecValidator) validateParameters() *Result {
|
||||
// - for each method, path is unique, regardless of path parameters
|
||||
// e.g. GET:/petstore/{id}, GET:/petstore/{pet}, GET:/petstore are
|
||||
// considered duplicate paths
|
||||
// considered duplicate paths, if StrictPathParamUniqueness is enabled.
|
||||
// - each parameter should have a unique `name` and `type` combination
|
||||
// - each operation should have only 1 parameter of type body
|
||||
// - there must be at most 1 parameter in body
|
||||
// - parameters with pattern property must specify valid patterns
|
||||
// - $ref in parameters must resolve
|
||||
// - path param must be required
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
rexGarbledPathSegment := mustCompileRegexp(`.*[{}\s]+.*`)
|
||||
for method, pi := range s.expandedAnalyzer().Operations() {
|
||||
methodPaths := make(map[string]map[string]string)
|
||||
for path, op := range pi {
|
||||
pathToAdd := pathHelp.stripParametersInPath(path)
|
||||
if s.Options.StrictPathParamUniqueness {
|
||||
pathToAdd := pathHelp.stripParametersInPath(path)
|
||||
|
||||
// Warn on garbled path afer param stripping
|
||||
if rexGarbledPathSegment.MatchString(pathToAdd) {
|
||||
res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
|
||||
}
|
||||
// Warn on garbled path afer param stripping
|
||||
if rexGarbledPathSegment.MatchString(pathToAdd) {
|
||||
res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
|
||||
}
|
||||
|
||||
// Check uniqueness of stripped paths
|
||||
if _, found := methodPaths[method][pathToAdd]; found {
|
||||
// Check uniqueness of stripped paths
|
||||
if _, found := methodPaths[method][pathToAdd]; found {
|
||||
|
||||
// Sort names for stable, testable output
|
||||
if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
|
||||
res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
|
||||
// Sort names for stable, testable output
|
||||
if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
|
||||
res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
|
||||
} else {
|
||||
res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
|
||||
}
|
||||
} else {
|
||||
res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
|
||||
}
|
||||
} else {
|
||||
if _, found := methodPaths[method]; !found {
|
||||
methodPaths[method] = map[string]string{}
|
||||
}
|
||||
methodPaths[method][pathToAdd] = path // Original non stripped path
|
||||
if _, found := methodPaths[method]; !found {
|
||||
methodPaths[method] = map[string]string{}
|
||||
}
|
||||
methodPaths[method][pathToAdd] = path // Original non stripped path
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var bodyParams []string
|
||||
@ -659,7 +677,23 @@ func (s *SpecValidator) validateParameters() *Result {
|
||||
// TODO: should be done after param expansion
|
||||
res.Merge(s.checkUniqueParams(path, method, op))
|
||||
|
||||
// pick the root schema from the swagger specification which describes a parameter
|
||||
origSchema, ok := s.schema.Definitions["parameter"]
|
||||
if !ok {
|
||||
panic("unexpected swagger schema: missing #/definitions/parameter")
|
||||
}
|
||||
// clone it once to avoid expanding a global schema (e.g. swagger spec)
|
||||
paramSchema, err := deepCloneSchema(origSchema)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("can't clone schema: %v", err))
|
||||
}
|
||||
|
||||
for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
|
||||
// An expanded parameter must validate the Parameter schema (an unexpanded $ref always passes high-level schema validation)
|
||||
schv := newSchemaValidator(¶mSchema, s.schema, fmt.Sprintf("%s.%s.parameters.%s", path, method, pr.Name), s.KnownFormats, s.schemaOptions)
|
||||
obj := swag.ToDynamicJSON(pr)
|
||||
res.Merge(schv.Validate(obj))
|
||||
|
||||
// Validate pattern regexp for parameters with a Pattern property
|
||||
if _, err := compileRegexp(pr.Pattern); err != nil {
|
||||
res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern))
|
||||
@ -741,7 +775,7 @@ func (s *SpecValidator) validateParameters() *Result {
|
||||
|
||||
func (s *SpecValidator) validateReferencesValid() *Result {
|
||||
// each reference must point to a valid object
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
for _, r := range s.analyzer.AllRefs() {
|
||||
if !r.IsValidURI(s.spec.SpecFilePath()) { // Safeguard - spec should always yield a valid URI
|
||||
res.AddErrors(invalidRefMsg(r.String()))
|
||||
@ -767,7 +801,7 @@ func (s *SpecValidator) checkUniqueParams(path, method string, op *spec.Operatio
|
||||
// However, there are some issues with such a factorization:
|
||||
// - analysis does not seem to fully expand params
|
||||
// - param keys may be altered by x-go-name
|
||||
res := new(Result)
|
||||
res := pools.poolOfResults.BorrowResult()
|
||||
pnames := make(map[string]struct{})
|
||||
|
||||
if op.Parameters != nil { // Safeguard
|
||||
@ -802,3 +836,17 @@ func (s *SpecValidator) expandedAnalyzer() *analysis.Spec {
|
||||
}
|
||||
return s.analyzer
|
||||
}
|
||||
|
||||
func deepCloneSchema(src spec.Schema) (spec.Schema, error) {
|
||||
var b bytes.Buffer
|
||||
if err := gob.NewEncoder(&b).Encode(src); err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
|
||||
var dst spec.Schema
|
||||
if err := gob.NewDecoder(&b).Decode(&dst); err != nil {
|
||||
return spec.Schema{}, err
|
||||
}
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user