Skip to content

Add actions/dependency-review-action as PR-time blocking layer (#209)#220

Merged
TomHennen merged 7 commits into
mainfrom
claude/address-issue-209-X3JeP
May 17, 2026
Merged

Add actions/dependency-review-action as PR-time blocking layer (#209)#220
TomHennen merged 7 commits into
mainfrom
claude/address-issue-209-X3JeP

Conversation

@TomHennen
Copy link
Copy Markdown
Owner

Closes #209.

Summary

Adds a wrangle-wrapped actions/dependency-review-action as the PR-time blocking layer for newly-introduced vulnerable dependencies. Complements OSV-Scanner (periodic / full-lockfile, any event) with a diff-only pull_request-time gate — the layer #209 called out.

Shape

New tools/dependency-review/ (action-pattern, same shape as tools/zizmor/ and tools/scorecard/):

  • action.yml — wraps actions/dependency-review-action@v4.9.0 (2031cfc0...). Defaults: fail-on-severity=high and comment-summary-in-pr=never. The never default avoids forcing adopters to grant pull-requests: write; they can override the input if they want PR comments.
  • vulnerable_changes_to_sarif.sh — converts the upstream action's vulnerable-changes JSON output to SARIF 2.1.0 so the existing per-tool upload-sarif + lib/check_results.sh machinery 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 on action.yml plus 7 unit tests on the converter (empty/invalid input, single-vuln mapping, multi-result rule dedup, severity mapping).

Wired into actions/scan/action.yml as a uses: step gated on github.event_name == 'pull_request' (the upstream action errors out without the PR's base.sha / head.sha). Added a per-tool SARIF upload (category: wrangle/dependency-review), added dependency-review to the default tools input on both the composite and the reusable workflow, updated the scan README and docs/SPEC.md tool 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

  • OSV-Scanner, Zizmor, Scorecard — unchanged.
  • Reusable workflow permissions — unchanged. The default comment-summary-in-pr=never means pull-requests: write is still not required.
  • License-policy and denied-package findings from dep-review are NOT converted to SARIF (only vulnerable-changes is). 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/17
  • bats actions/scan/test.bats — 17/17
  • Full local bats suite (test/, test/lib/, test/integration/, tools/*/test.bats, actions/*/test.bats, build/actions/*/test.bats) — all green (the only failures locally are the pre-existing test_bump_action_pins.bats cases that need git commit signing, which is broken in this sandbox).
  • shellcheck clean across all scripts.
  • actionlint clean.
  • CI: Test workflow passes.
  • CI: Check Change workflow runs dep-review against this PR and reports cleanly (wrangle itself has no lockfile, so dep-review should find no changes).
  • Integration test passes (companion-repo dispatch via integration-test.yml).

https://claude.ai/code/session_01CWdHwxbGAKLFWPsEydLH7R


Generated by Claude Code

claude added 2 commits May 15, 2026 02:37
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
@TomHennen TomHennen temporarily deployed to integration-test May 15, 2026 02:44 — with GitHub Actions Inactive
@github-advanced-security
Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I think we'll have to revert these bumps before we submit, otherwise zizmor will get mad at us. See #218.

Comment thread actions/scan/README.md Outdated

`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.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

why not plumb those options through now? Is it just because we only have the "info", etc thing?

Comment thread tools/dependency-review/action.yml Outdated
TOOL_DIR: ${{ github.action_path }}
VULNERABLE_CHANGES: ${{ steps.depreview.outputs.vulnerable-changes }}
run: |
set -euo pipefail
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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>
@TomHennen TomHennen temporarily deployed to integration-test May 16, 2026 13:59 — with GitHub Actions Inactive
Comment thread actions/scan/action.yml
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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

Comment thread actions/scan/README.md Outdated
`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
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

I think we need to revert this too

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

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
@TomHennen TomHennen temporarily deployed to integration-test May 16, 2026 14:08 — with GitHub Actions Inactive
@TomHennen TomHennen merged commit 3f41018 into main May 17, 2026
7 checks passed
TomHennen added a commit that referenced this pull request May 17, 2026
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>
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.

Add actions/dependency-review-action to actions/scan (PR-time blocking layer)

3 participants