Skip to content

Commit af5cd0c

Browse files
ci(reusables): gate Radicle mirror + Instant Sync dispatch on secret presence (auto-fixes 65 repos) (#305)
## Summary Two source-level fixes in shared workflows. Zero fan-out PRs needed — both fixes auto-propagate to every caller via the existing reusable/standalone patterns. ## Fix 1: `mirror-reusable.yml` mirror-radicle (26 repos auto-fixed) **Root cause:** mirror-radicle's three working steps fired unconditionally when `vars.RADICLE_MIRROR_ENABLED == 'true'`, even when `secrets.RADICLE_KEY` was empty. The `echo > ~/.radicle/keys/radicle` write also failed because the parent directory `~/.radicle/keys/` doesn't exist by default. **Fix:** - `if: \${{ secrets.RADICLE_KEY != '' }}` on Setup Rust / Install Radicle / Mirror to Radicle steps - `mkdir -p ~/.radicle/keys` before the key write - New inverse-gate "Skipped" advisory step that prints a `::notice` instead of failing ## Fix 2: `instant-sync.yml` dispatch (39 repos auto-fixed) **Root cause:** `peter-evans/repository-dispatch` ran unconditionally on every push; without `secrets.FARM_DISPATCH_TOKEN` the action falls back to `GITHUB_TOKEN`, which cannot dispatch cross-repo and returns HTTP 401 "Bad credentials". **Fix:** - `if: \${{ secrets.FARM_DISPATCH_TOKEN != '' }}` on the Trigger Propagation step - Inverse-gate `::notice` advisory step ## Why source-level Both files are imported via `workflow_call` / direct-paste templates across ~289 estate caller wrappers. Source-level gate = automatic per-repo fix. ## Owner action for full activation (optional) - mirror-radicle: configure `RADICLE_KEY` (per-repo or org-level secret). - instant-sync: configure org-level `FARM_DISPATCH_TOKEN` PAT with repo scope. This PR makes those owner actions **optional** — without the secret the workflow is no-op; with the secret it works. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fee07db commit af5cd0c

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

.github/workflows/instant-sync.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ jobs:
1515
dispatch:
1616
runs-on: ubuntu-latest
1717
steps:
18+
# Gate the cross-repo repository_dispatch on FARM_DISPATCH_TOKEN
19+
# being configured. Without the PAT, peter-evans/repository-dispatch
20+
# falls back to GITHUB_TOKEN — which cannot dispatch cross-repo and
21+
# returns HTTP 401 "Bad credentials", failing the job. Caught 39
22+
# estate repos on the 2026-05-30 audit. With this gate the workflow
23+
# gracefully skips on repos where the secret has not been
24+
# propagated, instead of red-ing main on every push.
1825
- name: Trigger Propagation
26+
if: ${{ secrets.FARM_DISPATCH_TOKEN != '' }}
1927
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v3
2028
with:
2129
token: ${{ secrets.FARM_DISPATCH_TOKEN }}
@@ -29,6 +37,13 @@ jobs:
2937
"forges": ""
3038
}
3139
40+
- name: Skipped (FARM_DISPATCH_TOKEN not configured)
41+
if: ${{ secrets.FARM_DISPATCH_TOKEN == '' }}
42+
env:
43+
REPO_NAME: ${{ github.event.repository.name }}
44+
run: |
45+
echo "::notice::FARM_DISPATCH_TOKEN secret not configured on ${REPO_NAME}; skipping cross-repo dispatch. Configure the org-level FARM_DISPATCH_TOKEN PAT (repo scope) to enable instant forge propagation."
46+
3247
- name: Confirm
3348
env:
3449
REPO_NAME: ${{ github.event.repository.name }}

.github/workflows/mirror-reusable.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,34 @@ jobs:
156156
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
157157
with:
158158
fetch-depth: 0
159+
# All Radicle steps gate on secrets.RADICLE_KEY being set on the
160+
# caller repo (resolved via `secrets: inherit`). Without this gate
161+
# the workflow burned ~3 minutes of Rust+Radicle install on every
162+
# push to every RADICLE_MIRROR_ENABLED repo only to fail at
163+
# `~/.radicle/keys/radicle: No such file or directory` because the
164+
# `echo "" > ...` write into a non-existent dir errors out — and
165+
# even if the dir existed, the empty-key write would never sync.
166+
# Caught 26 estate repos on the 2026-05-30 audit. The vars gate
167+
# answers "is Radicle mirror desired here?"; the secret gate
168+
# answers "are we configured to actually do it?".
159169
- name: Setup Rust
170+
if: ${{ secrets.RADICLE_KEY != '' }}
160171
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # stable
161172
with:
162173
toolchain: stable
163174
- name: Install Radicle
175+
if: ${{ secrets.RADICLE_KEY != '' }}
164176
run: |
165177
cargo install radicle-cli --locked
166178
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
167179
- name: Mirror to Radicle
180+
if: ${{ secrets.RADICLE_KEY != '' }}
168181
run: |
182+
mkdir -p ~/.radicle/keys
169183
echo "${{ secrets.RADICLE_KEY }}" > ~/.radicle/keys/radicle
170184
chmod 600 ~/.radicle/keys/radicle
171185
rad sync --announce || echo "Radicle sync attempted"
186+
- name: Skipped (RADICLE_KEY not configured)
187+
if: ${{ secrets.RADICLE_KEY == '' }}
188+
run: |
189+
echo "::notice::RADICLE_MIRROR_ENABLED=true but secrets.RADICLE_KEY is empty. Skipping Radicle mirror. Configure the RADICLE_KEY org/repo secret to enable."

0 commit comments

Comments
 (0)