Skip to content

ci(openapi): require the pinned server commit to be reachable from server main - #171

Merged
tiankaima merged 1 commit into
mainfrom
chore/openapi-pin-reachability
Sep 20, 2026
Merged

tiankaima merged 1 commit into
mainfrom
chore/openapi-pin-reachability

Conversation

@tiankaima

@tiankaima tiankaima commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Outcome

  • Require the pinned commit to be an ancestor of server main.
  • Use the same reachability safeguards for source provenance and synchronization.
  • Fail closed when the checkout is shallow, main is unavailable, or the pinned commit cannot be inspected.

The Bot cannot silently generate a client from an unmerged server branch.

Refs Life-USTC/server#1101

The OpenAPI contract is pinned to an exact Life-USTC/server commit, and
verification only asserted that the server checkout is *at* that commit.
CI checks out exactly the pinned SHA, so that assertion is a tautology.

A pull-request head SHA stays fetchable from the server repository
forever, so the pin could point at a commit that was never on main and
every check still passed: the provenance verified, the checkout matched,
and the vendored spec was byte-identical to the source.

Life-USTC/cli hit this for real. It was pinned at
fea7bb21ead65fa4da1d51d8ef36ef914a647783 ("fix(young): complete release
contracts", 2026-09-15), a pull-request head that is not an ancestor of
server main -- the server squash-merges, so PR heads never land there.
The CLI client was generated from a discarded branch snapshot while CI
reported success.

Add `openapi-contract.sh verify-reachable SERVER_DIR`, which asserts
`git merge-base --is-ancestor <pin> <main>` against the server checkout,
and wire it into CI and the nightly sync through
`make check-openapi-reachability`.

Ancestry needs real history, so the server checkouts now use
`fetch-depth: 0` and fetch `refs/heads/main` explicitly. A shallow
checkout stays shallow even after fetching main, so the script refuses
to run there instead of guessing: a check that cannot be evaluated is
worse than no check. The same refusal covers a missing main ref and a
pin the checkout does not contain.

scripts/openapi-contract.test.sh builds synthetic server histories and
proves the check rejects an unmerged branch head -- including the case
where provenance, HEAD, and the vendored spec all agree -- and accepts
both the main tip and an older commit on main. It runs in CI next to the
deploy-mac smoke test via `make check-scripts`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tiankaima
tiankaima merged commit 923c01d into main Sep 20, 2026
3 checks passed
@tiankaima
tiankaima deleted the chore/openapi-pin-reachability branch September 20, 2026 04:39
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