Skip to content

ci(security): run the weekly Dependabot fix routine in GitHub Actions (Bundler) - #336

Merged
PMerlet merged 8 commits into
mainfrom
ci/security-fixes-workflow
Jul 30, 2026
Merged

ci(security): run the weekly Dependabot fix routine in GitHub Actions (Bundler)#336
PMerlet merged 8 commits into
mainfrom
ci/security-fixes-workflow

Conversation

@PMerlet

@PMerlet PMerlet commented Jul 30, 2026

Copy link
Copy Markdown
Member

Why

The weekly "Fix vulnerabilities" claude.ai cloud routines have been failing with 403 on the Dependabot alerts API. Root cause (established 2026-07-23): the Claude cloud environments' GitHub proxy replaces the Authorization header of every request to api.github.com with its own GitHub App user-to-server token — regardless of any PAT configured in the environment — and that token cannot read Dependabot alerts, Actions runs, or commit statuses. This is by design ("keeps your real GitHub credentials outside the sandbox"), so the routine can never work there.

This PR moves the same routine into GitHub Actions (instructions adapted from npm/yarn to Bundler for this repo), where secrets reach the job untouched.

What

  • .github/workflows/security-fixes.yml — scheduled job (Thursdays 11:00 UTC, same slot as before), runs the agent via anthropics/claude-code-action@v1, 120 min timeout, manual trigger available (workflow_dispatch).
  • .github/security-fixes-prompt.md — the agent instructions (same battle-tested prompt as the cloud routine: preflight probe, strict triage with explicit ignore reasons, 7-day age gate, narrowest-bump-first strategy, pin/resolution hygiene audit, PR with the :lock: security label pinging @first_level_support, CI monitoring with a 3-retry cap).

Before merging — org secrets required

The workflow needs two organization-level secrets (shared by the 5 repos getting this workflow: forestadmin-server, forestadmin, toolbelt, agent-nodejs, agent-ruby):

Secret Value
SECURITY_GH_PAT The "Claude routines" fine-grained PAT (Dependabot alerts RO, Contents RW, Workflows RW, Pull requests RW, Issues RW, Actions RW, Commit statuses RO on the 5 repos)
ANTHROPIC_API_KEY A Claude API key

Without them, the run stops at preflight with an explicit error message.

Notes

  • The claude.ai cloud routines are disabled (kept for reference, not deleted).
  • First run: next Thursday 13:00 Paris — or trigger it manually from the Actions tab to validate earlier.

🤖 Generated with Claude Code

Note

Add weekly automated Dependabot security-fix workflow using Claude

  • Adds security-fixes.yml, a GitHub Actions workflow that runs weekly (and on manual dispatch) to automate Dependabot alert triage and dependency bumps for the Ruby/Bundler monorepo.
  • The workflow checks out the repo, installs Ruby 3.4 deps, then invokes anthropics/claude-code-action with ANTHROPIC_API_KEY and SECURITY_GH_PAT to execute the runbook in security-fixes-prompt.md.
  • The runbook defines alert triage logic, dependency bump strategy, PR creation/labeling flow, and CI retry procedures with exact shell commands and API calls.
  • Concurrency is limited to one run at a time via the security-fixes group, with a 240-minute job timeout.

Macroscope summarized 128b73c.

The claude.ai cloud routines cannot call the Dependabot alerts API (the
cloud GitHub proxy substitutes its own app token on api.github.com by
design). Same schedule (Thursdays 11:00 UTC), same agent instructions,
now running where the SECURITY_GH_PAT secret reaches the job untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/security-fixes-prompt.md Outdated
Comment thread .github/security-fixes-prompt.md
Comment thread .github/security-fixes-prompt.md Outdated
Comment thread .github/workflows/security-fixes.yml Outdated
…kflow

- raise the job timeout to 240 min to cover the full CI-polling retry budget
- resume the existing security/<date> branch and PR on same-day reruns
- refresh the head SHA after each corrective push during CI monitoring
- treat an empty combined-status (total_count: 0) as no status gate
- provide GH_PAT at job level instead of step level

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/workflows/security-fixes.yml
- override the action's default guardrails (--append-system-prompt) so the
  unattended agent actually pushes the security branch and opens the PR
- same-day rerun now supersedes the dated branch with --force-with-lease
  (recomputed from scratch), instead of fragile stash/resume logic that
  could carry stale history from closed PRs
