Skip to content

Scope Dependabot to our beyond-template packages - #224

Open
alex-rawlings-yyc wants to merge 19 commits into
mainfrom
dependabot-security-updates
Open

Scope Dependabot to our beyond-template packages#224
alex-rawlings-yyc wants to merge 19 commits into
mainfrom
dependabot-security-updates

Conversation

@alex-rawlings-yyc

@alex-rawlings-yyc alex-rawlings-yyc commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Template-owned dependencies move only when we merge template changes, so the allow list covers just the packages this extension adds. Security updates stay inert until the repo's dependency graph is enabled.


This change is Reviewable

Summary by CodeRabbit

  • Chores
    • Added monthly automated checks for npm and GitHub Actions updates.
    • Limited dependency updates to extension-owned packages and excluded sibling file dependencies.
    • Grouped compatible test-tooling and workflow updates while keeping major updates separate.
    • Added dependency-scope validation to linting to detect unsupported or inconsistent dependencies.
  • Documentation
    • Documented dependency validation, update coverage, version exceptions, and template synchronization requirements.

@alex-rawlings-yyc alex-rawlings-yyc self-assigned this Aug 13, 2026
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d00c7cc9-7167-4eaa-8662-41fc5d56bd29

📝 Walkthrough

Walkthrough

Added dependency-scope validation against a recorded merged template commit. The lint workflow now fetches full history, Dependabot manages monthly updates, and the README documents baseline and dependency-scope maintenance.

Changes

Dependency scope validation

Layer / File(s) Summary
Implement dependency-scope validation
scripts/check-dependency-scope.cjs
The script reads the template manifest and Dependabot configuration. It detects dependency-scope violations, stale version exceptions, unsupported file: dependencies, and unavailable or unmerged baselines.
Wire validation and dependency updates
package.json, .github/workflows/lint.yml, .github/dependabot.yml
The lint command runs dependency validation. The workflow fetches full Git history. Dependabot performs monthly npm and GitHub Actions updates with grouped minor and patch updates.
Document baseline maintenance
README.md
The README documents merged template commit updates, dependency-scope ownership, version exceptions, template comparison, and shallow-clone handling.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: 🟡 Moderate · up to a0bd2

Adding js-yaml without updating package-lock.json will cause the lint workflow's dependency installation to fail, so the change is not ready to merge until the lockfile is regenerated and committed.

Sequence Diagram(s)

sequenceDiagram
  participant Lint as npm lint
  participant Scope as check-dependency-scope.cjs
  participant Git as Git history
  participant Config as Dependabot config
  Lint->>Scope: Run dependency-scope validation
  Scope->>Git: Read merged template commit manifest
  Scope->>Config: Read npm allow and ignore lists
  Scope->>Scope: Compare manifests and validate scope
  Scope-->>Lint: Report violations and exit status
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: restricting Dependabot updates to packages introduced by the extension.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dependabot-security-updates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alex-rawlings-yyc alex-rawlings-yyc linked an issue Aug 13, 2026 that may be closed by this pull request
@alex-rawlings-yyc

alex-rawlings-yyc commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Why this config has an ignore block

Dependabot cannot run on this repo without it. platform-bible-utils, papi-dts, and
platform-bible-react are file: deps resolving against a sibling paranext-core checkout —
present on dev machines and in CI (test.yml clones both repos), absent inside Dependabot's
container. It aborts during file fetching before reaching any of our packages:

ERROR Error during file fetching; aborting: The following path based
dependencies could not be retrieved: platform-bible-utils

Naming the three in ignore makes the fetcher skip them. This is also why no repo in the
paranext org has a dependabot.yml — the template carries the same file: deps.

Verified before opening this PR

Run against an identical package.json + package-lock.json in a scratch repo
(alex-rawlings-yyc/dependabot-pathdep-test), so nothing unproven landed on main:

  • Job completed successfully — the path-dependency abort is gone, and npm regenerated the
    lockfile without the sibling checkout.
  • Three PRs, as designed: one grouped test-tooling PR (@playwright/test,
    @testing-library/user-event, ws — all patch), plus eslint-plugin-jest 28→29 and
    @testing-library/jest-dom 6→7 as separate majors.
  • Scope confirmed: the only version changes were our packages and Playwright's own
    transitives. No template-owned package was bumped.

