Skip to content

ci: read the bot PAT from an environment in every workflow - #6169

Merged
max-sixty merged 1 commit into
mainfrom
tend-secret-env
Aug 9, 2026
Merged

ci: read the bot PAT from an environment in every workflow#6169
max-sixty merged 1 commit into
mainfrom
tend-secret-env

Conversation

@max-sixty

@max-sixty max-sixty commented Aug 8, 2026

Copy link
Copy Markdown
Member

tend check fails repo-secret-allowlist: TEND_BOT_TOKEN is a repo-level secret, so every workflow the repo runs can read the bot's PAT, including workflows a same-repo PR branch adds. The allowlist escape hatch isn't available for this one — tend refuses TEND_BOT_TOKEN in secrets.allowed at config load, on the grounds that a repo-level copy is exactly what the environment gate exists to prevent.

So every consumer moves behind an environment. The generated tend-*.yaml jobs already do this. The five hand-written ones split by the ref they run at, which is what decides the environment: a deployment branch policy is evaluated against the run's ref, and a job naming an environment that doesn't admit its ref is refused before its first step.

Job Ref Environment
tests.yaml:update-rust-toolchain main (schedule-only) tend
pull-request-target.yaml:backport base branch tend
release.yaml:brew-dispatcher tag release
release.yaml:publish-winget tag release
release.yaml:push-web-branch tag release

backport also gains a base.ref == 'main' condition. pull_request_target runs at the base branch's ref, and tend admits only main, so without it the backport PRs that merge into web would hit a refused environment rather than skipping. Backports flow out of main, so this doesn't lose anything.

The three release jobs pick up the required reviewers already on the release environment. GitHub approves per job rather than per environment, so a release will ask for approval in a couple more rounds than it does today.

Secret operations

release now holds its own TEND_BOT_TOKEN, copied from the bot's gh credential per the install skill's step 8c, so the three release jobs have a token the moment this lands.

That leaves the deletion, which is what makes the check pass. It goes after this merges, not before: a job naming an environment can still read a repo-level secret of the same name, so the workflows keep working across the merge, and deleting early would leave the ungated jobs on main with an empty token.

gh secret delete TEND_BOT_TOKEN --repo PRQL/prql
Why the release jobs can't use the tend environment

tend holds the token already, but its policy admits only main, and tend's own environment check asserts that. A release job runs at refs/tags/X.Y.Z. release is the environment whose policy covers that ref, and tend's credential-environments check requires required reviewers on any environment a workflow reaches on a release: trigger, which release has.

This was written by Claude Code on behalf of max-sixty

The generated tend-*.yaml jobs already name the `tend` environment; the
hand-written consumers still read `TEND_BOT_TOKEN` at repo level, where
every workflow the repo runs can reach it.

Gate the remaining five: `tests.yaml:update-rust-toolchain` and
`pull-request-target.yaml:backport` run on `main`, so they take `tend`;
the three release-time jobs run on a tag, so they take `release`.

Restrict the backport job to a `main` base while doing so, since
`pull_request_target` runs at the base branch's ref and the `tend`
environment admits only `main`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@prql-bot prql-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked each job's ref against the environment it now names, and the pairing holds: tend's deployment policy is the main branch only, release's is the *.*.* tag pattern. update-rust-toolchain is gated on nightly-upstream, which is github.event_name == 'schedule' && github.repository_owner == 'prql', so its ref is always main; the backport job's new base.ref == 'main' condition is what turns a would-be refused-environment failure on web-based PRs into a skip; and the three release jobs are all if: github.event_name == 'release', so the unconditional environment: release is right there rather than the ${{ ... || '' }} form publish-js/publish-to-cargo need for their off-release dry runs. Every remaining secrets.TEND_BOT_TOKEN reference now sits in a job that names an environment.

One note on the two secret operations: the ordering in the description is load-bearing rather than stylistic. The release environment currently holds only SNAPCRAFT_STORE_CREDENTIALS, so deleting the repo-level copy before gh secret set ... --env release lands would leave brew-dispatcher, publish-winget and push-web-branch reading an empty token — and that wouldn't surface until the next release.

The one red check, nightly / nightly-release / build-prqlc (macos-15-intel, ...), is a transient rustup fetch failure (dns error: failed to lookup address information pulling rustc-1.96.1-x86_64-apple-darwin.tar.xz), unrelated to this change. nightly is in check-ok-to-merge's allowed-failures, and that gate is green.

@max-sixty
max-sixty merged commit 8a45b8a into main Aug 9, 2026
152 of 153 checks passed
@max-sixty
max-sixty deleted the tend-secret-env branch August 9, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants