diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-05-29 12:15:36 +0300 |
|---|---|---|
| committer | Yuriy Andamasov <yuriy@vyos.io> | 2026-05-29 12:15:36 +0300 |
| commit | 1fa39bd7ac64898f7a21922bc0f195d115d3cdeb (patch) | |
| tree | 223d18bbeca66b00b432cb6892cda28a6eef2f11 | |
| parent | 5da6f5c1671f5ac0b6e431d1ec17b1fe26e5c3c5 (diff) | |
| download | vyos-documentation-1fa39bd7ac64898f7a21922bc0f195d115d3cdeb.tar.gz vyos-documentation-1fa39bd7ac64898f7a21922bc0f195d115d3cdeb.zip | |
ci(ai-validation): allow Pass 2 review on external-contributor PRs
The upstream `anthropics/claude-code-action` performs a write-permission
check on `github.actor` before our skip logic runs. On `pull_request_target`
the actor is the PR author; external contributors resolve to `read` and the
action exits 1 with `Actor does not have write permissions to the repository`.
Net effect: AI validation has been failing on every external-contributor PR
(LiudmylaNad, teslazonda, scottlaird in the last 4 weeks) while succeeding
on maintainer PRs. Failure reproduced on run 26541079685 (PR #2061).
Fix: set `allowed_non_write_users: '*'` on the Pass 2 step. The action
bypasses the actor check when this input is set and `github_token` is
provided (already the case). The action also auto-scrubs Anthropic / cloud
/ GHA secrets from subprocess envs when this input is set.
Safe in THIS workflow because the existing defense-in-depth bounds what
Pass 2 can do with untrusted PR content:
- `allowedTools` restricted to inline-comment + read-only surfaces
- `github_token` is the PR-scoped default (not the broader VYOS_APP_ID)
- prompt marks PR content as untrusted via `<UNTRUSTED-PR-CONTENT>`
- workspace-wipe removes `CLAUDE.md` / `.claude/` before Pass 2
- prepare bundles MD via `git show HEAD:<path>` (blob, not `cp`)
Full rationale inlined as a comment block above the new input.
🤖 Generated by [robots](https://vyos.io)
| -rw-r--r-- | .github/workflows/ai-validation.yml | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/.github/workflows/ai-validation.yml b/.github/workflows/ai-validation.yml index 58cd6c38..ed0d3e5e 100644 --- a/.github/workflows/ai-validation.yml +++ b/.github/workflows/ai-validation.yml @@ -566,6 +566,41 @@ jobs: # source / vyos-1x checkouts above, and has no write access # on vyos/vyos-documentation PRs. github_token: ${{ github.token }} + # Bypass the upstream action's actor write-permission check. The + # check (src/github/validation/permissions.ts in claude-code-action) + # calls getCollaboratorPermissionLevel on github.actor and fails + # with `Actor does not have write permissions to the repository` + # when an external contributor opens a PR, because the actor on + # pull_request_target is the PR author and forks resolve to + # `read`. That kills validation on every fork PR before any of + # our own skip logic runs — defeating the workflow's entire + # purpose (catching CLI/default-value drift in contributions + # from non-maintainers). Failure mode reproduced on run + # 26541079685 (PR #2061 from LiudmylaNad); same pattern hit + # every external contributor PR in the prior 4 weeks. + # + # Setting '*' is safe in THIS workflow specifically because the + # surrounding defense-in-depth bounds what Pass 2 can do with + # untrusted PR content: + # - allowedTools is restricted to inline-comment + read-only + # surfaces (no Bash arbitrary, no Write, no Edit — see the + # claude_args block below) + # - github_token is the workflow's PR-scoped default token + # (pull-requests:write + issues:write + contents:read) — + # NOT the broader VYOS_APP_ID token, which is only used for + # the vyos-1x / reviewer-source checkouts + # - the prompt explicitly marks PR content as untrusted with + # <UNTRUSTED-PR-CONTENT> markers and tells Claude to treat + # it as data, not instructions + # - the workspace-wipe step removes CLAUDE.md / .claude/ + # before this step runs, so fork-controlled session + # instructions can't be auto-loaded + # - prepare bundles MD files via `git show HEAD:<path>` (blob + # extraction, not `cp`) — symlinks resolve to their target + # paths, not their content + # - the action auto-scrubs Anthropic / cloud / GHA secrets + # from subprocess envs when this input is set + allowed_non_write_users: '*' # claude-code-action@v1 removed the top-level `model` input; CLI # flags including --model now travel via `claude_args` (see the # claude_args: block at the bottom of this step). |
