Two findings from a full-tree audit today. Both are invisible to CI, for different reasons.
1. npm ci cannot install this repo
On origin/development, npm 11.13.0, Node 22.22.0:
npm error code EUSAGE
npm error `npm ci` can only install packages when your package.json and
npm error package-lock.json or npm-shrinkwrap.json are in sync.
npm error Missing: @gouvfr/dsfr-token@ from lock file
npm error Missing: @gouvfr/dsfr-weave@ from lock file
Both are peerDependencies of @gouvfr/dsfr-nexus, which the lockfile carries but their entries do not:
peerDependencies :: node_modules/@gouvfr/dsfr-nexus -> @gouvfr/dsfr-token *
peerDependencies :: node_modules/@gouvfr/dsfr-weave -> @gouvfr/dsfr-weave *
It is specifically the peer set, not the runtime tree. Walking every dependencies entry in package-lock.json and resolving it the way npm does (own node_modules/, then each ancestor) gives 0 unresolved runtime deps — so the lock is internally consistent for dependencies and incomplete only for peers. That is the known npm-11 lockfile-peer-pruning shape: a lock generated by an npm that pruned peers, replayed by an npm that requires them.
Fix: regenerate with npm install on npm 11 and commit the lock. Worth also pinning the npm version CI uses, so the lock is always written and replayed by the same major.
Why nothing reported it
.github/workflows/code-quality.yml contains no npm ci or npm install of its own — the install happens inside the shared workflow. Whatever it does there evidently still succeeds, so the repo has a lockfile that a developer (and the hydra-gates checkers) cannot install from, while CI stays green.
Concretely: it made gate-22 (manifest-validation) and gate-53 (effective-manifest-crossref) unrunnable in a full-tree audit — both refuse to run fail-open when ajv is not resolvable, which is correct behaviour and reported honestly:
[gate-22] manifest-validation: FAIL — SCHEMA VALIDATION DID NOT HAPPEN — Ajv is not resolvable ...
[gate-53] effective-manifest-crossref: FAIL — ajv not resolvable ... refusing to run fail-open
With ajv supplied via NODE_PATH from a scratch install, both PASS. So they are not findings — but they were also not measurable in this repo without working around the lockfile.
2. The docs lockfile that actually ships is unscanned
Dependabot scans the default branch, which is main. main still has docusaurus/; development moved it to docs/ in 11048b7. So all 43 npm alerts name docusaurus/package-lock.json — a path deleted on development — and zero name docs/package-lock.json, which is the tree that ships.
docs/package-lock.json on development carries the same packages, several at older versions than the ones the open dependabot PR is trying to bump:
| package |
docs/ on development |
note |
fast-uri |
3.1.0 |
#144 bumps docusaurus/ 3.1.2 → 3.1.4 (2 advisories) |
js-yaml |
3.14.2, 4.1.1 |
2 high + 2 medium on the scanned copy |
shell-quote |
1.8.3 |
1 critical on the scanned copy |
websocket-driver |
0.7.4 |
1 critical on the scanned copy |
dompurify |
3.3.1 |
5 medium + 4 low |
webpack-dev-server |
5.2.3 |
6 medium |
postcss |
8.5.6 |
1 high |
serialize-javascript |
6.0.2 |
1 high |
brace-expansion |
1.1.12 |
2 high |
svgo |
— |
1 high |
Fix: add a dependabot.yml entry for directory: /docs (npm), and bump docs/package-lock.json on development. Until then the alert list describes a directory on its way out and says nothing about the one that ships.
Root package-lock.json also has 13 open alerts — 5 high on fast-uri, 2 high postcss, 1 high each js-yaml / flatted / brace-expansion — with no open PR against it either.
Context
Found while measuring nldesign's gates full-tree (no --scope-to-diff) at origin/development 7b0fade. Blocker notes left on #144; #102 and #104 closed as superseded.
Two findings from a full-tree audit today. Both are invisible to CI, for different reasons.
1.
npm cicannot install this repoOn
origin/development, npm 11.13.0, Node 22.22.0:Both are peerDependencies of
@gouvfr/dsfr-nexus, which the lockfile carries but their entries do not:It is specifically the peer set, not the runtime tree. Walking every
dependenciesentry inpackage-lock.jsonand resolving it the way npm does (ownnode_modules/, then each ancestor) gives 0 unresolved runtime deps — so the lock is internally consistent fordependenciesand incomplete only for peers. That is the known npm-11 lockfile-peer-pruning shape: a lock generated by an npm that pruned peers, replayed by an npm that requires them.Fix: regenerate with
npm installon npm 11 and commit the lock. Worth also pinning the npm version CI uses, so the lock is always written and replayed by the same major.Why nothing reported it
.github/workflows/code-quality.ymlcontains nonpm ciornpm installof its own — the install happens inside the shared workflow. Whatever it does there evidently still succeeds, so the repo has a lockfile that a developer (and the hydra-gates checkers) cannot install from, while CI stays green.Concretely: it made gate-22 (manifest-validation) and gate-53 (effective-manifest-crossref) unrunnable in a full-tree audit — both refuse to run fail-open when
ajvis not resolvable, which is correct behaviour and reported honestly:With
ajvsupplied viaNODE_PATHfrom a scratch install, both PASS. So they are not findings — but they were also not measurable in this repo without working around the lockfile.2. The docs lockfile that actually ships is unscanned
Dependabot scans the default branch, which is
main.mainstill hasdocusaurus/;developmentmoved it todocs/in11048b7. So all 43 npm alerts namedocusaurus/package-lock.json— a path deleted ondevelopment— and zero namedocs/package-lock.json, which is the tree that ships.docs/package-lock.jsonondevelopmentcarries the same packages, several at older versions than the ones the open dependabot PR is trying to bump:docs/on developmentfast-uridocusaurus/3.1.2 → 3.1.4 (2 advisories)js-yamlshell-quotewebsocket-driverdompurifywebpack-dev-serverpostcssserialize-javascriptbrace-expansionsvgoFix: add a
dependabot.ymlentry fordirectory: /docs(npm), and bumpdocs/package-lock.jsonondevelopment. Until then the alert list describes a directory on its way out and says nothing about the one that ships.Root
package-lock.jsonalso has 13 open alerts — 5 high onfast-uri, 2 highpostcss, 1 high eachjs-yaml/flatted/brace-expansion— with no open PR against it either.Context
Found while measuring nldesign's gates full-tree (no
--scope-to-diff) atorigin/development7b0fade. Blocker notes left on #144; #102 and #104 closed as superseded.