- phase 8: startup guard against vacuous green (zero workflow runs),
  all-green now also requires combined status success when contexts exist,
  failing status contexts are reported explicitly
- agent-ruby: Gemfile.lock is gitignored (library repo) — preflight and
  fix strategy reworked around gemspec/Gemfile constraints, local-only lock

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/security-fixes-prompt.md Outdated
- pin anthropics/claude-code-action to an immutable commit SHA (supply
  chain: the job holds ANTHROPIC_API_KEY and a repo-write PAT)
- fetch the remote security branch before --force-with-lease so the lease
  has an expected value (fresh checkouts only fetch the default branch)
- set SHA via git rev-parse HEAD on every path, including PR reuse
- agent-ruby: treat all packages/*/*.gemspec as direct-dependency owners
  (monorepo of published gems); Gemfile pins flagged as CI-only fixes;
  generate the local Gemfile.lock in the workflow before the agent runs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/security-fixes-prompt.md Outdated
- treat skipped/neutral workflow conclusions as non-failures; only
  failure/timed_out/cancelled/action_required trigger remediation
- the 'unreachable code path' IGNORE reason now requires call-chain or
  configuration evidence — a negative repo grep alone is insufficient

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/security-fixes-prompt.md Outdated
Comment thread .github/security-fixes-prompt.md Outdated
PMerlet and others added 2 commits July 30, 2026 11:15
- the _example/ ignore rule now requires a workspace-aware resolved-tree
  check (npm ls --all / yarn why); manifest grep is not sufficient
- direct bumps and resolutions/overrides pins now target the smallest
  patched version within the parent-compatible major instead of an
  unbounded >= range that could resolve to a breaking major

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- direct bumps now require an explicit upper bound on the current major
  (a bare >= lets Bundler resolve a later breaking major)
- the dev-only triage rule matches this Gemfile's actual group name,
  :development, :tests (plural)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread .github/security-fixes-prompt.md Outdated
Comment thread .github/security-fixes-prompt.md Outdated
Comment thread .github/security-fixes-prompt.md Outdated
… review

Reviewed by three independent adversarial passes (git/GitHub semantics,
clean-runner toolchain reality, internal consistency) on top of the
Macroscope findings. Notable fixes:

Runner reality:
- drop 'corepack enable': with packageManager yarn@1.22.19 pinned and
  Node 22.12's bundled corepack, every yarn call dies on the npm registry
  key rotation (Cannot find matching keyid); the preinstalled yarn 1.22
  handles these repos fine
- raise claude-code-action Bash timeouts (BASH_DEFAULT/MAX_TIMEOUT_MS):
  monorepo installs exceed the default 10-min hard cap
- agent-ruby: all dependency resolution/verification now happens in the
  owning package's own Gemfile (packages/*/), not the root dev-only
  bundle, which proves nothing about shipped gems

GitHub semantics:
- document that SECURITY_GH_PAT needs Workflows RW (pushing uses: bumps)
- Actions log download spelled out as the 302-then-unauthenticated-fetch
  dance; a naive authed -L follow is rejected by blob storage
- ensure-label-first flow: POST /issues/labels silently auto-creates
  missing labels with a random color, the 422 branch was dead code
- Yarn 1 'redundant resolution' audit now deletes the lockfile blocks
  before re-resolving (plain install conservatively keeps the pin)
- phase 8 explicitly flags app-based check runs as unmonitored

Consistency:
- no-changes gate moved to the top of phase 7 (was buried in Constraints)
- phase 5 keeps removals in the working tree; single commit in phase 7
- CI conclusion taxonomy is now exhaustive (skipped/neutral green;
  everything else including stale/startup_failure is a failure)
- retry cap defined as 'at most 3 fix commits'; flaky rerun doesn't count
- split abort messages for missing token vs failed probe
- 'Could not auto-fix' added to the PR description spec
- Yarn-1-only resolutions mechanics (root-level, scoped keys); removed
  npm/pnpm dead branches and the ruby 'conservative lockfile update'
  impossible fix category; polling batched into one Bash loop per call

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PMerlet
PMerlet merged commit 0f58d2b into main Jul 30, 2026
48 checks passed
@PMerlet
PMerlet deleted the ci/security-fixes-workflow branch July 30, 2026 11:16
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.

1 participant