Skip to content

fix(ci): resolve repo-root-relative git paths in OpenAPI base comparisons#335

Open
jeremi wants to merge 1 commit into
mainfrom
chore/openapi-base-compare
Open

fix(ci): resolve repo-root-relative git paths in OpenAPI base comparisons#335
jeremi wants to merge 1 commit into
mainfrom
chore/openapi-base-compare

Conversation

@jeremi

@jeremi jeremi commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

  • Both products' just openapi-contract <base_ref> checks (backed by
    products/notary/scripts/check-openapi-contract.sh and
    crates/registry-relay/scripts/check-openapi-contract.sh) use git's
    <rev>:<path> object syntax to fetch the OpenAPI document (and, for
    Relay, the reference config) at a base ref for an oasdiff breaking
    comparison.
  • That syntax resolves <path> relative to the repo root, not the
    current working directory. Both scripts cd into their product
    directory (products/notary / crates/registry-relay) and then build
    the git object path from a directory-relative SPEC_PATH (e.g.
    openapi/registry-notary.openapi.json), which git then looks up at the
    repo root, where it doesn't exist. git cat-file -e fails, and the
    script's existing "handle bootstrap: file didn't exist at that ref yet"
    branch quietly treats a path-resolution bug as though the file
    never existed at the base ref, prints an innocuous-looking message,
    and exits 0. No breaking-change diff ever runs.

Reproduction (before the fix)

From products/notary, with origin/main fetched:

$ OPENAPI_CONTRACT_BASE_REF=origin/main bash scripts/check-openapi-contract.sh
OpenAPI spec did not exist at 'origin/main'; skipped breaking-change diff
$ echo $?
0

but the file plainly exists at origin/main:

$ git cat-file -e origin/main:products/notary/openapi/registry-notary.openapi.json && echo found
found
$ git cat-file -e origin/main:openapi/registry-notary.openapi.json   # what the buggy script actually asked for
fatal: path 'openapi/registry-notary.openapi.json' does not exist in 'origin/main'

Same story for crates/registry-relay (SPEC_PATH and REFERENCE_CONFIG
both mis-resolve; just openapi-contract origin/main prints the same
false "did not exist... skipped" message and exits 0).

Fix

Minimal, path-resolution-only change to both scripts:

  • Compute the repo-root-relative form of each $ROOT-relative path via
    git rev-parse --show-prefix / --show-toplevel, and self-check it
    with -ef against the known-good local file before using it in any
    git cat-file / git show call. If the computed path doesn't resolve
    to the same file, the script now exits 1 with a clear
    "failed to resolve repo-root-relative path... refusing to run base-ref
    comparison" message instead of silently treating that as "file absent".
  • This keeps "file genuinely didn't exist yet at an older base ref"
    (legitimate bootstrap case, still exits 0 with the existing message)
    distinguishable from "we couldn't resolve which file to even ask git
    about" (now a loud, non-zero failure).

After the fix

$ cd products/notary && just openapi-contract origin/main
scripts/check-openapi-contract.sh "origin/main"
$ echo $?
0

target/openapi-contract/base.openapi.json is now actually written from
git show, and oasdiff breaking runs (no differences vs. origin/main,
since the branch only touches the two shell scripts). Same for
crates/registry-relay. The legitimate skip path was re-verified against
a real pre-existing-file base ref (the commit before
products/notary/openapi/registry-notary.openapi.json was added) and
still exits 0 with the "did not exist... skipped" message, unchanged.

Verification

  • shellcheck on both changed scripts: clean.
  • shfmt -i 4 -d on both: no diff introduced by this change (the two
    remaining reported lines are pre-existing > vs >"..." redirect
    spacing the file already had before this change; left untouched to keep
    the diff minimal and match surrounding style).
  • Manual before/after runs of both just openapi-contract <base_ref> and
    the underlying scripts directly, as shown above.
  • Manually simulated a re-introduction of the original bug (miscomputed
    repo-root-relative path) to confirm the new self-check fails loudly
    (exit 1, clear message) rather than silently skipping.

Note (not part of this fix)

While investigating, I noticed CI (.github/workflows/ci.yml) currently
invokes just openapi-contract with no base ref at all for either
product, so today this code path is never exercised in CI — the bug was
latent rather than actively causing false-green PRs. Whether/how to wire
OPENAPI_CONTRACT_BASE_REF (or a base_ref arg) into CI is a separate,
larger decision (e.g. what to diff against for PRs vs. pushes to main)
and is out of scope here; flagging it so it can be tracked separately.

Found during review of PR #332; does not block it.

Test plan

  • shellcheck on both changed scripts
  • shfmt -i 4 -d on both changed scripts (no new diff)
  • Reproduced the silent-skip bug before the fix (both scripts, both
    via direct invocation and via just openapi-contract origin/main)
  • Confirmed the fix performs the real oasdiff breaking comparison
    against origin/main after the fix (both scripts)
  • Confirmed the legitimate "file didn't exist at an older base ref"
    skip path still works and still exits 0
  • Confirmed a re-introduced path-miscomputation now fails loudly
    instead of silently skipping

…sons

Signed-off-by: Jeremi Joslin <jeremi@joslin.fr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant