Skip to content

Commit

Permalink
Add more checks (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
blva authored Jun 29, 2023
1 parent e93e1ba commit 5d42683
Show file tree
Hide file tree
Showing 41 changed files with 2,175 additions and 96 deletions.
68 changes: 48 additions & 20 deletions BREAKING-CHANGES-EXAMPLES.md

Large diffs are not rendered by default.

166 changes: 166 additions & 0 deletions checker/check-api-security-updated.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package checker

import (
"fmt"

"github.com/tufin/oasdiff/diff"
)

const (
APISecurityRemovedCheckId = "api-security-removed"
APISecurityAddedCheckId = "api-security-added"
APISecurityScopeAddedId = "api-security-scope-added"
APISecurityScopeRemovedId = "api-security-scope-removed"
APIGlobalSecurityRemovedCheckId = "api-global-security-removed"
APIGlobalSecurityAddedCheckId = "api-global-security-added"
APIGlobalSecurityScopeAddedId = "api-global-security-scope-added"
APIGlobalSecurityScopeRemovedId = "api-global-security-scope-removed"
)

func checkGlobalSecurity(diffReport *diff.Diff, operationsSources *diff.OperationsSourcesMap, config BackwardCompatibilityCheckConfig) []BackwardCompatibilityError {
result := make([]BackwardCompatibilityError, 0)
if diffReport.SecurityDiff == nil {
return result
}

for _, addedSecurity := range diffReport.SecurityDiff.Added {
result = append(result, BackwardCompatibilityError{
Id: APIGlobalSecurityAddedCheckId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APIGlobalSecurityAddedCheckId), ColorizedValue(addedSecurity)),
Operation: "N/A",
Path: "",
Source: "security." + addedSecurity,
OperationId: "N/A",
})
}

for _, removedSecurity := range diffReport.SecurityDiff.Deleted {
result = append(result, BackwardCompatibilityError{
Id: APIGlobalSecurityRemovedCheckId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APIGlobalSecurityRemovedCheckId), ColorizedValue(removedSecurity)),
Operation: "N/A",
Path: "",
Source: "security." + removedSecurity,
OperationId: "N/A",
})
}

for _, updatedSecurity := range diffReport.SecurityDiff.Modified {
for securitySchemeName, updatedSecuritySchemeScopes := range updatedSecurity {
for _, addedScope := range updatedSecuritySchemeScopes.Added {
result = append(result, BackwardCompatibilityError{
Id: APIGlobalSecurityScopeAddedId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APIGlobalSecurityScopeAddedId), ColorizedValue(addedScope), ColorizedValue(securitySchemeName)),
Operation: "N/A",
Path: "",
Source: "security.scopes." + addedScope,
OperationId: "N/A",
})
}
for _, deletedScope := range updatedSecuritySchemeScopes.Deleted {
result = append(result, BackwardCompatibilityError{
Id: APIGlobalSecurityScopeRemovedId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APIGlobalSecurityScopeRemovedId), ColorizedValue(deletedScope), ColorizedValue(securitySchemeName)),
Operation: "N/A",
Path: "",
Source: "security.scopes." + deletedScope,
OperationId: "N/A",
})
}
}
}

return result

}

func APISecurityUpdatedCheck(diffReport *diff.Diff, operationsSources *diff.OperationsSourcesMap, config BackwardCompatibilityCheckConfig) []BackwardCompatibilityError {
result := make([]BackwardCompatibilityError, 0)

result = append(result, checkGlobalSecurity(diffReport, operationsSources, config)...)

if diffReport.PathsDiff == nil || diffReport.PathsDiff.Modified == nil {
return result
}

for path, pathItem := range diffReport.PathsDiff.Modified {
if pathItem.OperationsDiff == nil {
continue
}
for operation, operationItem := range pathItem.OperationsDiff.Modified {

source := (*operationsSources)[operationItem.Revision]

if operationItem.SecurityDiff == nil {
continue
}

for _, addedSecurity := range operationItem.SecurityDiff.Added {
if addedSecurity == "" {
continue
}
result = append(result, BackwardCompatibilityError{
Id: APISecurityAddedCheckId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APISecurityAddedCheckId), ColorizedValue(addedSecurity)),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}

for _, deletedSecurity := range operationItem.SecurityDiff.Deleted {
if deletedSecurity == "" {
continue
}
result = append(result, BackwardCompatibilityError{
Id: APISecurityRemovedCheckId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APISecurityRemovedCheckId), ColorizedValue(deletedSecurity)),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}

for _, updatedSecurity := range operationItem.SecurityDiff.Modified {
if updatedSecurity.Empty() {
continue
}
for securitySchemeName, updatedSecuritySchemeScopes := range updatedSecurity {
for _, addedScope := range updatedSecuritySchemeScopes.Added {
result = append(result, BackwardCompatibilityError{
Id: APISecurityScopeAddedId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APISecurityScopeAddedId), ColorizedValue(addedScope), ColorizedValue(securitySchemeName)),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}
for _, deletedScope := range updatedSecuritySchemeScopes.Deleted {
result = append(result, BackwardCompatibilityError{
Id: APISecurityScopeRemovedId,
Level: INFO,
Text: fmt.Sprintf(config.i18n(APISecurityScopeRemovedId), ColorizedValue(deletedScope), ColorizedValue(securitySchemeName)),
Operation: operation,
OperationId: operationItem.Revision.OperationID,
Path: path,
Source: source,
})
}
}
}

}
}

return result
}
195 changes: 195 additions & 0 deletions checker/check-api-security-updated_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package checker_test

