Skip to content

v1.35.0

Latest

Choose a tag to compare

@reuvenharrison reuvenharrison released this 28 Oct 16:31
· 59 commits to main since this release
a4ba100

Deterministic diff output, a sunset-aware deprecation lifecycle, and the OAuth flows that were never checked

oasdiff diff now returns the same output on every run of the same comparison. Removing a deprecated request or response property follows its x-sunset date instead of reporting a plain removal. The OAuth security checks cover all four flows rather than only implicit, and compare URLs by meaning. Two crashes are fixed. This is the same code as v1.35.0-rc.1.

CLI changes

Deterministic output

  • diff returns the same output on every run (#1335). Parts of the diff were built by ranging over a map, and Go randomizes map iteration, so the order of added, deleted and modified entries moved between runs of the same comparison. Every map-based diff now goes through one helper that returns sorted lists, paths are listed by path then method, required and type lists are sorted, the YAML endpoints section is sorted, and an added and deleted media type that are equivalent are paired the same way every run. A new test compares 284 fixture pairs ten times each and requires identical JSON and YAML.
  • The duplicate endpoint error names both paths and how to fix it (#1336). It used to name one of the two clashing paths, picked at random, without saying what it clashed with. It now reports both paths with the file each came from, the same pair on every run, and suggests --include-path-params. The x-since-date error got the same treatment.

Deprecation

  • Removing a deprecated property follows its sunset date (#1305, thanks @BogdanYarotsky). Request properties and required response properties now use the lifecycle that parameters and endpoints already had: removing a deprecated property with no x-sunset reports request-property-removed-with-deprecation or response-required-property-removed-with-deprecation at info, removing one before its sunset date reports request-property-removed-before-sunset or response-required-property-removed-before-sunset at error, and removing one after its sunset date is not reported. A sunset date that cannot be parsed keeps the plain removal id, since the deprecation checks already report the bad date.

Security schemes

  • All four OAuth flows are checked (#1328). The checks read only the implicit flow, so changes to authorizationCode, password and clientCredentials were never reported: moving an authorizationCode flow's URLs to another host and dropping one of its scopes gave "No changes to report". Every URL and scope finding now names its flow, since the same scope can appear in two flows of one scheme, and api-security-component-oauth-refresh-url-changed is new.
  • Security scheme URLs are compared by meaning (#1328). https://Login.Example.com:443/token and https://login.example.com/token are no longer reported as a change. The comparison follows RFC 3986: case in the scheme and host, a default port, an empty path, and percent-encoding of unreserved characters are all equivalent. The four URL checks now share one level, warning, with a comment explaining the verdict; api-security-component-openid-connect-url-changed was an error, and the authorization and token URL checks were info.

Crashes

  • x-extensible-enum with numeric values no longer panics (#1343). An integer parameter or property written as x-extensible-enum: [1, 2] crashed breaking and changelog when a value was removed, because the items were read as strings. A removed number is now reported like any other removed value.
  • A self-referencing callback no longer overflows the stack (#1344). A callback whose operation carries the same callback recursed until the stack overflowed, even when a spec was compared with itself. diff, breaking, changelog and summary are all fixed, and each change is reported once, where the callback is first compared.

External $refs

  • One exit code for a refused external $ref (#1354). With --allow-external-refs=false, a refused $ref exited 123 when oasdiff's own reader was installed, which --open does, and 102 otherwise, so a CI step keying off the code could not reliably offer the remedy. Both paths now exit 123, and the two forms of the refusal are recognized by one predicate.
  • The capture reader applies the policy by default (#1347, #1352). The reader --open installs now refuses an external $ref before any read, and a call site that does not name a document gets the policy rather than silently getting none. The fix itself shipped in v1.34.1 and is published as GHSA-6h5x-f3qr-cp23; what is new here is that the reader fails closed.

Misc

  • kin-openapi v0.151.0 (#1332).
  • Third-party actions are pinned by digest and workflow tokens are least-privilege (#1340, thanks @huguesducharme).
  • A security policy (#1346), so a reporter has somewhere to send a finding.

Go package changes

  • New load.IsExternalRefDisallowed(err) (#1354). Answers for both refusal paths, oasdiff's reader and kin-openapi's own check, so a caller no longer has to match either form. The kin match is pinned by a test that runs the real loader, so a wording change upstream fails the test rather than silently reverting the behaviour.
  • utils.StringSet.ToStringList returns sorted values (#1335). This is what makes string-list diffs such as required and type deterministic; a caller that relied on the previous arbitrary order now gets a stable one.
  • Four new checker ids (#1305): RequestPropertyRemovedWithDeprecationId, RequestPropertyRemovedBeforeSunsetId, ResponseRequiredPropertyRemovedWithDeprecationId, ResponseRequiredPropertyRemovedBeforeSunsetId. Machine-readable output gains these ids, so a consumer matching on removal ids should expect them.