docs(release): tag step must be signed+annotated (git tag -s -m) (#624) #459
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
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # Default-feature builds + the canonical core test suite (AGENTS.md "Build & test"). | |
| build-default: | |
| name: Build & test (default features) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build workspace (default features) | |
| run: cargo build --workspace --locked | |
| # The release workflow is the only other caller of this script, and it runs on a tag — so | |
| # until now the script itself was unverified code on every PR that changed what it checks, | |
| # and a broken release verifier reached main invisibly (#278, #262). The binary argument is | |
| # the load-bearing part: the artifact leg is the only one that inspects a built executable | |
| # rather than the tree, and it is the leg that actually failed. A tree-only invocation here | |
| # would be a green row blind to exactly the class of failure this guards. | |
| - name: Verify the release version check agrees with the built binary | |
| run: | | |
| VERSION="$(cargo metadata --no-deps --format-version 1 \ | |
| | node -e 'const m=JSON.parse(require("fs").readFileSync(0,"utf8"));const p=m.packages.find(p=>p.name==="maxplayer");if(!p){process.stderr.write("no maxplayer package in cargo metadata\n");process.exit(1)}process.stdout.write(p.version)')" | |
| ./scripts/verify-release-version.sh "$VERSION" target/debug/maxplayer | |
| # One half of a pair — this build has `acp` off, and the acp job below runs the other verifier | |
| # on a build that has it on. Since #510 this is the ONLY place the racer verifier runs: a | |
| # release ships one binary with `acp` in, so nothing else exercises the buyer-only feature set. | |
| # It stays because that feature set is still supported from source and must keep compiling and | |
| # keep being acp-free, and because a surface verifier that has never run is not a guard. | |
| - name: Verify the racer surface (default features) | |
| run: ./scripts/verify-racer-surface.sh target/debug/maxplayer | |
| - name: Test maxplayer-core (default features) | |
| run: cargo test -p maxplayer-core --locked | |
| # The CLI crate's tests (cli unit tests, cli_e2e.rs, and the #126/#127/#131 daemon self-spawn | |
| # acceptance in mcp_daemon.rs, which drives the real built binary) run nowhere else: every | |
| # other test invocation in this file is -p maxplayer-core (#264). mcp_daemon.rs is gated on the | |
| # wallet feature, which is a default feature, so the default-feature job is the one that | |
| # satisfies its cfg gate. | |
| - name: Test maxplayer (CLI crate, default features) | |
| run: cargo test -p maxplayer --locked | |
| # Same gap, other crate (#264): the relay write-policy plugin's tests (the #372 config-flip | |
| # red-prove, #397 NIP-17 admission) are built by the workspace build but named by no test | |
| # invocation. The crate has no feature gates, so it runs here too. | |
| - name: Test maxplayer-relay-write-policy | |
| run: cargo test -p maxplayer-relay-write-policy --locked | |
| # The acp feature gates the seller-execute path and is off by default, so it rots silently unless | |
| # CI compiles it explicitly (issue #108). Build BOTH crates with acp on — maxplayer-core with the full | |
| # shipped feature combo — then run the acp-gated tests. | |
| build-acp: | |
| name: Build & test (acp) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build maxplayer (acp + wallet, release) | |
| run: cargo build -p maxplayer --release --features acp,wallet --locked | |
| - name: Build maxplayer-core (full shipped feature combo) | |
| run: cargo build -p maxplayer-core --features acp,gateway,git-delivery,wallet --locked | |
| # The acp-gated tests (the ACP driver units + the #223 seller-concurrency regression: | |
| # N jobs must OVERLAP on one LocalSet thread and the loop must stay live) only exist under | |
| # the acp feature — the default-feature job above compiles them out, so run them here. | |
| - name: Test maxplayer-core (acp) | |
| run: cargo test -p maxplayer-core --features acp --locked | |
| # The CLI crate's acp-gated tests run NOWHERE else: the default-feature job tests -p maxplayer | |
| # WITHOUT acp (so `#[cfg(feature = "acp")]` tests compile out), and the acp steps here only | |
| # BUILD -p maxplayer or TEST -p maxplayer-core (#264, same gap). Without this the seller-surface | |
| # CLI locks are a false green — they compile but never execute (#549): the `seller --help` | |
| # regression, the #542 no-alias foil, and the #533 doctor-wording pin. acp_smoke is `#[ignore]`d | |
| # (env-gated real agent), so it is reported ignored here, not run. | |
| - name: Test maxplayer (CLI crate, acp) | |
| run: cargo test -p maxplayer --features acp,wallet --locked | |
| # Paired with the racer check in the default-feature job: the two scripts must reach opposite | |
| # verdicts on the two builds, which is what shows each one moves with the feature rather than | |
| # with something incidental to the binary it happens to be handed. | |
| - name: Verify the seller surface (acp) | |
| run: ./scripts/verify-seller-surface.sh target/release/maxplayer | |
| # The money path runs in its OWN job, on its own runner, with no `needs:` — the isolation IS the | |
| # feature here, not an accident of layout (#271). Sharing a job means sharing fate: when the acp | |
| # concurrency test dies, every step still queued behind it is marked `skipped` while the job as a | |
| # whole reports `failure`, so the check list shows a single red row that cannot distinguish "the | |
| # money suite failed" from "the money suite never ran" — the one ambiguity a money gate must not | |
| # have. Job isolation is what empirically survives this fault: on run 30487009981 attempt 2 both | |
| # sibling jobs passed while that job died. `if: always()` is the cheaper edit but a weaker | |
| # guarantee — it keeps the suite on the same runner as the fault it is meant to outlive, and still | |
| # buries its result inside another job's conclusion. A separate runner also gives the suite its own | |
| # resource budget, which matters while the acp test's subprocess peak is the leading suspect. | |
| # Co-locating them bought nothing to trade away, either: this suite compiles its own feature set | |
| # (no acp, release) and so reuses none of the acp job's build output. The default-feature job | |
| # carries zero money teeth (it compiles the gateway/git-delivery/wallet tests out entirely), which | |
| # makes this the only job in CI that runs them. | |
| money-path: | |
| name: Money-path tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| # Release build: the money-path suite is run in release (as the local money gate is), which | |
| # also sidesteps a debug-only latent bug in the git-delivery HTTP transport | |
| # (git_transport::client_short builds a nested tokio runtime inside the async collect path and | |
| # panics on drop under debug). Interim: release-only until that transport-lifecycle bug is | |
| # fixed (#152); the money assertions here (tip-match refusal, zero-burn, no | |
| # journal/materialization) hold in release. | |
| - name: Test maxplayer-core (money-path suite) | |
| run: cargo test -p maxplayer-core --release --no-default-features --features gateway,git-delivery,wallet --locked | |
| # The release workflow triggers only on a tag, so no pull request ever exercises it. What CI can | |
| # check is that the gates keeping it from publishing are still in place — otherwise the property | |
| # holds only until somebody edits the file, and nothing would say so. | |
| release-gates: | |
| name: Release workflow gates | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - run: ./scripts/verify-release-workflow.sh | |
| # The tree-side platform surfaces — the npm payload packages, the launcher's pins and its | |
| # runtime resolver — held to .github/release-platforms.json on every pull request. | |
| # `--no-artifacts` skips only the built-artifact check (nothing is built in this job); the | |
| # drift #249 is about is a tree edit, so this catches it here, before a release is ever | |
| # dispatched, rather than only in the release workflow's own dry run. | |
| - run: ./scripts/verify-release-surface.sh --no-artifacts |