Repository navigation
v1.32.0
56 new checks, cycle-proof diff and flatten
The generated-rule engine now covers every increase and decrease of every bound keyword (catalog: 699 to 755 checks), and recursive schemas are handled end to end: no more stack overflows in diff or flatten, deterministic structured output, and flattened recursion that always serializes under stable names.
CLI changes
Detection rules
- Every bound keyword's increase and decrease is now checked (#1232). The rule engine that generates set/unset checks now also generates increased/decreased ones, closing 56 gaps at once: response headers get their first increase/decrease checks, parameters gain
maxProperties/minProperties/minContains/maxContainscoverage, and the widening response directions (for exampleresponse-body-max-decreased) are reported at info level.multipleOfis deliberately excluded: numeric order does not decide its effect, so it keeps its dedicated changed/generalized/specialized checks. - Exclusive bounds join the generated rules, fixing three latent bugs (#1226). In the OpenAPI 3.0 boolean form,
exclusiveMaximum: falsetotrueused to report nothing (it is a breaking set), addingexclusiveMaximum: falsewas reported as breaking (it changes nothing, false means not exclusive), and the false-to-true transition could be misreported as a value increase. - Added and deleted properties under an unflattened
allOfcarry the disclaimer (#1229). Existence changes insideallOfbranches now get the same warning cap and--flatten-allofhint as other findings there, and a schema that itself has anallOfis recognized by presence rather than only when theallOfchanged. oasdiff checksshows each rule's guards (#1227). A GUARDS column and a--tagsdimension expose the read-only / write-only guards, so a verdict downgraded by a guard is explained by the catalog instead of looking like a bug.
Recursive schemas: no crashes, deterministic output, serializable flatten
- Diffing ref-less cyclic schemas no longer overflows the stack (#1231, thanks @dimitropoulos). Schemas that reference themselves through in-memory links rather than
$ref(for example after--flatten-allofmerges a recursive component) are cut safely at the point of re-entry, whatever shape the cycle has. oasdiff flattenof recursiveallOfmerges always serializes (#1233, #1240, #1245). A cycle keeps its$refwhere one exists, a set that merges to a single schema reuses that schema with its name, and a genuinely anonymous merged cycle is hoisted intocomponents.schemasunder a name built from the merged component names (AllOfMerged_NodeA_NodeB), so the same cycle keeps the same name in every revision. Documented in docs/ALLOF.md (#1244).- A merge mixing a recursive branch with other constraints keeps them all (#1243). Such a node becomes an
allOfof the named cycle and the merged remaining constraints instead of silently dropping them, which could previously hide breaking changes in the flattened comparison. - Structured output for multi-cycle schemas is deterministic (#1237, thanks @BigMichi1 for the precise report in #1230). A schema participating in more than one reference cycle produced one of two different
--format json/yamloutputs at random; identical inputs now produce identical bytes, and the output is also more complete, each cycle edge carrying its own diff. Diffs of such schemas change once when you upgrade. - The
circularRefoutput field is removed (#1238). Cyclic-reference mismatches now appear as ordinary field-level diffs, which say strictly more; a pure rename of a cyclic$refis no longer reported, matching how non-cyclic$refrenames behave.
Validate
- New lint: mutability flags no request or response can ever see (#1228). A
readOnlyon a schema reachable only from requests, orwriteOnlyonly from responses, can never take effect;oasdiff validatenow flags both, walking webhooks and callbacks too.
Misc
- Ignore and severity-level files no longer swallow read errors (#1234). A failed read, for example a line past the scanner's size limit, is reported instead of silently dropping the unread entries.
- The install script is quoting-safe (#1241).
install.shhandles paths containing spaces, and the repo's shell (including workflowrun:blocks) is now gated by shellcheck and actionlint.
Go package changes
- Breaking:
diff.SchemaDiff.CircularRefDiffis removed (#1238), together with the ref-string circular guard it powered; the in-flight pair guard introduced in #1231 handles cycle termination for every cycle shape. - Breaking:
checker.BoundSetUnsetCheckis renamedBoundCheck(#1232), reflecting that it now reports increase and decrease as well. diff.SchemaBoundgainsWasIncreasedandWasDecreased(#1232), completing the bound classification API alongsideWasSetandWasUnset.checker.GetTransitionsexposes transition metadata (#1225): the named transition recognizers with the change kinds they claim and the checks that report them, powering the public OpenAPI Changes Model export.flatten/allof:MergeSpecguarantees marshalable output for recursive inputs (#1233, #1240, #1243): it repairs shared-reference identity after the in-place merge and names every anchored cycle.Merge(single schema, no components section) documents that a nameless recursive input yields an in-memory cycle that does not marshal.- Go 1.27 (#1224): toolchain moved to Go 1.27 and direct dependencies updated.