CI hardening: version lockstep, secretless publish, intake feedback (arch uplift)#31
Merged
Conversation
…and SCHEMA player bounds
CI correctness uplift for the games repo (architecture review findings,
Appendix B):
- Bump KIT_VERSION 2.1.1 -> 2.3.0 in validate.yml and publish.yml — the
newest shellcade-kit release that actually ships binaries (verified via
gh release list; no v2.7.x binary exists yet, that operator action is
tracked separately in the uplift plan).
- Add a "kit version lockstep" step to validate.yml: parse the embedded
kit module version from `shellcade-kit version` and compare it (sort -V)
against each changed game's go.mod require / Cargo.toml git tag pin,
failing the PR with an exact KIT_VERSION bump instruction when a game
requires a newer kit than the pinned conformance engine. This makes the
hand-maintained "bump together" comment a mechanical gate.
- Stop splicing the fork-controlled changed-dirs output into run blocks
via ${{ }}: every consuming step in validate.yml (3 steps + the new
guard) and publish.yml (contents:write + ADMIN_SECRET step) now passes
it as env DIRS so it is shell data, per authorize.yml's documented rule.
- Defense in depth: validate_game_dir.py now checks the full
games/<username>/<name> path shape, including the owner segment
([a-z0-9-]{1,32}), anchored on trailing segments so the documented
local "$(pwd)" invocation keeps working.
- SCHEMA.md: fix the player-bounds contradiction (1..8 -> the enforced
1..1024) and document the 8-seat smoke-script cap in the smoke.yaml row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…surface verified:false Security + feedback-loop uplift for publish.yml (architecture review findings, Appendix B: admin secret in build env [HIGH]; conformance-gate skew / fail-soft publish [HIGH]; invisible post-merge refusals [MED]): - Split publish.yml into two jobs, mirroring the validate/smoke-preview isolation pattern. The build job compiles community game code (cargo build.rs / proc-macros run arbitrary code) with NO secrets, read-only permissions, and `persist-credentials: false`; it builds the -opt=2 release profile, runs `shellcade-kit check` on that actual release artifact (sha256-verified kit fetch copied from validate.yml), logs the digest, and uploads the wasm as a workflow artifact. Job-level isolation, not step-level: a malicious build script can leave a background process reading later steps' environments. - The release job (needs: build) holds GITHUB_TOKEN + ADMIN_SECRET and runs zero game code: it downloads the artifacts, recomputes the sha256 from the bytes it actually attaches, derives vN, cuts the GitHub release, and POSTs the tag to /admin/game:publish. The changed-dirs list crosses jobs via a build-job output captured BEFORE any game code executes, so it is not build-script-influenceable. - Parse the game:publish response (status and body captured separately, authorize.yml pattern). 200 + verified:false is now LOUD: ::error with the slug/tag/verbatim reason, a marker-keyed comment upserted on the merged PR (cleared in place on a later clean pass), and a failed run. Transport-shaped outcomes (curl failure, non-200, empty or non-JSON body, missing secret) keep today's fail-soft path. - validate.yml: also build + `shellcade-kit check` the -opt=2 release profile pre-merge for TinyGo games (Rust already validates --release), closing the dev-profile-only PR gate the review flagged. OPERATOR ACTION when this lands: rotate SHELLCADE_ADMIN_SECRET — the old publish job exposed it to community build scripts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Close the two hygiene gaps from the architecture review (gap areas 3 and 4): - .github/workflows/vulncheck.yml: nightly whole-catalog dependency vuln scan — govulncheck (symbol-level) over every Go game module and cargo-audit over every Rust game, versions pinned like the existing toolchain pins. Each game is a standalone module, so the tree is walked per game. - .github/dependabot.yml: weekly bumps for workflow actions only; gomod and cargo are deliberately excluded because game directories are author-owned namespaces a bot PR may not touch. - CONTENT_POLICY.md: the content bar, a public (issue) and private (GitHub security reporting) report path, and the takedown sequence — operator pulls the game offline immediately, catalog removal follows by maintainer PR — plus appeals and namespace consequences. Linked from the README rules. Co-Authored-By: Claude Fable 5 <noreply@anthropic.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.
Hardens the catalog CI pipeline against the version-skew, supply-chain, and silent-failure issues found by the 2026-06-09 architecture review (PR'd from
arch-uplift/games; companions:kit#arch-uplift/kit, and a larger shellcade integration PR to follow).What's here
G1 — CI verifies with the engine the games actually use (
43b08d6)KIT_VERSION2.1.1 → 2.3.0 invalidate.yml+publish.yml(2.3.0 is the newest release that actually shipsshellcade-kitbinaries; v2.4–v2.7 are bare module tags).validate.yml: parses the embedded kit version fromshellcade-kit versionand compares (sort -V) against each changed game'sgo.mod/Cargo.tomlkit pin — fails with the exactKIT_VERSION-bump instruction instead of silently under-checking games that use newer kit features.${{ }}— every consuming step now usesenv: DIRS(the repo's own documented rule, applied uniformly).SCHEMA.mdplayer bounds corrected to 1..1024 with a note that smoke scripts drive at most 8 seats.G2 — publish pipeline: no secrets near game code, no silent never-go-live (
39ef38e)publish.ymlsplit into two jobs: a build job with zero secrets (permissions: contents: read,persist-credentials: false) that compiles changed games at the release profile, runsshellcade-kit checkon the actual-opt=2artifact (previously the published artifact was never checked), and uploads workflow artifacts; and a release job that downloads artifacts, cuts the GitHub release, and POSTs to/admin/game:publish— executing zero community code. Communitybuild.rs/proc-macros can no longer readSHELLCADE_ADMIN_SECRETor a write-scoped token.verified:falseemits::errorwith the verbatim reason, upserts a comment on the merged PR (authorize.yml's marker-keyed pattern), and fails the run. Fail-soft remains only for transport-level failures.G3 — supply-chain + content hygiene (
2cfba3f)govulncheck(Go games) +cargo-audit(Rust games) workflow; dependabot for Actions.CONTENT_POLICY.mdwith a report/takedown path, linked from the README.Operator actions after merge
SHELLCADE_ADMIN_SECRET— it has been exposed to community build scripts in the pre-split pipeline.shellcade-kitbinary for kit 2.7.x is released, bumpKIT_VERSION— the lockstep guard will flag any PR that needs it sooner.Part of the architecture-uplift program; finding details in the review report (internal).
🤖 Generated with Claude Code