Skip to content

ci(security-review): adopt always-report shape — paths input replaces workflow-level filter - #825

Merged
kyle-sexton merged 2 commits into
mainfrom
ci/security-review-always-report-caller
Jul 21, 2026
Merged

ci(security-review): adopt always-report shape — paths input replaces workflow-level filter#825
kyle-sexton merged 2 commits into
mainfrom
ci/security-review-always-report-caller

Conversation

@kyle-sexton

Copy link
Copy Markdown
Contributor

What

Phase II steps 1–2 caller adoption (enforcement rail, #509 — not closed here; step 3 remains):

  • .github/workflows/claude-security-review.yml: drop the workflow-level on.pull_request.paths filter; pass the same 26 security-sensitive patterns as the reusable workflow's new paths input; re-pin to the ci-workflows#189 merge SHA (99cb082). The workflow now triggers on every PR; the reusable workflow's changes job decides relevance and a not-applicable PR yields a name-stable SKIPPED security-review / security-review check a required-check ruleset reads as success.
  • docs/adr/0002: ordering-correction addendum — ci-workflows-first, because a caller-side if: on the uses: job registers a DIFFERENT check name when skipped (community discussion 72708: child context stays "Expected" and wedges prose PRs), and caller-first against the old pin would run a full security pass on every prose PR in the interim. Ruleset flip stays LAST (unchanged constraint).
  • docs/topics/ladder-climb-roadmap/PLAN.md: Phase II tagged DOING + dated scope-change note.

Phase II step 0 record (per plan sanity check)

  • Consumer inventory: direct contents-API enumeration of all 11 active melodic-software repos + the proving-ground scratch repo (gh search code returned a false empty and was not trusted) — exactly one consumer of the reusable security workflow: this repo's caller. Full sweep archived in session records.
  • Captured check context (live check runs 2026-07-21): security-review / security-review; caller job id and reusable job id unchanged by this PR, so the context is stable pre/post restructure.
  • Upstream verification: workflow-level path skip leaves a required check Pending (wedge); job-level conditional skip reports Success — troubleshooting-required-status-checks. Inner-job skip name-stability confirmed empirically on this repo (run 29793157393: skip-actors skip reported security-review / security-review conclusion=skipped).

Verification on THIS PR

This PR touches .github/** and docs: expect security-review / changes to run and security-review / security-review to run a real review (relevant=true). The docs-only skip path gets verified by a follow-up test PR before the step-3 ruleset gate.

No linked issue (this PR closes nothing; #509 completes at step 3).

Related

🤖 Generated with Claude Code

… workflow-level filter

Drop the workflow-level `on.pull_request.paths` filter and pass the same 26
security-sensitive patterns as the reusable workflow's new `paths` input
(ci-workflows#189, re-pinned to its merge SHA). The reusable workflow's
job-level gate now decides relevance: a not-applicable PR yields a
name-stable skipped `security-review / security-review` check that a
required-check ruleset reads as success, instead of a Pending wedge.

ADR 0002 gains an ordering-correction addendum (ci-workflows-first; a
caller-side `if:` on the `uses:` job registers a different check name when
skipped — community discussion 72708 — and caller-first on the old pin
would have run a full pass on every prose PR). Roadmap PLAN Phase II tagged
DOING with the matching scope-change note; step 0 results recorded there
(sole consumer = this caller; captured context unchanged).

Prepares Phase II step 3: the github-iac ruleset flip stays LAST and
user-gated.

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

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 20s —— View job


PR Review: ci(security-review) always-report shape adoption

Tasks

  • Gather context and understand the PR
  • Read changed files and diff
  • Review workflow changes
  • Review ADR addendum
  • Review PLAN.md update
  • Post findings

Summary

Clean, well-scoped Phase II step 2. No blocking findings. The core mechanics are correct and the documentation is thorough. Notes below.


.github/workflows/claude-security-review.yml

Pattern preservation — exact. All 26 patterns from the old on.pull_request.paths filter are present in the new paths input block, in the same order. No patterns were dropped or added. This is the highest-risk part of the migration (a missed pattern would silently shrink the security surface) and it's correct.

SHA pin. Updated from 0a5fd4c578f2a6278fdc0e586b8e08392e64299a (2026-07-20) to 99cb082ebb942b9da08e8345a851be5bf252ad79 (2026-07-21). The inline short-SHA comment matches the ci-workflows#189 merge SHA cited in the PR body. Correct.

cancel-in-progress: false — preserved and correct. Cancelling an in-flight security pass on a quick force-push would leave the check in a stale state; this setting prevents that.

Secret handling. One named secret (CLAUDE_CODE_OAUTH_TOKEN), no secrets: inherit. Least-privilege posture is maintained.

Header comment is accurate and precise — it explains the "no workflow-level path filter" decision and the wedge risk in plain terms. Appropriate for a future reader who might wonder why the filter was removed.


docs/adr/0002-default-on-ai-review-advisory-with-earned-promotion.md

The ordering correction addendum is well-reasoned. Two points:

  1. Sequence consistency. The first addendum (autonomy pipeline: no dedicated security-review pass — automated code review only #509) stated the sequence as "caller restructure → workflow always-report shape → required check." The second addendum (this PR) explicitly corrects that to ci-workflows-first. Reading both addenda in document order is unambiguous. No change needed — the correction is the point.

  2. Link. The trailing troubleshooting-required-status-checks link resolves to the GitHub docs page. The evidence for the skipped-uses:-job check-name behavior (community discussion 72708) is referenced by discussion number; it's not linked inline, but the PR body and plan note carry the evidence. Acceptable.


docs/topics/ladder-climb-roadmap/PLAN.md

Phase II tagged [DOING] with a dated scope-change note — correct.

Nit: The step list under Phase II still shows the original ordering (step 1 = caller, step 2 = ci-workflows), with the swap explained only in the prose block above. A reader skimming the numbered list won't immediately see that ci-workflows#189 is already done or that these steps ran in reverse of the list. Adding a (done — ci-workflows#189) note beside the ci-workflows step and a (this PR) note beside the caller step would let the list self-document its state without requiring a cross-read of the scope-change note. This is a suggestion only — the prose note is sufficient.


Verification gap (noted, not blocking)

The PR body explicitly defers the skip-path (docs-only PR → not-applicable verdict) test to a follow-up PR before the step-3 ruleset gate. That's the right call — locking step 3 on an observed skip is safer than assuming it works. The sanity check in PLAN.md (gh pr checks on a docs-only test PR showing Success with not-applicable) captures the acceptance bar.


Overall: Correct implementation, complete pattern migration, good documentation trail. The deferred skip-path verification is the remaining open item before step 3.

kyle-sexton added a commit to melodic-software/standards that referenced this pull request Jul 21, 2026
…ths input (#229)

## What

Add the reviewed runner-input contract for
`melodic-software/ci-workflows/.github/workflows/claude-security-review.yml@99cb082ebb942b9da08e8345a851be5bf252ad79`
(the ci-workflows#189 squash-merge SHA): `allowedInputs` gains `paths`;
routing (`runner-input`), secret mapping (`CLAUDE_CODE_OAUTH_TOKEN`),
and `allowedCallerPermissions` are identical to the reviewed `0a5fd4c`
entry, which stays until the last caller re-pins and can then be
retired.

## Why

The runner-policy gate correctly declined auto-approval on
claude-code-plugins#825 ("inputs changed since the previously reviewed
...@0a5fd4c"): the new pin's input surface grew by `paths` — the
always-report shape's relevance-scope input (job-level gate inside the
reusable workflow; a not-applicable PR yields a name-stable skipped
check a required-check ruleset reads as success). This is the
reviewed-contract update that gate exists to force. Context:
claude-code-plugins ADR 0002 addenda (#509 enforcement ruling + ordering
correction), ladder-climb roadmap Phase II.

## Verification

- `npm run lint:runner-policy` — Runner policy passed.
- `npm run test:runner-policy` — 227 pass / 0 fail (one EBUSY temp-dir
teardown flake on first Windows run, clean on rerun).
- `check-jsonschema --schemafile
components/runner-policy/policy.schema.json
components/runner-policy/policy.json` — ok.

No linked issue (reviewed-contract update; the enforcement-rail issue
lives in claude-code-plugins).

## Related

- melodic-software/ci-workflows#189 (merged, `99cb082`)
- melodic-software/claude-code-plugins#825 (blocked on this sync)
- melodic-software/claude-code-plugins#509 — enforcement rail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@claude

claude Bot commented Jul 21, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 28s —— View job


Tasks

  • Gather context and read changed files
  • Verify pattern migration completeness
  • Audit security posture and SHA pin
  • Review ADR addendum
  • Review PLAN.md update
  • Post findings

PR Review: ci(security-review) always-report shape adoption

Verdict: approve with one observation and one nit. The core mechanics are correct, the security surface is preserved, and the documentation trail is solid.


.github/workflows/claude-security-review.yml

Pattern migration — verified 26 for 26. Every pattern from the old on.pull_request.paths block appears in the new paths input, in the same order:

# Pattern
1–3 .github/**, .claude/**, scripts/**
4–9 plugins/*/hooks/** through plugins/*/commands/**
10–13 .claude-plugin/**, REVIEW.md, CLAUDE.md, AGENTS.md
14–15 plugins/*/src/**, plugins/*/dist/**
16–22 **/*.sh, **/*.ps1, **/*.mjs, **/*.ts, **/*.js, **/*.cjs, **/.mcp.json
23–26 **/mcp.json, **/package.json, **/package-lock.json, plugins/*/.claude-plugin/plugin.json

The format change from YAML-quoted list items (".github/**") to unquoted multiline block scalar (|) is correct — with: inputs accept newline-separated strings, not YAML sequence syntax, and the reusable workflow receives these as a single multiline string.

SHA pin — correct. 99cb082 matches ci-workflows#189's merge SHA. Short-SHA inline comment matches the full SHA. ✓

Security posture — unchanged and correct:

  • secrets: inherit not used ✓
  • Single named secret (CLAUDE_CODE_OAUTH_TOKEN) ✓
  • Workflow-level permissions: contents: read as a least-privilege default; job-level permissions add only what the security-review job needs (pull-requests: write, id-token: write) ✓
  • cancel-in-progress: false preserved ✓

Header comment accurately describes the deliberate absence of a workflow-level path filter and the wedge risk. Good for future maintainers who might otherwise "restore" the filter.

Observation — billing posture change (expected, justified, but worth noting explicitly):
The old workflow-level paths filter prevented GitHub Actions from allocating a run for non-security-relevant PRs entirely — zero minutes consumed. Now every PR allocates a workflow run; the filtering happens inside the reusable workflow. The trade-off (token overhead on every run vs. name-stable SKIPPED check enabling required-check enforcement) is correctly justified in the PR body and header comment. This is not a concern to block on — just flagging the change for the step-3 required-check cost model.


docs/adr/0002-default-on-ai-review-advisory-with-earned-promotion.md

The ordering correction addendum is logically tight. The key claim — that a skipped uses: job registers a different check name, leaving the child context "Expected" and wedging prose PRs — is cited to community discussion 72708 and corroborated by the GitHub troubleshooting link. The causal chain (ci-workflows-first → caller adoption → ruleset flip) follows directly.

Nit: ADR Decision §1 (line 29) still reads "a PATH FILTER over security-sensitive surfaces" — now a paths input evaluated inside the reusable workflow, not a caller-side filter. ADR immutability convention means the original decision text is appropriately left in place, and the addenda capture the evolution. A future reader reading Decision → Addendum 1 → Addendum 2 in order gets the full picture. No change needed, but awareness: if someone reads only the Decision section they'll see the old framing.


docs/topics/ladder-climb-roadmap/PLAN.md

[DOING] tag and the scope-change note are correct. The note captures the causal constraint ("caller-side if: on the uses: job registers a different check name") and cross-references the ADR addendum. The step-0 outcome (sole consumer = this repo's caller; captured context security-review / security-review) is recorded inline.

Nit (same as prior review): The numbered step list under Phase II still reflects the original ordering (caller first, ci-workflows second). The scope-change prose block above the list corrects this, but a reader skimming the list sees the old order. Adding a (done — ci-workflows#189) annotation to the ci-workflows step and a (this PR) to the caller step would make the list self-documenting without requiring a cross-read. Suggestion only — the prose block is sufficient.


Verification deferred (correct call)

The docs-only skip path (not-applicable verdict → name-stable security-review / security-review conclusion=skipped reads as Success under the required check) is deferred to a follow-up test PR before the step-3 ruleset gate. That's the right sequencing — empirical confirmation before flipping the ruleset.


Overall: Correct implementation. Pattern migration complete, security posture maintained, documentation trail sound. The billing observation is the only new item vs. the prior review; both nits are carry-forwards. Ready to merge once the skip-path verification PR passes.

@kyle-sexton
kyle-sexton merged commit 1b0eeab into main Jul 21, 2026
23 checks passed
@kyle-sexton
kyle-sexton deleted the ci/security-review-always-report-caller branch July 21, 2026 09:26
kyle-sexton added a commit that referenced this pull request Jul 21, 2026
## What

Append the Phase II status line to the roadmap PLAN scope-change note:
steps 1–2 landed (ci-workflows#189, standards#229 + sync #827, #825).

## Why

This PR is ALSO the plan's step-1 sanity check: it is docs-only (matches
none of the caller's 26 security-sensitive patterns), so it must show
`security-review / changes` = pass and `security-review /
security-review` = skipped (name-stable not-applicable verdict — not
Pending, not absent). That observed result gets cited at the step-3 user
gate before the ruleset PR opens.

No linked issue (status note; #509 completes at step 3).

## Related

- #509 — enforcement rail
- #825, melodic-software/ci-workflows#189,
melodic-software/standards#229

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton added a commit to melodic-software/standards that referenced this pull request Jul 21, 2026
…4c (#234)

## What

Remove the reviewed runner-input contract for
`claude-security-review.yml@0a5fd4c` — superseded by the `99cb082` entry
(#229). The sole caller re-pinned in claude-code-plugins#825 (merged);
`pull_request` runs evaluate the caller from the merge ref, so no open
PR resolves the old pin.

## Verification

`npm run lint:runner-policy` passed; `npm run test:runner-policy` —
first run hit the known Windows EBUSY temp-dir teardown flake (1 fail),
three consecutive reruns 227 pass / 0 fail; Linux CI is authoritative.

No linked issue.

## Related

- #229 (added the 99cb082 entry; recorded this retirement as follow-up)
- melodic-software/claude-code-plugins#825

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
kyle-sexton added a commit that referenced this pull request Jul 21, 2026
…-actor exception (#858)

## What

- ADR 0002 step-3 addendum: `security-review-gate` org ruleset ACTIVE
(github-iac#193 ruleset + #194 App-grant widening, production deploy
verified: `security-review / security-review` in
`required_status_checks` on this repo's main); operator-ratified
skip-actor exception (dependabot[bot], melodic-standards-sync[bot]) with
rationale and bounds; the PR-branch caller-file bound stated plainly.
New revisit trigger: any skip-actors addition re-opens the exception.
- Roadmap PLAN: Phase II [DONE] + step-3 status note.

Closes #509.

## Related

- ci-workflows#189, standards#229/#234, #825, #828, github-iac#193/#194
- Deploy run:
https://github.com/melodic-software/github-iac/actions/runs/29822200383

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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