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!
This commit is contained in:
Dave Shanley
2022-11-02 10:02:53 -04:00
parent 4b30fe3622
commit d27e66ff3d
21 changed files with 308 additions and 469 deletions

View File

@@ -1,9 +1,11 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley // Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT // 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. // 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 // - https://swagger.io/specification/v2/#securityDefinitionsObject
type SecurityRequirement struct { type SecurityRequirement struct {
Requirements map[string][]string Requirements map[string][]string
low *low.SecurityRequirement low *base.SecurityRequirement
} }
// NewSecurityRequirement creates a new high-level SecurityRequirement from a low-level one. // 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 := new(SecurityRequirement)
r.low = req r.low = req
values := make(map[string][]string) values := make(map[string][]string)
// to keep things fast, avoiding copying anything - makes it a little hard to read. // 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 var vals []string
for valK := range req.Values.Value[reqK].Value { for valK := range req.Requirements.Value[reqK].Value {
vals = append(vals, req.Values.Value[reqK].Value[valK].Value) vals = append(vals, req.Requirements.Value[reqK].Value[valK].Value)
} }
values[reqK.Value] = vals 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. // 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 return s.low
} }

View File

@@ -24,7 +24,7 @@ type Operation struct {
Responses *Responses Responses *Responses
Schemes []string Schemes []string
Deprecated bool Deprecated bool
Security []*SecurityRequirement Security []*base.SecurityRequirement
Extensions map[string]any Extensions map[string]any
low *low.Operation low *low.Operation
} }
@@ -88,9 +88,9 @@ func NewOperation(operation *low.Operation) *Operation {
o.Deprecated = operation.Deprecated.Value o.Deprecated = operation.Deprecated.Value
} }
if !operation.Security.IsEmpty() { if !operation.Security.IsEmpty() {
var sec []*SecurityRequirement var sec []*base.SecurityRequirement
for s := range operation.Security.Value { 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 o.Security = sec
} }

View File

@@ -38,7 +38,7 @@ type Swagger struct {
// The basePath does not support path templating. // The basePath does not support path templating.
BasePath string 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 // If the schemes is not included, the default scheme to be used is the one used to access
// the Swagger definition itself. // the Swagger definition itself.
Schemes []string 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 // 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. // requirements). Individual operations can override this definition.
// - https://swagger.io/specification/v2/#securityRequirementObject // - https://swagger.io/specification/v2/#securityRequirementObject
Security []*SecurityRequirement Security []*base.SecurityRequirement
// Tags are A list of tags used by the specification with additional metadata. // 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 // 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) d.SecurityDefinitions = NewSecurityDefinitions(document.SecurityDefinitions.Value)
} }
if !document.Security.IsEmpty() { if !document.Security.IsEmpty() {
var security []*SecurityRequirement var security []*base.SecurityRequirement
for s := range document.Security.Value { 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 d.Security = security
} }

View File

@@ -103,8 +103,8 @@ func TestNewSwaggerDocument_Security(t *testing.T) {
assert.Len(t, highDoc.Security[0].Requirements["global_auth"], 2) assert.Len(t, highDoc.Security[0].Requirements["global_auth"], 2)
wentLow := highDoc.Security[0].GoLow() wentLow := highDoc.Security[0].GoLow()
assert.Equal(t, 25, wentLow.Values.ValueNode.Line) assert.Equal(t, 25, wentLow.Requirements.ValueNode.Line)
assert.Equal(t, 5, wentLow.Values.ValueNode.Column) assert.Equal(t, 5, wentLow.Requirements.ValueNode.Column)
} }

View File