import (
"testing"

"github.com/stretchr/testify/require"
"github.com/tufin/oasdiff/checker"
"github.com/tufin/oasdiff/diff"
)

// CL: Adding a new global security to the API
func TestAPIGlobalSecurityyAdded(t *testing.T) {
s1, _ := open("../data/checker/api_security_global_added_base.yaml")
s2, err := open("../data/checker/api_security_global_added_revision.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-global-security-added",
Text: "the security scheme 'petstore_auth' was added to the API",
Comment: "",
Level: checker.INFO,
Operation: "N/A",
Path: "",
Source: "security.petstore_auth",
OperationId: "N/A",
}}, errs)
}

// CL: Removing a global security from the API
func TestAPIGlobalSecurityyDeleted(t *testing.T) {
s1, _ := open("../data/checker/api_security_global_added_revision.yaml")
s2, err := open("../data/checker/api_security_global_added_base.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-global-security-removed",
Text: "the security scheme 'petstore_auth' was removed from the API",
Comment: "",
Level: checker.INFO,
Operation: "N/A",
Path: "",
Source: "security.petstore_auth",
OperationId: "N/A",
}}, errs)
}

// CL: Removing a security scope from an API global security
func TestAPIGlobalSecurityScopeRemoved(t *testing.T) {
s1, _ := open("../data/checker/api_security_global_added_revision.yaml")
s2, err := open("../data/checker/api_security_global_added_revision.yaml")
require.Empty(t, err)

s2.Spec.Security[0]["petstore_auth"] = s2.Spec.Security[0]["petstore_auth"][:1]
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-global-security-scope-removed",
Text: "the security scope 'read:pets' was removed from the global security scheme 'petstore_auth'",
Comment: "",
Level: checker.INFO,
Operation: "N/A",
Path: "",
Source: "security.scopes.read:pets",
OperationId: "N/A",
}}, errs)
}

// CL: Adding a security scope from an API global security
func TestAPIGlobalSecurityScopeAdded(t *testing.T) {
s1, _ := open("../data/checker/api_security_global_added_revision.yaml")
s2, err := open("../data/checker/api_security_global_added_revision.yaml")
require.Empty(t, err)

s1.Spec.Security[0]["petstore_auth"] = s2.Spec.Security[0]["petstore_auth"][:1]
d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-global-security-scope-added",
Text: "the security scope 'read:pets' was added to the global security scheme 'petstore_auth'",
Comment: "",
Level: checker.INFO,
Operation: "N/A",
Path: "",
Source: "security.scopes.read:pets",
OperationId: "N/A",
}}, errs)
}

// CL: Adding a new security to the API endpoint
func TestAPISecurityAdded(t *testing.T) {
s1, _ := open("../data/checker/api_security_added_base.yaml")
s2, err := open("../data/checker/api_security_added_revision.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-security-added",
Text: "the endpoint scheme security 'petstore_auth' was added to the API",
Comment: "",
Level: checker.INFO,
Operation: "POST",
Path: "/subscribe",
Source: "../data/checker/api_security_added_revision.yaml",
OperationId: "",
}}, errs)
}

// CL: Removing a new security to the API endpoint
func TestAPISecurityDeleted(t *testing.T) {
s1, _ := open("../data/checker/api_security_added_revision.yaml")
s2, err := open("../data/checker/api_security_added_base.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-security-removed",
Text: "the endpoint scheme security 'petstore_auth' was removed from the API",
Comment: "",
Level: checker.INFO,
Operation: "POST",
Path: "/subscribe",
Source: "../data/checker/api_security_added_base.yaml",
OperationId: "",
}}, errs)
}

// CL: Removing a security scope from an API endpoint security
func TestAPISecurityScopeRemoved(t *testing.T) {
s1, _ := open("../data/checker/api_security_updated_base.yaml")
s2, err := open("../data/checker/api_security_updated_revision.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-security-scope-removed",
Text: "the security scope 'read:pets' was removed from the endpoint's security scheme 'petstore_auth'",
Comment: "",
Level: checker.INFO,
Operation: "POST",
Path: "/subscribe",
Source: "../data/checker/api_security_updated_revision.yaml",
OperationId: "",
}}, errs)
}

// CL: Adding a security scope to an API endpoint security
func TestAPISecurityScopeAdded(t *testing.T) {
s1, _ := open("../data/checker/api_security_updated_revision.yaml")
s2, err := open("../data/checker/api_security_updated_base.yaml")
require.Empty(t, err)

d, osm, err := diff.GetWithOperationsSourcesMap(getConfig(), s1, s2)
require.NoError(t, err)
errs := checker.CheckBackwardCompatibilityUntilLevel(singleCheckConfig(checker.APISecurityUpdatedCheck), d, osm, checker.INFO)
require.NotEmpty(t, errs)
require.Equal(t, checker.BackwardCompatibilityErrors{
{
Id: "api-security-scope-added",
Text: "the security scope 'read:pets' was added to the endpoint's security scheme 'petstore_auth'",
Comment: "",
Level: checker.INFO,
Operation: "POST",
Path: "/subscribe",
Source: "../data/checker/api_security_updated_base.yaml",
OperationId: "",
}}, errs)
}
Loading

0 comments on commit 5d42683

Please sign in to comment.