@codyswann/lisa 2.279.2 → 2.281.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.
- package/dist/cli/doctor-readiness-audit-allowlist.d.ts +7 -0
- package/dist/cli/doctor-readiness-audit-allowlist.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-audit-allowlist.js +177 -0
- package/dist/cli/doctor-readiness-audit-allowlist.js.map +1 -0
- package/dist/cli/doctor-readiness-capabilities.d.ts +33 -0
- package/dist/cli/doctor-readiness-capabilities.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-capabilities.js +26 -0
- package/dist/cli/doctor-readiness-capabilities.js.map +1 -0
- package/dist/cli/doctor-readiness-context-claims.d.ts +14 -0
- package/dist/cli/doctor-readiness-context-claims.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-context-claims.js +117 -0
- package/dist/cli/doctor-readiness-context-claims.js.map +1 -0
- package/dist/cli/doctor-readiness-context-mechanisms.d.ts +46 -0
- package/dist/cli/doctor-readiness-context-mechanisms.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-context-mechanisms.js +116 -0
- package/dist/cli/doctor-readiness-context-mechanisms.js.map +1 -0
- package/dist/cli/doctor-readiness-context.d.ts +16 -0
- package/dist/cli/doctor-readiness-context.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-context.js +244 -0
- package/dist/cli/doctor-readiness-context.js.map +1 -0
- package/dist/cli/doctor-readiness-delivery.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-delivery.js +1 -10
- package/dist/cli/doctor-readiness-delivery.js.map +1 -1
- package/dist/cli/doctor-readiness-domain.d.ts +17 -0
- package/dist/cli/doctor-readiness-domain.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-domain.js +197 -0
- package/dist/cli/doctor-readiness-domain.js.map +1 -0
- package/dist/cli/doctor-readiness-guardrails.d.ts +15 -0
- package/dist/cli/doctor-readiness-guardrails.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-guardrails.js +219 -0
- package/dist/cli/doctor-readiness-guardrails.js.map +1 -0
- package/dist/cli/doctor-readiness-operations.d.ts +103 -0
- package/dist/cli/doctor-readiness-operations.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-operations.js +207 -0
- package/dist/cli/doctor-readiness-operations.js.map +1 -0
- package/dist/cli/doctor-readiness-shared.d.ts +47 -0
- package/dist/cli/doctor-readiness-shared.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-shared.js +88 -0
- package/dist/cli/doctor-readiness-shared.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-scan.d.ts +67 -0
- package/dist/cli/doctor-readiness-supply-chain-scan.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-scan.js +316 -0
- package/dist/cli/doctor-readiness-supply-chain-scan.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain.d.ts +14 -0
- package/dist/cli/doctor-readiness-supply-chain.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain.js +231 -0
- package/dist/cli/doctor-readiness-supply-chain.js.map +1 -0
- package/dist/cli/doctor-readiness-workflows.d.ts +20 -0
- package/dist/cli/doctor-readiness-workflows.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-workflows.js +29 -7
- package/dist/cli/doctor-readiness-workflows.js.map +1 -1
- package/dist/cli/doctor-readiness-workspaces.d.ts +22 -0
- package/dist/cli/doctor-readiness-workspaces.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-workspaces.js +98 -0
- package/dist/cli/doctor-readiness-workspaces.js.map +1 -0
- package/dist/cli/doctor-readiness.d.ts.map +1 -1
- package/dist/cli/doctor-readiness.js +23 -13
- package/dist/cli/doctor-readiness.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +23 -0
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers shared by every readiness producer (PRD #1739, #1896).
|
|
3
|
+
*
|
|
4
|
+
* Three things were being re-implemented per producer: reading a repository file
|
|
5
|
+
* without letting a missing file throw, asking whether a repository path exists,
|
|
6
|
+
* and wrapping a non-blocking observation as a finding. The last one is the
|
|
7
|
+
* load-bearing case — an observation finding must carry NO `blocker` key,
|
|
8
|
+
* because the blocker engine stands a blocker up on any finding that names an id
|
|
9
|
+
* and carries evidence regardless of the finding's status. One definition means
|
|
10
|
+
* that rule cannot drift apart across producers.
|
|
11
|
+
* @module cli/doctor-readiness-shared
|
|
12
|
+
*/
|
|
13
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
14
|
+
import * as path from "node:path";
|
|
15
|
+
/**
|
|
16
|
+
* Read a repository-relative file, returning null when it cannot be read.
|
|
17
|
+
*
|
|
18
|
+
* Reading is best-effort by design: a file that cannot be read establishes
|
|
19
|
+
* nothing, and a readiness producer must never turn "could not look" into
|
|
20
|
+
* either a violation or a clean bill of health.
|
|
21
|
+
* @param root - Repository root
|
|
22
|
+
* @param relativePath - Repo-relative path (forward slashes)
|
|
23
|
+
* @returns File contents, or null
|
|
24
|
+
*/
|
|
25
|
+
export async function readFileOrNull(root, relativePath) {
|
|
26
|
+
try {
|
|
27
|
+
return await readFile(path.join(root, ...relativePath.split("/")), "utf8");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether a repository-relative directory exists.
|
|
35
|
+
* @param root - Repository root
|
|
36
|
+
* @param relativePath - Repo-relative directory path
|
|
37
|
+
* @returns True when the directory could be listed
|
|
38
|
+
*/
|
|
39
|
+
export async function directoryExists(root, relativePath) {
|
|
40
|
+
try {
|
|
41
|
+
await readdir(path.join(root, ...relativePath.split("/")));
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether a repository-relative path exists, as a file or a directory.
|
|
50
|
+
* @param root - Repository root
|
|
51
|
+
* @param relativePath - Repo-relative path
|
|
52
|
+
* @returns True when something is present at that path
|
|
53
|
+
*/
|
|
54
|
+
export async function pathExists(root, relativePath) {
|
|
55
|
+
return ((await readFileOrNull(root, relativePath)) !== null ||
|
|
56
|
+
(await directoryExists(root, relativePath)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Strip leading and trailing slashes from a repo-relative path fragment.
|
|
60
|
+
* Written without a regex quantifier so it cannot backtrack on hostile input.
|
|
61
|
+
* @param value - The path fragment
|
|
62
|
+
* @returns The fragment with empty segments removed
|
|
63
|
+
*/
|
|
64
|
+
export function trimSlashes(value) {
|
|
65
|
+
return value
|
|
66
|
+
.split("/")
|
|
67
|
+
.filter(segment => segment !== "")
|
|
68
|
+
.join("/");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Whether a value is a plain JSON object.
|
|
72
|
+
* @param value - Candidate value
|
|
73
|
+
* @returns True when the value is a non-null, non-array object
|
|
74
|
+
*/
|
|
75
|
+
export function isRecord(value) {
|
|
76
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Wrap non-blocking observations as findings. They deliberately carry no
|
|
80
|
+
* `blocker` key: naming one would stand a blocker up — and flip the whole
|
|
81
|
+
* repository to `NOT_READY` — on an observation that was never decidable.
|
|
82
|
+
* @param notes - Informational lines
|
|
83
|
+
* @returns Findings, one per note
|
|
84
|
+
*/
|
|
85
|
+
export function informationalFindings(notes) {
|
|
86
|
+
return notes.map(note => ({ observation: note, blocking: false }));
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=doctor-readiness-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-shared.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,YAAoB;IAEpB,IAAI,CAAC;QACH,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,YAAoB;IAEpB,OAAO,CACL,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,KAAK,IAAI;QACnD,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAC5C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,KAAK,EAAE,CAAC;SACjC,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAAwB;IAExB,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every lockfile spelling a JavaScript package manager writes. One of these
|
|
3
|
+
* being committed is what makes two installs resolve to the same tree.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LOCKFILES: readonly string[];
|
|
6
|
+
/**
|
|
7
|
+
* Whether a dependency spec resolves to whatever is newest at install time
|
|
8
|
+
* rather than to a version something was validated against.
|
|
9
|
+
*
|
|
10
|
+
* Four families are recognized, and the narrowness of each is deliberate — every
|
|
11
|
+
* over-eager rule here fails a correctly configured repository:
|
|
12
|
+
*
|
|
13
|
+
* - **Local protocols** resolve inside the repository and never float.
|
|
14
|
+
* - **Registry aliases** (`npm:left-pad@latest`) hide the real spec behind the
|
|
15
|
+
* alias, so the part after the version separator is re-tested.
|
|
16
|
+
* - **Repository clones** (`github:acme/widget`, `git+https://…/x.git`) float
|
|
17
|
+
* unless anchored to a `#<sha|tag>` revision, because the branch tip moves
|
|
18
|
+
* under the install. An archive URL (`…/widget-1.2.3.tgz`) is NOT a clone: it
|
|
19
|
+
* names one built artifact and is treated as pinned.
|
|
20
|
+
* - **Plain ranges** float only when they name no version at all. A `>=` floor
|
|
21
|
+
* in `overrides` is the recommended way to force a patched transitive
|
|
22
|
+
* dependency, so ranges are otherwise left alone.
|
|
23
|
+
* @param spec - The declared spec text
|
|
24
|
+
* @returns True when the spec floats
|
|
25
|
+
*/
|
|
26
|
+
export declare function isFloatingSpec(spec: string): boolean;
|
|
27
|
+
/** What reading the manifest established. */
|
|
28
|
+
export type ManifestOutcome = {
|
|
29
|
+
readonly kind: "ok";
|
|
30
|
+
readonly manifest: Record<string, unknown>;
|
|
31
|
+
} | {
|
|
32
|
+
readonly kind: "unassessable";
|
|
33
|
+
readonly reason: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Read and parse `package.json`, distinguishing "absent" from "unparseable" so
|
|
37
|
+
* the SKIP reason can say which one happened.
|
|
38
|
+
* @param root - Repository root
|
|
39
|
+
* @returns The parsed manifest, or the reason it cannot be assessed
|
|
40
|
+
*/
|
|
41
|
+
export declare function readManifest(root: string): Promise<ManifestOutcome>;
|
|
42
|
+
/** One declared dependency spec, flattened out of the manifest blocks. */
|
|
43
|
+
export interface DependencySpec {
|
|
44
|
+
readonly block: string;
|
|
45
|
+
readonly name: string;
|
|
46
|
+
readonly spec: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Flatten every versioned manifest block into one list of specs.
|
|
50
|
+
* @param manifest - Parsed `package.json`
|
|
51
|
+
* @returns Every declared spec across the versioned blocks
|
|
52
|
+
*/
|
|
53
|
+
export declare function collectSpecs(manifest: Record<string, unknown>): readonly DependencySpec[];
|
|
54
|
+
/**
|
|
55
|
+
* Find the committed lockfile, if any.
|
|
56
|
+
* @param root - Repository root
|
|
57
|
+
* @returns The lockfile name, or null when none is committed
|
|
58
|
+
*/
|
|
59
|
+
export declare function findLockfile(root: string): Promise<string | null>;
|
|
60
|
+
/**
|
|
61
|
+
* Find where the repository audits its dependency tree: a CI job, a git hook, a
|
|
62
|
+
* lefthook declaration, or an update bot.
|
|
63
|
+
* @param root - Repository root
|
|
64
|
+
* @returns The repo-relative path of the first gate found, or null
|
|
65
|
+
*/
|
|
66
|
+
export declare function findAuditGate(root: string): Promise<string | null>;
|
|
67
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-scan.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-scan.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,MAAM,EAOtC,CAAC;AAoFF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAepD;AAyCD,6CAA6C;AAC7C,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACnE;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAsC/D;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA2BzE;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AA4BD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,SAAS,cAAc,EAAE,CAI3B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOvE;AAkBD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxE"}
|
|
@@ -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"}
|