Skip to content

Commit

Permalink
extracted circular referenences back out
Browse files Browse the repository at this point in the history
just general better handling of circular references from libopenapi

also added a `debug` flag to allow log debugging to be turned on for the `lint` command.

Signed-off-by: quobix <dave@quobix.com>
  • Loading branch information
daveshanley committed Dec 3, 2023
1 parent af9879a commit ab09d18
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 7 deletions.
8 changes: 7 additions & 1 deletion cmd/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func GetLintCommand() *cobra.Command {
baseFlag, _ := cmd.Flags().GetString("base")
skipCheckFlag, _ := cmd.Flags().GetBool("skip-check")
remoteFlag, _ := cmd.Flags().GetBool("remote")
debugFlag, _ := cmd.Flags().GetBool("debug")

// disable color and styling, for CI/CD use.
// https://github.com/daveshanley/vacuum/issues/234
Expand All @@ -75,11 +76,16 @@ func GetLintCommand() *cobra.Command {
mf = true
}

logLevel := pterm.LogLevelError
if debugFlag {
logLevel = pterm.LogLevelDebug
}

// setup logging
handler := pterm.NewSlogHandler(&pterm.Logger{
Formatter: pterm.LogFormatterColorful,
Writer: os.Stdout,
Level: pterm.LogLevelError,
Level: logLevel,
ShowTime: false,
MaxWidth: 280,
KeyStyles: map[string]pterm.Style{
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func GetRootCommand() *cobra.Command {
rootCmd.PersistentFlags().StringP("base", "p", "", "Override Base URL or path to use for resolving local file based or remote references")
rootCmd.PersistentFlags().BoolP("remote", "u", true, "Allow local files and remote (http) references to be looked up")
rootCmd.PersistentFlags().BoolP("skip-check", "k", false, "Skip checking for a valid OpenAPI document, useful for linting fragments or non-OpenAPI documents")
rootCmd.PersistentFlags().BoolP("debug", "w", false, "Turn on debug logging")

regErr := rootCmd.RegisterFlagCompletionFunc("functions", cobra.FixedCompletions(
[]string{"so"}, cobra.ShellCompDirectiveFilterFileExt,
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/gizak/termui/v3 v3.1.0
github.com/json-iterator/go v1.1.12
github.com/mitchellh/mapstructure v1.5.0
github.com/pb33f/libopenapi v0.13.19
github.com/pb33f/libopenapi v0.13.20
github.com/pb33f/libopenapi-validator v0.0.32
github.com/pterm/pterm v0.12.71
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pb33f/libopenapi v0.13.19 h1:oFkaQuKx5ZaLwYuHv4W2QeDb+Pm4SU4xqgQdcy2XH58=
github.com/pb33f/libopenapi v0.13.19/go.mod h1:Lv2eEtsAtbRFlF8hjH82L8SIGoUNgemMVoKoB6A9THk=
github.com/pb33f/libopenapi v0.13.20 h1:u07mWNSL30sO8nj+kRjM9mDcqxOxq+Etso/oUFflvU4=
github.com/pb33f/libopenapi v0.13.20/go.mod h1:Lv2eEtsAtbRFlF8hjH82L8SIGoUNgemMVoKoB6A9THk=
github.com/pb33f/libopenapi-validator v0.0.32 h1:jM+IsUT8I0JOtdkgacGVQmTJayQ2AO5P6URI2HxN11g=
github.com/pb33f/libopenapi-validator v0.0.32/go.mod h1:1HbsnP1IVFEaLFtbK9eZXRqUpvtQEGmdstqbgMG+72A=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
Expand Down
4 changes: 2 additions & 2 deletions model/test_files/circular-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ components:
properties:
testThing:
"$ref": "#/components/schemas/One"
anyOf:
- "$ref": "#/components/schemas/Four"
anyOf:
- "$ref": "#/components/schemas/Four"
required:
- testThing
- anyOf
Expand Down
39 changes: 39 additions & 0 deletions motor/rule_applicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
version := docResolved.GetVersion()

var resolvingErrors []*index.ResolvingError
var circularReferences []*index.CircularReferenceResult

var rolodexResolved, rolodexUnresolved *index.Rolodex

Expand All @@ -265,6 +266,11 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
specResolved = rolodexResolved.GetRootIndex().GetRootNode()
specUnresolved = rolodexUnresolved.GetRootIndex().GetRootNode()

if rolodexResolved != nil && rolodexResolved.GetRootIndex() != nil {
resolvingErrors = rolodexResolved.GetRootIndex().GetResolver().GetResolvingErrors()
circularReferences = rolodexResolved.GetRootIndex().GetResolver().GetCircularReferences()
}

case '3':
_, resolvedModelErrors = docResolved.BuildV3Model()
rolodexResolved = docResolved.GetRolodex()
Expand All @@ -283,6 +289,7 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {

if rolodexResolved != nil && rolodexResolved.GetRootIndex() != nil {
resolvingErrors = rolodexResolved.GetRootIndex().GetResolver().GetResolvingErrors()
circularReferences = rolodexResolved.GetRootIndex().GetResolver().GetCircularReferences()
}

}
Expand Down Expand Up @@ -326,6 +333,7 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {

if rolodexResolved != nil && rolodexResolved.GetRootIndex() != nil {
resolvingErrors = rolodexResolved.GetRootIndex().GetResolver().GetResolvingErrors()
circularReferences = rolodexResolved.GetRootIndex().GetResolver().GetCircularReferences()
}
}

Expand Down Expand Up @@ -354,6 +362,24 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
HowToFix: "Ensure that all $ref values are resolvable and locatable within a local or remote document. " + CircularReferencesFix,
}

// add all circular reference errors to the results.
circularRefRule := &model.Rule{
Name: "Circular References",
Id: "circular-references",
Description: "Circular reference detected",
Message: "Circular reference detected",
Given: "$",
Resolved: false,
Recommended: true,
RuleCategory: model.RuleCategories[model.CategorySchemas],
Type: "validation",
Severity: model.SeverityWarn,
Then: model.RuleAction{
Function: "blank",
},
HowToFix: CircularReferencesFix,
}

// add all resolving errors to the results.
for _, er := range resolvingErrors {
res := model.RuleFunctionResult{
Expand All @@ -367,6 +393,19 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
ruleResults = append(ruleResults, res)
}

// add all circular references to the results.
for _, cr := range circularReferences {
res := model.RuleFunctionResult{
RuleId: "circular-references",
Rule: circularRefRule,
StartNode: cr.Start.Node,
EndNode: cr.LoopPoint.Node,
Message: fmt.Sprintf("Circular reference detected from %s", cr.Start.Definition),
Path: cr.GenerateJourneyPath(),
}
ruleResults = append(ruleResults, res)
}

for _, er := range indexResolved.GetReferenceIndexErrors() {
var idxError *index.IndexingError
errors.As(er, &idxError)
Expand Down
2 changes: 1 addition & 1 deletion motor/rule_applicator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1882,7 +1882,7 @@ components:
assert.Len(t, results.Errors, 0)

assert.NotNil(t, results)
assert.Equal(t, "infinite circular reference detected: one: one -> two -> one [14:7]",
assert.Equal(t, "infinite circular reference detected: #/components/schemas/one: one -> two -> one [14:7]",
results.Results[0].Message)
assert.Equal(t, "resolving-references", results.Results[0].RuleId)
}
Expand Down

0 comments on commit ab09d18

Please sign in to comment.