Worker cannot push .github/workflows/* — missing workflow scope
Trigger: a queue worker’s git push is rejected with:
! [remote rejected] feat/... -> feat/...
(refusing to allow an OAuth App to create or update workflow
`.github/workflows/<file>.yml` without `workflow` scope)
The commit itself succeeds — only the push is refused, and only when the diff touches
.github/workflows/. Any other path pushes fine, which is why this hits so rarely and looks
confusing when it does.
Why
Workers authenticate git via gh auth git-credential as the machine account (e.g. AI-Dev-IO1).
That login is an OAuth token (gho_…) whose scopes are gist, read:org, repo — no workflow.
GitHub refuses workflow-file writes from any OAuth token lacking that scope. Confirm with:
gh auth status # look at "Token scopes:" — no `workflow` = this playbook appliesDo not try to fix this by re-scoping the machine account interactively; the worker is headless.
Fix — push with the SOPS GH_TOKEN (has Workflows:write)
GH_TOKEN in secrets/monitoring.env.sops is a radieu fine-grained PAT that carries the
Workflows write permission. Use it for the push only; leave the gh login alone so gh issue /
gh pr keep working as the machine account.
GIT_ASKPASS is the safe delivery mechanism: the token stays in the environment and never reaches
argv, git config, or the remote URL. Never embed a token in the remote URL — that is exactly
how incident #4047 leaked a PAT at rest into /home/claude-runner/app.
export SOPS_AGE_KEY_FILE=/home/claude-runner/.age/p24-infra-keys.txt
cat > /tmp/askpass.sh <<'EOF'
#!/usr/bin/env bash
case "$1" in
Username*) echo "x-access-token" ;;
*) echo "$GIT_PW" ;;
esac
EOF
chmod +x /tmp/askpass.sh
TOK=$(sops --decrypt --input-type dotenv --output-type dotenv secrets/monitoring.env.sops \
| grep -m1 '^GH_TOKEN=' | cut -d= -f2- | tr -d '"' | tr -d '\r')
GIT_PW="$TOK" GIT_ASKPASS=/tmp/askpass.sh GIT_TERMINAL_PROMPT=0 \
git -c credential.helper= push https://github.com/radieu/p24-infra.git \
HEAD:refs/heads/<your-branch>
unset TOK GIT_PW; rm -f /tmp/askpass.sh-c credential.helper= is required — without it the gh helper supplies the scopeless gho_ token
and the push is rejected again.
After pushing — verify nothing leaked
git config --get remote.origin.url # must be tokenless
git config --local --list | grep -icE 'gh[pousr]_|github_pat_' # must be 0Scrub any push output before quoting it anywhere:
sed -E 's/(gh[pousr]_|github_pat_)[A-Za-z0-9_]*/\1***/g'
Notes
gh pr create/gh issue commentneed no special scope — only the push does. Once the branch is up, the rest of the worker flow proceeds as the machine account normally.- The same applies to merging a PR whose head branch adds workflow files: the merge is performed
server-side by GitHub, so it needs no
workflowscope from the worker. - If
GH_TOKENis ever rotated to a token without Workflows:write, this breaks. The symptom is identical to the above; re-check with thegh auth status/ push test before assuming otherwise.
Related: adding-new-worker.md · incident #4047 (PAT in remote URL)