@@ -48,7 +48,7 @@ type Document struct {
// to authorize a request. Individual operations can override this definition. To make security optional, // to authorize a request. Individual operations can override this definition. To make security optional,
// an empty security requirement ({}) can be included in the array. // an empty security requirement ({}) can be included in the array.
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object // - 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 // 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 // A list of tags used by the document with additional metadata. The order of the tags can be used to reflect on

View File

@@ -337,10 +337,10 @@ func TestNewDocument_Paths(t *testing.T) {
assert.Len(t, okResp.Links, 2) assert.Len(t, okResp.Links, 2)
assert.Equal(t, "locateBurger", okResp.Links["LocateBurger"].OperationId) assert.Equal(t, "locateBurger", okResp.Links["LocateBurger"].OperationId)
assert.Equal(t, 305, okResp.Links["LocateBurger"].GoLow().OperationId.ValueNode.Line) 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[0].Requirements, 1)
assert.Len(t, burgersOp.Post.Security.ValueRequirements[0]["OAuthScheme"], 2) assert.Len(t, burgersOp.Post.Security[0].Requirements["OAuthScheme"], 2)
assert.Equal(t, "read:burgers", burgersOp.Post.Security.ValueRequirements[0]["OAuthScheme"][0]) assert.Equal(t, "read:burgers", burgersOp.Post.Security[0].Requirements["OAuthScheme"][0])
assert.Equal(t, 118, burgersOp.Post.Security.GoLow().ValueRequirements[0].ValueNode.Line) assert.Equal(t, 118, burgersOp.Post.Security[0].GoLow().Requirements.ValueNode.Line)
assert.Len(t, burgersOp.Post.Servers, 1) assert.Len(t, burgersOp.Post.Servers, 1)
assert.Equal(t, "https://pb33f.io", burgersOp.Post.Servers[0].URL) assert.Equal(t, "https://pb33f.io", burgersOp.Post.Servers[0].URL)

View File

@@ -23,8 +23,8 @@ type Operation struct {
RequestBody *RequestBody RequestBody *RequestBody
Responses *Responses Responses *Responses
Callbacks map[string]*Callback Callbacks map[string]*Callback
Deprecated bool Deprecated *bool
Security *SecurityRequirement Security []*base.SecurityRequirement
Servers []*Server Servers []*Server
Extensions map[string]any Extensions map[string]any
low *low.Operation low *low.Operation
@@ -42,6 +42,7 @@ func NewOperation(operation *low.Operation) *Operation {
} }
o.Tags = tags o.Tags = tags
o.Summary = operation.Summary.Value o.Summary = operation.Summary.Value
o.Deprecated = &operation.Deprecated.Value
o.Description = operation.Description.Value o.Description = operation.Description.Value
if !operation.ExternalDocs.IsEmpty() { if !operation.ExternalDocs.IsEmpty() {
o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value) o.ExternalDocs = base.NewExternalDoc(operation.ExternalDocs.Value)
@@ -61,7 +62,11 @@ func NewOperation(operation *low.Operation) *Operation {
o.Responses = NewResponses(operation.Responses.Value) o.Responses = NewResponses(operation.Responses.Value)
} }
if !operation.Security.IsEmpty() { 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 var servers []*Server
for i := range operation.Servers.Value { for i := range operation.Servers.Value {

View File

@@ -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
}

View File

@@ -1,7 +1,7 @@
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley // Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
package v2 package base
import ( import (
"crypto/sha256" "crypto/sha256"
@@ -13,15 +13,16 @@ import (
"strings" "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 // 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). // 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 // 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/v2/#securityDefinitionsObject
// - https://swagger.io/specification/#security-requirement-object
type SecurityRequirement struct { 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) // 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], 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, Value: valueMap,
ValueNode: root, ValueNode: root,
} }
return nil 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 // Hash will return a consistent SHA256 Hash of the SecurityRequirement object
func (s *SecurityRequirement) Hash() [32]byte { func (s *SecurityRequirement) Hash() [32]byte {
var f []string var f []string
values := make(map[string][]string, len(s.Values.Value)) values := make(map[string][]string, len(s.Requirements.Value))
var valKeys []string var valKeys []string
for k := range s.Values.Value { for k := range s.Requirements.Value {
var vals []string var vals []string
for y := range s.Values.Value[k].Value { for y := range s.Requirements.Value[k].Value {
vals = append(vals, s.Values.Value[k].Value[y].Value) vals = append(vals, s.Requirements.Value[k].Value[y].Value)
// lol, I know. -------^^^^^ <- this is the actual value. // lol, I know. -------^^^^^ <- this is the actual value.
} }
sort.Strings(vals) sort.Strings(vals)

View File

@@ -487,7 +487,7 @@ func ExtractMap[PT Buildable[N], N any](
return nil, labelNode, valueNode, nil 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 // Maps
// map[string]interface{} for maps // map[string]interface{} for maps

View File

@@ -30,7 +30,7 @@ type Operation struct {
Responses low.NodeReference[*Responses] Responses low.NodeReference[*Responses]
Schemes low.NodeReference[[]low.ValueReference[string]] Schemes low.NodeReference[[]low.ValueReference[string]]
Deprecated low.NodeReference[bool] 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] 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 o.Responses = respBody
// extract parameters // extract security
sec, sln, svn, sErr := low.ExtractArray[*SecurityRequirement](SecurityLabel, root, idx) sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx)
if sErr != nil { if sErr != nil {
return sErr return sErr
} }
if sec != nil { if sec != nil {
o.Security = low.NodeReference[[]low.ValueReference[*SecurityRequirement]]{ o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
Value: sec, Value: sec,
KeyNode: sln, KeyNode: sln,
ValueNode: svn, ValueNode: svn,

View File

@@ -44,7 +44,7 @@ type Swagger struct {
// The basePath does not support path templating. // The basePath does not support path templating.
BasePath low.NodeReference[string] 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 // If the schemes is not included, the default scheme to be used is the one used to access
// the Swagger definition itself. // the Swagger definition itself.
Schemes low.NodeReference[[]low.ValueReference[string]] 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 // 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. // requirements). Individual operations can override this definition.
// - https://swagger.io/specification/v2/#securityRequirementObject // - 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. // 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 // 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) { 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 { if err != nil {
e <- err e <- err
return return
} }
doc.Security = low.NodeReference[[]low.ValueReference[*SecurityRequirement]]{ doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
Value: sec, Value: sec,
KeyNode: ln, KeyNode: ln,
ValueNode: vn, ValueNode: vn,

View File

@@ -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 { func extractSecurity(info *datamodel.SpecInfo, doc *Document, idx *index.SpecIndex) error {
sec, sErr := low.ExtractObject[*SecurityRequirement](SecurityLabel, info.RootNode, idx) sec, ln, vn, err := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, info.RootNode, idx)
if sErr != nil { if err != nil {
return sErr return err
}
doc.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
Value: sec,
KeyNode: ln,
ValueNode: vn,
} }
doc.Security = sec
return nil return nil
} }

View File

@@ -317,11 +317,7 @@ func TestCreateDocument_Paths(t *testing.T) {
assert.Equal(t, "$response.body#/id", burgerIdParam.Value) assert.Equal(t, "$response.body#/id", burgerIdParam.Value)
// check security requirements // check security requirements
security := burgersPost.Security.Value oAuthReq := burgersPost.FindSecurityRequirement("OAuthScheme")
assert.NotNil(t, security)
assert.Len(t, security.ValueRequirements, 1)
oAuthReq := security.FindRequirement("OAuthScheme")
assert.Len(t, oAuthReq, 2) assert.Len(t, oAuthReq, 2)
assert.Equal(t, "read:burgers", oAuthReq[0].Value) 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) { func TestCreateDocument_Doc_Security(t *testing.T) {
initTest() initTest()
security := doc.Security.Value oAuth := doc.FindSecurityRequirement("OAuthScheme")
assert.NotNil(t, security)
assert.Len(t, security.ValueRequirements, 1)
oAuth := security.FindRequirement("OAuthScheme")
assert.Len(t, oAuth, 2) assert.Len(t, oAuth, 2)
} }

View File

@@ -59,7 +59,7 @@ type Document struct {
// to authorize a request. Individual operations can override this definition. To make security optional, // to authorize a request. Individual operations can override this definition. To make security optional,
// an empty security requirement ({}) can be included in the array. // an empty security requirement ({}) can be included in the array.
// - https://spec.openapis.org/oas/v3.1.0#security-requirement-object // - 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 // 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 // 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 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. // TODO: this is early prototype mutation/modification code, keeping it around for later.
//func (d *Document) AddTag() *base.Tag { //func (d *Document) AddTag() *base.Tag {
// t := base.NewTag() // t := base.NewTag()

View File

@@ -30,7 +30,7 @@ type Operation struct {
Responses low.NodeReference[*Responses] Responses low.NodeReference[*Responses]
Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]] Callbacks low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*Callback]]
Deprecated low.NodeReference[bool] Deprecated low.NodeReference[bool]
Security low.NodeReference[*SecurityRequirement] Security low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]
Servers low.NodeReference[[]low.ValueReference[*Server]] Servers low.NodeReference[[]low.ValueReference[*Server]]
Extensions map[low.KeyReference[string]]low.ValueReference[any] 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) 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. // Build will extract external docs, parameters, request body, responses, callbacks, security and servers.
func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error { func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
o.Extensions = low.ExtractExtensions(root) o.Extensions = low.ExtractExtensions(root)
@@ -92,11 +104,17 @@ func (o *Operation) Build(root *yaml.Node, idx *index.SpecIndex) error {
} }
// extract security // extract security
sec, sErr := low.ExtractObject[*SecurityRequirement](SecurityLabel, root, idx) sec, sln, svn, sErr := low.ExtractArray[*base.SecurityRequirement](SecurityLabel, root, idx)
if sErr != nil { if sErr != nil {
return sErr return sErr
} }
o.Security = sec if sec != nil {
o.Security = low.NodeReference[[]low.ValueReference[*base.SecurityRequirement]]{
Value: sec,
KeyNode: sln,
ValueNode: svn,
}
}
// extract servers // extract servers
servers, sl, sn, serErr := low.ExtractArray[*Server](ServersLabel, root, idx) servers, sl, sn, serErr := low.ExtractArray[*Server](ServersLabel, root, idx)

View File

@@ -65,10 +65,10 @@ servers:
assert.Equal(t, "a nice callback", assert.Equal(t, "a nice callback",
n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value) n.FindCallback("niceCallback").Value.FindExpression("ohISee").Value.Description.Value)
assert.True(t, n.Deprecated.Value) assert.True(t, n.Deprecated.Value)
assert.Len(t, n.Security.Value.ValueRequirements, 1) assert.Len(t, n.Security.Value, 1)
assert.Len(t, n.Security.Value.FindRequirement("books"), 2) assert.Len(t, n.FindSecurityRequirement("books"), 2)
assert.Equal(t, "read:books", n.Security.Value.FindRequirement("books")[0].Value) assert.Equal(t, "read:books", n.FindSecurityRequirement("books")[0].Value)
assert.Equal(t, "write:books", n.Security.Value.FindRequirement("books")[1].Value) assert.Equal(t, "write:books", n.FindSecurityRequirement("books")[1].Value)
assert.Len(t, n.Servers.Value, 1) assert.Len(t, n.Servers.Value, 1)
assert.Equal(t, "https://pb33f.io", n.Servers.Value[0].Value.URL.Value) assert.Equal(t, "https://pb33f.io", n.Servers.Value[0].Value.URL.Value)
} }

View File

@@ -8,9 +8,7 @@ import (
"fmt" "fmt"
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"sort"
"strings" "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 // 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. // 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 // - https://spec.openapis.org/oas/v3.1.0#security-requirement-object
type SecurityRequirement struct { //type SecurityRequirement struct {
//
// FYI, I hate this data structure. Even without the low level wrapping, it sucks. // // 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]]] // ValueRequirements []low.ValueReference[map[low.KeyReference[string]]low.ValueReference[[]low.ValueReference[string]]]
} //}
// FindExtension attempts to locate an extension using the supplied key. // FindExtension attempts to locate an extension using the supplied key.
func (ss *SecurityScheme) FindExtension(ext string) *low.ValueReference[any] { 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, "|"))) 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, "|")))
}

