summaryrefslogtreecommitdiff
path: root/.github
diff options
context:
space:
mode:
authorYuriy Andamasov <yuriy@vyos.io>2026-05-29 12:15:36 +0300
committerYuriy Andamasov <yuriy@vyos.io>2026-05-29 12:15:36 +0300
commit1fa39bd7ac64898f7a21922bc0f195d115d3cdeb (patch)
tree223d18bbeca66b00b432cb6892cda28a6eef2f11 /.github
parent5da6f5c1671f5ac0b6e431d1ec17b1fe26e5c3c5 (diff)
downloadvyos-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)
Diffstat (limited to '.github')
-rw-r--r--.github/workflows/ai-validation.yml35
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).