Skip to content

Commit 00d5494

Browse files
os-warrenclaude
andauthored
feat(scripts): gate repository.directory against the manifest's own directory (#16446)
npm renders `repository.directory` as a package page's "source" deep link, so a value naming a directory this repo does not have publishes a 404 on the one link a consumer follows to read the code. Nothing in this repo read the field: measured over the tracked tree, zero reads of `.directory` in any `.mjs`/`.mts`, and `check-published-files.mjs` — which has exactly the right population and already parses every manifest — mentions `repository` not once. The notch is a category rather than an off-by-one: this repo gated published package CONTENTS and did not gate published package PROVENANCE METADATA. The new gate is a state check over every tracked manifest that DECLARES the field: the value must be well-formed, must name a directory that is IN the repository (read off `git ls-files`, because the deep link is served from the repository and not from the author's working tree), and must be the manifest's own directory. Stateless over the population on purpose — one of the three commits behind the known residue moved nothing at all, it edited `repository.url` in the same JSON object with the stale `directory` line as visible hunk context, so a rule that fired only on directory MOVES would have missed it exactly as the reviewers did. ⛔ It judges only manifests that declare the field. Whether declaring is mandatory for a publishable package is an open policy question and a maintainer's to answer, so silence is counted, listed and never a finding. Anti-vacuity, because this population is `git ls-files` plus a field predicate and empties silently from either side: two control probes drive the same tracked-directory predicate the invariants use in BOTH directions (a directory derived from the population must report EXISTS, an assembled impossible one must report MISSING) and no verdict prints unless both fire; MEASURED pins the census on a named commit with floors under it; and the `--self-test` carries a battery roster whose names and per-battery case floors red when a battery stops registering cases. Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y Co-authored-by: Claude <noreply@anthropic.com>
1 parent ce21963 commit 00d5494

3 files changed

Lines changed: 1028 additions & 0 deletions

File tree

.github/workflows/lint.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3597,6 +3597,29 @@ jobs:
35973597
- name: Published-files whitelist guard
35983598
run: pnpm check:published-files
35993599

3600+
# The PROVENANCE half of the same packaging hygiene (#15991). The guard
3601+
# above owns published package CONTENTS — what the tarball contains — and
3602+
# says nothing about where the tarball claims its source lives. npm renders
3603+
# `repository.directory` as the package page's "source" deep link, and
3604+
# until this gate NOTHING in this repo read the field: two
3605+
# `packages/triggers/*` manifests shipped a value naming
3606+
# `packages/plugins/plugin-trigger-*`, a path removed when the family was
3607+
# promoted, so both npm pages published a 404 on the one link a consumer
3608+
# follows to read the code. The history is why it is a state check over the
3609+
# whole population rather than a rule about moves: one of the three commits
3610+
# involved moved nothing at all — it edited `repository.url` in the same
3611+
# JSON object with the stale `directory` line as visible hunk context, and
3612+
# it shipped. Humans looked and missed it twice. ⛔ It judges only manifests
3613+
# that DECLARE the field; whether declaring is mandatory for a publishable
3614+
# package is an open policy question and a maintainer's to answer, so
3615+
# silence is counted and never a finding. Runs its own --self-test first:
3616+
# this population is `git ls-files` plus a field predicate, so a changed
3617+
# glob or a renamed field empties it silently and the production run would
3618+
# print exactly what a clean tree prints. Static read of tracked manifests;
3619+
# no build, no network, sub-second.
3620+
- name: Manifest repository.directory guard
3621+
run: pnpm check:manifest-repository-directory
3622+
36003623
# Engine test-double contract gate (#4550, from #4434). A test double
36013624
# LOOSER than the implementation it replaces turns a green suite into no
36023625
# suite at all, silently, on exactly the paths a double was introduced

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
"check:undeclared-dep-imports": "node scripts/check-undeclared-dep-imports.mjs --self-test && node scripts/check-undeclared-dep-imports.mjs",
146146
"check:keyed-text-bounds": "node scripts/check-keyed-text-bounds.mjs --self-test && node scripts/check-keyed-text-bounds.mjs",
147147
"check:published-files": "node scripts/check-published-files.mjs --self-test && node scripts/check-published-files.mjs",
148+
"check:manifest-repository-directory": "node scripts/check-manifest-repository-directory.mjs --self-test && node scripts/check-manifest-repository-directory.mjs",
148149
"check:published-readme-exports": "node scripts/check-published-readme-exports.mjs --self-test && node scripts/check-published-readme-exports.mjs",
149150
"check:published-readme-links": "node scripts/check-published-readme-links.mjs --self-test && node scripts/check-published-readme-links.mjs",
150151
"check:dual-build-cjs-loads": "node scripts/check-dual-build-cjs-loads.mjs --self-test && node scripts/check-dual-build-cjs-loads.mjs",

0 commit comments

Comments
 (0)