View File

@@ -5,6 +5,7 @@ package v3
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index" "github.com/pb33f/libopenapi/index"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -12,7 +13,7 @@ import (
) )
func TestSecurityRequirement_Build(t *testing.T) { func TestSecurityRequirement_Build(t *testing.T) {
yml := `- something: yml := `something:
- read:me - read:me
- write:me` - write:me`
@@ -20,13 +21,14 @@ func TestSecurityRequirement_Build(t *testing.T) {
_ = yaml.Unmarshal([]byte(yml), &idxNode) _ = yaml.Unmarshal([]byte(yml), &idxNode)
idx := index.NewSpecIndex(&idxNode) idx := index.NewSpecIndex(&idxNode)
var n SecurityRequirement var n base.SecurityRequirement
err := low.BuildModel(&idxNode, &n) err := low.BuildModel(&idxNode, &n)
assert.NoError(t, err) assert.NoError(t, err)
err = n.Build(idxNode.Content[0], idx) err = n.Build(idxNode.Content[0], idx)
assert.NoError(t, err) 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, "read:me", n.FindRequirement("something")[0].Value)
assert.Equal(t, "write:me", n.FindRequirement("something")[1].Value) assert.Equal(t, "write:me", n.FindRequirement("something")[1].Value)
assert.Nil(t, n.FindRequirement("none")) assert.Nil(t, n.FindRequirement("none"))

View File

@@ -5,10 +5,9 @@ package model
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "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" "github.com/pb33f/libopenapi/datamodel/low/v3"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"reflect"
) )
type SecurityRequirementChanges struct { type SecurityRequirementChanges struct {
@@ -33,76 +32,15 @@ func addedSecurityRequirement(vn *yaml.Node, name string, changes *[]*Change) {
nil, vn, false, nil, name) nil, vn, false, nil, name)
} }
func CompareSecurityRequirement(l, r any) *SecurityRequirementChanges { func CompareSecurityRequirement(l, r *base.SecurityRequirement) *SecurityRequirementChanges {
var changes []*Change var changes []*Change
sc := new(SecurityRequirementChanges) sc := new(SecurityRequirementChanges)
if reflect.TypeOf(&v2.SecurityRequirement{}) == reflect.TypeOf(l) && if low.AreEqual(l, r) {
reflect.TypeOf(&v2.SecurityRequirement{}) == reflect.TypeOf(r) { return nil
lSec := l.(*v2.SecurityRequirement)
rSec := r.(*v2.SecurityRequirement)
if low.AreEqual(lSec, rSec) {
return nil
}
checkSecurityRequirement(lSec.Values.Value, rSec.Values.Value, &changes)
} }
checkSecurityRequirement(l.Requirements.Value, r.Requirements.Value, &changes)
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])
}
}
}
sc.Changes = changes sc.Changes = changes
return sc 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)
}

