From e57f15a698e0bc04b972206ed220a3ea364c51b1 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Mon, 13 Jul 2026 14:20:21 +1000 Subject: [PATCH 1/4] feat(staged): add daily scheduled workflow to bump ACP tool pins Add .github/workflows/staged-bump-acp-tools.yml, a daily (06:30 UTC, plus workflow_dispatch) job that regenerates apps/staged/acp-tools.lock.json via 'just bump-acp-tools' and manages a PR with the result: - resets the bot-owned automation/update-acp-pins branch from main each run, so it stays single-commit and never diverges - exits successfully when the lockfile diff is clean (no upstream releases) - smoke-checks new pins with scripts/ensure-acp-tools.sh before pushing, since PR CI does not consume the lockfile - force-pushes the branch and creates a PR only when none is already open (refresh-in-place, no duplicates) - sets npm_config_registry to Block Artifactory so tarball URLs match dev-machine runs instead of churning to registry.npmjs.org Matches house workflow style: SHA-pinned actions, cashapp/activate-hermit for node/just, least-privilege permissions (contents + pull-requests write), and a concurrency group to prevent overlapping runs. Co-Authored-By: Claude Fable 5 Signed-off-by: Matt Toohey --- .github/workflows/staged-bump-acp-tools.yml | 87 +++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 .github/workflows/staged-bump-acp-tools.yml diff --git a/.github/workflows/staged-bump-acp-tools.yml b/.github/workflows/staged-bump-acp-tools.yml new file mode 100644 index 00000000..42847131 --- /dev/null +++ b/.github/workflows/staged-bump-acp-tools.yml @@ -0,0 +1,87 @@ +name: Staged Bump ACP Tools + +on: + schedule: + # Daily at 06:30 UTC. + - cron: "30 6 * * *" + workflow_dispatch: + +# One run at a time so a late-finishing run cannot race a newer one. +concurrency: + group: staged-bump-acp-tools + +env: + # The lockfile records registry-specific tarball URLs. Point npm at Block + # Artifactory so CI runs produce the same URLs as dev machines instead of + # rewriting them all to registry.npmjs.org. + npm_config_registry: https://global.block-artifacts.com/artifactory/api/npm/square-npm/ + +jobs: + bump: + name: Bump ACP tool pins + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + # Install hermit (manages node, just) + - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + + # The branch is bot-owned and single-commit: every run recreates it from + # main, so it never diverges or accumulates history. + - name: Reset automation branch from main + run: git switch --force-create automation/update-acp-pins + + - name: Bump ACP tool pins + run: just -f apps/staged/justfile bump-acp-tools + + # The recipe touches only the lockfile; a clean diff means no upstream + # releases and the run is done. + - name: Detect lockfile changes + id: bump + run: | + if git diff --quiet -- apps/staged/acp-tools.lock.json; then + echo "Lockfile unchanged; no upstream releases." + echo "changed=false" >> "$GITHUB_OUTPUT" + else + echo "changed=true" >> "$GITHUB_OUTPUT" + fi + + # PR CI does not consume the lockfile, so a broken pin would otherwise + # surface only at release time. Install the new pins (with integrity + # validation) before pushing them anywhere. The target is passed + # explicitly because the script's auto-detection needs rustc, which + # this job otherwise does not use. + - name: Smoke-check new pins + if: steps.bump.outputs.changed == 'true' + run: apps/staged/scripts/ensure-acp-tools.sh --target x86_64-unknown-linux-gnu + + - name: Commit and force-push + if: steps.bump.outputs.changed == 'true' + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git commit -m "chore(staged): bump bundled ACP tools to latest" \ + -- apps/staged/acp-tools.lock.json + git push --force origin automation/update-acp-pins + + # Refresh-in-place: while a PR for this branch is open, the force-push + # above already updated it to show the fresh pins rebased on current + # main. Only create a PR when none is open. + - name: Create PR if none open + if: steps.bump.outputs.changed == 'true' + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + open_prs="$(gh pr list --head automation/update-acp-pins --state open --json number --jq length)" + if [ "$open_prs" = "0" ]; then + gh pr create \ + --base main \ + --head automation/update-acp-pins \ + --title "chore(staged): bump bundled ACP tools to latest" \ + --body "Automated daily bump of the ACP bridge tool pins in \`apps/staged/acp-tools.lock.json\` via \`just bump-acp-tools\`. The new pins were smoke-checked in the workflow run by installing them with \`scripts/ensure-acp-tools.sh\`. While this PR is open, each daily run force-pushes the latest pins to this branch." + else + echo "Open PR already exists for automation/update-acp-pins; it now shows the fresh pins." + fi From bffb97d5d0d6c25d85265a477f47000ee34a7d49 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Mon, 13 Jul 2026 16:43:48 +1000 Subject: [PATCH 2/4] fix(staged): drop the Artifactory registry override from the bump workflow The workflow pinned npm_config_registry to Block Artifactory so the regenerated lockfile would keep the same tarball URLs as dev-machine runs. But GitHub-hosted runners have no Artifactory credentials, so both the bump (npm view) and the smoke check (npm install) would fail against that registry. Remove the override and let CI use the default registry; the first scheduled run will rewrite the lockfile tarball URLs to registry.npmjs.org once and they stay stable after that. Co-Authored-By: Claude Fable 5 Signed-off-by: Matt Toohey --- .github/workflows/staged-bump-acp-tools.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/staged-bump-acp-tools.yml b/.github/workflows/staged-bump-acp-tools.yml index 42847131..e30c3f5f 100644 --- a/.github/workflows/staged-bump-acp-tools.yml +++ b/.github/workflows/staged-bump-acp-tools.yml @@ -10,12 +10,6 @@ on: concurrency: group: staged-bump-acp-tools -env: - # The lockfile records registry-specific tarball URLs. Point npm at Block - # Artifactory so CI runs produce the same URLs as dev machines instead of - # rewriting them all to registry.npmjs.org. - npm_config_registry: https://global.block-artifacts.com/artifactory/api/npm/square-npm/ - jobs: bump: name: Bump ACP tool pins From fbbec3312737952b5ee0d8e9ae9b33b53724ad5e Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 14 Jul 2026 11:50:32 +1000 Subject: [PATCH 3/4] ci: bump checkout and activate-hermit pins, use exact-version comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub Advanced Security (zizmor) flagged the actions/checkout and cashapp/activate-hermit pins because their '# v6' / '# v1' comments reference floating major tags that upstream has since moved past the pinned SHAs. The pins themselves were valid release commits (v6.0.2 and v01.1.2), just stale. Bump both pins to the current releases across all seven workflows: - actions/checkout df4cb1c0 (v6.0.3, verified against upstream tags) - cashapp/activate-hermit cea9af79 (v1.1.5, verified against upstream) Comments now name the exact release (# v6.0.3, # v1.1.5) instead of a floating major, so they stay accurate to the pinned SHA and the zizmor check stays green across future upstream patch releases. No generator or template produces these workflows — the stale pins spread by copy-paste — so editing the seven YAML files is the complete change. Co-Authored-By: Claude Fable 5 Signed-off-by: Matt Toohey --- .github/workflows/crates-ci.yml | 4 ++-- .github/workflows/differ-ci.yml | 4 ++-- .github/workflows/penpal-ci.yml | 4 ++-- .github/workflows/penpal-release.yml | 6 +++--- .github/workflows/staged-bump-acp-tools.yml | 4 ++-- .github/workflows/staged-ci.yml | 4 ++-- .github/workflows/staged-release.yml | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/crates-ci.yml b/.github/workflows/crates-ci.yml index 1f253114..cbe9ab66 100644 --- a/.github/workflows/crates-ci.yml +++ b/.github/workflows/crates-ci.yml @@ -29,10 +29,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Install hermit (manages rust, just) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # Cache Cargo dependencies - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 diff --git a/.github/workflows/differ-ci.yml b/.github/workflows/differ-ci.yml index bd2a0078..5ae49fd1 100644 --- a/.github/workflows/differ-ci.yml +++ b/.github/workflows/differ-ci.yml @@ -35,10 +35,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Install hermit (manages node, rust, just) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # Enable pnpm via corepack (node ships with corepack; version comes from packageManager in package.json) - run: corepack enable pnpm diff --git a/.github/workflows/penpal-ci.yml b/.github/workflows/penpal-ci.yml index 12c5e6f2..2920ee11 100644 --- a/.github/workflows/penpal-ci.yml +++ b/.github/workflows/penpal-ci.yml @@ -31,10 +31,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Install hermit (manages node, rust, just, go) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # Cache Cargo dependencies - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 diff --git a/.github/workflows/penpal-release.yml b/.github/workflows/penpal-release.yml index 89d13c2b..3abe4ad9 100644 --- a/.github/workflows/penpal-release.yml +++ b/.github/workflows/penpal-release.yml @@ -15,7 +15,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Validate that the git tag version matches Cargo.toml to prevent # mismatched artifact names vs Homebrew URLs (see package.sh line 9). @@ -30,7 +30,7 @@ jobs: fi # Install hermit (manages node, rust, just, go) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # Cache Cargo dependencies - uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2 @@ -89,7 +89,7 @@ jobs: contents: write actions: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: fetch-depth: 0 fetch-tags: true diff --git a/.github/workflows/staged-bump-acp-tools.yml b/.github/workflows/staged-bump-acp-tools.yml index e30c3f5f..c40d2520 100644 --- a/.github/workflows/staged-bump-acp-tools.yml +++ b/.github/workflows/staged-bump-acp-tools.yml @@ -18,10 +18,10 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Install hermit (manages node, just) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # The branch is bot-owned and single-commit: every run recreates it from # main, so it never diverges or accumulates history. diff --git a/.github/workflows/staged-ci.yml b/.github/workflows/staged-ci.yml index e4bfa2a1..3bcbdde0 100644 --- a/.github/workflows/staged-ci.yml +++ b/.github/workflows/staged-ci.yml @@ -35,10 +35,10 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 # Install hermit (manages node, rust, just) - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 # Enable pnpm via corepack (node ships with corepack; version comes from packageManager in package.json) - run: corepack enable pnpm diff --git a/.github/workflows/staged-release.yml b/.github/workflows/staged-release.yml index 9c2c4146..de6e821e 100644 --- a/.github/workflows/staged-release.yml +++ b/.github/workflows/staged-release.yml @@ -17,9 +17,9 @@ jobs: contents: write id-token: write steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1 + - uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1.1.5 - run: corepack enable pnpm From b6cf974c0142facf7c8c09aa19de940ee2b50eb3 Mon Sep 17 00:00:00 2001 From: Matt Toohey Date: Tue, 14 Jul 2026 12:08:32 +1000 Subject: [PATCH 4/4] ci(staged): smoke-check all lockfile targets in the ACP bump workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bump workflow smoke-checked only x86_64-unknown-linux-gnu — the runner's native triple and arguably the least-consumed target: releases build for aarch64-apple-darwin, and dev machines install the darwin and linux entries via `just dev`/`just install`. Since PR CI does not consume the lockfile, a target-specific bad pin (partial publish, darwin-only packaging change, broken tarball) would merge unattended and surface only at release time or on a dev's next `just dev`. Install the new pins for every target in the lockfile instead. The target list is derived from acp-tools.lock.json rather than hardcoded, so it cannot drift when targets are added or removed, and every derived target is guaranteed to have lock entries. ensure-acp-tools.sh already passes --os/--cpu/--libc to npm on every install and never executes the tools, so the Linux runner validates the darwin entries the same way (verified: all four targets install and pass integrity/executable validation cross-platform). Prompted by a Codex review comment asking to smoke-check the release target; extended to all four targets since dev machines consume the rest. Co-Authored-By: Claude Fable 5 Signed-off-by: Matt Toohey --- .github/workflows/staged-bump-acp-tools.yml | 24 +++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/.github/workflows/staged-bump-acp-tools.yml b/.github/workflows/staged-bump-acp-tools.yml index c40d2520..61bdf51f 100644 --- a/.github/workflows/staged-bump-acp-tools.yml +++ b/.github/workflows/staged-bump-acp-tools.yml @@ -44,13 +44,23 @@ jobs: fi # PR CI does not consume the lockfile, so a broken pin would otherwise - # surface only at release time. Install the new pins (with integrity - # validation) before pushing them anywhere. The target is passed - # explicitly because the script's auto-detection needs rustc, which - # this job otherwise does not use. - - name: Smoke-check new pins + # surface only at release time (aarch64-apple-darwin) or on a dev + # machine's next `just dev`. Install the new pins (with integrity + # validation) for every target in the lockfile before pushing them + # anywhere; npm's --os/--cpu flags let this Linux runner install the + # foreign-platform entries too. Targets are passed explicitly because + # the script's auto-detection needs rustc, which this job otherwise + # does not use. + - name: Smoke-check new pins for all lockfile targets if: steps.bump.outputs.changed == 'true' - run: apps/staged/scripts/ensure-acp-tools.sh --target x86_64-unknown-linux-gnu + run: | + targets="$(node -e ' + const { tools } = require("./apps/staged/acp-tools.lock.json"); + process.stdout.write([...new Set(tools.map((tool) => tool.target))].sort().join("\n")); + ')" + while IFS= read -r target; do + apps/staged/scripts/ensure-acp-tools.sh --target "$target" + done <<< "$targets" - name: Commit and force-push if: steps.bump.outputs.changed == 'true' @@ -75,7 +85,7 @@ jobs: --base main \ --head automation/update-acp-pins \ --title "chore(staged): bump bundled ACP tools to latest" \ - --body "Automated daily bump of the ACP bridge tool pins in \`apps/staged/acp-tools.lock.json\` via \`just bump-acp-tools\`. The new pins were smoke-checked in the workflow run by installing them with \`scripts/ensure-acp-tools.sh\`. While this PR is open, each daily run force-pushes the latest pins to this branch." + --body "Automated daily bump of the ACP bridge tool pins in \`apps/staged/acp-tools.lock.json\` via \`just bump-acp-tools\`. The new pins were smoke-checked in the workflow run by installing them for every lockfile target with \`scripts/ensure-acp-tools.sh\`. While this PR is open, each daily run force-pushes the latest pins to this branch." else echo "Open PR already exists for automation/update-acp-pins; it now shows the fresh pins." fi