@codyswann/lisa 2.279.2 → 2.280.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/cli/doctor-readiness-audit-allowlist.d.ts +7 -0
  2. package/dist/cli/doctor-readiness-audit-allowlist.d.ts.map +1 -0
  3. package/dist/cli/doctor-readiness-audit-allowlist.js +177 -0
  4. package/dist/cli/doctor-readiness-audit-allowlist.js.map +1 -0
  5. package/dist/cli/doctor-readiness-context-claims.d.ts +14 -0
  6. package/dist/cli/doctor-readiness-context-claims.d.ts.map +1 -0
  7. package/dist/cli/doctor-readiness-context-claims.js +117 -0
  8. package/dist/cli/doctor-readiness-context-claims.js.map +1 -0
  9. package/dist/cli/doctor-readiness-context-mechanisms.d.ts +46 -0
  10. package/dist/cli/doctor-readiness-context-mechanisms.d.ts.map +1 -0
  11. package/dist/cli/doctor-readiness-context-mechanisms.js +116 -0
  12. package/dist/cli/doctor-readiness-context-mechanisms.js.map +1 -0
  13. package/dist/cli/doctor-readiness-context.d.ts +16 -0
  14. package/dist/cli/doctor-readiness-context.d.ts.map +1 -0
  15. package/dist/cli/doctor-readiness-context.js +244 -0
  16. package/dist/cli/doctor-readiness-context.js.map +1 -0
  17. package/dist/cli/doctor-readiness-delivery.d.ts.map +1 -1
  18. package/dist/cli/doctor-readiness-delivery.js +1 -10
  19. package/dist/cli/doctor-readiness-delivery.js.map +1 -1
  20. package/dist/cli/doctor-readiness-shared.d.ts +47 -0
  21. package/dist/cli/doctor-readiness-shared.d.ts.map +1 -0
  22. package/dist/cli/doctor-readiness-shared.js +88 -0
  23. package/dist/cli/doctor-readiness-shared.js.map +1 -0
  24. package/dist/cli/doctor-readiness-supply-chain-scan.d.ts +67 -0
  25. package/dist/cli/doctor-readiness-supply-chain-scan.d.ts.map +1 -0
  26. package/dist/cli/doctor-readiness-supply-chain-scan.js +316 -0
  27. package/dist/cli/doctor-readiness-supply-chain-scan.js.map +1 -0
  28. package/dist/cli/doctor-readiness-supply-chain.d.ts +14 -0
  29. package/dist/cli/doctor-readiness-supply-chain.d.ts.map +1 -0
  30. package/dist/cli/doctor-readiness-supply-chain.js +231 -0
  31. package/dist/cli/doctor-readiness-supply-chain.js.map +1 -0
  32. package/dist/cli/doctor-readiness-workspaces.d.ts +22 -0
  33. package/dist/cli/doctor-readiness-workspaces.d.ts.map +1 -0
  34. package/dist/cli/doctor-readiness-workspaces.js +98 -0
  35. package/dist/cli/doctor-readiness-workspaces.js.map +1 -0
  36. package/dist/cli/doctor-readiness.d.ts.map +1 -1
  37. package/dist/cli/doctor-readiness.js +7 -3
  38. package/dist/cli/doctor-readiness.js.map +1 -1
  39. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  40. package/dist/core/upstream-evidence-manifest.js +13 -0
  41. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  42. package/package.json +1 -1
  43. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-agy/plugin.json +1 -1
  46. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  48. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  49. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-expo-agy/plugin.json +1 -1
  56. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  61. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  66. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  71. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  75. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  76. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  80. package/plugins/lisa-rails-agy/plugin.json +1 -1
  81. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  85. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  86. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  90. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  91. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Offline supply-chain scanning for the dependencies/supply-chain readiness
