Repository navigation
ci: let Relock commit its lock onto any base branch - #483
Merged
Merged
Conversation
The propose job downloaded the verified lock over its sparse checkout of
main, then switched to the tested base revision. When the base's uv.lock
differs from main's, git refuses to carry that local change across
("Your local changes ... would be overwritten by checkout"), so every
relock onto such a branch failed after all its verification. Runs
40155755520 and 40158406513 hit it on the bundle branch, and their locks
had to be committed by hand (#481). Earlier runs all used base=main,
whose tip is the tested revision, so the switch changed nothing.
The artifact now downloads to $RUNNER_TEMP/relocked-lock, outside the
checkout. The host check and the digest match run on it there, with
main's validator, before the token is exposed, as before. Only after the
base revision is checked out is it copied in, and the file about to be
staged is matched to the digest once more.
test_the_verified_lock_is_committed_onto_any_base runs the job's own
steps against a sparse checkout of main in a temporary repository, with
a stub gh. It covers three bases: main itself, a branch that shares
main's lock, and a branch with its own lock. The last failed with CI's
exact error before the change, and all three now push the verified
bytes, and nothing else, onto the tested revision.
test_the_committed_bytes_are_the_bytes_that_were_verified now also pins
the second digest match between the copy and `git add`; removing it or
moving it before the copy fails that test.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Required CI completion remains unconfirmed for this write-enabled workflow change.
No open issues 🎉
What changed in this PR
Fixes #481 by allowing Relock to commit its verified lock onto a base branch whose uv.lock differs from main’s, without changing the existing validation or token boundaries.
Changes:
- Downloads the artifact outside the checkout, copies it after switching to the tested revision, and rechecks its digest before staging.
- Adds regression coverage for three base-branch scenarios and the copy/check/stage order.
- Documents support for arbitrary base branches and the second digest check.
| File | Description |
|---|---|
tests/test_lockfile.py |
Adds base-branch regression tests and digest-order assertions. |
docs/dev/quality-gates.md |
Explains artifact placement and validation before staging. |
.github/workflows/relock.yml |
Defers copying the verified lock until after checkout of the tested base. |
Review effort: Balanced
The stub recorded every gh call and always succeeded, and the test only looked for the one `pr create` line. So a workflow that also ran, say, `gh pr merge "$branch" --squash || true` would pass while doing exactly what the repository forbids. The stub now writes each call's exact argv, NUL-separated, to its own numbered file, and accepts only `gh auth setup-git` and `gh pr create`; any other call fails the step and stays on record. The test asserts the whole call sequence, not one line. Injecting `gh pr merge "$branch" --squash || true` after the push now fails the call-set assertion, and the unguarded form fails the step with "unexpected gh call"; both passed before. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The stub accepted any `pr create`, and the test compared only the first four arguments after it, so appending `--repo other/target` (or a stray argument) to the workflow's call kept the recorded prefix and the call count intact and passed, while the real pull request would target another repository. The test now requires the options to be exactly --base, --head, --title and --body, in that order, pairs them, and checks each value: the base, the pushed branch, the relock title, and a body that names the tested revision. Comparing the whole argv would copy the body's prose into the test, so the option names pin the shape and the values pin what matters. Adding `--repo other/target` or a positional argument to the call now fails the test; both passed before. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #481
Summary
The Relock workflow's
proposejob downloaded the verifieduv.lockover its sparse checkout ofmain, then switched to the tested base revision withgit checkout -b "$branch" "$BASE_SHA". When the base'suv.lockdiffers frommain's, git refuses to carry that local change across:Every relock onto such a branch therefore failed after all its verification. Runs 40155755520 and 40158406513 hit it on #482's branch, and both locks had to be committed by hand. Earlier runs all used
base=main, whose tip is the tested revision, so the switch changed nothing.$RUNNER_TEMP/relocked-lock, outside the checkout.main's validator) and the digest match run on it there, before the token is exposed, as before.git add --sparse uv.lock.main), the write-token boundary, and the branch-from-BASE_SHArule.docs/dev/quality-gates.mdnow says the base can be any branch and describes the second digest match.Verification
tests/test_lockfile.py::test_the_verified_lock_is_committed_onto_any_baseruns the job's own steps against a temporary repository: a bare origin, a sparse checkout ofmain, the artifact placed wheredownload-artifactputs it, and a stubgh. It is parametrized over three bases:mainitself, a branch that sharesmain's lock, and a branch with its own lock. Before the change, the last case failed with CI's exact error and the first two passed, matching real runs.ghstub (after review) records each call's exact arguments and accepts onlygh auth setup-gitandgh pr create. The test asserts the whole call sequence, so a workflow that also rangh pr mergewould fail it, whether or not the call is guarded with|| true. Both forms were checked by mutation. Thepr createoptions must be exactly--base,--head,--titleand--body, in that order, with the expected values, so an added--repoor a stray argument also fails the test.test_the_committed_bytes_are_the_bytes_that_were_verifiednow also pins it between the copy andgit add. Removing that match, or moving it before the copy, fails the test with a message naming the problem.sha256sum, falling back toshasum -a 256(same options) where the system one is BSD's.uvx zizmor .github/workflows/relock.ymlreports no findings, with the same 4 suppressed asmain's copy.Run locally on macOS with Python 3.13 and the frozen lock. Each step ran directly with the project's environment rather than through
make, because this machine cannot sync from PyPI:pytest -p no:tach tests/test_lockfile.py tests/test_docs_links.py tests/test_docs_build_config.py tests/test_ci_workflow.pypython scripts/check_source_size.pyruff check src/ tests/andruff format --check src/ tests/SKIP=mypy,source-size pre-commit run --files <changed files>mypytach checkpytest -n 8 -qThe workflow itself only runs on dispatch. The next Relock run on a non-
mainbase will be the first end-to-end use.This PR's CI on the final head (
6a63a41f, hosted runners, four xdist workers) passed every required check:pre-commit,security(including zizmor),dependency-review,analyze, and:test (3.11)test (3.12)test (3.13)windows-testChecklist
make checkpasses locally.and a fail-closed audit entry, and sensitive reads are still masked.