From d27e66ff3d016b2619c722a6fb3c8946613cac7e Mon Sep 17 00:00:00 2001 From: Dave Shanley Date: Wed, 2 Nov 2022 10:02:53 -0400 Subject: [PATCH] Refactored SecurityRequirement **breaking change** The v3 model is wrong and out of sync with the spec. It's been corrected, so the v2 and v2 model for SecurityRequirement have been collapsed down into a base model., they are the same data structures. This has allowed me to delete the complexity of sharing two different models for the same structure, by unifying the model correctly. I am not sure why I decided to change the v3 model, oh well, its been corrected. Long live swagger! --- .../high/{v2 => base}/security_requirement.go | 18 +- datamodel/high/v2/operation.go | 6 +- datamodel/high/v2/swagger.go | 8 +- datamodel/high/v2/swagger_test.go | 4 +- datamodel/high/v3/document.go | 2 +- datamodel/high/v3/document_test.go | 8 +- datamodel/high/v3/operation.go | 11 +- datamodel/high/v3/security_requirement.go | 49 --- .../low/{v2 => base}/security_requirement.go | 27 +- datamodel/low/extraction_functions.go | 2 +- datamodel/low/v2/operation.go | 8 +- datamodel/low/v2/swagger.go | 8 +- datamodel/low/v3/create_document.go | 12 +- datamodel/low/v3/create_document_test.go | 12 +- datamodel/low/v3/document.go | 14 +- datamodel/low/v3/operation.go | 24 +- datamodel/low/v3/operation_test.go | 8 +- datamodel/low/v3/security_scheme.go | 98 +---- datamodel/low/v3/security_scheme_test.go | 8 +- what-changed/model/security_requirement.go | 80 +--- .../model/security_requirement_test.go | 370 +++++++++--------- 21 files changed, 308 insertions(+), 469 deletions(-) rename datamodel/high/{v2 => base}/security_requirement.go (72%) delete mode 100644 datamodel/high/v3/security_requirement.go rename datamodel/low/{v2 => base}/security_requirement.go (72%) diff --git a/datamodel/high/v2/security_requirement.go b/datamodel/high/base/security_requirement.go similarity index 72% rename from datamodel/high/v2/security_requirement.go rename to datamodel/high/base/security_requirement.go index 1d1e060..39cae3f 100644 --- a/datamodel/high/v2/security_requirement.go +++ b/datamodel/high/base/security_requirement.go @@ -1,9 +1,11 @@ // Copyright 2022 Princess B33f Heavy Industries / Dave Shanley // SPDX-License-Identifier: MIT -package v2 +package base -import low "github.com/pb33f/libopenapi/datamodel/low/v2" +import ( + "github.com/pb33f/libopenapi/datamodel/low/base" +) // SecurityRequirement is a high-level representation of a Swagger / OpenAPI 2 SecurityRequirement object. // @@ -14,19 +16,19 @@ import low "github.com/pb33f/libopenapi/datamodel/low/v2" // - https://swagger.io/specification/v2/#securityDefinitionsObject type SecurityRequirement struct { Requirements map[string][]string - low *low.SecurityRequirement + low *base.SecurityRequirement } // NewSecurityRequirement creates a new high-level SecurityRequirement from a low-level one. -func NewSecurityRequirement(req *low.SecurityRequirement) *SecurityRequirement { +func NewSecurityRequirement(req *base.SecurityRequirement) *SecurityRequirement { r := new(SecurityRequirement) r.low = req values := make(map[string][]string) // to keep things fast, avoiding copying anything - makes it a little hard to read. - for reqK := range req.Values.Value { + for reqK := range req.Requirements.Value { var vals []string - for valK := range req.Values.Value[reqK].Value { - vals = append(vals, req.Values.Value[reqK].Value[valK].Value) + for valK := range req.Requirements.Value[reqK].Value { + vals = append(vals, req.Requirements.Value[reqK].Value[valK].Value) } values[reqK.Value] = vals } @@ -35,6 +37,6 @@ func NewSecurityRequirement(req *low.SecurityRequirement) *SecurityRequirement { } // GoLow returns the low-level SecurityRequirement used to create the high-level one. -func (s *SecurityRequirement) GoLow() *low.SecurityRequirement { +func (s *SecurityRequirement) GoLow() *base.SecurityRequirement { return s.low } diff --git a/datamodel/high/v2/operation.go b/datamodel/high/v2/operation.go index df86a25..8dbccb7 100644 --- a/datamodel/high/v2/operation.go +++ b/datamodel/high/v2/operation.go @@ -24,7 +24,7 @@ type Operation struct { Responses *Responses Schemes []string Deprecated bool - Security []*SecurityRequirement + Security []*base.SecurityRequirement Extensions map[string]any low *low.Operation } @@ -88,9 +88,9 @@ func NewOperation(operation *low.Operation) *Operation { o.Deprecated = operation.Deprecated.Value } if !operation.Security.IsEmpty() { - var sec []*SecurityRequirement + var sec []*base.SecurityRequirement for s := range operation.Security.Value { - sec = append(sec, NewSecurityRequirement(operation.Security.Value[s].Value)) + sec = append(sec, base.NewSecurityRequirement(operation.Security.Value[s].Value)) } o.Security = sec } diff --git a/datamodel/high/v2/swagger.go b/datamodel/high/v2/swagger.go index ce7bac1..fcbe9f5 100644 --- a/datamodel/high/v2/swagger.go +++ b/datamodel/high/v2/swagger.go @@ -38,7 +38,7 @@ type Swagger struct { // The basePath does not support path templating. BasePath string - // Schemes represents the transfer protocol of the API. Values MUST be from the list: "http", "https", "ws", "wss". + // Schemes represents the transfer protocol of the API. Requirements MUST be from the list: "http", "https", "ws", "wss". // If the schemes is not included, the default scheme to be used is the one used to access // the Swagger definition itself. Schemes []string @@ -77,7 +77,7 @@ type Swagger struct { // describes alternative security schemes that can be used (that is, there is a logical OR between the security // requirements). Individual operations can override this definition. // - https://swagger.io/specification/v2/#securityRequirementObject - Security []*SecurityRequirement + Security []*base.SecurityRequirement // Tags are A list of tags used by the specification with additional metadata. // The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used @@ -150,9 +150,9 @@ func NewSwaggerDocument(document *low.Swagger) *Swagger { d.SecurityDefinitions = NewSecurityDefinitions(document.SecurityDefinitions.Value) } if !document.Security.IsEmpty() { - var security []*SecurityRequirement + var security []*base.SecurityRequirement for s := range document.Security.Value { - security = append(security, NewSecurityRequirement(document.Security.Value[s].Value)) + security = append(security, base.NewSecurityRequirement(document.Security.Value[s].Value)) } d.Security = security } diff --git a/datamodel/high/v2/swagger_test.go b/datamodel/high/v2/swagger_test.go index a96f726..472faee 100644 --- a/datamodel/high/v2/swagger_test.go +++ b/datamodel/high/v2/swagger_test.go @@ -103,8 +103,8 @@ func TestNewSwaggerDocument_Security(t *testing.T) { assert.Len(t, highDoc.Security[0].Requirements["global_auth"], 2) wentLow := highDoc.Security[0].GoLow() - assert.Equal(t, 25, wentLow.Values.ValueNode.Line) - assert.Equal(t, 5, wentLow.Values.ValueNode.Column) + assert.Equal(t, 25, wentLow.Requirements.ValueNode.Line) + assert.Equal(t, 5, wentLow.Requirements.ValueNode.Column) } diff --git a/datamodel/high/v3/document.go b/datamodel/high/v3/document.go index 1941587..7c24479 100644 --- a/datamodel/high/v3/document.go +++ b/datamodel/high/v3/document.go @@ -48,7 +48,7 @@ type Document struct { // to authorize a request. Individual operations can override this definition. To make security optional, // an empty security requirement ({}) can be included in the array. // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object - Security *SecurityRequirement + Security *base.SecurityRequirement // Tags is a slice of base.Tag instances defined by the specification // A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on diff --git a/datamodel/high/v3/document_test.go b/datamodel/high/v3/document_test.go index 29ecdc0..80e2c93 100644 --- a/datamodel/high/v3/document_test.go +++ b/datamodel/high/v3/document_test.go @@ -337,10 +337,10 @@ func TestNewDocument_Paths(t *testing.T) { assert.Len(t, okResp.Links, 2) assert.Equal(t, "locateBurger", okResp.Links["LocateBurger"].OperationId) assert.Equal(t, 305, okResp.Links["LocateBurger"].GoLow().OperationId.ValueNode.Line) - assert.Len(t, burgersOp.Post.Security.ValueRequirements[0], 1) - assert.Len(t, burgersOp.Post.Security.ValueRequirements[0]["OAuthScheme"], 2) - assert.Equal(t, "read:burgers", burgersOp.Post.Security.ValueRequirements[0]["OAuthScheme"][0]) - assert.Equal(t, 118, burgersOp.Post.Security.GoLow().ValueRequirements[0].ValueNode.Line) + assert.Len(t, burgersOp.Post.Security[0].Requirements, 1) + assert.Len(t, burgersOp.Post.Security[0].Requirements["OAuthScheme"], 2) + assert.Equal(t, "read:burgers", burgersOp.Post.Security[0].Requirements["OAuthScheme"][0]) + assert.Equal(t, 118, burgersOp.Post.Security[0].GoLow().Requirements.ValueNode.Line) assert.Len(t, burgersOp.Post.Servers, 1) assert.Equal(t, "https://pb33f.io", burgersOp.Post.Servers[0].URL) diff --git a/datamodel/high/v3/operation.go b/datamodel/high/v3/operation.go index 011035c..98c65e7 100644 --- a/datamodel/high/v3/operation.go +++ b/datamodel/high/v3/operation.go @@ -23,8 +23,8 @@ type Operation struct { RequestBody *RequestBody Responses *Responses Callbacks map[string]*Callback - Deprecated bool - Security *SecurityRequirement + Deprecated *bool + Security []*base.SecurityRequirement Servers []*Server Extensions map[string]any low *low.Operation @@ -42,6 +42,7 @@ func NewOperation(operation *low.Operation) *Operation { } o.Tags = tags o.Summary = operation.Summary.Value + o.Deprecated = &operation.Deprecated.Value o.Description = operation.Description.Value if !operation.ExternalDocs.IsEmpty() { o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value) @@ -61,7 +62,11 @@ func NewOperation(operation *low.Operation) *Operation { o.Responses = NewResponses(operation.Responses.Value) } if !operation.Security.IsEmpty() { - o.Security = NewSecurityRequirement(operation.Security.Value) + var sec []*base.SecurityRequirement + for s := range operation.Security.Value { + sec = append(sec, base.NewSecurityRequirement(operation.Security.Value[s].Value)) + } + o.Security = sec } var servers []*Server for i := range operation.Servers.Value { diff --git a/datamodel/high/v3/security_requirement.go b/datamodel/high/v3/security_requirement.go deleted file mode 100644 index d9fb3ec..0000000 --- a/datamodel/high/v3/security_requirement.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley -// SPDX-License-Identifier: MIT - -package v3 - -import low "github.com/pb33f/libopenapi/datamodel/low/v3" - -// SecurityRequirement is a high-level representation of an OpenAPI 3+ SecurityRequirement object that is backed -// by a low-level one. -// -// It lists the required security schemes to execute this operation. The name used for each property MUST correspond -// to a security scheme declared in the Security Schemes under the Components Object. -// -// Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a -// request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are -// required to convey security information. -// -// When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the -// Security Requirement Objects in the list needs to be satisfied to authorize the request. -// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object -type SecurityRequirement struct { - ValueRequirements []map[string][]string - low *low.SecurityRequirement -} - -// NewSecurityRequirement will create a new high-level SecurityRequirement instance, from a low-level one. -func NewSecurityRequirement(req *low.SecurityRequirement) *SecurityRequirement { - r := new(SecurityRequirement) - r.low = req - var values []map[string][]string - for i := range req.ValueRequirements { - valmap := make(map[string][]string) - for k, v := range req.ValueRequirements[i].Value { - var mItems []string - for h := range v.Value { - mItems = append(mItems, v.Value[h].Value) - } - valmap[k.Value] = mItems - } - values = append(values, valmap) - } - r.ValueRequirements = values - return r -} - -// GoLow returns the low-level SecurityRequirement instance used to create the high-level one. -func (s *SecurityRequirement) GoLow() *low.SecurityRequirement { - return s.low -} diff --git a/datamodel/low/v2/security_requirement.go b/datamodel/low/base/security_requirement.go similarity index 72% rename from datamodel/low/v2/security_requirement.go rename to datamodel/low/base/security_requirement.go index 662626f..df884b7 100644 --- a/datamodel/low/v2/security_requirement.go +++ b/datamodel/low/base/security_requirement.go @@ -1,7 +1,7 @@ // Copyright 2022 Princess B33f Heavy Industries / Dave Shanley // SPDX-License-Identifier: MIT -package v2 +package base import ( "crypto/sha256" @@ -13,15 +13,16 @@ import ( "strings" ) -// SecurityRequirement is a low-level representation of a Swagger / OpenAPI 2 SecurityRequirement object. +// SecurityRequirement is a low-level representation of a Swagger / OpenAPI 3 SecurityRequirement object. // // SecurityRequirement lists the required security schemes to execute this operation. The object can have multiple // security schemes declared in it which are all required (that is, there is a logical AND between the schemes). // // The name used for each property MUST correspond to a security scheme declared in the Security Definitions // - https://swagger.io/specification/v2/#securityDefinitionsObject +// - https://swagger.io/specification/#security-requirement-object type SecurityRequirement struct { - Values low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] + Requirements low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] } // Build will extract security requirements from the node (the structure is odd, to be honest) @@ -49,22 +50,32 @@ func (s *SecurityRequirement) Build(root *yaml.Node, _ *index.SpecIndex) error { ValueNode: root.Content[i], } } - s.Values = low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]{ + s.Requirements = low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]{ Value: valueMap, ValueNode: root, } return nil } +// FindRequirement will attempt to locate a security requirement string from a supplied name. +func (s *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] { + for k := range s.Requirements.Value { + if k.Value == name { + return s.Requirements.Value[k].Value + } + } + return nil +} + // Hash will return a consistent SHA256 Hash of the SecurityRequirement object func (s *SecurityRequirement) Hash() [32]byte { var f []string - values := make(map[string][]string, len(s.Values.Value)) + values := make(map[string][]string, len(s.Requirements.Value)) var valKeys []string - for k := range s.Values.Value { + for k := range s.Requirements.Value { var vals []string - for y := range s.Values.Value[k].Value { - vals = append(vals, s.Values.Value[k].Value[y].Value) + for y := range s.Requirements.Value[k].Value { + vals = append(vals, s.Requirements.Value[k].Value[y].Value) // lol, I know. -------^^^^^ <- this is the actual value. } sort.Strings(vals) diff --git a/datamodel/low/extraction_functions.go b/datamodel/low/extraction_functions.go index 937105c..4a1f324 100644 --- a/datamodel/low/extraction_functions.go +++ b/datamodel/low/extraction_functions.go @@ -487,7 +487,7 @@ func ExtractMap[PT Buildable[N], N any]( return nil, labelNode, valueNode, nil } -// ExtractExtensions will extract any 'x-' prefixed key nodes from a root node into a map. Values have been pre-cast: +// ExtractExtensions will extract any 'x-' prefixed key nodes from a root node into a map. Requirements have been pre-cast: // // Maps // map[string]interface{} for maps diff --git a/datamodel/low/v2/operation.go b/datamodel/low/v2/operation.go index fd76655..92756d5 100644 --- a/datamodel/low/v2/operation.go +++ b/datamodel/low/v2/operation.go @@ -30,7 +30,7 @@ type Operation struct { Responses low.NodeReference[*Responses] Schemes low.NodeReference[[]low.ValueReference[string]] Deprecated low.NodeReference[bool] - Security low.NodeReference[[]low.ValueReference[*SecurityRequirement]] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] Extensions map[low.KeyReference[string]]low.ValueReference[any] } @@ -65,13 +65,13 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { } o.Responses = respBody - // extract parameters - sec, sln, svn, sErr := low.ExtractArray[*SecurityRequirement](SecurityLabel, root, idx) + // extract security + sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) if sErr != nil { return sErr } if sec != nil { - o.Security = low.NodeReference[[]low.ValueReference[*SecurityRequirement]]{ + o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ Value: sec, KeyNode: sln, ValueNode: svn, diff --git a/datamodel/low/v2/swagger.go b/datamodel/low/v2/swagger.go index 5e07e71..be61a46 100644 --- a/datamodel/low/v2/swagger.go +++ b/datamodel/low/v2/swagger.go @@ -44,7 +44,7 @@ type Swagger struct { // The basePath does not support path templating. BasePath low.NodeReference[string] - // Schemes represents the transfer protocol of the API. Values MUST be from the list: "http", "https", "ws", "wss". + // Schemes represents the transfer protocol of the API. Requirements MUST be from the list: "http", "https", "ws", "wss". // If the schemes is not included, the default scheme to be used is the one used to access // the Swagger definition itself. Schemes low.NodeReference[[]low.ValueReference[string]] @@ -83,7 +83,7 @@ type Swagger struct { // describes alternative security schemes that can be used (that is, there is a logical OR between the security // requirements). Individual operations can override this definition. // - https://swagger.io/specification/v2/#securityRequirementObject - Security low.NodeReference[[]low.ValueReference[*SecurityRequirement]] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] // Tags are A list of tags used by the specification with additional metadata. // The order of the tags can be used to reflect on their order by the parsing tools. Not all tags that are used @@ -245,12 +245,12 @@ func extractTags(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- b } func extractSecurity(root *yaml.Node, doc *Swagger, idx *index.SpecIndex, c chan<- bool, e chan<- error) { - sec, ln, vn, err := low.ExtractArray[*SecurityRequirement](SecurityLabel, root, idx) + sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) if err != nil { e <- err return } - doc.Security = low.NodeReference[[]low.ValueReference[*SecurityRequirement]]{ + doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ Value: sec, KeyNode: ln, ValueNode: vn, diff --git a/datamodel/low/v3/create_document.go b/datamodel/low/v3/create_document.go index d90d614..336f000 100644 --- a/datamodel/low/v3/create_document.go +++ b/datamodel/low/v3/create_document.go @@ -76,11 +76,15 @@ func extractInfo(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) } func extractSecurity(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error { - sec, sErr := low.ExtractObject[*SecurityRequirement](SecurityLabel, info.RootNode, idx) - if sErr != nil { - return sErr + sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, info.RootNode, idx) + if err != nil { + return err + } + doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: ln, + ValueNode: vn, } - doc.Security = sec return nil } diff --git a/datamodel/low/v3/create_document_test.go b/datamodel/low/v3/create_document_test.go index eda142b..0601a60 100644 --- a/datamodel/low/v3/create_document_test.go +++ b/datamodel/low/v3/create_document_test.go @@ -317,11 +317,7 @@ func TestCreateDocument_Paths(t *testing.T) { assert.Equal(t, "$response.body#/id", burgerIdParam.Value) // check security requirements - security := burgersPost.Security.Value - assert.NotNil(t, security) - assert.Len(t, security.ValueRequirements, 1) - - oAuthReq := security.FindRequirement("OAuthScheme") + oAuthReq := burgersPost.FindSecurityRequirement("OAuthScheme") assert.Len(t, oAuthReq, 2) assert.Equal(t, "read:burgers", oAuthReq[0].Value) @@ -453,11 +449,7 @@ func TestCreateDocument_Components_Links(t *testing.T) { func TestCreateDocument_Doc_Security(t *testing.T) { initTest() - security := doc.Security.Value - assert.NotNil(t, security) - assert.Len(t, security.ValueRequirements, 1) - - oAuth := security.FindRequirement("OAuthScheme") + oAuth := doc.FindSecurityRequirement("OAuthScheme") assert.Len(t, oAuth, 2) } diff --git a/datamodel/low/v3/document.go b/datamodel/low/v3/document.go index f906e0a..f1934d6 100644 --- a/datamodel/low/v3/document.go +++ b/datamodel/low/v3/document.go @@ -59,7 +59,7 @@ type Document struct { // to authorize a request. Individual operations can override this definition. To make security optional, // an empty security requirement ({}) can be included in the array. // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object - Security low.NodeReference[*SecurityRequirement] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] // Tags is a slice of base.Tag instances defined by the specification // A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on @@ -84,6 +84,18 @@ type Document struct { Index *index.SpecIndex } +// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name. +func (d *Document) FindSecurityRequirement(name string) []low.ValueReference[string] { + for k := range d.Security.Value { + for i := range d.Security.Value[k].Value.Requirements.Value { + if i.Value == name { + return d.Security.Value[k].Value.Requirements.Value[i].Value + } + } + } + return nil +} + // TODO: this is early prototype mutation/modification code, keeping it around for later. //func (d *Document) AddTag() *base.Tag { // t := base.NewTag() diff --git a/datamodel/low/v3/operation.go b/datamodel/low/v3/operation.go index 981433e..7a6fb33 100644 --- a/datamodel/low/v3/operation.go +++ b/datamodel/low/v3/operation.go @@ -30,7 +30,7 @@ type Operation struct { Responses low.NodeReference[*Responses] Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]] Deprecated low.NodeReference[bool] - Security low.NodeReference[*SecurityRequirement] + Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]] Servers low.NodeReference[[]low.ValueReference[*Server]] Extensions map[low.KeyReference[string]]low.ValueReference[any] } @@ -40,6 +40,18 @@ func (o *Operation) FindCallback(callback string) *low.ValueReference[*Callback] return low.FindItemInMap[*Callback](callback, o.Callbacks.Value) } +// FindSecurityRequirement will attempt to locate a security requirement string from a supplied name. +func (o *Operation) FindSecurityRequirement(name string) []low.ValueReference[string] { + for k := range o.Security.Value { + for i := range o.Security.Value[k].Value.Requirements.Value { + if i.Value == name { + return o.Security.Value[k].Value.Requirements.Value[i].Value + } + } + } + return nil +} + // Build will extract external docs, parameters, request body, responses, callbacks, security and servers. func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { o.Extensions = low.ExtractExtensions(root) @@ -92,11 +104,17 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { } // extract security - sec, sErr := low.ExtractObject[*SecurityRequirement](SecurityLabel, root, idx) + sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx) if sErr != nil { return sErr } - o.Security = sec + if sec != nil { + o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{ + Value: sec, + KeyNode: sln, + ValueNode: svn, + } + } // extract servers servers, sl, sn, serErr := low.ExtractArray[*Server](ServersLabel, root, idx) diff --git a/datamodel/low/v3/operation_test.go b/datamodel/low/v3/operation_test.go index 3082d76..7c6004c 100644 --- a/datamodel/low/v3/operation_test.go +++ b/datamodel/low/v3/operation_test.go @@ -65,10 +65,10 @@ servers: assert.Equal(t, "a nice callback", n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value) assert.True(t, n.Deprecated.Value) - assert.Len(t, n.Security.Value.ValueRequirements, 1) - assert.Len(t, n.Security.Value.FindRequirement("books"), 2) - assert.Equal(t, "read:books", n.Security.Value.FindRequirement("books")[0].Value) - assert.Equal(t, "write:books", n.Security.Value.FindRequirement("books")[1].Value) + assert.Len(t, n.Security.Value, 1) + assert.Len(t, n.FindSecurityRequirement("books"), 2) + assert.Equal(t, "read:books", n.FindSecurityRequirement("books")[0].Value) + assert.Equal(t, "write:books", n.FindSecurityRequirement("books")[1].Value) assert.Len(t, n.Servers.Value, 1) assert.Equal(t, "https://pb33f.io", n.Servers.Value[0].Value.URL.Value) } diff --git a/datamodel/low/v3/security_scheme.go b/datamodel/low/v3/security_scheme.go index a63271b..90c1c11 100644 --- a/datamodel/low/v3/security_scheme.go +++ b/datamodel/low/v3/security_scheme.go @@ -8,9 +8,7 @@ import ( "fmt" "github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/index" - "github.com/pb33f/libopenapi/utils" "gopkg.in/yaml.v3" - "sort" "strings" ) @@ -48,11 +46,11 @@ type SecurityScheme struct { // When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the // Security Requirement Objects in the list needs to be satisfied to authorize the request. // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object -type SecurityRequirement struct { - - // FYI, I hate this data structure. Even without the low level wrapping, it sucks. - ValueRequirements []low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] -} +//type SecurityRequirement struct { +// +// // FYI, I hate this data structure. Even without the low level wrapping, it sucks. +// ValueRequirements []low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] +//} // FindExtension attempts to locate an extension using the supplied key. func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] { @@ -105,89 +103,3 @@ func (ss *SecurityScheme) Hash() [32]byte { } return sha256.Sum256([]byte(strings.Join(f, "|"))) } - -// FindRequirement will attempt to locate a security requirement string from a supplied name. -func (sr *SecurityRequirement) FindRequirement(name string) []low.ValueReference[string] { - for _, r := range sr.ValueRequirements { - for k, v := range r.Value { - if k.Value == name { - return v.Value - } - } - } - return nil -} - -// Build will extract all security requirements -func (sr *SecurityRequirement) Build(root *yaml.Node, _ *index.SpecIndex) error { - if utils.IsNodeArray(root) { - var requirements []low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]] - for _, n := range root.Content { - var currSec *yaml.Node - if utils.IsNodeMap(n) { - res := make(map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) - var dat []low.ValueReference[string] - for i, r := range n.Content { - if i%2 == 0 { - currSec = r - continue - } - if utils.IsNodeArray(r) { - // value (should be) an array of strings - var keyValues []low.ValueReference[string] - for _, strN := range r.Content { - keyValues = append(keyValues, low.ValueReference[string]{ - Value: strN.Value, - ValueNode: strN, - }) - } - dat = keyValues - } - } - if currSec != nil { - res[low.KeyReference[string]{ - Value: currSec.Value, - KeyNode: currSec, - }] = low.ValueReference[[]low.ValueReference[string]]{ - Value: dat, - ValueNode: currSec, - } - requirements = append(requirements, - low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]{ - Value: res, - ValueNode: n, - }) - } - } - } - sr.ValueRequirements = requirements - } - return nil -} - -// Hash will return a consistent SHA256 Hash of the SecurityRequirement object -func (sr *SecurityRequirement) Hash() [32]byte { - var f []string - for i := range sr.ValueRequirements { - req := sr.ValueRequirements[i].Value - values := make(map[string][]string, len(req)) - var valKeys []string - for k := range req { - var vals []string - for y := range req[k].Value { - vals = append(vals, req[k].Value[y].Value) - } - sort.Strings(vals) - valKeys = append(valKeys, k.Value) - if len(vals) > 0 { - values[k.Value] = vals - } - } - sort.Strings(valKeys) - for val := range valKeys { - f = append(f, fmt.Sprintf("%s-%s", valKeys[val], - strings.Join(values[valKeys[val]], "|"))) - } - } - return sha256.Sum256([]byte(strings.Join(f, "|"))) -} diff --git a/datamodel/low/v3/security_scheme_test.go b/datamodel/low/v3/security_scheme_test.go index 0994f64..1067b1c 100644 --- a/datamodel/low/v3/security_scheme_test.go +++ b/datamodel/low/v3/security_scheme_test.go @@ -5,6 +5,7 @@ package v3 import ( "github.com/pb33f/libopenapi/datamodel/low" + "github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/index" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" @@ -12,7 +13,7 @@ import ( ) func TestSecurityRequirement_Build(t *testing.T) { - yml := `- something: + yml := `something: - read:me - write:me` @@ -20,13 +21,14 @@ func TestSecurityRequirement_Build(t *testing.T) { _ = yaml.Unmarshal([]byte(yml), &idxNode) idx := index.NewSpecIndex(&idxNode) - var n SecurityRequirement + var n base.SecurityRequirement err := low.BuildModel(&idxNode, &n) assert.NoError(t, err) err = n.Build(idxNode.Content[0], idx) + assert.NoError(t, err) - assert.Len(t, n.ValueRequirements, 1) + assert.Len(t, n.Requirements.Value, 1) assert.Equal(t, "read:me", n.FindRequirement("something")[0].Value) assert.Equal(t, "write:me", n.FindRequirement("something")[1].Value) assert.Nil(t, n.FindRequirement("none")) diff --git a/what-changed/model/security_requirement.go b/what-changed/model/security_requirement.go index b540408..ba85291 100644 --- a/what-changed/model/security_requirement.go +++ b/what-changed/model/security_requirement.go @@ -5,10 +5,9 @@ package model import ( "github.com/pb33f/libopenapi/datamodel/low" - "github.com/pb33f/libopenapi/datamodel/low/v2" + "github.com/pb33f/libopenapi/datamodel/low/base" "github.com/pb33f/libopenapi/datamodel/low/v3" "gopkg.in/yaml.v3" - "reflect" ) type SecurityRequirementChanges struct { @@ -33,76 +32,15 @@ func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) { nil, vn, false, nil, name) } -func CompareSecurityRequirement(l, r any) *SecurityRequirementChanges { +func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges { var changes []*Change sc := new(SecurityRequirementChanges) - if reflect.TypeOf(&v2.SecurityRequirement{}) == reflect.TypeOf(l) && - reflect.TypeOf(&v2.SecurityRequirement{}) == reflect.TypeOf(r) { - - lSec := l.(*v2.SecurityRequirement) - rSec := r.(*v2.SecurityRequirement) - - if low.AreEqual(lSec, rSec) { - return nil - } - checkSecurityRequirement(lSec.Values.Value, rSec.Values.Value, &changes) - + if low.AreEqual(l, r) { + return nil } - - if reflect.TypeOf(&v3.SecurityRequirement{}) == reflect.TypeOf(l) && - reflect.TypeOf(&v3.SecurityRequirement{}) == reflect.TypeOf(r) { - - lSec := l.(*v3.SecurityRequirement) - rSec := r.(*v3.SecurityRequirement) - - if low.AreEqual(lSec, rSec) { - return nil - } - - // can we find anyone to dance with? - findPartner := func(key string, - search map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]] { - for k := range search { - if k.Value == key { - return search[k] - } - } - return nil - } - - // Yes, this exists. - lValues := make(map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) - rValues := make(map[low.KeyReference[string]]map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]) - for i := range lSec.ValueRequirements { - for k := range lSec.ValueRequirements[i].Value { - lValues[k] = lSec.ValueRequirements[i].Value - } - } - for i := range rSec.ValueRequirements { - for k := range rSec.ValueRequirements[i].Value { - rValues[k] = rSec.ValueRequirements[i].Value - } - } - - // look through left and right slices to see if we recognize anything. - for k := range lValues { - if p := findPartner(k.Value, rValues); p != nil { - checkSecurityRequirement(lValues[k], p, &changes) - continue - } - CreateChange(&changes, ObjectRemoved, v3.SecurityLabel, - k.KeyNode, nil, true, lValues[k], nil) - } - for k := range rValues { - if ok := findPartner(k.Value, lValues); ok == nil { - CreateChange(&changes, ObjectAdded, v3.SecurityLabel, - nil, k.KeyNode, false, nil, rValues[k]) - } - } - } - + checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes) sc.Changes = changes return sc } @@ -199,11 +137,3 @@ func checkSecurityRequirement(lSec, rSec map[low.KeyReference[string]]low.ValueR } } } - -func CompareSecurityRequirementV3(l, r *v3.SecurityRequirement) *SecurityRequirementChanges { - return CompareSecurityRequirement(l, r) -} - -func CompareSecurityRequirementV2(l, r *v2.SecurityRequirement) *SecurityRequirementChanges { - return CompareSecurityRequirement(l, r) -} diff --git a/what-changed/model/security_requirement_test.go b/what-changed/model/security_requirement_test.go index c7fc9a9..0b2cbb9 100644 --- a/what-changed/model/security_requirement_test.go +++ b/what-changed/model/security_requirement_test.go @@ -5,8 +5,7 @@ package model import ( "github.com/pb33f/libopenapi/datamodel/low" - "github.com/pb33f/libopenapi/datamodel/low/v2" - "github.com/pb33f/libopenapi/datamodel/low/v3" + "github.com/pb33f/libopenapi/datamodel/low/base" "github.com/stretchr/testify/assert" "gopkg.in/yaml.v3" "testing" @@ -27,15 +26,15 @@ func TestCompareSecurityRequirement_V2(t *testing.T) { _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Nil(t, extChanges) } @@ -60,15 +59,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) @@ -92,15 +91,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&rDoc, &lDoc) + extChanges := CompareSecurityRequirement(&rDoc, &lDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges()) } @@ -124,15 +123,15 @@ milk: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 4, extChanges.TotalChanges()) assert.Equal(t, 2, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) @@ -160,15 +159,15 @@ milk: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) @@ -195,15 +194,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) @@ -233,15 +232,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) @@ -267,15 +266,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 3, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges()) } @@ -301,15 +300,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Nil(t, extChanges) } @@ -333,15 +332,15 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&rDoc, &lDoc) + extChanges := CompareSecurityRequirement(&rDoc, &lDoc) assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) @@ -369,167 +368,168 @@ biscuit: _ = yaml.Unmarshal([]byte(right), &rNode) // create low level objects - var lDoc v2.SecurityRequirement - var rDoc v2.SecurityRequirement + var lDoc base.SecurityRequirement + var rDoc base.SecurityRequirement _ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&rNode, &rDoc) _ = lDoc.Build(lNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil) // compare - extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) + extChanges := CompareSecurityRequirement(&lDoc, &rDoc) assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) } -func TestCompareSecurityRequirement_V3(t *testing.T) { - - left := `- auth: - - pizza - - pie` - - right := `- auth: - - pie - - pizza` - - var lNode, rNode yaml.Node - _ = yaml.Unmarshal([]byte(left), &lNode) - _ = yaml.Unmarshal([]byte(right), &rNode) - - // create low level objects - var lDoc v3.SecurityRequirement - var rDoc v3.SecurityRequirement - _ = low.BuildModel(&lNode, &lDoc) - _ = low.BuildModel(&rNode, &rDoc) - _ = lDoc.Build(lNode.Content[0], nil) - _ = rDoc.Build(rNode.Content[0], nil) - - // compare - extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) - assert.Nil(t, extChanges) -} - -func TestCompareSecurityRequirement_V3_AddARole(t *testing.T) { - - left := `- auth: - - pizza - - pie` - - right := `- auth: - - pie - - pizza - - beer` - - var lNode, rNode yaml.Node - _ = yaml.Unmarshal([]byte(left), &lNode) - _ = yaml.Unmarshal([]byte(right), &rNode) - - // create low level objects - var lDoc v3.SecurityRequirement - var rDoc v3.SecurityRequirement - _ = low.BuildModel(&lNode, &lDoc) - _ = low.BuildModel(&rNode, &rDoc) - _ = lDoc.Build(lNode.Content[0], nil) - _ = rDoc.Build(rNode.Content[0], nil) - - // compare - extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) - assert.Equal(t, 1, extChanges.TotalChanges()) - assert.Equal(t, 0, extChanges.TotalBreakingChanges()) - assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) -} - -func TestCompareSecurityRequirement_V3_RemoveRole(t *testing.T) { - - left := `- auth: - - pizza - - pie` - - right := `- auth: - - pie - - pizza - - beer` - - var lNode, rNode yaml.Node - _ = yaml.Unmarshal([]byte(left), &lNode) - _ = yaml.Unmarshal([]byte(right), &rNode) - - // create low level objects - var lDoc v3.SecurityRequirement - var rDoc v3.SecurityRequirement - _ = low.BuildModel(&lNode, &lDoc) - _ = low.BuildModel(&rNode, &rDoc) - _ = lDoc.Build(lNode.Content[0], nil) - _ = rDoc.Build(rNode.Content[0], nil) - - // compare - extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) - assert.Equal(t, 1, extChanges.TotalChanges()) - assert.Equal(t, 1, extChanges.TotalBreakingChanges()) - assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) -} - -func TestCompareSecurityRequirement_V3_AddAReq(t *testing.T) { - - left := `- auth: - - pizza - - pie` - - right := `- auth: - - pie - - pizza -- coffee: - - filter - - espresso` - - var lNode, rNode yaml.Node - _ = yaml.Unmarshal([]byte(left), &lNode) - _ = yaml.Unmarshal([]byte(right), &rNode) - - // create low level objects - var lDoc v3.SecurityRequirement - var rDoc v3.SecurityRequirement - _ = low.BuildModel(&lNode, &lDoc) - _ = low.BuildModel(&rNode, &rDoc) - _ = lDoc.Build(lNode.Content[0], nil) - _ = rDoc.Build(rNode.Content[0], nil) - - // compare - extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) - assert.Equal(t, 1, extChanges.TotalChanges()) - assert.Equal(t, 0, extChanges.TotalBreakingChanges()) - assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) -} - -func TestCompareSecurityRequirement_V3_RemoveAReq(t *testing.T) { - - left := `- coffee: - - filter - - espresso` - - right := `- coffee: - - filter - - espresso -- auth: - - pizza - - pie` - - var lNode, rNode yaml.Node - _ = yaml.Unmarshal([]byte(left), &lNode) - _ = yaml.Unmarshal([]byte(right), &rNode) - - // create low level objects - var lDoc v3.SecurityRequirement - var rDoc v3.SecurityRequirement - _ = low.BuildModel(&lNode, &lDoc) - _ = low.BuildModel(&rNode, &rDoc) - _ = lDoc.Build(lNode.Content[0], nil) - _ = rDoc.Build(rNode.Content[0], nil) - - // compare - extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) - assert.Equal(t, 1, extChanges.TotalChanges()) - assert.Equal(t, 1, extChanges.TotalBreakingChanges()) - assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) -} +// +//func TestCompareSecurityRequirement_V3(t *testing.T) { +// +// left := `- auth: +// - pizza +// - pie` +// +// right := `- auth: +// - pie +// - pizza` +// +// var lNode, rNode yaml.Node +// _ = yaml.Unmarshal([]byte(left), &lNode) +// _ = yaml.Unmarshal([]byte(right), &rNode) +// +// // create low level objects +// var lDoc v3.SecurityRequirement +// var rDoc v3.SecurityRequirement +// _ = low.BuildModel(&lNode, &lDoc) +// _ = low.BuildModel(&rNode, &rDoc) +// _ = lDoc.Build(lNode.Content[0], nil) +// _ = rDoc.Build(rNode.Content[0], nil) +// +// // compare +// extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) +// assert.Nil(t, extChanges) +//} +// +//func TestCompareSecurityRequirement_V3_AddARole(t *testing.T) { +// +// left := `- auth: +// - pizza +// - pie` +// +// right := `- auth: +// - pie +// - pizza +// - beer` +// +// var lNode, rNode yaml.Node +// _ = yaml.Unmarshal([]byte(left), &lNode) +// _ = yaml.Unmarshal([]byte(right), &rNode) +// +// // create low level objects +// var lDoc v3.SecurityRequirement +// var rDoc v3.SecurityRequirement +// _ = low.BuildModel(&lNode, &lDoc) +// _ = low.BuildModel(&rNode, &rDoc) +// _ = lDoc.Build(lNode.Content[0], nil) +// _ = rDoc.Build(rNode.Content[0], nil) +// +// // compare +// extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) +// assert.Equal(t, 1, extChanges.TotalChanges()) +// assert.Equal(t, 0, extChanges.TotalBreakingChanges()) +// assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) +//} +// +//func TestCompareSecurityRequirement_V3_RemoveRole(t *testing.T) { +// +// left := `- auth: +// - pizza +// - pie` +// +// right := `- auth: +// - pie +// - pizza +// - beer` +// +// var lNode, rNode yaml.Node +// _ = yaml.Unmarshal([]byte(left), &lNode) +// _ = yaml.Unmarshal([]byte(right), &rNode) +// +// // create low level objects +// var lDoc v3.SecurityRequirement +// var rDoc v3.SecurityRequirement +// _ = low.BuildModel(&lNode, &lDoc) +// _ = low.BuildModel(&rNode, &rDoc) +// _ = lDoc.Build(lNode.Content[0], nil) +// _ = rDoc.Build(rNode.Content[0], nil) +// +// // compare +// extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) +// assert.Equal(t, 1, extChanges.TotalChanges()) +// assert.Equal(t, 1, extChanges.TotalBreakingChanges()) +// assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) +//} +// +//func TestCompareSecurityRequirement_V3_AddAReq(t *testing.T) { +// +// left := `- auth: +// - pizza +// - pie` +// +// right := `- auth: +// - pie +// - pizza +//- coffee: +// - filter +// - espresso` +// +// var lNode, rNode yaml.Node +// _ = yaml.Unmarshal([]byte(left), &lNode) +// _ = yaml.Unmarshal([]byte(right), &rNode) +// +// // create low level objects +// var lDoc v3.SecurityRequirement +// var rDoc v3.SecurityRequirement +// _ = low.BuildModel(&lNode, &lDoc) +// _ = low.BuildModel(&rNode, &rDoc) +// _ = lDoc.Build(lNode.Content[0], nil) +// _ = rDoc.Build(rNode.Content[0], nil) +// +// // compare +// extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) +// assert.Equal(t, 1, extChanges.TotalChanges()) +// assert.Equal(t, 0, extChanges.TotalBreakingChanges()) +// assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) +//} +// +//func TestCompareSecurityRequirement_V3_RemoveAReq(t *testing.T) { +// +// left := `- coffee: +// - filter +// - espresso` +// +// right := `- coffee: +// - filter +// - espresso +//- auth: +// - pizza +// - pie` +// +// var lNode, rNode yaml.Node +// _ = yaml.Unmarshal([]byte(left), &lNode) +// _ = yaml.Unmarshal([]byte(right), &rNode) +// +// // create low level objects +// var lDoc v3.SecurityRequirement +// var rDoc v3.SecurityRequirement +// _ = low.BuildModel(&lNode, &lDoc) +// _ = low.BuildModel(&rNode, &rDoc) +// _ = lDoc.Build(lNode.Content[0], nil) +// _ = rDoc.Build(rNode.Content[0], nil) +// +// // compare +// extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) +// assert.Equal(t, 1, extChanges.TotalChanges()) +// assert.Equal(t, 1, extChanges.TotalBreakingChanges()) +// assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) +//}