Skip to content

fix(workflows): restore CI Claude permissions broken by claude-code-action bump (pipeline generated nothing since July 5)#9651

Merged
MarkusNeusinger merged 3 commits into
mainfrom
fix/claude-action-workspace-trust
Jul 23, 2026
Merged

fix(workflows): restore CI Claude permissions broken by claude-code-action bump (pipeline generated nothing since July 5)#9651
MarkusNeusinger merged 3 commits into
mainfrom
fix/claude-action-workspace-trust

Conversation

@MarkusNeusinger

@MarkusNeusinger MarkusNeusinger commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Problem

No implementation has been generated repo-wide since July 1. Every impl-generate run since the July 5 Dependabot bump of anthropics/claude-code-action (#9513, again #9643) shows the same signature: the Claude step reports is_error: false after 30 turns ($1.5-2.0 spent), but permission_denials_count: 18-20 and neither the implementation file nor plot-light.png/plot-dark.png exist afterwards. The daily-regen preflight steps (spec polish, similarity audit) show the same denials (1 and 7 per run). Because failures never advance the metadata updated timestamp, daily-regen re-picks the same oldest spec (heatmap-calendar) every tick and burns 15 failing runs per cycle.

Root cause

The action bump carried a Claude Code CLI bump: 2.1.170 → 2.1.211. Newer CLIs ignore permissions.allow entries from .claude/settings.json when the workspace has not been trusted (interactive trust dialog / hasTrustDialogAccepted in ~/.claude.json) — and a fresh CI runner is never trusted. So the repo's allowlist (Write, Edit, Bash, …) was silently dropped and headless mode denied every write-capable tool call. Claude "finished" politely after being denied ~19 times, the action reported success, and the workflow failed later at the metadata/image steps.

Reproduced locally on CLI 2.1.218 with the repo's exact allowlist in a scratch project:

Ignoring 7 permissions.allow entries from .claude/settings.json: this workspace
has not been trusted. Run Claude Code interactively here once and accept the
trust dialog, or set projects["…"].hasTrustDialogAccepted: true in ~/.claude.json.

Write denied, no file created (turns=2, exactly the CI pattern).

Fix

Pass the repo's settings file explicitly — the trust gate honors an explicit --settings flag as opt-in. Verified locally: same prompt, same allowlist, with --settings .claude/settings.json the file is written with 0 denials.

Applied to all 12 claude-code-action steps across 7 workflows (impl-generate ×2, impl-repair ×2, spec-create ×2, daily-regen ×2, util-claude ×2, impl-review, report-validate):

claude_args: "--model … --settings ${{ github.workspace }}/.claude/settings.json"

Also fixed while in the file: a backtick fragment in the metadata step's Python-heredoc comment was command-substituted by bash on every run (--model: command not found in all run logs) — now single-quoted.

Why there is no green branch-CI proof

Branch-side validation of any change to these workflows is structurally impossible: the action's OAuth token exchange rejects runs whose workflow file differs from the default branch (401 Workflow validation failed. The workflow file must exist and have identical content to the version on the repository's default branch.). This was verified with a dispatch of a pinned test variant — Claude never even started. The local reproduction above is the validation.

Post-merge confirmation run

After merge, dispatch a single real generation and confirm it produces files:

gh workflow run impl-generate.yml -f specification_id=heatmap-calendar -f library=matplotlib -f model=sonnet

Expected: permission_denials_count: 0, implementation + both PNGs committed, run green through metadata/image steps.

🤖 Generated with Claude Code

