Repository navigation
feat(cli): verify Actions artifact handoffs - #7
Merged
Merged
Conversation
Replace the three actions/github-script artifact-metadata blocks (OB-06, GR-05, OP-03) with `release-cli verify handoff`. Each caller now validates the metadata tuple through the GitHub API before downloading: the artifact must exist, belong to the current run, be unexpired, and report the digest the caller expects. This introduces the program's first genuine port and adapter. `ArtifactMeta` is declared in the consuming pubgh package and implemented by ghact over go-github v82, with a Mockery-generated mock under the adapter. A pinned Mockery 3.7.3 plus scripts/check-mocks.sh keeps checked-in mocks byte-identical to the generator, and both are wired into `moon run root:check`. Bounded retry lives in the engine with an injected sleep, deliberately matching the octokit `retries: 3` semantics it replaces: four attempts total with 1s, 2s, and 4s waits, retrying only rate-limit and 5xx responses, never absent, auth, or malformed ones, and returning immediately on cancellation. The three-owner handoff split is preserved and stated explicitly: the CLI checks the API tuple, the SHA-pinned download-artifact step still owns the ZIP transport digest, and later commands verify extracted content. The CLI never claims to recompute the transport digest. GITHUB_API_URL and GITHUB_SERVER_URL are honored so Enterprise Server consumers work and the composed command is testable against a local stub. Missing or malformed configuration exits 2 before any network call; a tuple mismatch exits 1. Tokens never enter domain values, outputs, or wrapped errors. Reviewed over two rounds and audited against AGENTS.md. The Actions output port was dropped from this slice for lack of a production caller, and the sentinel set was reduced to the two with real consumers.
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.
Summary
Second slice of the
release-cliprogram (plan §3 PR 2). Replaces the threeactions/github-scriptartifact-metadata blocks withrelease-cli verify handoff, and introduces the program's first genuine port, adapter, and generated mock.Replaced, about 36 lines each: OB-06 in
go-oci-build.yml, GR-05 inpublish-github-release.yml, OP-03 inpublish-oci-image.yml.pubgh.ArtifactMetais declared in the consuminginternal/stage/pubghpackage and implemented byinternal/adapter/ghactovergo-github/v82, with a Mockery-generated mock under the adapter.3.7.3is pinned;scripts/check-mocks.shproves the checked-in mocks are byte-identical to the pinned generator's output. Both run inmoon run root:check.verify handoff, then the unchangedactions/download-artifactstep.verify-setup-installed.ymlexercises the composite's installed acquisition path. It cannot pass until a release exists, so it is intentionally not a merge gate.Behavior preserved
The three replaced blocks validated that the artifact exists, belongs to the current run, is unexpired, and matches the expected digest, with
retries: 3. All of that is preserved.Retry lives in the engine with an injected sleep function, matching the
@octokit/plugin-retrysemantics it replaces: four attempts total, waits of 1s, 2s, and 4s, retrying only rate-limit and 5xx responses, never absent, authentication, or malformed responses, and returning immediately on context cancellation.The three-owner handoff split is stated explicitly in the docs and enforced in code: the CLI verifies the API metadata tuple, the SHA-pinned
download-artifactstep owns the artifact ZIP transport digest, and later CLI commands verify extracted content. The CLI never claims to recompute the transport digest.Contract
GITHUB_API_URLandGITHUB_SERVER_URLare honored, so Enterprise Server consumers work and the composed command is testable against a local stub. An explicitly empty value is rejected rather than silently retargeting to github.com.cli-pathinput. Every existing input, output, secret, permission, and concurrency group is unchanged. There is still nocli-versioninput.Verification
mise exec -- moon run root:checkgreen across all seven tasks: format, lint, build, test, protocol stamp, mocks freshness, check.handoff mismatchplus a specific detail; 404 exits 1 after exactly one request; permanent 503 exits 1 after exactly four requests over about 7s; a flaky endpoint recovers within the budget; a missing token exits 2 with zero requests. The token string appears in no stdout or stderr in any case.verify handoffcorrectly writes noGITHUB_OUTPUTnames.download-artifactsteps are untouched; the only added use is the dogfood binary download, gated oncli-path.Review
Two review rounds (verdict: go) and one
AGENTS.mdconformance audit.Blocking defects found and fixed:
verify handoffsteps passed no token. Actions does not exportGITHUB_TOKENintorun:environments, so the command would have exited 2 on every real run.ErrRetryableexisted with no consumer.Also fixed: the client hardcoded
api.github.comand ignoredGITHUB_API_URL, which broke Enterprise Server portability and made the composed command untestable off CI; the mocks freshness check invoked an ambient Mockery 3.7.1 instead of the pinned 3.7.3 and usedgit status, so it failed on any newly added mock;attestations: readwas missing from theoci-imagejob; composite outputs were interpolated into shell rather than passed throughenv:; an explicitly emptyGITHUB_API_URLsilently selected github.com; and the cancellation path returned a raw*url.Errorcontaining the request URL.Scope removals accepted during review, both for lack of a production caller: the
cli.Actionsport withinternal/adapter/actenvand its generated mock, and the error-sentinel set reduced from eight to the two with real consumers.Follow-ups recorded in the journal
verify-setup-installed.ymlshould be dispatched immediately after the first release exists, and its run retained as evidence.pubgh, notghact, so a future direct caller ofghact.Client.Getwould get no retry. Noted for PR 3.Human acceptance requested. I have not merged.