Skip to content

Commit

Permalink
Add lint flag to allow ignore circular references in arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
eli-l authored and daveshanley committed Jan 26, 2024
1 parent 4491f4b commit 95d2349
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 53 deletions.
111 changes: 58 additions & 53 deletions cmd/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func GetLintCommand() *cobra.Command {
allResults, _ := cmd.Flags().GetBool("all-results")
timeoutFlag, _ := cmd.Flags().GetInt("timeout")
hardModeFlag, _ := cmd.Flags().GetBool("hard-mode")
ignoreArrayCircleRef, _ := cmd.Flags().GetBool("ignore-array-circle-ref")

// disable color and styling, for CI/CD use.
// https://github.com/daveshanley/vacuum/issues/234
Expand Down Expand Up @@ -176,28 +177,29 @@ func GetLintCommand() *cobra.Command {
}

lfr := lintFileRequest{
fileName: arg,
baseFlag: baseFlag,
remote: remoteFlag,
multiFile: mf,
skipCheckFlag: skipCheckFlag,
silent: silent,
detailsFlag: detailsFlag,
timeFlag: timeFlag,
failSeverityFlag: failSeverityFlag,
categoryFlag: categoryFlag,
snippetsFlag: snippetsFlag,
errorsFlag: errorsFlag,
noMessageFlag: noMessage,
allResultsFlag: allResults,
totalFiles: len(args),
fileIndex: i,
defaultRuleSets: defaultRuleSets,
selectedRS: selectedRS,
functions: customFunctions,
lock: &printLock,
logger: logger,
timeoutFlag: timeoutFlag,
fileName: arg,
baseFlag: baseFlag,
remote: remoteFlag,
multiFile: mf,
skipCheckFlag: skipCheckFlag,
silent: silent,
detailsFlag: detailsFlag,
timeFlag: timeFlag,
failSeverityFlag: failSeverityFlag,
categoryFlag: categoryFlag,
snippetsFlag: snippetsFlag,
errorsFlag: errorsFlag,
noMessageFlag: noMessage,
allResultsFlag: allResults,
totalFiles: len(args),
fileIndex: i,
defaultRuleSets: defaultRuleSets,
selectedRS: selectedRS,
functions: customFunctions,
lock: &printLock,
logger: logger,
timeoutFlag: timeoutFlag,
ignoreArrayCircleRef: ignoreArrayCircleRef,
}
fs, fp, err := lintFile(lfr)

Expand Down Expand Up @@ -243,6 +245,7 @@ func GetLintCommand() *cobra.Command {
cmd.Flags().BoolP("no-message", "m", false, "Hide the message output when using -d to show details")
cmd.Flags().BoolP("all-results", "a", false, "Render out all results, regardless of the number when using -d")
cmd.Flags().StringP("fail-severity", "n", model.SeverityError, "Results of this level or above will trigger a failure exit code")
cmd.Flags().Bool("ignore-array-circle-ref", false, "Ignore circular array references")

regErr := cmd.RegisterFlagCompletionFunc("category", cobra.FixedCompletions([]string{
model.CategoryAll,
Expand Down Expand Up @@ -271,28 +274,29 @@ func GetLintCommand() *cobra.Command {
}

type lintFileRequest struct {
fileName string
baseFlag string
multiFile bool
remote bool
skipCheckFlag bool
silent bool
detailsFlag bool
timeFlag bool
noMessageFlag bool
allResultsFlag bool
failSeverityFlag string
categoryFlag string
snippetsFlag bool
errorsFlag bool
totalFiles int
fileIndex int
timeoutFlag int
defaultRuleSets rulesets.RuleSets
selectedRS *rulesets.RuleSet
functions map[string]model.RuleFunction
lock *sync.Mutex
logger *slog.Logger
fileName string
baseFlag string
multiFile bool
remote bool
skipCheckFlag bool
silent bool
detailsFlag bool
timeFlag bool
noMessageFlag bool
allResultsFlag bool
failSeverityFlag string
categoryFlag string
snippetsFlag bool
errorsFlag bool
totalFiles int
fileIndex int
timeoutFlag int
ignoreArrayCircleRef bool
defaultRuleSets rulesets.RuleSets
selectedRS *rulesets.RuleSet
functions map[string]model.RuleFunction
lock *sync.Mutex
logger *slog.Logger
}

func lintFile(req lintFileRequest) (int64, int, error) {
Expand All @@ -311,15 +315,16 @@ func lintFile(req lintFileRequest) (int64, int, error) {
}

result := motor.ApplyRulesToRuleSet(&motor.RuleSetExecution{
RuleSet: req.selectedRS,
Spec: specBytes,
SpecFileName: req.fileName,
CustomFunctions: req.functions,
Base: req.baseFlag,
AllowLookup: req.remote,
SkipDocumentCheck: req.skipCheckFlag,
Logger: req.logger,
Timeout: time.Duration(req.timeoutFlag) * time.Second,
RuleSet: req.selectedRS,
Spec: specBytes,
SpecFileName: req.fileName,
CustomFunctions: req.functions,
Base: req.baseFlag,
AllowLookup: req.remote,
SkipDocumentCheck: req.skipCheckFlag,
Logger: req.logger,
Timeout: time.Duration(req.timeoutFlag) * time.Second,
IgnoreCircularArrayRef: req.ignoreArrayCircleRef,
})

results := result.Results
Expand Down
7 changes: 7 additions & 0 deletions motor/rule_applicator.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ type RuleSetExecution struct {
SkipDocumentCheck bool // Skip the document check, useful for fragments and non openapi specs.
Logger *slog.Logger // A custom logger.
Timeout time.Duration // The timeout for each rule to run, prevents run-away rules, default is five seconds.

// https://pb33f.io/libopenapi/circular-references/#circular-reference-results
IgnoreCircularArrayRef bool // Ignore array circular references
}

// RuleSetExecutionResult returns the results of running the ruleset against the supplied spec.
Expand Down Expand Up @@ -111,6 +114,10 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
docConfig := datamodel.NewDocumentConfiguration()
//docConfig.SkipCircularReferenceCheck = true

if execution.IgnoreCircularArrayRef {
docConfig.IgnoreArrayCircularReferences = true
}

// add new pretty logger.
if execution.Logger == nil {
var logger *slog.Logger
Expand Down
43 changes: 43 additions & 0 deletions motor/rule_applicator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,49 @@ components:
assert.Equal(t, "resolving-references", results.Results[0].RuleId)
}

func TestRuleSet_InfiniteCircularLoop_AllowArrayRecursion(t *testing.T) {

yml := `openapi: 3.1.0
paths:
/one:
get:
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/arr'
components:
schemas:
arr:
type: array
items:
$ref: '#/components/schemas/obj'
obj:
type: object
properties:
self:
$ref: '#/components/schemas/obj'`

rules := make(map[string]*model.Rule)
rules["openapi-tags-alphabetical"] = rulesets.GetOpenApiTagsAlphabeticalRule()

rs := &rulesets.RuleSet{
Rules: rules,
}

rse := &RuleSetExecution{
RuleSet: rs,
Spec: []byte(yml),
IgnoreCircularArrayRef: true,
}
results := ApplyRulesToRuleSet(rse)
assert.Len(t, results.Errors, 0)

assert.NotNil(t, results)
assert.Len(t, results.Results, 0)
}

func TestApplyRules_TestRules_Custom_Document_Pattern(t *testing.T) {

yaml := `rules:
Expand Down

0 comments on commit 95d2349

Please sign in to comment.