Upstream context (source/changelog audit of the action + CLI)

  • Version mapping: 11ba6048 = action v1.0.142 (bundled CLI 2.1.170, worked) → Dependabot deps(actions): bump the actions group across 1 directory with 3 updates #9513 (July 5) = v1.0.159 (CLI 2.1.195, first broken) → deps(actions): Bump the actions group across 3 directories with 6 updates #9643 (July 20) = v1.0.175 (CLI 2.1.211, still broken). The action's agent-mode permission plumbing is identical across all three refs — the only variable is the bundled CLI.
  • The trust hardening is deliberate upstream direction: CLI 2.1.196 stopped honoring repo self-approval via committed .claude/settings.json (MCP), and 2.1.207 documents that only user, --settings, and managed settings remain trusted sources. That is why the explicit --settings flag is the upstream-blessed mechanism, not a workaround.
  • No action version fixes this: audited through the latest release v1.0.181 (CLI 2.1.218) — the action never establishes workspace trust, so future Dependabot bumps stay broken without this flag. Keep --settings in claude_args permanently.
  • Deliberately not chosen: --permission-mode bypassPermissions (works, but drops the allowlist semantics and any future deny rules) and pinning the action back to v1.0.142 (forgoes the v1.0.175 CI-correctness fixes: is_error → real failure, PR-trigger iterator hang, Bun tsconfig crash).

…their permissions

Since the July 5 claude-code-action bump (Claude Code CLI 2.1.170 ->
2.1.211), the CLI ignores permissions.allow entries from
.claude/settings.json when the workspace is not trusted - and a CI
checkout never is. Every pipeline Claude step has run with zero write
permissions since then: 18-20 tool denials per run, no implementation
files, no plots, nothing generated repo-wide since July 1.

Passing --settings .claude/settings.json in claude_args is honored by
the trust gate as an explicit opt-in (verified locally on CLI 2.1.218:
denial reproduced without the flag, file written with it). Apply it to
all 12 claude-code-action steps across the 7 workflows.

Also fix a backtick fragment in the metadata step's Python heredoc
comment that bash command-substituted on every run
("--model: command not found").

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 23, 2026 21:08
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MarkusNeusinger added a commit that referenced this pull request Jul 23, 2026
Root cause of the pipeline breakage is found and fixed in PR #9651 —
no further validation runs on this branch are needed or even possible:
the action's OAuth token exchange 401s any run whose workflow file
differs from the default branch ('Workflow validation failed. The
workflow file must exist and have identical content to the version on
the repository's default branch.'). That 401 is also why the earlier
July-1-pin validation run produced an empty result: Claude never
started, so it neither confirmed nor refuted the action-version
hypothesis. The actual mechanism (confirmed by local repro): CLI
2.1.171+ ignores permissions.allow from .claude/settings.json in
untrusted workspaces, and CI checkouts are never trusted; explicit
--settings in claude_args is honored and fixes it.

impl-generate.yml is now byte-identical to main again, leaving this PR
with only its cron-offset + watchdog-liveness content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Restores write-capable Claude Code execution in CI after a claude-code-action/CLI bump caused .claude/settings.json permissions.allow entries to be ignored in untrusted workspaces, preventing all pipeline-generated files from being created.

Changes:

  • Adds an explicit --settings ${{ github.workspace }}/.claude/settings.json to all anthropics/claude-code-action steps so the allowlist is honored in CI.
  • Fixes a bash command-substitution issue in impl-generate where backticks inside the Python -c "..." string were executed by the shell.
  • Documents both fixes in CHANGELOG.md under Fixed.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
CHANGELOG.md Adds an Unreleased “Fixed” entry documenting the restored Claude pipeline permissions and the metadata-step backtick substitution fix.
.github/workflows/util-claude.yml Passes --settings to Claude Code runs to restore allowlisted tool permissions.
.github/workflows/spec-create.yml Passes --settings to both spec-create Claude steps to restore write/edit capabilities.
.github/workflows/report-validate.yml Passes --settings to the Claude validation step to restore allowlisted permissions.
.github/workflows/impl-review.yml Passes --settings to the AI quality review step to ensure consistent permissions.
.github/workflows/impl-repair.yml Passes --settings to repair + retry Claude steps so repairs can actually write changes.
.github/workflows/impl-generate.yml Passes --settings to generate + retry steps; removes backticks in the Python -c block comment to prevent shell command substitution.
.github/workflows/daily-regen.yml Passes --settings to spec-polish and similarity-audit Claude steps so they can write outputs when needed.

… 2.1.211

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 23, 2026 21:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@MarkusNeusinger
MarkusNeusinger merged commit 9be4435 into main Jul 23, 2026
8 checks passed
@MarkusNeusinger
MarkusNeusinger deleted the fix/claude-action-workspace-trust branch July 23, 2026 21:17
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