Browse Source

ci: migrate scan-plugins.yml to Workload Identity Federation auth (#1991)

* ci: migrate scan-plugins.yml to Workload Identity Federation auth

Replaces the static ANTHROPIC_API_KEY repo secret with Workload
Identity Federation: the scan-plugins shared action mints a GitHub
OIDC token (id-token: write) and the claude CLI exchanges it for a
short-lived bearer. The federation rule is bound to this repository
(repository_id-pinned).

Depends on anthropics/claude-plugins-community#34 (adds the WIF
inputs to the shared action). Pinned to that PR's head SHA; will
re-pin to a main-branch SHA once #34 merges.

Drops the 'Require ANTHROPIC_API_KEY' fail-closed guard — the WIF
inputs are literal in this file, so the action's skip-if-no-auth
path can't trigger. Updates the prompt-injection security comment
to reflect the short-lived bearer model.

* scan-plugins: re-pin to cpc#34 merge commit on main

claude-plugins-community#34 merged at e85f0d65b4fc87f07862e1dcdc467950514414ec — re-pinning from
the PR head SHA to the squash-merge commit on main so the pin survives
any future branch GC.
zenexer-ant 3 months ago
parent
commit
1b527e2ee7
1 changed files with 23 additions and 20 deletions
  1. 23 20
      .github/workflows/scan-plugins.yml

+ 23 - 20
.github/workflows/scan-plugins.yml

@@ -32,6 +32,7 @@ on:
 
 permissions:
   contents: read
+  id-token: write # Anthropic Workload Identity Federation (scan-plugins action)
 
 # Serialize scans per ref so concurrent runs (a re-dispatch racing the
 # original, or a manual dispatch) don't both restore the same cache, scan
@@ -76,18 +77,11 @@ jobs:
             echo "relevant=true" >> "$GITHUB_OUTPUT"
           fi
 
-      # The shared action no-ops gracefully when ANTHROPIC_API_KEY is unset
-      # (sensible default for community repos). Here `scan` is a required
-      # check, so a silent no-op would make it a rubber stamp — fail closed.
-      - name: Require ANTHROPIC_API_KEY when a scan is needed
-        if: steps.changes.outputs.relevant == 'true'
-        env:
-          API_KEY_SET: ${{ secrets.ANTHROPIC_API_KEY != '' }}
-        run: |
-          if [[ "$API_KEY_SET" != "true" ]]; then
-            echo "::error::ANTHROPIC_API_KEY is not configured; refusing to skip a required policy scan."
-            exit 1
-          fi
+      # Auth: the shared scan-plugins action below uses Workload Identity
+      # Federation (anthropic-federation-rule-id input) — the IDs are literal
+      # in this file, so the action's "skip if no auth" path can't trigger.
+      # The previous "Require ANTHROPIC_API_KEY" fail-closed guard is
+      # therefore no longer needed.
 
       # Verdict cache, keyed on the policy content hash. A prompt change
       # invalidates every cached verdict — that is intentional. The save key
@@ -200,9 +194,17 @@ jobs:
         # The verdict (cached + fresh) is what gates the job, not the action's
         # exit code, and the revert workflow needs the artifact even on failure.
         continue-on-error: true
-        uses: anthropics/claude-plugins-community/.github/actions/scan-plugins@b277757588871fe55b2620de8c6dfda470e2e9d8
+        # Pinned to claude-plugins-community#34 (WIF input support).
+        # TODO: re-pin to a main-branch SHA once #34 merges.
+        uses: anthropics/claude-plugins-community/.github/actions/scan-plugins@e85f0d65b4fc87f07862e1dcdc467950514414ec
         with:
-          anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
+          # Anthropic auth via Workload Identity Federation — the action
+          # mints a GitHub OIDC token (id-token: write above) and the claude
+          # CLI exchanges it for a short-lived bearer. The federation rule is
+          # bound to this repository (repository_id-pinned).
+          anthropic-federation-rule-id: fdrl_0147kJdru6bZKTtzwFNEqsDf
+          anthropic-organization-id: 1ec12c5c-6542-4da8-bf2f-c15919aef01c
+          anthropic-service-account-id: svac_01DnC3BtPHGjYJEGeuUUXZ8v
           marketplace-path: .scan-cache/scan-targets.json
           policy-prompt: .github/policy/prompt.md
           fail-on-findings: "true"
@@ -241,12 +243,13 @@ jobs:
           fi
 
           # Defense in depth: the scan action runs Claude with Read access over
-          # a cloned external repo and ANTHROPIC_API_KEY in its process env. A
-          # successful prompt injection could coerce the model to put key
-          # material into `summary`/`violations`. The action's own step summary
-          # already carries that risk; this workflow adds an artifact and a PR
-          # comment, both public sinks. Scrub any key-shaped token here so it
-          # never reaches the cache, artifact, or comment.
+          # a cloned external repo. With WIF auth the process env carries a
+          # short-lived OIDC JWT (masked) and the CLI's exchanged bearer
+          # rather than a long-lived sk-ant- key, which bounds the blast
+          # radius of a prompt-injection exfil to a token that expires in
+          # minutes. The sk-ant- scrubber stays as defense-in-depth (covers
+          # any future static-key fallback) so key-shaped strings still never
+          # reach the cache, artifact, or PR comment.
           jq -c '(.. | strings) |= gsub("sk-ant-[A-Za-z0-9_-]{8,}"; "[REDACTED]")' \
             "$CACHE_DIR/scanned-raw.json" > "$CACHE_DIR/scanned-raw.json.tmp"
           mv "$CACHE_DIR/scanned-raw.json.tmp" "$CACHE_DIR/scanned-raw.json"