@codyswann/lisa 2.310.1 → 2.310.2
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-supply-chain-constants.d.ts +12 -0
- package/dist/cli/doctor-readiness-supply-chain-constants.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-constants.js +12 -0
- package/dist/cli/doctor-readiness-supply-chain-constants.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-python-assess.d.ts +8 -0
- package/dist/cli/doctor-readiness-supply-chain-python-assess.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-python-assess.js +137 -0
- package/dist/cli/doctor-readiness-supply-chain-python-assess.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-python.d.ts +38 -0
- package/dist/cli/doctor-readiness-supply-chain-python.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-python.js +210 -0
- package/dist/cli/doctor-readiness-supply-chain-python.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-ruby-assess.d.ts +8 -0
- package/dist/cli/doctor-readiness-supply-chain-ruby-assess.d.ts.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain-ruby-assess.js +128 -0
- package/dist/cli/doctor-readiness-supply-chain-ruby-assess.js.map +1 -0
- package/dist/cli/doctor-readiness-supply-chain.d.ts +1 -2
- package/dist/cli/doctor-readiness-supply-chain.d.ts.map +1 -1
- package/dist/cli/doctor-readiness-supply-chain.js +8 -94
- package/dist/cli/doctor-readiness-supply-chain.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +5 -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,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared identifiers and limits for the dependencies/supply-chain readiness
|
|
3
|
+
* producer.
|
|
4
|
+
* @module cli/doctor-readiness-supply-chain-constants
|
|
5
|
+
*/
|
|
6
|
+
/** The dependencies/supply-chain readiness dimension id (readiness-rubric). */
|
|
7
|
+
export declare const DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID = "dependencies-supply-chain";
|
|
8
|
+
/** The ship blocker for an owned surface with no confidence model. */
|
|
9
|
+
export declare const SUPPLY_CHAIN_BLOCKER_ID = "B5";
|
|
10
|
+
/** Most evidence lines carried into a single finding, to keep it readable. */
|
|
11
|
+
export declare const MAX_EVIDENCE_LINES = 12;
|
|
12
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-constants.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,sCAAsC,8BACtB,CAAC;AAE9B,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,KAAK,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared identifiers and limits for the dependencies/supply-chain readiness
|
|
3
|
+
* producer.
|
|
4
|
+
* @module cli/doctor-readiness-supply-chain-constants
|
|
5
|
+
*/
|
|
6
|
+
/** The dependencies/supply-chain readiness dimension id (readiness-rubric). */
|
|
7
|
+
export const DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID = "dependencies-supply-chain";
|
|
8
|
+
/** The ship blocker for an owned surface with no confidence model. */
|
|
9
|
+
export const SUPPLY_CHAIN_BLOCKER_ID = "B5";
|
|
10
|
+
/** Most evidence lines carried into a single finding, to keep it readable. */
|
|
11
|
+
export const MAX_EVIDENCE_LINES = 12;
|
|
12
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-constants.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+EAA+E;AAC/E,MAAM,CAAC,MAAM,sCAAsC,GACjD,2BAA2B,CAAC;AAE9B,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAE5C,8EAA8E;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReadinessDimensionRecord } from "./doctor-readiness-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Assess Python/Poetry dependencies when no JavaScript manifest exists.
|
|
4
|
+
* @param root - Repository root to assess
|
|
5
|
+
* @returns The B5 record, or null when no Python manifest exists
|
|
6
|
+
*/
|
|
7
|
+
export declare function assessPythonDependenciesSupplyChainDimension(root: string): Promise<ReadinessDimensionRecord | null>;
|
|
8
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-python-assess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-python-assess.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-python-assess.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAgG5E;;;;GAIG;AACH,wBAAsB,4CAA4C,CAChE,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAqD1C"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python/Poetry B5 readiness record construction.
|
|
3
|
+
* @module cli/doctor-readiness-supply-chain-python-assess
|
|
4
|
+
*/
|
|
5
|
+
import { informationalFindings } from "./doctor-readiness-shared.js";
|
|
6
|
+
import { DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID, MAX_EVIDENCE_LINES, SUPPLY_CHAIN_BLOCKER_ID, } from "./doctor-readiness-supply-chain-constants.js";
|
|
7
|
+
import { findPythonAuditGate, findPythonLockfile, isFloatingPythonSpec, readPythonManifest, } from "./doctor-readiness-supply-chain-python.js";
|
|
8
|
+
const PYPROJECT_TOML = "pyproject.toml";
|
|
9
|
+
const POETRY_LOCK = "poetry.lock";
|
|
10
|
+
/**
|
|
11
|
+
* Build the rubric-shaped B5 finding from evidence lines.
|
|
12
|
+
* @param violations - Evidence lines
|
|
13
|
+
* @returns The B5 finding
|
|
14
|
+
*/
|
|
15
|
+
function supplyChainFinding(violations) {
|
|
16
|
+
const shown = violations.slice(0, MAX_EVIDENCE_LINES);
|
|
17
|
+
const overflow = violations.length - shown.length;
|
|
18
|
+
return {
|
|
19
|
+
blocker: SUPPLY_CHAIN_BLOCKER_ID,
|
|
20
|
+
invariant_violated: "belief that the owned surface still works rests on a repeatable install " +
|
|
21
|
+
"and a standing audit, not on hope",
|
|
22
|
+
evidence: shown.join(" | ") +
|
|
23
|
+
(overflow > 0
|
|
24
|
+
? ` | (+${overflow} further finding(s) of the same kind)`
|
|
25
|
+
: ""),
|
|
26
|
+
why_proof_missed: "the test suite proves things about the code in the tree it happened to " +
|
|
27
|
+
"install, so a tree that drifts — or one carrying a known advisory nobody " +
|
|
28
|
+
"checks for — still reports green",
|
|
29
|
+
root_correction: "commit a lockfile, name a version for every dependency spec, and run a " +
|
|
30
|
+
"dependency audit on every push",
|
|
31
|
+
machinery_to_remove: [
|
|
32
|
+
"manual dependency review with no standing lockfile and audit gate",
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build a stated-reason SKIP record.
|
|
38
|
+
* @param reason - Why the dimension was not assessed
|
|
39
|
+
* @returns The SKIP dimension record
|
|
40
|
+
*/
|
|
41
|
+
function skipRecord(reason) {
|
|
42
|
+
return {
|
|
43
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
44
|
+
status: "SKIP",
|
|
45
|
+
findings: [{ reason, skip: true }],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build B5 evidence lines for a Python/Poetry project.
|
|
50
|
+
* @param specs - Poetry dependency specs under assessment
|
|
51
|
+
* @param lockfile - Committed lockfile path, or null when absent
|
|
52
|
+
* @param auditGate - Audit gate path, or null when absent
|
|
53
|
+
* @returns Evidence lines for B5 violations
|
|
54
|
+
*/
|
|
55
|
+
function pythonSupplyChainViolations(specs, lockfile, auditGate) {
|
|
56
|
+
if (specs.length === 0) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return [
|
|
60
|
+
...(lockfile === null
|
|
61
|
+
? [
|
|
62
|
+
`\`${PYPROJECT_TOML}\` declares ${specs.length} Poetry dependency ` +
|
|
63
|
+
`spec(s) but no \`${POETRY_LOCK}\` is committed — two Poetry ` +
|
|
64
|
+
"installs can resolve to different package versions, so what was " +
|
|
65
|
+
"validated is not provably what gets installed",
|
|
66
|
+
]
|
|
67
|
+
: []),
|
|
68
|
+
...specs
|
|
69
|
+
.filter(spec => isFloatingPythonSpec(spec.spec))
|
|
70
|
+
.map(spec => `\`${PYPROJECT_TOML}\` Poetry dependency \`${spec.name}\` names no ` +
|
|
71
|
+
"version constraint, so Poetry may resolve whatever satisfies the " +
|
|
72
|
+
"repository today rather than a version any run intentionally chose"),
|
|
73
|
+
...(auditGate === null
|
|
74
|
+
? [
|
|
75
|
+
"no Python dependency-audit gate was found anywhere — no " +
|
|
76
|
+
"`pip-audit`/`safety check`/`safety scan`/`osv-scanner` step in " +
|
|
77
|
+
"`.github/workflows/*.yml`, none in a git hook, and no " +
|
|
78
|
+
"`dependabot.yml` pip entry or Python Renovate manager — so a " +
|
|
79
|
+
"newly disclosed advisory in this Python tree would never be " +
|
|
80
|
+
"noticed by anything",
|
|
81
|
+
]
|
|
82
|
+
: []),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Assess Python/Poetry dependencies when no JavaScript manifest exists.
|
|
87
|
+
* @param root - Repository root to assess
|
|
88
|
+
* @returns The B5 record, or null when no Python manifest exists
|
|
89
|
+
*/
|
|
90
|
+
export async function assessPythonDependenciesSupplyChainDimension(root) {
|
|
91
|
+
const python = await readPythonManifest(root);
|
|
92
|
+
if (python.kind === "absent") {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (python.kind === "unassessable") {
|
|
96
|
+
return skipRecord(python.reason);
|
|
97
|
+
}
|
|
98
|
+
if (python.specs.length === 0) {
|
|
99
|
+
return skipRecord("`pyproject.toml` was found but declares no Poetry dependencies, so " +
|
|
100
|
+
"this repository owns no Python third-party surface a confidence " +
|
|
101
|
+
"model could cover; supply-chain confidence is not established either way");
|
|
102
|
+
}
|
|
103
|
+
const lockfile = await findPythonLockfile(root);
|
|
104
|
+
const auditGate = await findPythonAuditGate(root);
|
|
105
|
+
const violations = pythonSupplyChainViolations(python.specs, lockfile, auditGate);
|
|
106
|
+
const observations = [
|
|
107
|
+
...(lockfile === null ? [] : [`Python lockfile in use: \`${lockfile}\`.`]),
|
|
108
|
+
...(auditGate === null
|
|
109
|
+
? []
|
|
110
|
+
: [`Python dependency-audit gate declared in \`${auditGate}\`.`]),
|
|
111
|
+
];
|
|
112
|
+
if (violations.length > 0) {
|
|
113
|
+
return {
|
|
114
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
115
|
+
status: "FAIL",
|
|
116
|
+
findings: [
|
|
117
|
+
supplyChainFinding(violations),
|
|
118
|
+
...informationalFindings(observations),
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
124
|
+
status: "PASS",
|
|
125
|
+
findings: [
|
|
126
|
+
{
|
|
127
|
+
evidence: `Inspected ${python.specs.length} Poetry dependency spec(s) in ` +
|
|
128
|
+
"`pyproject.toml`: each dependency names a constraint, " +
|
|
129
|
+
"`poetry.lock` is committed, and a Python dependency-audit gate is " +
|
|
130
|
+
"declared.",
|
|
131
|
+
checked: [SUPPLY_CHAIN_BLOCKER_ID],
|
|
132
|
+
},
|
|
133
|
+
...informationalFindings(observations),
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-python-assess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-python-assess.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-python-assess.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** One Poetry dependency declaration flattened from `pyproject.toml`. */
|
|
2
|
+
export interface PythonDependencySpec {
|
|
3
|
+
readonly manifestPath: "pyproject.toml";
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly spec: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** What reading a Python/Poetry manifest established. */
|
|
8
|
+
export type PythonManifestOutcome = {
|
|
9
|
+
readonly kind: "absent";
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "unassessable";
|
|
12
|
+
readonly reason: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly kind: "ok";
|
|
15
|
+
readonly manifestPath: "pyproject.toml";
|
|
16
|
+
readonly specs: readonly PythonDependencySpec[];
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Read the Poetry dependency manifest when no JavaScript manifest exists.
|
|
20
|
+
* @param root - Repository root
|
|
21
|
+
* @returns Parsed Poetry specs, or absent when this is not a Poetry project
|
|
22
|
+
*/
|
|
23
|
+
export declare function readPythonManifest(root: string): Promise<PythonManifestOutcome>;
|
|
24
|
+
/**
|
|
25
|
+
* Find the committed Python/Poetry lockfile.
|
|
26
|
+
* @param root - Repository root
|
|
27
|
+
* @returns The lockfile path, or null when none is committed
|
|
28
|
+
*/
|
|
29
|
+
export declare function findPythonLockfile(root: string): Promise<string | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Find where the repository audits its Python dependency tree.
|
|
32
|
+
* @param root - Repository root
|
|
33
|
+
* @returns The repo-relative path of the first Python audit gate found, or null
|
|
34
|
+
*/
|
|
35
|
+
export declare function findPythonAuditGate(root: string): Promise<string | null>;
|
|
36
|
+
/** Check whether a Poetry dependency spec floats. */
|
|
37
|
+
export declare function isFloatingPythonSpec(spec: string | null): boolean;
|
|
38
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-python.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-python.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-python.ts"],"names":[],"mappings":"AAsDA,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,yDAAyD;AACzD,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACjD,CAAC;AAmFN;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,qBAAqB,CAAC,CA2ChC;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE7E;AAyBD;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BxB;AAED,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEjE"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python/Poetry scanning for the dependencies/supply-chain readiness producer
|
|
3
|
+
* (B5, PRD #1739, #1896).
|
|
4
|
+
* @module cli/doctor-readiness-supply-chain-python
|
|
5
|
+
*/
|
|
6
|
+
/* eslint-disable jsdoc/require-param, jsdoc/require-returns -- typed scanner helpers are self-describing */
|
|
7
|
+
import { readdir } from "node:fs/promises";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { parse as parseToml } from "smol-toml";
|
|
10
|
+
import { isRecord, readFileOrNull } from "./doctor-readiness-shared.js";
|
|
11
|
+
/** The Poetry project manifest this scanner reads. */
|
|
12
|
+
const PYPROJECT_TOML = "pyproject.toml";
|
|
13
|
+
/** The Poetry lockfile this scanner requires. */
|
|
14
|
+
const POETRY_LOCK = "poetry.lock";
|
|
15
|
+
/** Dependabot ecosystem spelling for Python dependency updates. */
|
|
16
|
+
const PYTHON_ECOSYSTEM_PATTERN = /package-ecosystem:\s*["']?pip\b/i;
|
|
17
|
+
/** Commands and scanners that audit Python dependencies. */
|
|
18
|
+
const PYTHON_AUDIT_GATE_PATTERN = /\b(pip-audit|safety\s+(?:check|scan)|osv-scanner|snyk|trivy|grype)\b/i;
|
|
19
|
+
/** Renovate manager spellings for Python dependencies. */
|
|
20
|
+
const RENOVATE_PYTHON_PATTERN = /\b(poetry|pep621|pip_requirements|pip-compile|pipenv)\b/i;
|
|
21
|
+
/** Poetry spec strings that resolve to whatever is newest. */
|
|
22
|
+
const FLOATING_SPECS = new Set(["", "*", "latest"]);
|
|
23
|
+
/** Files that may declare an audit gate in their text. */
|
|
24
|
+
const GATE_DIRECTORIES = [
|
|
25
|
+
path.join(".github", "workflows"),
|
|
26
|
+
".husky",
|
|
27
|
+
];
|
|
28
|
+
/** Single-file gate declarations checked by text match. */
|
|
29
|
+
const GATE_FILES = [
|
|
30
|
+
"lefthook.yml",
|
|
31
|
+
"lefthook.yaml",
|
|
32
|
+
".lefthook.yml",
|
|
33
|
+
];
|
|
34
|
+
/** Update bots whose mere presence is a standing confidence model. */
|
|
35
|
+
const UPDATE_BOT_FILES = [
|
|
36
|
+
path.join(".github", "dependabot.yml"),
|
|
37
|
+
path.join(".github", "dependabot.yaml"),
|
|
38
|
+
path.join(".github", "renovate.json"),
|
|
39
|
+
"renovate.json",
|
|
40
|
+
".renovaterc",
|
|
41
|
+
".renovaterc.json",
|
|
42
|
+
];
|
|
43
|
+
/** Check whether a repo-relative file can be read. */
|
|
44
|
+
async function fileExists(root, relativePath) {
|
|
45
|
+
return (await readFileOrNull(root, relativePath)) !== null;
|
|
46
|
+
}
|
|
47
|
+
/** List direct files under a repo-relative directory. */
|
|
48
|
+
async function listDirectory(root, relativeDir) {
|
|
49
|
+
try {
|
|
50
|
+
const entries = await readdir(path.join(root, relativeDir), {
|
|
51
|
+
withFileTypes: true,
|
|
52
|
+
});
|
|
53
|
+
return entries
|
|
54
|
+
.filter(entry => entry.isFile())
|
|
55
|
+
.map(entry => path.join(relativeDir, entry.name))
|
|
56
|
+
.sort((a, b) => a.localeCompare(b));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Read a nested record by path. */
|
|
63
|
+
function nestedRecord(value, keys) {
|
|
64
|
+
if (keys.length === 0) {
|
|
65
|
+
return isRecord(value) ? value : null;
|
|
66
|
+
}
|
|
67
|
+
if (!isRecord(value)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const [key, ...rest] = keys;
|
|
71
|
+
return key === undefined ? null : nestedRecord(value[key], rest);
|
|
72
|
+
}
|
|
73
|
+
/** Extract the version-bearing part of a Poetry dependency declaration. */
|
|
74
|
+
function poetrySpec(value) {
|
|
75
|
+
if (typeof value === "string") {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
if (!isRecord(value)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
if (typeof value.version === "string") {
|
|
82
|
+
return value.version;
|
|
83
|
+
}
|
|
84
|
+
if (typeof value.path === "string" ||
|
|
85
|
+
typeof value.file === "string" ||
|
|
86
|
+
typeof value.url === "string") {
|
|
87
|
+
return "local";
|
|
88
|
+
}
|
|
89
|
+
if (typeof value.git === "string") {
|
|
90
|
+
return typeof value.rev === "string" || typeof value.tag === "string"
|
|
91
|
+
? "git-ref"
|
|
92
|
+
: null;
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
/** Flatten one Poetry dependency table, excluding the Python runtime. */
|
|
97
|
+
function collectPoetrySpecs(table) {
|
|
98
|
+
if (table === null) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
return Object.entries(table).flatMap(([name, value]) => name.toLowerCase() === "python"
|
|
102
|
+
? []
|
|
103
|
+
: [{ manifestPath: "pyproject.toml", name, spec: poetrySpec(value) }]);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Read the Poetry dependency manifest when no JavaScript manifest exists.
|
|
107
|
+
* @param root - Repository root
|
|
108
|
+
* @returns Parsed Poetry specs, or absent when this is not a Poetry project
|
|
109
|
+
*/
|
|
110
|
+
export async function readPythonManifest(root) {
|
|
111
|
+
const source = await readFileOrNull(root, PYPROJECT_TOML);
|
|
112
|
+
if (source === null) {
|
|
113
|
+
return { kind: "absent" };
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const parsed = parseToml(source);
|
|
117
|
+
const dependencies = nestedRecord(parsed, [
|
|
118
|
+
"tool",
|
|
119
|
+
"poetry",
|
|
120
|
+
"dependencies",
|
|
121
|
+
]);
|
|
122
|
+
const group = nestedRecord(parsed, ["tool", "poetry", "group"]);
|
|
123
|
+
if (dependencies === null && group === null) {
|
|
124
|
+
return {
|
|
125
|
+
kind: "unassessable",
|
|
126
|
+
reason: "`pyproject.toml` was found, but no Poetry dependency tables were " +
|
|
127
|
+
"found; Python supply-chain confidence is not established because " +
|
|
128
|
+
"this offline pass only assesses Poetry projects today",
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const groupSpecs = group === null
|
|
132
|
+
? []
|
|
133
|
+
: Object.values(group).flatMap(entry => collectPoetrySpecs(nestedRecord(entry, ["dependencies"])));
|
|
134
|
+
return {
|
|
135
|
+
kind: "ok",
|
|
136
|
+
manifestPath: PYPROJECT_TOML,
|
|
137
|
+
specs: [...collectPoetrySpecs(dependencies), ...groupSpecs],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return {
|
|
142
|
+
kind: "unassessable",
|
|
143
|
+
reason: "`pyproject.toml` could not be parsed, so Python dependency specs " +
|
|
144
|
+
`were never read and nothing about them is established: ${error instanceof Error ? error.message : String(error)}`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Find the committed Python/Poetry lockfile.
|
|
150
|
+
* @param root - Repository root
|
|
151
|
+
* @returns The lockfile path, or null when none is committed
|
|
152
|
+
*/
|
|
153
|
+
export async function findPythonLockfile(root) {
|
|
154
|
+
return (await fileExists(root, POETRY_LOCK)) ? POETRY_LOCK : null;
|
|
155
|
+
}
|
|
156
|
+
/** Check whether an update-bot config watches Python dependencies. */
|
|
157
|
+
function coversPythonTree(botFile, source) {
|
|
158
|
+
return botFile.includes("dependabot")
|
|
159
|
+
? PYTHON_ECOSYSTEM_PATTERN.test(source)
|
|
160
|
+
: RENOVATE_PYTHON_PATTERN.test(source);
|
|
161
|
+
}
|
|
162
|
+
/** Extract an executable command-shaped line from CI/hook text. */
|
|
163
|
+
function executableCommandCandidate(line) {
|
|
164
|
+
const trimmed = line.trim();
|
|
165
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const commandish = trimmed.startsWith("- ")
|
|
169
|
+
? trimmed.slice(2).trim()
|
|
170
|
+
: trimmed;
|
|
171
|
+
if (!commandish.toLowerCase().startsWith("run:")) {
|
|
172
|
+
return commandish;
|
|
173
|
+
}
|
|
174
|
+
const command = commandish.slice("run:".length).trim();
|
|
175
|
+
return command === "|" || command === ">" ? null : command;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find where the repository audits its Python dependency tree.
|
|
179
|
+
* @param root - Repository root
|
|
180
|
+
* @returns The repo-relative path of the first Python audit gate found, or null
|
|
181
|
+
*/
|
|
182
|
+
export async function findPythonAuditGate(root) {
|
|
183
|
+
for (const botFile of UPDATE_BOT_FILES) {
|
|
184
|
+
const source = await readFileOrNull(root, botFile);
|
|
185
|
+
if (source !== null && coversPythonTree(botFile, source)) {
|
|
186
|
+
return botFile.split(path.sep).join("/");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const scanned = [
|
|
190
|
+
...(await Promise.all(GATE_DIRECTORIES.map(dir => listDirectory(root, dir)))).flat(),
|
|
191
|
+
...GATE_FILES,
|
|
192
|
+
];
|
|
193
|
+
for (const file of scanned) {
|
|
194
|
+
const source = await readFileOrNull(root, file);
|
|
195
|
+
if (source !== null &&
|
|
196
|
+
source.split(/\r?\n/).some(line => {
|
|
197
|
+
const command = executableCommandCandidate(line);
|
|
198
|
+
return command !== null && PYTHON_AUDIT_GATE_PATTERN.test(command);
|
|
199
|
+
})) {
|
|
200
|
+
return file.split(path.sep).join("/");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
/** Check whether a Poetry dependency spec floats. */
|
|
206
|
+
export function isFloatingPythonSpec(spec) {
|
|
207
|
+
return spec === null || FLOATING_SPECS.has(spec.trim().toLowerCase());
|
|
208
|
+
}
|
|
209
|
+
/* eslint-enable jsdoc/require-param, jsdoc/require-returns -- restore repository documentation defaults */
|
|
210
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-python.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-python.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ReadinessDimensionRecord } from "./doctor-readiness-types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Assess Ruby/Bundler dependencies when no JavaScript manifest exists.
|
|
4
|
+
* @param root - Repository root to assess
|
|
5
|
+
* @returns The B5 record, or null when no Ruby manifest exists
|
|
6
|
+
*/
|
|
7
|
+
export declare function assessRubyDependenciesSupplyChainDimension(root: string): Promise<ReadinessDimensionRecord | null>;
|
|
8
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-ruby-assess.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-ruby-assess.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-ruby-assess.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAsF5E;;;;GAIG;AACH,wBAAsB,0CAA0C,CAC9D,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAgD1C"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ruby/Bundler B5 readiness record construction.
|
|
3
|
+
* @module cli/doctor-readiness-supply-chain-ruby-assess
|
|
4
|
+
*/
|
|
5
|
+
import { informationalFindings } from "./doctor-readiness-shared.js";
|
|
6
|
+
import { DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID, SUPPLY_CHAIN_BLOCKER_ID, } from "./doctor-readiness-supply-chain-constants.js";
|
|
7
|
+
import { findRubyAuditGate, findRubyLockfile, readRubyManifest, } from "./doctor-readiness-supply-chain-ruby.js";
|
|
8
|
+
/**
|
|
9
|
+
* Build the rubric-shaped B5 finding from evidence lines.
|
|
10
|
+
* @param violations - Evidence lines
|
|
11
|
+
* @returns The B5 finding
|
|
12
|
+
*/
|
|
13
|
+
function supplyChainFinding(violations) {
|
|
14
|
+
return {
|
|
15
|
+
blocker: SUPPLY_CHAIN_BLOCKER_ID,
|
|
16
|
+
invariant_violated: "belief that the owned surface still works rests on a repeatable install " +
|
|
17
|
+
"and a standing audit, not on hope",
|
|
18
|
+
evidence: violations.join(" | "),
|
|
19
|
+
why_proof_missed: "the test suite proves things about the code in the tree it happened to " +
|
|
20
|
+
"install, so a tree that drifts — or one carrying a known advisory nobody " +
|
|
21
|
+
"checks for — still reports green",
|
|
22
|
+
root_correction: "commit a lockfile, name a version for every dependency spec, and run a " +
|
|
23
|
+
"dependency audit on every push",
|
|
24
|
+
machinery_to_remove: [
|
|
25
|
+
"manual dependency review with no standing lockfile and audit gate",
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Build a stated-reason SKIP record.
|
|
31
|
+
* @param reason - Why the dimension was not assessed
|
|
32
|
+
* @returns The SKIP dimension record
|
|
33
|
+
*/
|
|
34
|
+
function skipRecord(reason) {
|
|
35
|
+
return {
|
|
36
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
37
|
+
status: "SKIP",
|
|
38
|
+
findings: [{ reason, skip: true }],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build B5 evidence lines for a Ruby/Bundler project.
|
|
43
|
+
* @param specs - Ruby dependency specs under assessment
|
|
44
|
+
* @param lockfile - Committed lockfile path, or null when absent
|
|
45
|
+
* @param auditGate - Audit gate path, or null when absent
|
|
46
|
+
* @returns Evidence lines for B5 violations
|
|
47
|
+
*/
|
|
48
|
+
function rubySupplyChainViolations(specs, lockfile, auditGate) {
|
|
49
|
+
if (specs.length === 0) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
return [
|
|
53
|
+
...(lockfile === null
|
|
54
|
+
? [
|
|
55
|
+
`\`Gemfile\` declares ${specs.length} gem dependency spec(s) but ` +
|
|
56
|
+
"no `Gemfile.lock` is committed — two Bundler installs can " +
|
|
57
|
+
"resolve to different gem versions, so what was validated is not " +
|
|
58
|
+
"provably what gets installed",
|
|
59
|
+
]
|
|
60
|
+
: []),
|
|
61
|
+
...specs
|
|
62
|
+
.filter(spec => spec.spec === null)
|
|
63
|
+
.map(spec => `\`Gemfile\` gem \`${spec.name}\` names no version constraint, so ` +
|
|
64
|
+
"Bundler may resolve whatever satisfies the repository today rather " +
|
|
65
|
+
"than a version any run intentionally chose"),
|
|
66
|
+
...(auditGate === null
|
|
67
|
+
? [
|
|
68
|
+
"no Ruby dependency-audit gate was found anywhere — no `bundle " +
|
|
69
|
+
"audit`/`bundler-audit` step in `.github/workflows/*.yml`, none " +
|
|
70
|
+
"in a git hook, and no `dependabot.yml` bundler entry or " +
|
|
71
|
+
"`renovate.json` — so a newly disclosed advisory in this gem tree " +
|
|
72
|
+
"would never be noticed by anything",
|
|
73
|
+
]
|
|
74
|
+
: []),
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Assess Ruby/Bundler dependencies when no JavaScript manifest exists.
|
|
79
|
+
* @param root - Repository root to assess
|
|
80
|
+
* @returns The B5 record, or null when no Ruby manifest exists
|
|
81
|
+
*/
|
|
82
|
+
export async function assessRubyDependenciesSupplyChainDimension(root) {
|
|
83
|
+
const ruby = await readRubyManifest(root);
|
|
84
|
+
if (ruby.kind === "absent") {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (ruby.kind === "unassessable") {
|
|
88
|
+
return skipRecord(ruby.reason);
|
|
89
|
+
}
|
|
90
|
+
if (ruby.specs.length === 0) {
|
|
91
|
+
return skipRecord("`Gemfile` was found but declares no gem dependencies, so this " +
|
|
92
|
+
"repository owns no Ruby third-party surface a confidence model could " +
|
|
93
|
+
"cover; supply-chain confidence is not established either way");
|
|
94
|
+
}
|
|
95
|
+
const lockfile = await findRubyLockfile(root);
|
|
96
|
+
const auditGate = await findRubyAuditGate(root);
|
|
97
|
+
const violations = rubySupplyChainViolations(ruby.specs, lockfile, auditGate);
|
|
98
|
+
const observations = [
|
|
99
|
+
...(lockfile === null ? [] : [`Ruby lockfile in use: \`${lockfile}\`.`]),
|
|
100
|
+
...(auditGate === null
|
|
101
|
+
? []
|
|
102
|
+
: [`Ruby dependency-audit gate declared in \`${auditGate}\`.`]),
|
|
103
|
+
];
|
|
104
|
+
if (violations.length > 0) {
|
|
105
|
+
return {
|
|
106
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
107
|
+
status: "FAIL",
|
|
108
|
+
findings: [
|
|
109
|
+
supplyChainFinding(violations),
|
|
110
|
+
...informationalFindings(observations),
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
id: DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID,
|
|
116
|
+
status: "PASS",
|
|
117
|
+
findings: [
|
|
118
|
+
{
|
|
119
|
+
evidence: `Inspected ${ruby.specs.length} gem dependency spec(s) in ` +
|
|
120
|
+
"`Gemfile`: each gem names a constraint, `Gemfile.lock` is " +
|
|
121
|
+
"committed, and a Ruby dependency-audit gate is declared.",
|
|
122
|
+
checked: [SUPPLY_CHAIN_BLOCKER_ID],
|
|
123
|
+
},
|
|
124
|
+
...informationalFindings(observations),
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=doctor-readiness-supply-chain-ruby-assess.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain-ruby-assess.js","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain-ruby-assess.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ReadinessDimensionRecord } from "./doctor-readiness-types.js";
|
|
2
|
-
|
|
3
|
-
export declare const DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID = "dependencies-supply-chain";
|
|
2
|
+
export { DEPENDENCIES_SUPPLY_CHAIN_DIMENSION_ID } from "./doctor-readiness-supply-chain-constants.js";
|
|
4
3
|
/**
|
|
5
4
|
* Assess the dependencies/supply-chain dimension: B5, "an owned compatibility or
|
|
6
5
|
* security surface has no confidence model". Offline by construction — it reads
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor-readiness-supply-chain.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor-readiness-supply-chain.d.ts","sourceRoot":"","sources":["../../src/cli/doctor-readiness-supply-chain.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAE5E,OAAO,EAAE,sCAAsC,EAAE,MAAM,8CAA8C,CAAC;AAwJtG;;;;;;;;GAQG;AACH,wBAAsB,sCAAsC,CAC1D,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,wBAAwB,CAAC,CAqEnC"}
|