One thing reviewers will see: the grouped PR also adds six
@tailwindcss/oxide-wasm32-wasi/node_modules/* lockfile entries. Those are optional wasm platform
deps npm materializes on any lockfile regeneration — nothing is bumped or removed. It is not the
allow list leaking.

Known limitation

allow is name-based, and npm doesn't support dependency-type: indirect, so there is no way to
express "these packages plus everything they pull in." Advisories against transitive deps of the 14
won't raise a PR — both vulnerabilities currently reachable only through our packages are in Jest's
istanbul chain (test-exclude → brace-expansion, @istanbuljs/load-nyc-config → js-yaml). They
clear when Dependabot bumps jest, not via a security PR. Left unpinned deliberately: they're
dev-only, nothing ships them, and hand-pinning transitives in package.json is exactly what this
policy avoids.

Separately

Dependabot alerts and security updates still can't fire — this repo's dependency graph has
zero manifests, so alerts have been silently empty since January (npm audit reports 5). That
needs Settings → Advanced Security, independent of this PR. Version updates need only this file.

@alex-rawlings-yyc
alex-rawlings-yyc marked this pull request as ready for review August 13, 2026 20:52

@imnasnainaec imnasnainaec left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@imnasnainaec reviewed all commit messages and made 1 comment.
Reviewable status: 0 of 1 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc).


.github/dependabot.yml line 15 at r1 (raw file):

    directory: /
    schedule:
      interval: weekly

Weekly can be pretty annoying. I'd opt for monthly.

@imnasnainaec imnasnainaec left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❓ Might we want a script that compares our package-lock.json to the template's, to prevent drift?

@imnasnainaec made 3 comments.
Reviewable status: 0 of 1 files reviewed, 3 unresolved discussions (waiting on alex-rawlings-yyc).


.github/dependabot.yml line 12 at r1 (raw file):

version: 2
updates:
  - package-ecosystem: npm

⛏️ from Devin that I agree with:

Only npm is covered; GitHub Actions workflows get no updates

The repo has six workflows under .github/workflows/ plus composite actions in .github/actions/, and no github-actions ecosystem entry is configured. Action pins therefore receive neither version nor security updates. This is consistent with the PR's npm-only scoping, but the template rationale (lockfile conflicts on template merges) does not apply to action pins, so a separate github-actions entry may be worth adding later.


.github/dependabot.yml line 19 at r1 (raw file):

    # checkout, which exists on developer machines and in CI but not inside
    # Dependabot's container. Without these entries Dependabot aborts the whole
    # job during file fetching and never reaches the allow list below.

❓ from Devin:

Ignore entries may not actually prevent the abort on file: dependencies
The comment claims Dependabot "aborts the whole job during file fetching" for the three file:../paranext-core/... dependencies and that these ignore entries prevent it. ignore rules are applied when Dependabot filters the parsed dependency list, which happens after the file fetcher/parser stage; if the failure genuinely occurs during file fetching or lockfile parsing, ignore would not suppress it. Since these three packages are also absent from allow, the entries are otherwise redundant. Worth confirming against an actual Dependabot run log rather than relying on the stated rationale.

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Might the comparing the lockfiles be too noisy? Though, if we're only updating it on Template merge, it may not actually be

@alex-rawlings-yyc made 4 comments.
Reviewable status: 0 of 1 files reviewed, 3 unresolved discussions (waiting on alex-rawlings-yyc and imnasnainaec).


.github/dependabot.yml line 12 at r1 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ from Devin that I agree with:

Only npm is covered; GitHub Actions workflows get no updates

The repo has six workflows under .github/workflows/ plus composite actions in .github/actions/, and no github-actions ecosystem entry is configured. Action pins therefore receive neither version nor security updates. This is consistent with the PR's npm-only scoping, but the template rationale (lockfile conflicts on template merges) does not apply to action pins, so a separate github-actions entry may be worth adding later.

Do we want to add an issue to address this later or do it right now?


.github/dependabot.yml line 15 at r1 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

Weekly can be pretty annoying. I'd opt for monthly.

Agreed


.github/dependabot.yml line 19 at r1 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

❓ from Devin:

Ignore entries may not actually prevent the abort on file: dependencies
The comment claims Dependabot "aborts the whole job during file fetching" for the three file:../paranext-core/... dependencies and that these ignore entries prevent it. ignore rules are applied when Dependabot filters the parsed dependency list, which happens after the file fetcher/parser stage; if the failure genuinely occurs during file fetching or lockfile parsing, ignore would not suppress it. Since these three packages are also absent from allow, the entries are otherwise redundant. Worth confirming against an actual Dependabot run log rather than relying on the stated rationale.

I'm looking into this now; I'll come back with some sort of answer

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Claude's thoughts:

Worth doing, and I went and measured it — the drift is real, but it's the manifest that's checkable, not the lockfile.

package.json vs template/main:

shared deps: 57  |  version-range mismatches: 2
  @tailwindcss/postcss: tmpl ^4.0.0 vs ours ^4.3.0
  tailwindcss:          tmpl ^4.0.0 vs ours ^4.3.0
ours-only: 14   ← exactly the allow list in this PR, no more, no less
template-only: 0

package-lock.json vs template/main:

ours 1266 packages, template 1012
only in ours: 390   only in template: 136
shared package, different version: 278   (mostly @babel/*, all ours-newer)

~670 differences today, with no Dependabot PR ever merged — a lockfile comparison would need ~670 baselined exceptions before it could report anything new. It isn't the template running ahead of us either; template/main is only 3 commits past our last update-from-template, and none of them touch dependencies.

The cause is known: 5f44a9d (the React 19 / Tailwind 4 baseline) is a commit shared with the template, so at that point our lockfile was the template's and described none of our own dependencies. 791ffd6 the next day regenerated it (+343 packages, −89, 219 version changes) — 219 of the 278 in one commit. The rest came from running core:reinstall before committing on a handful of feature PRs. Our policy is that the lockfile moves only on template merges and, once this lands, Dependabot PRs.

One wrinkle worth naming: there's a third legitimate case. Our lockfile snapshots the full dependency manifests of the three file:-linked core libs, and two of those feature-PR lockfile diffs carried real changes to them (#131 platform-bible-react; #180 platform-bible-react + platform-bible-utils). Since CI installs the extension with npm ci, if core's manifest changes never land we'd be testing against a tree that doesn't match the core we cloned. So core-lib syncs have to be allowed through.

Which suggests two checks, neither of them a lockfile diff:

  1. Lockfile changed, package.json didn't, and no ../paranext-core/lib/* entry changed — that's incidental drift with nothing legitimate in it. Checked against history it catches the five accidental ones and passes #131 and #180. Exempt Dependabot and update-from-template PRs.
  2. Manifest comparison — shared deps must have identical ranges; every ours-only dep must be in allow; every allow entry must be in our package.json and absent from the template's. That mechanizes the "keep the allow list in sync" instruction in the header comment, which is the part most likely to rot. Fires today on the two Tailwind entries — deliberate, from the React 19 / Tailwind 4 work, but recorded nowhere.

Happy to write both. Probably a separate PR from this one — want me to open an issue?

(Resetting the existing 278 back onto the template's pins is possible but I'd skip it: it downgrades 278 transitives for cosmetic gain, and check 1 stops the bleeding either way.)

@alex-rawlings-yyc made 3 comments.
Reviewable status: 0 of 1 files reviewed, 3 unresolved discussions (waiting on alex-rawlings-yyc and imnasnainaec).


.github/dependabot.yml line 12 at r1 (raw file):

Previously, alex-rawlings-yyc (Alex Rawlings) wrote…

Do we want to add an issue to address this later or do it right now?

Claude's opinion:

Agreed this is a gap, though I'd argue the template rationale doesn't apply here at all — I checked, and none of our action pins match the template's. It floats major tags (actions/checkout@v4, github/codeql-action@v3, ncipollo/release-action@v1); we SHA-pinned every one of them back in #82. All four template-owned workflows are already locally modified too (lint.yml +19/-5, publish.yml +68/-10, codeql.yml +5/-3, bump-versions.yml +4/-4), and update-from-template lands as a hand-curated squash — #204 was one file — so there's no mechanical merge for a pin bump to conflict with.

The more pressing part is that SHA-pinning opts us out of updates and we never added the thing that puts them back. The pins are frozen where #82 left them:

actions/checkout      pinned v6.0.2 (2026-01-09)  ->  latest v7.0.1 (2026-07-20)   major behind
actions/setup-node    pinned v6.4.0 (2026-04-20)  ->  latest v7.0.0 (2026-07-14)   major behind
github/codeql-action  pinned       (2026-05-22)  ->  latest bundle (2026-08-12)   ~3 months

CodeQL three months stale is the one I'd least like to leave sitting. Since our pins already carry # v6.0.2-style comments, Dependabot maintains the SHA and the comment together — no extra setup:

  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: monthly
    groups:
      actions:
        patterns: ['*']

Happy to add that here rather than defer it — it's six lines and the npm half of this config is already doing the harder job. Shout if you'd rather it went in its own PR.


.github/dependabot.yml line 19 at r1 (raw file):

Previously, alex-rawlings-yyc (Alex Rawlings) wrote…

I'm looking into this now; I'll come back with some sort of answer

Good check to insist on — I'd only verified that the config works, not that ignore was the reason it works. Turns out it is, and the finding's premise doesn't hold for npm.

The claim is that ignore is applied when filtering the parsed dependency list, downstream of the file fetcher. npm's fetcher actually consults the ignore list itself, in two places in npm_and_yarn/lib/dependabot/npm_and_yarn/file_fetcher.rb. In path_dependencies, before it ever tries to fetch:

if dependency_ignored?(name)
  Dependabot.logger.info(
    "Ignored local path dependency '#{cleaned_name}' for package '#{name}' as it matches the ignore list."
  )
  next
end

begin
  file = fetch_file_from_host(filename, fetch_submodules: true)

and again in build_unfetchable_deps, which is the path that actually bites us:

filtered_deps = unfetchable_deps.reject do |name, _path|
  if dependency_ignored?(name)
    Dependabot.logger.info("Ignored unfetchable path dependency '#{name}' as it matches the ignore list.")
    true

Our three don't trip either hard raise PathDependenciesNotReachable guard — those fire only on /-absolute paths or traversal past the repo root, and ../paranext-core/... is neither. So without ignore they fall through to fetch_file_from_hostDependencyFileNotFoundunfetchable_depsPathDependencyBuilder, which is where the abort originates.

That also answers the "otherwise redundant" half: the fetcher calls dependency_ignored? and never looks at allow, so leaving the three out of allow cannot substitute for listing them in ignore. The two keys aren't interchangeable here.

The comment was misleading about the mechanism ("never reaches the allow list" implied allow was the relevant knob), so I've rewritten it to name ignore specifically and say why allow can't cover it.

Worth noting the related bug reports where ignore genuinely doesn't suppress this are other ecosystems — dependabot/dependabot-core#14425 is Bundler, and it's closed with a fix.

@alex-rawlings-yyc
alex-rawlings-yyc force-pushed the dependabot-security-updates branch from 020c0e5 to e7a4469 Compare August 17, 2026 16:39

@imnasnainaec imnasnainaec left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oops, I meant just comparing package.json with the template's. We don't worry about lockfile drift; rather we update package-lock.json after syncing from the template (and we could do the same atop a dependabot update for the non-template packages).

@imnasnainaec reviewed all commit messages, made 2 comments, and resolved 2 discussions.
Reviewable status: 0 of 1 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc).


.github/dependabot.yml line 12 at r1 (raw file):

Previously, alex-rawlings-yyc (Alex Rawlings) wrote…

Claude's opinion:

Agreed this is a gap, though I'd argue the template rationale doesn't apply here at all — I checked, and none of our action pins match the template's. It floats major tags (actions/checkout@v4, github/codeql-action@v3, ncipollo/release-action@v1); we SHA-pinned every one of them back in #82. All four template-owned workflows are already locally modified too (lint.yml +19/-5, publish.yml +68/-10, codeql.yml +5/-3, bump-versions.yml +4/-4), and update-from-template lands as a hand-curated squash — #204 was one file — so there's no mechanical merge for a pin bump to conflict with.

The more pressing part is that SHA-pinning opts us out of updates and we never added the thing that puts them back. The pins are frozen where #82 left them:

actions/checkout      pinned v6.0.2 (2026-01-09)  ->  latest v7.0.1 (2026-07-20)   major behind
actions/setup-node    pinned v6.4.0 (2026-04-20)  ->  latest v7.0.0 (2026-07-14)   major behind
github/codeql-action  pinned       (2026-05-22)  ->  latest bundle (2026-08-12)   ~3 months

CodeQL three months stale is the one I'd least like to leave sitting. Since our pins already carry # v6.0.2-style comments, Dependabot maintains the SHA and the comment together — no extra setup:

  - package-ecosystem: github-actions
    directory: /
    schedule:
      interval: monthly
    groups:
      actions:
        patterns: ['*']

Happy to add that here rather than defer it — it's six lines and the npm half of this config is already doing the harder job. Shout if you'd rather it went in its own PR.

I'm inclined toward here over its own pr.

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added a script that does the comparison and added it to npm run lint

@alex-rawlings-yyc made 2 comments.
Reviewable status: 0 of 6 files reviewed, 1 unresolved discussion (waiting on imnasnainaec).


.github/dependabot.yml line 12 at r1 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

I'm inclined toward here over its own pr.

Added

Template-owned dependencies move only when we merge template changes, so
the allow list covers just the packages this extension adds. Security
updates stay inert until the repo's dependency graph is enabled.
npm's file fetcher consults `ignore` and never `allow`, so the comment
claiming the job "never reaches the allow list" named the wrong key.
SHA-pinned actions receive no updates without an ecosystem entry, and
nothing enforced the allow list's "absent from the template" rule.
Comparing against the template's moving head turned lint red on every PR
whenever the template bumped a shared range; reading the baseline out of
this repo's own history also lets CI drop the template checkout.
Failures
name a stale baseline as a possible cause, since it inverts their
advice.
@alex-rawlings-yyc
alex-rawlings-yyc force-pushed the dependabot-security-updates branch from d991f0b to a0bd260 Compare August 17, 2026 20:07
coderabbitai[bot]

This comment was marked as outdated.

A squashed template update leaves the pinned commit unreachable, which
would
fail every build; the copy also drops lint's git dependency and CI-only
skip.
Add npm run template:baseline and document when the refresh is needed.
merged-template-package.json from the template
commit that merge brought in, rather than acting on the lines above. Run
npm run template:baseline
while template/main still points at that commit.
The recorded id still named the state merged by #65. That template
commit's manifest is byte-identical to #204's, so only the id lagged —
the checked-in baseline copy needs no change.
Refreshing it runs a script rather than a shell redirect, which
truncated the file before git could fail. The check also compares
peerDependencies and names the file it could not parse.
npm run template:baseline now rewrites MERGED_TEMPLATE_COMMIT itself, so
skipping a manual step can no longer leave the check naming a template
state it did not compare against. Every failure path reports alike and
writes nothing.
An unreadable baseline, manifest, or Dependabot config reached Node's
default handler, so the conflict markers a template merge leaves in the
baseline arrived with no route back. A config carrying no updates key
hits the missing-ecosystem guard instead of throwing a TypeError.
Reads-before-writes leaves the pair in step only when a read fails; a
throw between the two writes still desynchronizes them.
imnasnainaec

This comment was marked as resolved.

imnasnainaec

This comment was marked as resolved.

A pattern outliving the package it names went unreported. Allow-list
wildcards are now rejected rather than misread as literal names, and a
baseline refresh that fails mid-way says which write landed.
Renames the group to match its contents, and syncs the template manifest
copy into the other two ignore files.
The check verified that each group pattern matched something on the
allow
list, but not the reverse, so an addition could drift out of the group
as
js-yaml had.

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@alex-rawlings-yyc made 6 comments.
Reviewable status: 6 of 13 files reviewed, 6 unresolved discussions (waiting on imnasnainaec).


.prettierignore line 3 at r6 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

These 3 *ignore files are now out of sync.

Fixed — the entry and its comment are in all three, and they diff clean below #endregion.

One thing to flag: I reworded the comment from "whatever reformatting our config would impose" to "whatever our tooling would impose on it". The original is Prettier-specific and would be untrue in the two files that don't rewrite anything, and byte-identity across the three seemed the stronger convention. Happy to put the sharper wording back and accept the divergence if you'd rather.

Also worth knowing the entry is defensive rather than load-bearing — running Prettier over a copy of merged-template-package.json returns it byte-identical, so the template's manifest is already Prettier-clean. It guards a future one that isn't.


.github/dependabot.yml line 60 at r3 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

Why leave out js-yaml here?

No good reason — it was the only devDependency we add that wasn't in there, so an oversight rather than a decision.

Renamed the group to dev-tooling and added it, so membership is now "everything we add on top of the template that isn't runtime". The only ungrouped allow entries left are the three that ship to users:

allow entries not in any group: @reduxjs/toolkit, fast-xml-parser, react-redux

Your first comment made me look at whether anything would have caught this, and nothing would have — the check verified that each pattern matches something on the allow list, but not the reverse, so the next dev dependency could have drifted out exactly as js-yaml did. That direction is enforced now too:

✗ js-yaml: a dev dependency on the allow list that no group collects, so its updates arrive as a pull request of their own — add it to a group, or record here why it stays out

Runtime dependencies and the file: entries are exempt by construction rather than by exception, so the three above stay quiet. There's deliberately no exception list yet — if a dev dependency ever genuinely wants its own pull request, that's a change to the check, and the message says so rather than pretending an escape hatch exists.

Comment thread scripts/check-dependency-scope.cjs Outdated
Comment thread scripts/check-dependency-scope.cjs
Comment thread scripts/check-dependency-scope.cjs
Comment thread scripts/refresh-template-baseline.cjs
An entry naming no package crashed the check on `undefined`; an ignore
entry whose package has left package.json now says so.
A second entry scopes another directory's package.json, so merging its
lists
would misreport the root manifest. The baseline and allow-list comments
now
name `npm run template:baseline` and the `file:` carve-out they left
out.
Also record why peerDependencies stay in the comparison, and the
inert allow entry a peer dependency beyond the template would be
asked for.
imnasnainaec

This comment was marked as resolved.

`process.exit` does not wait for an asynchronous one, and stderr is
asynchronous on a Windows terminal and on a POSIX pipe. Also match a
recorded commit id at either object-format width so a refresh can read
back what it wrote, fit the scope hint to every way that read fails, and
drop a hardcoded count from the config's comment.

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@alex-rawlings-yyc made 4 comments.
Reviewable status: 9 of 13 files reviewed, 4 unresolved discussions (waiting on imnasnainaec).


.github/dependabot.yml line 18 at r8 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ drop hardcoded "three"

Removed


scripts/check-dependency-scope.cjs line 326 at r8 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ Devin-caught:

scripts/check-dependency-scope.cjs:R326

Failure hint is off-target for the "more than one npm ecosystem entry" case

readOrFail(readNpmScope, UNSCOPED_DEPENDABOT_CONFIG_HINT) attaches a hint about there being no npm entry to declare the lists, but readNpmScope also throws when it finds two or more npm entries (scripts/check-dependency-scope.cjs:143-146). In that case the printed hint contradicts the error message it follows. Cosmetic only — the thrown message itself carries the actionable guidance.

Agreed, and it's broader than the two-entry case: readNpmScope has three throw sites — unreadable or non-YAML config, no npm entry, more than one — and readOrFail pairs a single hint with all of them. Reworded it to say where the lists live rather than to prescribe adding an entry, which fits every one:

✗ 2 npm ecosystem entries in .github/dependabot.yml, and this check reads one — name the directory each covers here, or teach this check to pick out the one scoping the package.json beside it
ℹ The allow, ignore, and group lists this check holds package.json to live in that file, declared by the one npm ecosystem entry scoping the directory package.json sits in.

Ran both failure modes against a temporarily-edited config to check the pairing reads straight.


scripts/refresh-template-baseline.cjs line 29 at r8 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ Could use {40,} or {40,64} to cover the Devin-observed SHA-256 repo edgecase.

Fixed


scripts/report-failure.cjs line 5 at r8 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ Devin suggestion:

scripts/report-failure.cjs:R1-5

Diagnostic output can be truncated by immediate process exit

fail writes to stderr and calls process.exit(1) in the same tick; the same pattern appears at scripts/check-dependency-scope.cjs:321-331. When stdout/stderr is a pipe (npm scripts under CI), Node's writes are asynchronous and process.exit does not wait for them, so a long violation list plus the stale-baseline hint can in principle be cut short. Messages here are far below the pipe buffer so this is unlikely to bite in practice; setting process.exitCode and returning would remove the risk entirely, and the trailing process.exit(0) on the success path is unnecessary either way.

Fixed — fail now writes the whole report with one fs.writeSync(2, …) before exiting, and the violation list in check-dependency-scope.cjs goes through the same writer instead of a console.error loop.

I couldn't reproduce the truncation: on the pinned Node (22.22.0), 50,000 console.error lines followed immediately by process.exit(1) came through a pipe complete and in order. But that's Node making POSIX stdio pipes blocking as an implementation detail — the documented contract is the opposite, and a Windows terminal is async outright, so the old code was only correct by accident.

Two notes on the suggestion itself. process.exitCode plus a return isn't a drop-in: all six call sites rely on fail never returning, so readOrFail would hand back undefined for scope, and refresh-template-baseline.cjs would reach commit.slice(0, 7) on undefined — the friendly message swapped for the TypeError this module exists to prevent. And the trailing process.exit(0) isn't in this PR; the only one under scripts/ is in delete-temp-files.cjs, which the branch doesn't touch.

I left the stdout preamble on console.log. fs.writeSync on fd 1 throws EPIPE when a consumer closes early, and trading a stack trace for two informational lines seemed the wrong way round.

@imnasnainaec imnasnainaec left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@imnasnainaec reviewed 3 files and all commit messages, made 1 comment, and resolved 4 discussions.
Reviewable status: 12 of 13 files reviewed, 1 unresolved discussion (waiting on alex-rawlings-yyc).


scripts/check-dependency-scope.cjs line 150 at r9 (raw file):

  const dependencyNames = (entries) => (entries ?? []).map((entry) => entry['dependency-name']);
  const groups = Object.entries(npmEntry.groups ?? {}).flatMap(([group, definition]) =>

⛏️ Devin suggestion:

scripts/check-dependency-scope.cjs:R150-152

Group parsing ignores exclude-patterns, so a group can look like it collects a package it does not

readNpmScope reads only definition.patterns (scripts/check-dependency-scope.cjs:150-152). Dependabot groups also accept exclude-patterns, and dependency-type. If someone later adds exclude-patterns to dev-tooling, findUngroupedDevDependencies would still consider an excluded package grouped and stay silent, defeating the very guarantee that function exists for. Nothing today declares an exclusion, so this is a latent blind spot rather than a live miss; a throw on any group key this check cannot read (mirroring the findUnsupportedEntries treatment of allow/ignore) would keep the two in step.

`findUngroupedDevDependencies` reads a group as the packages its
patterns collect. Dependabot also narrows a group by `exclude-patterns`
and by `dependency-type`, and either one leaves a package the group
drops still reading as collected, so the check that exists to catch an
ungrouped dev dependency would pass over it in silence. Nothing declares
either key today, which is what makes it a blind spot rather than a
miss: the guarantee would lapse quietly the first time one arrived.

Report any key beyond those the check reads, in the shape
`findUnsupportedEntries` already uses for an allow or ignore entry it
cannot read. `applies-to` and `update-types` stay unreported: both are
declared today and narrow which updates a group collects rather than
which packages, and packages are the axis the group checks reason about.

An unread key holds back the two checks that open a group and no others,
since the rest never read one. Both read the allow list as literal names
too, so an unreadable allow entry still holds them as before.

@alex-rawlings-yyc alex-rawlings-yyc left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@alex-rawlings-yyc made 1 comment.
Reviewable status: 12 of 13 files reviewed, 1 unresolved discussion (waiting on imnasnainaec).


scripts/check-dependency-scope.cjs line 150 at r9 (raw file):

Previously, imnasnainaec (D. Ror.) wrote…

⛏️ Devin suggestion:

scripts/check-dependency-scope.cjs:R150-152

Group parsing ignores exclude-patterns, so a group can look like it collects a package it does not

readNpmScope reads only definition.patterns (scripts/check-dependency-scope.cjs:150-152). Dependabot groups also accept exclude-patterns, and dependency-type. If someone later adds exclude-patterns to dev-tooling, findUngroupedDevDependencies would still consider an excluded package grouped and stay silent, defeating the very guarantee that function exists for. Nothing today declares an exclusion, so this is a latent blind spot rather than a live miss; a throw on any group key this check cannot read (mirroring the findUnsupportedEntries treatment of allow/ignore) would keep the two in step.

Real, and fixed in readNpmScope / findUnsupportedGroupKeys.

I narrowed it slightly from "throw on any group key this check cannot read". applies-to and update-types are declared today and are deliberately unread: they narrow which updates a group collects, not which packages, and the config comment beside them already records that majors arrive ungrouped on purpose. Package membership is the only axis findUngroupedDevDependencies reasons about, so those two are safe to pass over and everything else is not — which catches exclude-patterns and dependency-type alike, and any key Dependabot adds later.

The report follows findUnsupportedEntries rather than throwing: same violation-string shape, and it holds back only the two checks that open a group. The rest never read one, so an unread group key shouldn't suppress an allow-list or template violation that is perfectly readable. In the other direction the dependency does hold: both group checks read the allow list as literal names too, so an unreadable allow entry still holds them as before.

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 dependabot for security updates

2 participants