3
+ * producer (B5, PRD #1739, #1896).
4
+ *
5
+ * The B5 question — does belief that the owned surface still works rest on more
6
+ * than hope — is answered from four repository facts: a committed lockfile, the
7
+ * dependency specs the manifest names, whether anything anywhere audits the
8
+ * tree, and whether each audit exception carries the decision behind it. This
9
+ * module gathers those facts; its sibling turns them into the rubric-shaped
10
+ * dimension record. Splitting them keeps each file inside the repository's
11
+ * file-size budget and keeps the gathering independently testable.
12
+ *
13
+ * Reading is offline and best-effort by construction: an unreadable file
14
+ * establishes nothing and is passed over, never reported as a violation.
15
+ * @module cli/doctor-readiness-supply-chain-scan
16
+ */
17
+ import { readdir } from "node:fs/promises";
18
+ import * as path from "node:path";
19
+ import { isRecord, readFileOrNull } from "./doctor-readiness-shared.js";
20
+ /**
21
+ * Every lockfile spelling a JavaScript package manager writes. One of these
22
+ * being committed is what makes two installs resolve to the same tree.
23
+ */
24
+ export const LOCKFILES = [
25
+ "bun.lock",
26
+ "bun.lockb",
27
+ "package-lock.json",
28
+ "npm-shrinkwrap.json",
29
+ "yarn.lock",
30
+ "pnpm-lock.yaml",
31
+ ];
32
+ /**
33
+ * Manifest blocks whose specs must name a version. `peerDependencies` is
34
+ * deliberately excluded: `*` there is the conventional way to say "any host
35
+ * version works", not a floating install.
36
+ */
37
+ const VERSIONED_BLOCKS = [
38
+ "dependencies",
39
+ "devDependencies",
40
+ "optionalDependencies",
41
+ "overrides",
42
+ "resolutions",
43
+ ];
44
+ /**
45
+ * Specs that resolve to whatever is newest at install time. Deliberately narrow:
46
+ * a `>=` floor in `overrides` is the recommended way to force a patched
47
+ * transitive dependency, so treating ranges as floating would fault the very
48
+ * remediation the audit gate asks for.
49
+ */
50
+ const FLOATING_SPECS = new Set([
51
+ "",
52
+ "*",
53
+ "x",
54
+ "X",
55
+ "*.*",
56
+ "*.*.*",
57
+ "latest",
58
+ "next",
59
+ "*.x",
60
+ ]);
61
+ /**
62
+ * Protocols that resolve to something inside this repository rather than to a
63
+ * published version, so there is nothing to pin and nothing to drift.
64
+ */
65
+ const LOCAL_PROTOCOLS = [
66
+ "workspace:",
67
+ "file:",
68
+ "link:",
69
+ "portal:",
70
+ ];
71
+ /**
72
+ * Protocols that clone a source tree. Without a ref these resolve to whatever
73
+ * the default branch holds at install time, which is the drift B5 cares about.
74
+ * Each alternative ends in `:` or `+` on purpose — a colonless `bitbucket`
75
+ * alternative would match the ordinary registry package `bitbucket-client`.
76
+ */
77
+ const GIT_FETCH_PROTOCOL = /^(github:|gitlab:|bitbucket:|git\+|git:)/i;
78
+ /** An `http(s)` spec, which may clone a repository or download an archive. */
79
+ const HTTP_SPEC = /^https?:\/\//i;
80
+ /**
81
+ * Whether a source-fetch spec is anchored to one revision by a `#<sha|tag>`
82
+ * suffix. Written without a regex so it cannot backtrack on a hostile spec.
83
+ * @param spec - The declared spec text
84
+ * @returns True when a non-empty ref follows a `#`
85
+ */
86
+ function hasImmutableRef(spec) {
87
+ const marker = spec.indexOf("#");
88
+ return marker >= 0 && spec.slice(marker + 1).trim() !== "";
89
+ }
90
+ /**
91
+ * Whether a spec clones a git repository.
92
+ *
93
+ * The distinction this draws is the whole point: `git+https://…/widget.git`
94
+ * tracks a moving branch tip, but `https://…/widget-1.2.3.tgz` names one built
95
+ * archive that cannot become something newer tomorrow. Demanding a `#ref` of an
96
+ * archive URL would fault a repository that is already perfectly pinned.
97
+ * @param spec - The declared spec text
98
+ * @returns True when the spec resolves by cloning a repository
99
+ */
100
+ function clonesRepository(spec) {
101
+ const beforeRef = spec.split("#")[0] ?? "";
102
+ return (GIT_FETCH_PROTOCOL.test(spec) ||
103
+ (HTTP_SPEC.test(spec) && beforeRef.toLowerCase().endsWith(".git")));
104
+ }
105
+ /**
106
+ * Whether a dependency spec resolves to whatever is newest at install time
107
+ * rather than to a version something was validated against.
108
+ *
109
+ * Four families are recognized, and the narrowness of each is deliberate — every
110
+ * over-eager rule here fails a correctly configured repository:
111
+ *
112
+ * - **Local protocols** resolve inside the repository and never float.
113
+ * - **Registry aliases** (`npm:left-pad@latest`) hide the real spec behind the
114
+ * alias, so the part after the version separator is re-tested.
115
+ * - **Repository clones** (`github:acme/widget`, `git+https://…/x.git`) float
116
+ * unless anchored to a `#<sha|tag>` revision, because the branch tip moves
117
+ * under the install. An archive URL (`…/widget-1.2.3.tgz`) is NOT a clone: it
118
+ * names one built artifact and is treated as pinned.
119
+ * - **Plain ranges** float only when they name no version at all. A `>=` floor
120
+ * in `overrides` is the recommended way to force a patched transitive
121
+ * dependency, so ranges are otherwise left alone.
122
+ * @param spec - The declared spec text
123
+ * @returns True when the spec floats
124
+ */
125
+ export function isFloatingSpec(spec) {
126
+ const trimmed = spec.trim();
127
+ if (LOCAL_PROTOCOLS.some(protocol => trimmed.startsWith(protocol))) {
128
+ return false;
129
+ }
130
+ if (/^npm:/i.test(trimmed)) {
131
+ const separator = trimmed.lastIndexOf("@");
132
+ return separator > "npm:".length
133
+ ? isFloatingSpec(trimmed.slice(separator + 1))
134
+ : true;
135
+ }
136
+ if (clonesRepository(trimmed)) {
137
+ return !hasImmutableRef(trimmed);
138
+ }
139
+ return FLOATING_SPECS.has(trimmed.toLowerCase());
140
+ }
141
+ /**
142
+ * Commands and actions that actually audit the DEPENDENCY tree. A job merely
143
+ * titled "Security Scan" is deliberately not enough: a secret scanner proves
144
+ * nothing about the dependency tree, and counting it would be a false green —
145
+ * the worst direction to err for a confidence model.
146
+ */
147
+ const AUDIT_GATE_PATTERN = /\b(npm|bun|yarn|pnpm)\s+audit\b|audit-ci|osv-scanner|dependency-review-action|\bsnyk\b|\btrivy\b|\bgrype\b/i;
148
+ /**
149
+ * An update bot covering the JavaScript dependency tree. A `dependabot.yml`
150
+ * that only watches `github-actions` never looks at `package.json`, so its mere
151
+ * presence is not a confidence model for the dependencies.
152
+ */
153
+ const JS_ECOSYSTEM_PATTERN = /package-ecosystem:\s*["']?(npm|bun|yarn|pnpm)\b/i;
154
+ /** Files that may declare an audit gate in their text. */
155
+ const GATE_DIRECTORIES = [
156
+ path.join(".github", "workflows"),
157
+ ".husky",
158
+ ];
159
+ /** Single-file gate declarations checked by text match. */
160
+ const GATE_FILES = [
161
+ "lefthook.yml",
162
+ "lefthook.yaml",
163
+ ".lefthook.yml",
164
+ ];
165
+ /** Update bots whose mere presence is a standing confidence model. */
166
+ const UPDATE_BOT_FILES = [
167
+ path.join(".github", "dependabot.yml"),
168
+ path.join(".github", "dependabot.yaml"),
169
+ path.join(".github", "renovate.json"),
170
+ "renovate.json",
171
+ ".renovaterc",
172
+ ".renovaterc.json",
173
+ ];
174
+ /**
175
+ * Whether a repository-relative path exists.
176
+ * @param root - Repository root
177
+ * @param relativePath - Repo-relative path
178
+ * @returns True when the file could be read
179
+ */
180
+ async function fileExists(root, relativePath) {
181
+ return (await readFileOrNull(root, relativePath)) !== null;
182
+ }
183
+ /**
184
+ * List the files directly inside a repository-relative directory.
185
+ * @param root - Repository root
186
+ * @param relativeDir - Repo-relative directory
187
+ * @returns Repo-relative file paths (empty when the directory is absent)
188
+ */
189
+ async function listDirectory(root, relativeDir) {
190
+ try {
191
+ const entries = await readdir(path.join(root, relativeDir), {
192
+ withFileTypes: true,
193
+ });
194
+ return entries
195
+ .filter(entry => entry.isFile())
196
+ .map(entry => path.join(relativeDir, entry.name))
197
+ .sort((a, b) => a.localeCompare(b));
198
+ }
199
+ catch {
200
+ return [];
201
+ }
202
+ }
203
+ /**
204
+ * Read and parse `package.json`, distinguishing "absent" from "unparseable" so
205
+ * the SKIP reason can say which one happened.
206
+ * @param root - Repository root
207
+ * @returns The parsed manifest, or the reason it cannot be assessed
208
+ */
209
+ export async function readManifest(root) {
210
+ const source = await readFileOrNull(root, "package.json");
211
+ if (source === null) {
212
+ return {
213
+ kind: "unassessable",
214
+ reason: "no `package.json` was found, so this repository declares no " +
215
+ "JavaScript dependency surface to build a confidence model for; " +
216
+ "supply-chain confidence is not established either way",
217
+ };
218
+ }
219
+ try {
220
+ const parsed = JSON.parse(source);
221
+ if (!isRecord(parsed)) {
222
+ throw new Error("manifest is not a JSON object");
223
+ }
224
+ return { kind: "ok", manifest: parsed };
225
+ }
226
+ catch (error) {
227
+ return {
228
+ kind: "unassessable",
229
+ reason: "`package.json` could not be parsed, so its dependency specs were " +
230
+ `never read and nothing about them is established: ${error instanceof Error ? error.message : String(error)}`,
231
+ };
232
+ }
233
+ }
234
+ /**
235
+ * Flatten one manifest block into `name → spec` pairs. `overrides` nests, so a
236
+ * nested map is walked rather than skipped — a floating spec one level down
237
+ * installs exactly as loosely as one at the top.
238
+ * @param block - Block name, e.g. `dependencies`
239
+ * @param value - The block's raw value
240
+ * @param prefix - Accumulated name path for nested overrides
241
+ * @returns Flattened specs
242
+ */
243
+ function flattenBlock(block, value, prefix = "") {
244
+ if (!isRecord(value)) {
245
+ return [];
246
+ }
247
+ return Object.entries(value).flatMap(([name, spec]) => {
248
+ const qualified = prefix === "" ? name : `${prefix}.${name}`;
249
+ if (typeof spec === "string") {
250
+ return [{ block, name: qualified, spec }];
251
+ }
252
+ return flattenBlock(block, spec, qualified);
253
+ });
254
+ }
255
+ /**
256
+ * Flatten every versioned manifest block into one list of specs.
257
+ * @param manifest - Parsed `package.json`
258
+ * @returns Every declared spec across the versioned blocks
259
+ */
260
+ export function collectSpecs(manifest) {
261
+ return VERSIONED_BLOCKS.flatMap(block => flattenBlock(block, manifest[block]));
262
+ }
263
+ /**
264
+ * Find the committed lockfile, if any.
265
+ * @param root - Repository root
266
+ * @returns The lockfile name, or null when none is committed
267
+ */
268
+ export async function findLockfile(root) {
269
+ for (const candidate of LOCKFILES) {
270
+ if (await fileExists(root, candidate)) {
271
+ return candidate;
272
+ }
273
+ }
274
+ return null;
275
+ }
276
+ /**
277
+ * Whether an update-bot config actually watches the JavaScript dependency tree.
278
+ * Dependabot declares an ecosystem per entry, so a config covering only
279
+ * `github-actions` is not a confidence model for `package.json`. Renovate has no
280
+ * such per-file declaration and defaults to every manager it detects, so its
281
+ * presence is taken at face value.
282
+ * @param botFile - Repo-relative bot config path
283
+ * @param source - The config's text
284
+ * @returns True when the bot covers the JavaScript dependencies
285
+ */
286
+ function coversJavaScriptTree(botFile, source) {
287
+ return botFile.includes("dependabot")
288
+ ? JS_ECOSYSTEM_PATTERN.test(source)
289
+ : true;
290
+ }
291
+ /**
292
+ * Find where the repository audits its dependency tree: a CI job, a git hook, a
293
+ * lefthook declaration, or an update bot.
294
+ * @param root - Repository root
295
+ * @returns The repo-relative path of the first gate found, or null
296
+ */
297
+ export async function findAuditGate(root) {
298
+ for (const botFile of UPDATE_BOT_FILES) {
299
+ const source = await readFileOrNull(root, botFile);
300
+ if (source !== null && coversJavaScriptTree(botFile, source)) {
301
+ return botFile.split(path.sep).join("/");
302
+ }
303
+ }
304
+ const scanned = [
305
+ ...(await Promise.all(GATE_DIRECTORIES.map(dir => listDirectory(root, dir)))).flat(),
306
+ ...GATE_FILES,
307
+ ];
308
+ for (const file of scanned) {
309
+ const source = await readFileOrNull(root, file);
310
+ if (source !== null && AUDIT_GATE_PATTERN.test(source)) {
311
+ return file.split(path.sep).join("/");
312
+ }
313
+ }
314
+ return null;
315
+ }
316
+ //# sourceMappingURL=doctor-readiness-supply-chain-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-readiness-supply-chain-scan.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ReadinessDimensionRecord } from "./doctor-readiness-types.js";
2
+ /** The dependencies/supply-chain readiness dimension id (readiness-rubric). */
3
+ export declare const DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID = "dependencies-supply-chain";
4
+ /**
5
+ * Assess the dependencies/supply-chain dimension: B5, "an owned compatibility or
6
+ * security surface has no confidence model". Offline by construction — it reads
7
+ * only the repository's manifest, lockfiles, CI declarations, git hooks, and
8
+ * audit allowlists, and degrades to a stated-reason SKIP wherever those files
9
+ * cannot settle the question.
10
+ * @param root - Project root to assess
11
+ * @returns The dependencies/supply-chain dimension record
12
+ */
13
+ export declare function assessDependenciesSupplyChainDimension(root: string): Promise<ReadinessDimensionRecord>;
14
+ //# sourceMappingURL=doctor-readiness-supply-chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-readiness-supply-chain.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E,+EAA+E;AAC/E,eAAO,MAAM,sCAAsC,8BACtB,CAAC;AAsL9B;;;;;;;;GAQG;AACH,wBAAsB,sCAAsC,CAC1D,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,wBAAwB,CAAC,CA8CnC"}
@@ -0,0 +1,231 @@
1
+ /**
2
+ * The dependencies/supply-chain readiness producer — ship blocker B5
3
+ * (PRD #1739, #1896).
4
+ *
5
+ * Dimension 6 of the `readiness-rubric` asks whether belief that the owned
6
+ * surface still works rests on more than hope. Four things, read offline from
7
+ * the repository's own files, decide that: the dependency tree resolves to the
8
+ * same versions twice (a lockfile), the manifest names versions rather than
9
+ * "whatever is newest" (no floating specs), something somewhere actually audits
10
+ * the tree (a CI scan, a git hook, or an update bot), and every audit exception
11
+ * carries the decision that made it acceptable.
12
+ *
13
+ * Two disciplines are load-bearing rather than stylistic:
14
+ *
15
+ * 1. **A finding names a `blocker` id ONLY on an actual violation.** The blocker
16
+ * engine stands a blocker up on any finding that names an id and carries
17
+ * evidence, regardless of the finding's status — so a clean repository's PASS
18
+ * finding must carry no `blocker` key, or a healthy repository reports
19
+ * NOT_READY.
20
+ * The scanning half — reading the manifest, the lockfile, the audit gates, and
21
+ * the audit allowlists — lives in `doctor-readiness-supply-chain-scan`; this
22
+ * module turns what it found into the rubric-shaped dimension record.
23
+ *
24
+ * 2. **Never manufacture RED or GREEN from absence.** A repository with no
25
+ * manifest, an unparseable manifest, or no declared dependencies owns no
26
+ * dependency surface this producer can speak to, so it renders a
27
+ * stated-reason SKIP — never a violation, and never a false-green PASS.
28
+ * @module cli/doctor-readiness-supply-chain
29
+ */
30
+ import { informationalFindings } from "./doctor-readiness-shared.js";
31
+ import { auditExceptionViolations } from "./doctor-readiness-audit-allowlist.js";
32
+ import { collectSpecs, findAuditGate, findLockfile, isFloatingSpec, LOCKFILES, readManifest, } from "./doctor-readiness-supply-chain-scan.js";
33
+ import { resolveWorkspaceMembers, } from "./doctor-readiness-workspaces.js";
34
+ /** The dependencies/supply-chain readiness dimension id (readiness-rubric). */
35
+ export const DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID = "dependencies-supply-chain";
36
+ /** The ship blocker for an owned surface with no confidence model. */
37
+ const SUPPLY_CHAIN_BLOCKER_ID = "B5";
38
+ /** Most evidence lines carried into a single finding, to keep it readable. */
39
+ const MAX_EVIDENCE_LINES = 12;
40
+ /**
41
+ * Build the evidence line for a manifest with no committed lockfile.
42
+ * @param specCount - How many specs the manifest declares
43
+ * @returns One evidence line
44
+ */
45
+ function lockfileEvidence(specCount) {
46
+ return (`\`package.json\` declares ${specCount} dependency spec(s) but no lockfile ` +
47
+ `is committed (looked for ${LOCKFILES.join(", ")}) — two installs can ` +
48
+ "resolve to different trees, so what was validated is not provably what " +
49
+ "gets installed");
50
+ }
51
+ /**
52
+ * Whether a floating-looking spec is really a link to a package in this
53
+ * repository. `"@acme/utils": "*"` against a workspace member resolves to the
54
+ * local package, which is the workspace idiom rather than a floating install —
55
+ * so faulting it would fail every correctly configured monorepo.
56
+ *
57
+ * When workspaces are declared but no member name could be resolved (an
58
+ * unreadable child manifest, an unsupported glob), a bare `*` is exempted
59
+ * anyway: the repository has told us it links locally, and absence of proof is
60
+ * not proof of a violation.
61
+ * @param spec - The declared spec
62
+ * @param workspaces - What resolving the workspace members established
63
+ * @returns True when the spec links to a workspace member
64
+ */
65
+ function linksWorkspaceMember(spec, workspaces) {
66
+ if (!workspaces.declared) {
67
+ return false;
68
+ }
69
+ return (workspaces.names.has(spec.name) ||
70
+ (workspaces.names.size === 0 && spec.spec.trim() === "*"));
71
+ }
72
+ /**
73
+ * Assess a repository's dependency confidence model.
74
+ * @param root - Repository root
75
+ * @param specs - Declared dependency specs
76
+ * @param workspaces - What resolving the workspace members established
77
+ * @returns Evidence lines for violations, and non-blocking observations
78
+ */
79
+ async function collectFindings(root, specs, workspaces) {
80
+ const lockfile = await findLockfile(root);
81
+ const auditGate = await findAuditGate(root);
82
+ const floating = specs.filter(spec => isFloatingSpec(spec.spec) && !linksWorkspaceMember(spec, workspaces));
83
+ return {
84
+ violations: [
85
+ ...(lockfile === null ? [lockfileEvidence(specs.length)] : []),
86
+ ...floating.map(spec => `\`package.json\` \`${spec.block}.${spec.name}\` is \`${spec.spec}\`, ` +
87
+ "which resolves to whatever is newest at install time rather than to " +
88
+ "a version anything was ever validated against"),
89
+ ...(auditGate === null
90
+ ? [
91
+ "no dependency-audit gate covering the JavaScript tree was found " +
92
+ "anywhere — no `npm`/`bun` audit step in `.github/workflows/*.yml`, " +
93
+ "none in a git hook, and no `dependabot.yml` npm entry or " +
94
+ "`renovate.json` — so a newly disclosed advisory in this tree " +
95
+ "would never be noticed by anything",
96
+ ]
97
+ : []),
98
+ ...(await auditExceptionViolations(root)),
99
+ ],
100
+ observations: [
101
+ ...(lockfile === null ? [] : [`Lockfile in use: \`${lockfile}\`.`]),
102
+ ...(auditGate === null
103
+ ? []
104
+ : [`Dependency-audit gate declared in \`${auditGate}\`.`]),
105
+ ...(workspaces.declared ? [workspaceObservation(workspaces)] : []),
106
+ ],
107
+ };
108
+ }
109
+ /**
110
+ * State what the workspace exemption actually did.
111
+ *
112
+ * The two cases must not be described in the same words. When member manifests
113
+ * resolved, named packages were exempted because they provably link locally.
114
+ * When none resolved, a bare `*` was exempted on the strength of the
115
+ * `workspaces` declaration alone — a deliberate refusal to manufacture a
116
+ * violation from absence, but NOT a resolved link, and reporting it as
117
+ * "0 package name(s) were exempted" would describe the opposite of what
118
+ * happened.
119
+ * @param workspaces - What resolving the workspace members established
120
+ * @returns One operator-language observation
121
+ */
122
+ function workspaceObservation(workspaces) {
123
+ return workspaces.names.size > 0
124
+ ? `Workspaces are declared, so ${workspaces.names.size} locally linked ` +
125
+ "package name(s) were exempted from the floating-spec check."
126
+ : "Workspaces are declared but no member manifests resolved offline, so " +
127
+ "bare `*` specs were treated as workspace links rather than as " +
128
+ "floating installs. Whether they really link locally is not established.";
129
+ }
130
+ /**
131
+ * Build the rubric-shaped B5 finding from its evidence lines.
132
+ * @param violations - Evidence lines
133
+ * @returns The B5 finding
134
+ */
135
+ function supplyChainFinding(violations) {
136
+ const shown = violations.slice(0, MAX_EVIDENCE_LINES);
137
+ const overflow = violations.length - shown.length;
138
+ return {
139
+ blocker: SUPPLY_CHAIN_BLOCKER_ID,
140
+ invariant_violated: "belief that the owned surface still works rests on a repeatable install " +
141
+ "and a standing audit, not on hope",
142
+ evidence: shown.join(" | ") +
143
+ (overflow > 0
144
+ ? ` | (+${overflow} further finding(s) of the same kind)`
145
+ : ""),
146
+ why_proof_missed: "the test suite proves things about the code in the tree it happened to " +
147
+ "install, so a tree that drifts — or one carrying a known advisory nobody " +
148
+ "checks for — still reports green",
149
+ root_correction: "commit a lockfile, name a version for every dependency spec, run a " +
150
+ "dependency audit on every push, and record the decision behind each " +
151
+ "audit exception next to the exception itself",
152
+ machinery_to_remove: [
153
+ "audit exceptions kept alive with no written decision, which cost review " +
154
+ "attention every cycle and prove nothing",
155
+ ],
156
+ };
157
+ }
158
+ /**
159
+ * Describe what the spec check established, without overstating the bare-`*`
160
+ * workspace fallback as a resolved link.
161
+ * @param workspaces - What resolving the workspace members established
162
+ * @returns One clause for the PASS evidence
163
+ */
164
+ function describeSpecCleanliness(workspaces) {
165
+ return workspaces.declared && workspaces.names.size === 0
166
+ ? "every one names a version, except bare `*` specs exempted because " +
167
+ "workspaces are declared but no member manifests resolved offline"
168
+ : "every one names a version or links a workspace member";
169
+ }
170
+ /**
171
+ * Build the stated-reason SKIP for a repository with no assessable manifest.
172
+ * @param reason - Why the dimension was not assessed
173
+ * @returns The SKIP dimension record
174
+ */
175
+ function skipRecord(reason) {
176
+ return {
177
+ id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
178
+ status: "SKIP",
179
+ findings: [{ reason, skip: true }],
180
+ };
181
+ }
182
+ /**
183
+ * Assess the dependencies/supply-chain dimension: B5, "an owned compatibility or
184
+ * security surface has no confidence model". Offline by construction — it reads
185
+ * only the repository's manifest, lockfiles, CI declarations, git hooks, and
186
+ * audit allowlists, and degrades to a stated-reason SKIP wherever those files
187
+ * cannot settle the question.
188
+ * @param root - Project root to assess
189
+ * @returns The dependencies/supply-chain dimension record
190
+ */
191
+ export async function assessDependenciesSupplyChainDimension(root) {
192
+ const outcome = await readManifest(root);
193
+ if (outcome.kind === "unassessable") {
194
+ return skipRecord(outcome.reason);
195
+ }
196
+ const specs = collectSpecs(outcome.manifest);
197
+ if (specs.length === 0) {
198
+ return skipRecord("`package.json` declares no dependencies, so this repository owns no " +
199
+ "third-party surface a confidence model could cover; supply-chain " +
200
+ "confidence is not established either way");
201
+ }
202
+ const workspaces = await resolveWorkspaceMembers(root, outcome.manifest);
203
+ const { violations, observations } = await collectFindings(root, specs, workspaces);
204
+ if (violations.length > 0) {
205
+ return {
206
+ id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
207
+ status: "FAIL",
208
+ findings: [
209
+ supplyChainFinding(violations),
210
+ ...informationalFindings(observations),
211
+ ],
212
+ };
213
+ }
214
+ return {
215
+ id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
216
+ status: "PASS",
217
+ findings: [
218
+ {
219
+ evidence: `Inspected ${specs.length} dependency spec(s) in the root ` +
220
+ `\`package.json\`: ${describeSpecCleanliness(workspaces)}, a ` +
221
+ "lockfile is committed, a dependency-audit gate covering the " +
222
+ "JavaScript tree is declared, and every active audit exception " +
223
+ "carries a written decision. Workspace child manifests are not " +
224
+ "walked, so this speaks only to the root manifest.",
225
+ checked: [SUPPLY_CHAIN_BLOCKER_ID],
226
+ },
227
+ ...informationalFindings(observations),
228
+ ],
229
+ };
230
+ }
231
+ //# sourceMappingURL=doctor-readiness-supply-chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-readiness-supply-chain.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /** What resolving the repository's workspace members established. */
2
+ export interface WorkspaceMembers {
3
+ /** Whether the repository declares workspaces at all. */
4
+ readonly declared: boolean;
5
+ /** Names of the local packages the workspaces resolve to. */
6
+ readonly names: ReadonlySet<string>;
7
+ }
8
+ /**
9
+ * Resolve the local package names a repository's workspace globs expand to.
10
+ *
11
+ * This exists because `"@acme/utils": "*"` against a workspace member is the
12
+ * workspace-link idiom, not a floating install: it resolves to the package in
13
+ * this repository. Faulting it would fail every correctly configured monorepo.
14
+ * Glob support is deliberately shallow (a single trailing `*`), and an
15
+ * unresolvable glob simply contributes no names — absence never manufactures a
16
+ * violation.
17
+ * @param root - Repository root
18
+ * @param manifest - Parsed root `package.json`
19
+ * @returns Whether workspaces are declared, and the member names resolved
20
+ */
21
+ export declare function resolveWorkspaceMembers(root: string, manifest: Record<string, unknown>): Promise<WorkspaceMembers>;
22
+ //# sourceMappingURL=doctor-readiness-workspaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor-readiness-workspaces.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-workspaces.ts"],"names":[],"mappings":"AAwBA,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACrC;AA6BD;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC,gBAAgB,CAAC,CAwB3B"}