Skip to content

dep-review: invert change_type filter to fail safe against schema drift#229

Merged
TomHennen merged 2 commits into
mainfrom
dep-review-change-type-failsafe
May 18, 2026
Merged

dep-review: invert change_type filter to fail safe against schema drift#229
TomHennen merged 2 commits into
mainfrom
dep-review-change-type-failsafe

Conversation

@TomHennen
Copy link
Copy Markdown
Owner

What

tools/dependency-review/vulnerable_changes_to_sarif.sh filtered changes with select((.change_type // "added") == "added"). This switches it to != "removed".

Why

Reviewing the change_type handling raised the question: the filter keeps added and drops removed — is there an updated (or other) case being missed?

There isn't. actions/dependency-review-action's ChangeSchema defines change_type: z.enum(['added', 'removed']) — exactly two values. A dependency version bump is not a third type; it's emitted as a removed (old version) + added (new version) pair, so added already catches every introduced version.

But == "added" is an allowlist that fails silent: if the upstream enum ever gains a value, a vulnerable change of that new type would be dropped rather than flagged — the wrong direction for a security gate.

The question the converter actually answers is "is this vulnerable package present at the PR's head?" — true for every change except a removed. So != "removed" is both the semantically precise test and fails safe: an unknown future change_type is still surfaced.

Behavior is identical today (only added/removed exist). A new test (converter: unrecognized change_type is surfaced) locks in the fail-safe behavior; the existing removed and missing-change_type tests still pass unchanged.

Also: documented the scope choice (no behavior change)

While here, documented something the converter does silently: it converts vulnerable changes regardless of scope (runtime / development / unknown) — a vulnerable dev/build-time dependency is flagged exactly like a runtime one. That's the conservative default (block on any introduced vuln); a comment in the script and a note in SPEC.md now make it an explicit, intentional choice. Scope-aware policy (à la fail-on-scopes) would belong with the per-tool config design in #221. No code change — just documentation, per review preference.

Testing

bats tools/dependency-review/test.bats — 31/31 pass (was 30; +1 new). shellcheck clean.

Origin

Review discussion on #220.

vulnerable_changes_to_sarif.sh selected `change_type == "added"`. The
dependency-review change_type enum is exactly {added, removed}, so a
version bump arrives as a removed+added pair and `added` already catches
every introduced version — there is no `updated` type to miss. But the
`== "added"` allowlist fails *silent*: if the upstream enum ever gains a
value, a vulnerable change of that type would be dropped, not flagged.

Test `!= "removed"` instead. The question the converter answers is "is
this vulnerable package present at the PR head?" — true for everything
except a removal. Behavior is identical today; it now fails safe against
schema drift. Adds a test locking that in.

Also document (no behavior change) that vulnerable changes are converted
regardless of `scope` — development/build-time deps are flagged like
runtime ones, the conservative default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
With the filter now testing `!= "removed"`, the `// "added"` default
no longer affects any decision: a missing or null change_type is
`null`, and `null != "removed"` already keeps it. Simplify the filter
to `.change_type != "removed"` and reword the header comment, which
still claimed a missing change_type "defaults to added" — true under
the old `== "added"` test, but vacuous now. Behavior is unchanged.
@TomHennen TomHennen temporarily deployed to integration-test May 18, 2026 23:36 — with GitHub Actions Inactive
@TomHennen TomHennen merged commit eba824e into main May 18, 2026
8 checks passed
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