Add actions/dependency-review-action as PR-time blocking layer (#209)#220
Conversation
Adds a wrangle-wrapped dependency-review tool that fires on `pull_request` events to block PRs introducing known-vulnerable dependencies. Complements OSV-Scanner (periodic, full-lockfile) with a diff-only PR-time gate, the layer the original issue called out. New files: - tools/dependency-review/action.yml — wraps actions/dependency-review-action@v4.9.0, defaults to fail-on-severity=high and comment-summary-in-pr=never so the adopter's workflow doesn't need pull-requests: write. - tools/dependency-review/vulnerable_changes_to_sarif.sh — converts the upstream action's vulnerable-changes JSON to SARIF so the existing per-tool upload-sarif + check_results.sh machinery works unchanged. - tools/dependency-review/SPEC.md and test.bats. Wired into actions/scan/action.yml as an action-pattern tool, gated on `pull_request` (the upstream action errors out without the PR diff base/head refs). Added to the default tools list and to the reusable workflow's default. Updated scan README and docs/SPEC.md tool tables. https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
The new tools/dependency-review/ directory doesn't exist on main yet, so the previous pin (e858013...) wouldn't resolve when actions/scan loads tools/dependency-review@<sha>. Bump every TomHennen/wrangle/... self-ref to this branch's HEAD so the PR's CI can resolve everything. The build_and_publish_* and build_shell workflow pins are bumped by the same script run; their content is unchanged at this SHA but the comment date is refreshed, which is the bump_action_pins.sh idempotent- on-matching-SHA behavior. https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
- vulnerable_changes_to_sarif.sh:
* Buffer jq output and check exit code before writing — malformed
SARIF must exit 2, not silently emit partial output (CLAUDE.md
adapter contract).
* Stop mutating the caller's input file when empty; feed "[]" to
jq via stdin instead.
* Omit `helpUri` and `shortDescription.text` keys entirely when the
advisory has no URL / summary, instead of emitting empty strings
(SARIF 2.1.0 strict validators reject empty-URI helpUri).
* Explicit "low" branch in sarif_level alongside security_severity
so the two mappings stay consistent; unknown severity falls
through to note / 0.0 for both.
- action.yml: build SARIF in a temp file and atomic-mv on success, so
a converter failure leaves the previous (or no) SARIF rather than
a half-written one at the destination path.
- test.bats: add tests for the new paths — change with no
vulnerabilities array, missing advisory_url (helpUri omitted),
advisory text with quotes/newlines/backslash/unicode, unknown
severity falling back to note+0.0.
- README / SPEC: document that fail-on-severity and
comment-summary-in-pr inputs are on the tool wrapper but not yet
forwarded by actions/scan; clarify the "check_results.sh is the
gate" wording is PR-event-only.
https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
Previous bump left check_source_change.yml pointing at actions/scan@11e842f — the parent of the pin-fix commit, where actions/scan/action.yml still referenced dependency-review@e858013 (a SHA that does not contain the new tools/dependency-review directory). Result: the check-change CI job failed with "action configuration files are missing" when the composite tried to load the dep-review wrapper. Bump every self-ref to the current HEAD so the composite resolves the wrapper at a SHA that does contain it. https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
I think we'll have to revert these bumps before we submit, otherwise zizmor will get mad at us. See #218.
|
|
||
| `dependency-review` only runs on `pull_request` events (the upstream action needs the PR diff). On `push` events it is silently skipped, the same way `scorecard` is silently skipped on PRs. | ||
|
|
||
| The default severity threshold is `high` and PR comments are off. These knobs are exposed as inputs on `tools/dependency-review/action.yml` (`fail-on-severity`, `comment-summary-in-pr`) but `actions/scan/action.yml` does not currently forward them — adopters who need different thresholds either call `TomHennen/wrangle/tools/dependency-review@<sha>` directly in their own composite, or open an issue for `actions/scan` to expose passthrough inputs. The default severity (`high`) blocks high+critical advisories; lower severities are reported informationally via SARIF without failing the check. |
There was a problem hiding this comment.
why not plumb those options through now? Is it just because we only have the "info", etc thing?
| TOOL_DIR: ${{ github.action_path }} | ||
| VULNERABLE_CHANGES: ${{ steps.depreview.outputs.vulnerable-changes }} | ||
| run: | | ||
| set -euo pipefail |
There was a problem hiding this comment.
this should be in a script and not inlined, right?
…t pin churn Three review comments from @TomHennen: 1. action.yml inline shell -> script. The "Convert vulnerable-changes to SARIF" + "Generate human-readable output" run: blocks are now a single collect_outputs.sh script (CLAUDE.md "Inline Shell" rule). collect_outputs.sh reads VULNERABLE_CHANGES from env, converts to SARIF atomically (temp + mv), and writes output.md. The action.yml now only has one-line script-call run: blocks. 2. Plumb dep-review options through. actions/scan and the check_source_change.yml reusable workflow now expose dependency-review-fail-on-severity and dependency-review-comment-summary-in-pr inputs, forwarded to the tool wrapper. Previously the wrapper exposed them but actions/scan didn't pass them, so adopters had to fork. README/SPEC updated. 3. Revert spurious self-ref pin churn. bump_action_pins.sh bumped build_and_publish_{container,npm,python}.yml and build_shell.yml as a side effect even though none of their referenced composites changed in this PR. Reverted those four files to main state to avoid the zizmor impostor-commit problem (#218). The check_source_change.yml / actions/scan dep-review pins are kept at the branch SHA so CI can dogfood the new tool during review. Tests: collect_outputs.sh unit tests added; action.yml structural test asserts no inline conditionals/loops; actions/scan tests assert the new passthrough inputs are forwarded. https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
…write Follow-up to dep-review review feedback (after 1dcc0e1): - actions/scan/README.md: the dependency-review-fail-on-severity row claimed lower-severity advisories are "reported via SARIF without failing the check". False in both directions — the upstream action pre-filters vulnerable-changes by fail-on-severity (lower severities never reach the SARIF), and lib/check_results.sh counts every SARIF result regardless of level (anything that does reach it blocks). Rewrote the row to describe actual behavior. - vulnerable_changes_to_sarif.sh: only convert change_type "added" entries. A "removed" entry means the PR drops a vulnerable dependency — converting it would block the PR for fixing a vuln. Missing change_type defaults to "added". - collect_outputs.sh: create the SARIF temp file inside the metadata directory so the final mv is a same-filesystem rename. Previously mktemp'd in $TMPDIR, making the "atomic write" a cross-device copy. - Added set -f to both dep-review scripts (CLAUDE.md / check_results.sh convention for scripts handling external tool output). - SPEC.md: document that a dep-review tool error fails open (continue-on-error + empty output -> empty SARIF -> passing gate), and clarify the SARIF level vs check_results.sh gate interaction. - test.bats: tests for change_type "removed" (zero results) and missing change_type (converted). Deferred to issues: per-tool config via native config files (#221), action-pattern tools failing open on tool error (#222). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Per the other discussion I don't love this being plumbed through here. Instead of setting this president now let's revert and defer to that issue.
There was a problem hiding this comment.
Reverted in 7655596. Dropped the dependency-review-fail-on-severity / dependency-review-comment-summary-in-pr inputs and the with: forwarding from both actions/scan/action.yml and check_source_change.yml. The Dependency Review step now just uses the wrapper's defaults (fail-on-severity: high, comment-summary-in-pr: never); per-tool config is deferred to #221. The wrapper action keeps its own inputs for callers invoking tools/dependency-review directly.
Generated by Claude Code
| `dependency-review` only runs on `pull_request` events (the upstream action needs the PR diff). On `push` events it is silently skipped, the same way `scorecard` is silently skipped on PRs. | ||
|
|
||
| The default severity threshold is `high` and PR comments are off. These knobs are exposed as inputs on `tools/dependency-review/action.yml` (`fail-on-severity`, `comment-summary-in-pr`) but `actions/scan/action.yml` does not currently forward them — adopters who need different thresholds either call `TomHennen/wrangle/tools/dependency-review@<sha>` directly in their own composite, or open an issue for `actions/scan` to expose passthrough inputs. The default severity (`high`) blocks high+critical advisories; lower severities are reported informationally via SARIF without failing the check. | ||
| ### Tuning dependency-review |
There was a problem hiding this comment.
I think we need to revert this too
There was a problem hiding this comment.
Reverted in 7655596 — removed the "Tuning dependency-review" section and replaced it with a one-line note that per-tool config is deferred to #221.
Generated by Claude Code
Per review feedback: don't set the precedent of plumbing per-tool config through actions/scan ad-hoc. Per-tool configuration is deferred to the native config-file design in #221. - actions/scan/action.yml: drop the dependency-review-fail-on-severity and dependency-review-comment-summary-in-pr inputs and the with: forwarding on the Dependency Review step. The wrapper's defaults (fail-on-severity: high, comment-summary-in-pr: never) apply. - check_source_change.yml: drop the matching workflow_call inputs and forwarding. - actions/scan/README.md: remove the "Tuning dependency-review" section; note that per-tool config is deferred to #221. - tools/dependency-review/SPEC.md: the wrapper still exposes fail-on-severity / comment-summary-in-pr inputs for direct callers, but actions/scan no longer forwards them. - test.bats: replace the passthrough-forwarding assertions with a negative assertion that actions/scan does not expose per-tool config. The wrapper action (tools/dependency-review/action.yml) keeps its own inputs so callers invoking it directly can still configure it. https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
Standard post-merge pin refresh. #213 left the .github/workflows/ pins at its branch SHA (2baa182); #220 left actions/scan/action.yml's tools/dependency-review ref at its branch SHA (075238e). Bump every TomHennen/wrangle/...@<sha> self-ref to main HEAD (68b1cae) so the reusable workflows and the scan composite resolve internal actions at a main commit, not a feature branch. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Closes #209.
Summary
Adds a wrangle-wrapped
actions/dependency-review-actionas the PR-time blocking layer for newly-introduced vulnerable dependencies. Complements OSV-Scanner (periodic / full-lockfile, any event) with a diff-onlypull_request-time gate — the layer #209 called out.Shape
New
tools/dependency-review/(action-pattern, same shape astools/zizmor/andtools/scorecard/):action.yml— wrapsactions/dependency-review-action@v4.9.0(2031cfc0...). Defaults:fail-on-severity=highandcomment-summary-in-pr=never. Theneverdefault avoids forcing adopters to grantpull-requests: write; they can override the input if they want PR comments.vulnerable_changes_to_sarif.sh— converts the upstream action'svulnerable-changesJSON output to SARIF 2.1.0 so the existing per-toolupload-sarif+lib/check_results.shmachinery works unchanged. Severity → SARIF level mapping: critical/high → error, moderate → warning, low → note.SPEC.md— documents pattern, trigger, SARIF conversion, severity table, known limitations.test.bats— structural tests onaction.ymlplus 7 unit tests on the converter (empty/invalid input, single-vuln mapping, multi-result rule dedup, severity mapping).Wired into
actions/scan/action.ymlas auses:step gated ongithub.event_name == 'pull_request'(the upstream action errors out without the PR'sbase.sha/head.sha). Added a per-tool SARIF upload (category: wrangle/dependency-review), addeddependency-reviewto the defaulttoolsinput on both the composite and the reusable workflow, updated the scan README anddocs/SPEC.mdtool tables.Pins were bumped to the PR HEAD so CI can resolve
TomHennen/wrangle/tools/dependency-review@<sha>(the directory doesn't exist on main yet).What this does NOT change
comment-summary-in-pr=nevermeanspull-requests: writeis still not required.vulnerable-changesis). The upstream action still exits non-zero on those, but wrangle's gate is the SARIF-derived count.Test plan
bats tools/dependency-review/test.bats— 17/17bats actions/scan/test.bats— 17/17test/,test/lib/,test/integration/,tools/*/test.bats,actions/*/test.bats,build/actions/*/test.bats) — all green (the only failures locally are the pre-existingtest_bump_action_pins.batscases that need git commit signing, which is broken in this sandbox).shellcheckclean across all scripts.actionlintclean.Testworkflow passes.Check Changeworkflow runs dep-review against this PR and reports cleanly (wrangle itself has no lockfile, so dep-review should find no changes).integration-test.yml).https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R
Generated by Claude Code