View File

@@ -5,8 +5,7 @@ package model
import ( import (
"github.com/pb33f/libopenapi/datamodel/low" "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"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"testing" "testing"
@@ -27,15 +26,15 @@ func TestCompareSecurityRequirement_V2(t *testing.T) {
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Nil(t, extChanges) assert.Nil(t, extChanges)
} }
@@ -60,15 +59,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -92,15 +91,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&rDoc, &lDoc) extChanges := CompareSecurityRequirement(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges())
} }
@@ -124,15 +123,15 @@ milk:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 4, extChanges.TotalChanges()) assert.Equal(t, 4, extChanges.TotalChanges())
assert.Equal(t, 2, extChanges.TotalBreakingChanges()) assert.Equal(t, 2, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
@@ -160,15 +159,15 @@ milk:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 2, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
@@ -195,15 +194,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -233,15 +232,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 2, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
@@ -267,15 +266,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 3, extChanges.TotalChanges()) assert.Equal(t, 3, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges())
} }
@@ -301,15 +300,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Nil(t, extChanges) assert.Nil(t, extChanges)
} }
@@ -333,15 +332,15 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&rDoc, &lDoc) extChanges := CompareSecurityRequirement(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalChanges()) assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) assert.Equal(t, 1, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
@@ -369,167 +368,168 @@ biscuit:
_ = yaml.Unmarshal([]byte(right), &rNode) _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects // create low level objects
var lDoc v2.SecurityRequirement var lDoc base.SecurityRequirement
var rDoc v2.SecurityRequirement var rDoc base.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) _ = low.BuildModel(&lNode, &lDoc)
_ = low.BuildModel(&rNode, &rDoc) _ = low.BuildModel(&rNode, &rDoc)
_ = lDoc.Build(lNode.Content[0], nil) _ = lDoc.Build(lNode.Content[0], nil)
_ = rDoc.Build(rNode.Content[0], nil) _ = rDoc.Build(rNode.Content[0], nil)
// compare // compare
extChanges := CompareSecurityRequirementV2(&lDoc, &rDoc) extChanges := CompareSecurityRequirement(&lDoc, &rDoc)
assert.Equal(t, 2, extChanges.TotalChanges()) assert.Equal(t, 2, extChanges.TotalChanges())
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) assert.Equal(t, 0, extChanges.TotalBreakingChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
} }
func TestCompareSecurityRequirement_V3(t *testing.T) { //
//func TestCompareSecurityRequirement_V3(t *testing.T) {
left := `- auth: //
- pizza // left := `- auth:
- pie` // - pizza
// - pie`
right := `- auth: //
- pie // right := `- auth:
- pizza` // - pie
// - pizza`
var lNode, rNode yaml.Node //
_ = yaml.Unmarshal([]byte(left), &lNode) // var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(right), &rNode) // _ = yaml.Unmarshal([]byte(left), &lNode)
// _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects //
var lDoc v3.SecurityRequirement // // create low level objects
var rDoc v3.SecurityRequirement // var lDoc v3.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) // var rDoc v3.SecurityRequirement
_ = low.BuildModel(&rNode, &rDoc) // _ = low.BuildModel(&lNode, &lDoc)
_ = lDoc.Build(lNode.Content[0], nil) // _ = low.BuildModel(&rNode, &rDoc)
_ = rDoc.Build(rNode.Content[0], nil) // _ = lDoc.Build(lNode.Content[0], nil)
// _ = rDoc.Build(rNode.Content[0], nil)
// compare //
extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) // // compare
assert.Nil(t, extChanges) // extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc)
} // assert.Nil(t, extChanges)
//}
func TestCompareSecurityRequirement_V3_AddARole(t *testing.T) { //
//func TestCompareSecurityRequirement_V3_AddARole(t *testing.T) {
left := `- auth: //
- pizza // left := `- auth:
- pie` // - pizza
// - pie`
right := `- auth: //
- pie // right := `- auth:
- pizza // - pie
- beer` // - pizza
// - beer`
var lNode, rNode yaml.Node //
_ = yaml.Unmarshal([]byte(left), &lNode) // var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(right), &rNode) // _ = yaml.Unmarshal([]byte(left), &lNode)
// _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects //
var lDoc v3.SecurityRequirement // // create low level objects
var rDoc v3.SecurityRequirement // var lDoc v3.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) // var rDoc v3.SecurityRequirement
_ = low.BuildModel(&rNode, &rDoc) // _ = low.BuildModel(&lNode, &lDoc)
_ = lDoc.Build(lNode.Content[0], nil) // _ = low.BuildModel(&rNode, &rDoc)
_ = rDoc.Build(rNode.Content[0], nil) // _ = lDoc.Build(lNode.Content[0], nil)
// _ = rDoc.Build(rNode.Content[0], nil)
// compare //
extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) // // compare
assert.Equal(t, 1, extChanges.TotalChanges()) // extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc)
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) // assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) // assert.Equal(t, 0, extChanges.TotalBreakingChanges())
} // assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
//}
func TestCompareSecurityRequirement_V3_RemoveRole(t *testing.T) { //
//func TestCompareSecurityRequirement_V3_RemoveRole(t *testing.T) {
left := `- auth: //
- pizza // left := `- auth:
- pie` // - pizza
// - pie`
right := `- auth: //
- pie // right := `- auth:
- pizza // - pie
- beer` // - pizza
// - beer`
var lNode, rNode yaml.Node //
_ = yaml.Unmarshal([]byte(left), &lNode) // var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(right), &rNode) // _ = yaml.Unmarshal([]byte(left), &lNode)
// _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects //
var lDoc v3.SecurityRequirement // // create low level objects
var rDoc v3.SecurityRequirement // var lDoc v3.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) // var rDoc v3.SecurityRequirement
_ = low.BuildModel(&rNode, &rDoc) // _ = low.BuildModel(&lNode, &lDoc)
_ = lDoc.Build(lNode.Content[0], nil) // _ = low.BuildModel(&rNode, &rDoc)
_ = rDoc.Build(rNode.Content[0], nil) // _ = lDoc.Build(lNode.Content[0], nil)
// _ = rDoc.Build(rNode.Content[0], nil)
// compare //
extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) // // compare
assert.Equal(t, 1, extChanges.TotalChanges()) // extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) // assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) // assert.Equal(t, 1, extChanges.TotalBreakingChanges())
} // assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
//}
func TestCompareSecurityRequirement_V3_AddAReq(t *testing.T) { //
//func TestCompareSecurityRequirement_V3_AddAReq(t *testing.T) {
left := `- auth: //
- pizza // left := `- auth:
- pie` // - pizza
// - pie`
right := `- auth: //
- pie // right := `- auth:
- pizza // - pie
- coffee: // - pizza
- filter //- coffee:
- espresso` // - filter
// - espresso`
var lNode, rNode yaml.Node //
_ = yaml.Unmarshal([]byte(left), &lNode) // var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(right), &rNode) // _ = yaml.Unmarshal([]byte(left), &lNode)
// _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects //
var lDoc v3.SecurityRequirement // // create low level objects
var rDoc v3.SecurityRequirement // var lDoc v3.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) // var rDoc v3.SecurityRequirement
_ = low.BuildModel(&rNode, &rDoc) // _ = low.BuildModel(&lNode, &lDoc)
_ = lDoc.Build(lNode.Content[0], nil) // _ = low.BuildModel(&rNode, &rDoc)
_ = rDoc.Build(rNode.Content[0], nil) // _ = lDoc.Build(lNode.Content[0], nil)
// _ = rDoc.Build(rNode.Content[0], nil)
// compare //
extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc) // // compare
assert.Equal(t, 1, extChanges.TotalChanges()) // extChanges := CompareSecurityRequirementV3(&lDoc, &rDoc)
assert.Equal(t, 0, extChanges.TotalBreakingChanges()) // assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType) // assert.Equal(t, 0, extChanges.TotalBreakingChanges())
} // assert.Equal(t, ObjectAdded, extChanges.Changes[0].ChangeType)
//}
func TestCompareSecurityRequirement_V3_RemoveAReq(t *testing.T) { //
//func TestCompareSecurityRequirement_V3_RemoveAReq(t *testing.T) {
left := `- coffee: //
- filter // left := `- coffee:
- espresso` // - filter
// - espresso`
right := `- coffee: //
- filter // right := `- coffee:
- espresso // - filter
- auth: // - espresso
- pizza //- auth:
- pie` // - pizza
// - pie`
var lNode, rNode yaml.Node //
_ = yaml.Unmarshal([]byte(left), &lNode) // var lNode, rNode yaml.Node
_ = yaml.Unmarshal([]byte(right), &rNode) // _ = yaml.Unmarshal([]byte(left), &lNode)
// _ = yaml.Unmarshal([]byte(right), &rNode)
// create low level objects //
var lDoc v3.SecurityRequirement // // create low level objects
var rDoc v3.SecurityRequirement // var lDoc v3.SecurityRequirement
_ = low.BuildModel(&lNode, &lDoc) // var rDoc v3.SecurityRequirement
_ = low.BuildModel(&rNode, &rDoc) // _ = low.BuildModel(&lNode, &lDoc)
_ = lDoc.Build(lNode.Content[0], nil) // _ = low.BuildModel(&rNode, &rDoc)
_ = rDoc.Build(rNode.Content[0], nil) // _ = lDoc.Build(lNode.Content[0], nil)
// _ = rDoc.Build(rNode.Content[0], nil)
// compare //
extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc) // // compare
assert.Equal(t, 1, extChanges.TotalChanges()) // extChanges := CompareSecurityRequirementV3(&rDoc, &lDoc)
assert.Equal(t, 1, extChanges.TotalBreakingChanges()) // assert.Equal(t, 1, extChanges.TotalChanges())
assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType) // assert.Equal(t, 1, extChanges.TotalBreakingChanges())
} // assert.Equal(t, ObjectRemoved, extChanges.Changes[0].ChangeType)
//}