auditor-lambda 0.3.40 → 0.3.41
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/audit-code-wrapper-lib.mjs +20 -2
- package/dist/cli/args.d.ts +59 -0
- package/dist/cli/args.js +244 -0
- package/dist/cli/dispatch.d.ts +80 -0
- package/dist/cli/dispatch.js +528 -0
- package/dist/cli/prompts.d.ts +18 -0
- package/dist/cli/prompts.js +130 -0
- package/dist/cli/steps.d.ts +29 -0
- package/dist/cli/steps.js +30 -0
- package/dist/cli/waveManifest.d.ts +40 -0
- package/dist/cli/waveManifest.js +41 -0
- package/dist/cli/workerResult.d.ts +18 -0
- package/dist/cli/workerResult.js +42 -0
- package/dist/cli.d.ts +2 -22
- package/dist/cli.js +160 -973
- package/dist/extractors/browserExtension.d.ts +1 -3
- package/dist/extractors/browserExtension.js +2 -2
- package/dist/extractors/designAssessment.d.ts +1 -3
- package/dist/extractors/disposition.d.ts +2 -1
- package/dist/extractors/disposition.js +3 -0
- package/dist/extractors/flows.d.ts +1 -3
- package/dist/extractors/flows.js +2 -2
- package/dist/extractors/graph.d.ts +1 -2
- package/dist/extractors/graph.js +4 -326
- package/dist/extractors/graphManifestEdges.d.ts +1 -1
- package/dist/extractors/graphPathUtils.d.ts +1 -1
- package/dist/extractors/graphPythonImports.d.ts +3 -0
- package/dist/extractors/graphPythonImports.js +326 -0
- package/dist/extractors/risk.d.ts +1 -2
- package/dist/extractors/surfaces.d.ts +1 -3
- package/dist/extractors/surfaces.js +2 -2
- package/dist/io/artifacts.d.ts +1 -5
- package/dist/io/artifacts.js +1 -1
- package/dist/io/runArtifacts.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/orchestrator/advance.d.ts +1 -0
- package/dist/orchestrator/advance.js +8 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +27 -0
- package/dist/orchestrator/fileAnchors.d.ts +1 -1
- package/dist/orchestrator/fileIntegrity.d.ts +7 -0
- package/dist/orchestrator/fileIntegrity.js +41 -0
- package/dist/orchestrator/flowCoverage.d.ts +1 -1
- package/dist/orchestrator/flowPlanning.d.ts +1 -1
- package/dist/orchestrator/flowRequeue.d.ts +1 -1
- package/dist/orchestrator/internalExecutors.d.ts +3 -1
- package/dist/orchestrator/internalExecutors.js +23 -5
- package/dist/orchestrator/nextStep.d.ts +2 -1
- package/dist/orchestrator/nextStep.js +1 -1
- package/dist/orchestrator/planning.d.ts +1 -1
- package/dist/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.js +21 -113
- package/dist/orchestrator/runtimeValidation.d.ts +1 -1
- package/dist/orchestrator/taskBuilder.d.ts +1 -1
- package/dist/orchestrator/taskBuilder.js +1 -12
- package/dist/orchestrator/unionFind.d.ts +7 -0
- package/dist/orchestrator/unionFind.js +32 -0
- package/dist/orchestrator/unitBuilder.d.ts +2 -2
- package/dist/orchestrator/unitBuilder.js +4 -18
- package/dist/prompts/renderWorkerPrompt.js +18 -1
- package/dist/providers/claudeCodeProvider.d.ts +4 -4
- package/dist/providers/claudeCodeProvider.js +9 -3
- package/dist/providers/constants.d.ts +1 -1
- package/dist/providers/constants.js +1 -1
- package/dist/providers/index.d.ts +1 -2
- package/dist/providers/index.js +5 -4
- package/dist/providers/localSubprocessProvider.d.ts +2 -2
- package/dist/providers/localSubprocessProvider.js +1 -1
- package/dist/providers/opencodeProvider.d.ts +4 -4
- package/dist/providers/opencodeProvider.js +7 -2
- package/dist/providers/spawnLoggedCommand.d.ts +3 -1
- package/dist/providers/spawnLoggedCommand.js +21 -0
- package/dist/providers/subprocessTemplateProvider.d.ts +4 -4
- package/dist/providers/subprocessTemplateProvider.js +8 -3
- package/dist/providers/vscodeTaskProvider.d.ts +3 -4
- package/dist/providers/vscodeTaskProvider.js +2 -2
- package/dist/quota/discoveredLimits.js +1 -1
- package/dist/quota/hostLimits.d.ts +1 -2
- package/dist/quota/hostLimits.js +4 -46
- package/dist/quota/index.d.ts +18 -15
- package/dist/quota/index.js +4 -9
- package/dist/quota/scheduler.d.ts +1 -3
- package/dist/quota/scheduler.js +1 -2
- package/dist/reporting/synthesis.d.ts +1 -2
- package/dist/reporting/synthesis.js +2 -0
- package/dist/reporting/workBlocks.d.ts +1 -2
- package/dist/supervisor/operatorHandoff.js +1 -1
- package/dist/supervisor/runLedger.d.ts +1 -1
- package/dist/supervisor/runLedger.js +2 -2
- package/dist/supervisor/sessionConfig.d.ts +1 -1
- package/dist/supervisor/sessionConfig.js +1 -3
- package/dist/types/reviewPlanning.d.ts +1 -1
- package/dist/types/workerSession.d.ts +6 -0
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +1 -1
- package/dist/validation/auditResults.d.ts +1 -1
- package/dist/validation/auditResults.js +1 -1
- package/dist/validation/sessionConfig.d.ts +2 -3
- package/dist/validation/sessionConfig.js +2 -3
- package/package.json +4 -2
- package/scripts/postinstall.mjs +0 -1
- package/dist/io/json.d.ts +0 -10
- package/dist/io/json.js +0 -142
- package/dist/providers/types.d.ts +0 -33
- package/dist/providers/types.js +0 -1
- package/dist/quota/compositeQuotaSource.d.ts +0 -7
- package/dist/quota/compositeQuotaSource.js +0 -20
- package/dist/quota/errorParsers/claudeCodeErrorParser.d.ts +0 -6
- package/dist/quota/errorParsers/claudeCodeErrorParser.js +0 -39
- package/dist/quota/errorParsers/genericErrorParser.d.ts +0 -9
- package/dist/quota/errorParsers/genericErrorParser.js +0 -7
- package/dist/quota/errorParsers/index.d.ts +0 -5
- package/dist/quota/errorParsers/index.js +0 -12
- package/dist/quota/errorParsing.d.ts +0 -7
- package/dist/quota/errorParsing.js +0 -69
- package/dist/quota/fileLock.d.ts +0 -6
- package/dist/quota/fileLock.js +0 -64
- package/dist/quota/learnedQuotaSource.d.ts +0 -7
- package/dist/quota/learnedQuotaSource.js +0 -25
- package/dist/quota/limits.d.ts +0 -16
- package/dist/quota/limits.js +0 -77
- package/dist/quota/quotaSource.d.ts +0 -12
- package/dist/quota/quotaSource.js +0 -1
- package/dist/quota/slidingWindow.d.ts +0 -4
- package/dist/quota/slidingWindow.js +0 -28
- package/dist/quota/state.d.ts +0 -15
- package/dist/quota/state.js +0 -148
- package/dist/quota/types.d.ts +0 -67
- package/dist/quota/types.js +0 -1
- package/dist/reporting/rootCause.d.ts +0 -10
- package/dist/reporting/rootCause.js +0 -146
- package/dist/types/disposition.d.ts +0 -9
- package/dist/types/disposition.js +0 -1
- package/dist/types/flows.d.ts +0 -17
- package/dist/types/flows.js +0 -1
- package/dist/types/graph.d.ts +0 -22
- package/dist/types/graph.js +0 -1
- package/dist/types/risk.d.ts +0 -9
- package/dist/types/risk.js +0 -1
- package/dist/types/runLedger.d.ts +0 -17
- package/dist/types/runLedger.js +0 -6
- package/dist/types/sessionConfig.d.ts +0 -79
- package/dist/types/sessionConfig.js +0 -15
- package/dist/types/surfaces.d.ts +0 -15
- package/dist/types/surfaces.js +0 -1
- package/dist/validation/basic.d.ts +0 -13
- package/dist/validation/basic.js +0 -46
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { graphEdge, normalizeGraphPath, resolveCandidate, } from "./graphPathUtils.js";
|
|
3
|
+
const PYTHON_SOURCE_EXTENSIONS = [".py", ".pyi"];
|
|
4
|
+
const PYTHON_PACKAGE_INDEX_FILES = ["__init__.py", "__init__.pyi"];
|
|
5
|
+
const IMPORT_EDGE_CONFIDENCE = 0.95;
|
|
6
|
+
export function isPythonSourcePath(path) {
|
|
7
|
+
const normalized = normalizeGraphPath(path).toLowerCase();
|
|
8
|
+
return PYTHON_SOURCE_EXTENSIONS.some((extension) => normalized.endsWith(extension));
|
|
9
|
+
}
|
|
10
|
+
function stripPythonLineComment(line) {
|
|
11
|
+
let quote;
|
|
12
|
+
let escaped = false;
|
|
13
|
+
for (let index = 0; index < line.length; index++) {
|
|
14
|
+
const char = line[index];
|
|
15
|
+
if (escaped) {
|
|
16
|
+
escaped = false;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (quote) {
|
|
20
|
+
if (char === "\\") {
|
|
21
|
+
escaped = true;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (char === quote) {
|
|
25
|
+
quote = undefined;
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (char === "'" || char === '"') {
|
|
30
|
+
quote = char;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (char === "#") {
|
|
34
|
+
return line.slice(0, index);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return line;
|
|
38
|
+
}
|
|
39
|
+
function pythonParenDelta(line) {
|
|
40
|
+
let quote;
|
|
41
|
+
let escaped = false;
|
|
42
|
+
let delta = 0;
|
|
43
|
+
for (const char of line) {
|
|
44
|
+
if (escaped) {
|
|
45
|
+
escaped = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (quote) {
|
|
49
|
+
if (char === "\\") {
|
|
50
|
+
escaped = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (char === quote) {
|
|
54
|
+
quote = undefined;
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (char === "'" || char === '"') {
|
|
59
|
+
quote = char;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (char === "(") {
|
|
63
|
+
delta += 1;
|
|
64
|
+
}
|
|
65
|
+
else if (char === ")") {
|
|
66
|
+
delta -= 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return delta;
|
|
70
|
+
}
|
|
71
|
+
function pythonLogicalLines(content) {
|
|
72
|
+
const logicalLines = [];
|
|
73
|
+
let pending = "";
|
|
74
|
+
let parenDepth = 0;
|
|
75
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
76
|
+
const stripped = stripPythonLineComment(rawLine).trim();
|
|
77
|
+
if (stripped.length === 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (pending.length === 0 && !/^(?:import|from)\s+/i.test(stripped)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const continued = stripped.endsWith("\\");
|
|
84
|
+
const line = continued ? stripped.slice(0, -1).trimEnd() : stripped;
|
|
85
|
+
pending = pending.length > 0 ? `${pending} ${line}` : line;
|
|
86
|
+
parenDepth += pythonParenDelta(line);
|
|
87
|
+
if (!continued && parenDepth <= 0) {
|
|
88
|
+
logicalLines.push(pending.replace(/\s+/g, " ").trim());
|
|
89
|
+
pending = "";
|
|
90
|
+
parenDepth = 0;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (pending.length > 0) {
|
|
94
|
+
logicalLines.push(pending.replace(/\s+/g, " ").trim());
|
|
95
|
+
}
|
|
96
|
+
return logicalLines;
|
|
97
|
+
}
|
|
98
|
+
function unwrapPythonImportList(value) {
|
|
99
|
+
let trimmed = value.trim();
|
|
100
|
+
if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
|
|
101
|
+
trimmed = trimmed.slice(1, -1).trim();
|
|
102
|
+
}
|
|
103
|
+
return trimmed;
|
|
104
|
+
}
|
|
105
|
+
function splitPythonImportList(value) {
|
|
106
|
+
const items = [];
|
|
107
|
+
let current = "";
|
|
108
|
+
let quote;
|
|
109
|
+
let escaped = false;
|
|
110
|
+
let parenDepth = 0;
|
|
111
|
+
for (const char of unwrapPythonImportList(value)) {
|
|
112
|
+
if (escaped) {
|
|
113
|
+
current += char;
|
|
114
|
+
escaped = false;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (quote) {
|
|
118
|
+
current += char;
|
|
119
|
+
if (char === "\\") {
|
|
120
|
+
escaped = true;
|
|
121
|
+
}
|
|
122
|
+
else if (char === quote) {
|
|
123
|
+
quote = undefined;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (char === "'" || char === '"') {
|
|
128
|
+
current += char;
|
|
129
|
+
quote = char;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (char === "(") {
|
|
133
|
+
parenDepth += 1;
|
|
134
|
+
current += char;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (char === ")") {
|
|
138
|
+
parenDepth -= 1;
|
|
139
|
+
current += char;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (char === "," && parenDepth === 0) {
|
|
143
|
+
const item = current.trim();
|
|
144
|
+
if (item.length > 0) {
|
|
145
|
+
items.push(item);
|
|
146
|
+
}
|
|
147
|
+
current = "";
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
current += char;
|
|
151
|
+
}
|
|
152
|
+
const item = current.trim();
|
|
153
|
+
if (item.length > 0) {
|
|
154
|
+
items.push(item);
|
|
155
|
+
}
|
|
156
|
+
return items;
|
|
157
|
+
}
|
|
158
|
+
function stripPythonAlias(value) {
|
|
159
|
+
return value.replace(/\s+as\s+[A-Za-z_]\w*$/i, "").trim();
|
|
160
|
+
}
|
|
161
|
+
function isPythonIdentifier(value) {
|
|
162
|
+
return /^[A-Za-z_]\w*$/.test(value);
|
|
163
|
+
}
|
|
164
|
+
function isPythonAbsoluteModuleSpecifier(value) {
|
|
165
|
+
return /^[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*$/.test(value);
|
|
166
|
+
}
|
|
167
|
+
function isPythonRelativeModuleSpecifier(value) {
|
|
168
|
+
return /^\.+(?:[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)?$/.test(value);
|
|
169
|
+
}
|
|
170
|
+
function isPythonModuleSpecifier(value) {
|
|
171
|
+
return (isPythonAbsoluteModuleSpecifier(value) ||
|
|
172
|
+
isPythonRelativeModuleSpecifier(value));
|
|
173
|
+
}
|
|
174
|
+
function pythonModulePath(specifier) {
|
|
175
|
+
return specifier.split(".").filter(Boolean).join("/");
|
|
176
|
+
}
|
|
177
|
+
function resolvePythonPathCandidate(candidate, pathLookup) {
|
|
178
|
+
const normalized = normalizeGraphPath(candidate).replace(/\/+$/, "");
|
|
179
|
+
if (normalized.length === 0 || normalized === "." || normalized === "..") {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
return resolveCandidate(normalized, pathLookup);
|
|
183
|
+
}
|
|
184
|
+
function pythonPathMatchesModule(path, modulePath) {
|
|
185
|
+
const normalizedPath = normalizeGraphPath(path).toLowerCase();
|
|
186
|
+
const normalizedModulePath = normalizeGraphPath(modulePath).toLowerCase();
|
|
187
|
+
return (PYTHON_SOURCE_EXTENSIONS.some((extension) => {
|
|
188
|
+
const moduleFile = `${normalizedModulePath}${extension}`;
|
|
189
|
+
return (normalizedPath === moduleFile ||
|
|
190
|
+
normalizedPath.endsWith(`/${moduleFile}`));
|
|
191
|
+
}) ||
|
|
192
|
+
PYTHON_PACKAGE_INDEX_FILES.some((indexFile) => {
|
|
193
|
+
const packageFile = posix.join(normalizedModulePath, indexFile);
|
|
194
|
+
return (normalizedPath === packageFile ||
|
|
195
|
+
normalizedPath.endsWith(`/${packageFile}`));
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
function commonDirectoryPrefixLength(left, right) {
|
|
199
|
+
const leftParts = normalizeGraphPath(left).split("/").filter(Boolean);
|
|
200
|
+
const rightParts = normalizeGraphPath(right).split("/").filter(Boolean);
|
|
201
|
+
let count = 0;
|
|
202
|
+
while (count < leftParts.length &&
|
|
203
|
+
count < rightParts.length &&
|
|
204
|
+
leftParts[count].toLowerCase() === rightParts[count].toLowerCase()) {
|
|
205
|
+
count += 1;
|
|
206
|
+
}
|
|
207
|
+
return count;
|
|
208
|
+
}
|
|
209
|
+
function resolvePythonAbsoluteModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
210
|
+
const modulePath = pythonModulePath(specifier);
|
|
211
|
+
const direct = resolvePythonPathCandidate(modulePath, pathLookup);
|
|
212
|
+
if (direct) {
|
|
213
|
+
return direct;
|
|
214
|
+
}
|
|
215
|
+
const matches = [...new Set(pathLookup.values())].filter((path) => isPythonSourcePath(path) && pythonPathMatchesModule(path, modulePath));
|
|
216
|
+
if (matches.length === 1) {
|
|
217
|
+
return matches[0];
|
|
218
|
+
}
|
|
219
|
+
if (matches.length === 0) {
|
|
220
|
+
return undefined;
|
|
221
|
+
}
|
|
222
|
+
const fromDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
223
|
+
const scored = matches
|
|
224
|
+
.map((target) => ({
|
|
225
|
+
target,
|
|
226
|
+
score: commonDirectoryPrefixLength(fromDir, posix.dirname(normalizeGraphPath(target))),
|
|
227
|
+
}))
|
|
228
|
+
.sort((a, b) => b.score - a.score || a.target.localeCompare(b.target));
|
|
229
|
+
const bestScore = scored[0]?.score ?? 0;
|
|
230
|
+
const bestMatches = scored.filter((item) => item.score === bestScore);
|
|
231
|
+
if (bestScore > 0 && bestMatches.length === 1) {
|
|
232
|
+
return bestMatches[0].target;
|
|
233
|
+
}
|
|
234
|
+
const srcMatches = matches.filter((target) => normalizeGraphPath(target).toLowerCase().startsWith("src/"));
|
|
235
|
+
return srcMatches.length === 1 ? srcMatches[0] : undefined;
|
|
236
|
+
}
|
|
237
|
+
function resolvePythonRelativeModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
238
|
+
const match = /^(\.+)(.*)$/.exec(specifier);
|
|
239
|
+
if (!match) {
|
|
240
|
+
return undefined;
|
|
241
|
+
}
|
|
242
|
+
const level = match[1].length;
|
|
243
|
+
const remainder = match[2] ?? "";
|
|
244
|
+
let baseDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
245
|
+
for (let index = 1; index < level; index++) {
|
|
246
|
+
const next = posix.dirname(baseDir);
|
|
247
|
+
if (next === baseDir) {
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
baseDir = next;
|
|
251
|
+
}
|
|
252
|
+
const modulePath = pythonModulePath(remainder);
|
|
253
|
+
const candidate = modulePath.length > 0 ? posix.join(baseDir, modulePath) : baseDir;
|
|
254
|
+
return resolvePythonPathCandidate(candidate, pathLookup);
|
|
255
|
+
}
|
|
256
|
+
function resolvePythonModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
257
|
+
if (isPythonRelativeModuleSpecifier(specifier)) {
|
|
258
|
+
return resolvePythonRelativeModuleSpecifier(fromPath, specifier, pathLookup);
|
|
259
|
+
}
|
|
260
|
+
if (isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
261
|
+
return resolvePythonAbsoluteModuleSpecifier(fromPath, specifier, pathLookup);
|
|
262
|
+
}
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
function appendPythonImportedSpecifier(moduleSpecifier, importedName) {
|
|
266
|
+
return moduleSpecifier.endsWith(".")
|
|
267
|
+
? `${moduleSpecifier}${importedName}`
|
|
268
|
+
: `${moduleSpecifier}.${importedName}`;
|
|
269
|
+
}
|
|
270
|
+
function addPythonImportEdge(edges, fromPath, target, kind, specifier) {
|
|
271
|
+
if (!target || target === fromPath) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
edges.push(graphEdge({
|
|
275
|
+
from: fromPath,
|
|
276
|
+
to: target,
|
|
277
|
+
kind,
|
|
278
|
+
confidence: IMPORT_EDGE_CONFIDENCE,
|
|
279
|
+
reason: `Resolved Python import specifier '${specifier}'.`,
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
export function extractPythonImportEdges(fromPath, content, pathLookup) {
|
|
283
|
+
if (!isPythonSourcePath(fromPath)) {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
const edges = [];
|
|
287
|
+
for (const line of pythonLogicalLines(content)) {
|
|
288
|
+
const importMatch = /^import\s+(.+)$/i.exec(line);
|
|
289
|
+
if (importMatch) {
|
|
290
|
+
for (const rawSpecifier of splitPythonImportList(importMatch[1] ?? "")) {
|
|
291
|
+
const specifier = stripPythonAlias(rawSpecifier);
|
|
292
|
+
if (!isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, specifier, pathLookup), "python-import", specifier);
|
|
296
|
+
}
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const fromImportMatch = /^from\s+([.\w]+)\s+import\s+(.+)$/i.exec(line);
|
|
300
|
+
if (!fromImportMatch) {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
const moduleSpecifier = fromImportMatch[1] ?? "";
|
|
304
|
+
if (!isPythonModuleSpecifier(moduleSpecifier)) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const importedNames = splitPythonImportList(fromImportMatch[2] ?? "")
|
|
308
|
+
.map(stripPythonAlias)
|
|
309
|
+
.filter((name) => name !== "*" && isPythonIdentifier(name));
|
|
310
|
+
const submoduleTargets = importedNames
|
|
311
|
+
.map((name) => appendPythonImportedSpecifier(moduleSpecifier, name))
|
|
312
|
+
.map((specifier) => ({
|
|
313
|
+
specifier,
|
|
314
|
+
target: resolvePythonModuleSpecifier(fromPath, specifier, pathLookup),
|
|
315
|
+
}))
|
|
316
|
+
.filter((item) => item.target);
|
|
317
|
+
if (submoduleTargets.length > 0) {
|
|
318
|
+
for (const { specifier, target } of submoduleTargets) {
|
|
319
|
+
addPythonImportEdge(edges, fromPath, target, "python-from-import", specifier);
|
|
320
|
+
}
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, moduleSpecifier, pathLookup), "python-from-import", moduleSpecifier);
|
|
324
|
+
}
|
|
325
|
+
return edges;
|
|
326
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { UnitManifest } from "../types.js";
|
|
2
2
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
3
|
-
import type { CriticalFlowManifest } from "
|
|
4
|
-
import type { RiskRegister } from "../types/risk.js";
|
|
3
|
+
import type { CriticalFlowManifest, RiskRegister } from "@audit-tools/shared";
|
|
5
4
|
export declare function buildRiskRegister(unitManifest: UnitManifest, criticalFlows?: CriticalFlowManifest, externalAnalyzerResults?: ExternalAnalyzerResults): RiskRegister;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
|
-
import type { FileDisposition } from "
|
|
3
|
-
import type { GraphBundle } from "../types/graph.js";
|
|
4
|
-
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
2
|
+
import type { FileDisposition, GraphBundle, SurfaceManifest } from "@audit-tools/shared";
|
|
5
3
|
/**
|
|
6
4
|
* Detects likely execution surfaces from file paths using the shared extractor
|
|
7
5
|
* heuristics, primarily to seed later audit planning.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildBrowserExtensionSurfacesFromGraph } from "./browserExtension.js";
|
|
2
|
-
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
+
import { buildDispositionMap, isAuditExcludedStatus } from "./disposition.js";
|
|
3
3
|
import { EXTRACTOR_HEURISTIC_NOTE, isBackgroundSurfacePath, isNetworkSurfacePath, isSurfacePath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
4
4
|
function methodsForPath(path) {
|
|
5
5
|
const normalized = normalizeExtractorPath(path);
|
|
@@ -15,7 +15,7 @@ function methodsForPath(path) {
|
|
|
15
15
|
export function buildSurfaceManifest(repoManifest, disposition, options = {}) {
|
|
16
16
|
const surfaces = [];
|
|
17
17
|
const seen = new Set();
|
|
18
|
-
const dispositionMap =
|
|
18
|
+
const dispositionMap = buildDispositionMap(disposition);
|
|
19
19
|
function addSurface(surface) {
|
|
20
20
|
const key = `${surface.kind}:${surface.entrypoint}`;
|
|
21
21
|
if (seen.has(key)) {
|
package/dist/io/artifacts.d.ts
CHANGED
|
@@ -2,15 +2,11 @@ import { cp, rm } from "node:fs/promises";
|
|
|
2
2
|
import type { AuditResult, AuditTask, CoverageMatrix, RepoManifest, UnitManifest } from "../types.js";
|
|
3
3
|
import type { AuditState } from "../types/auditState.js";
|
|
4
4
|
import type { ArtifactMetadataManifest } from "../types/artifactMetadata.js";
|
|
5
|
-
import type { FileDisposition } from "
|
|
5
|
+
import type { FileDisposition, CriticalFlowManifest, GraphBundle, RiskRegister, SurfaceManifest } from "@audit-tools/shared";
|
|
6
6
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
7
7
|
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
8
|
-
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
9
|
-
import type { GraphBundle } from "../types/graph.js";
|
|
10
|
-
import type { RiskRegister } from "../types/risk.js";
|
|
11
8
|
import type { AuditPlanMetrics, ReviewPacket } from "../types/reviewPlanning.js";
|
|
12
9
|
import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
|
|
13
|
-
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
14
10
|
import type { DesignAssessment } from "../types/designAssessment.js";
|
|
15
11
|
import type { ToolingManifest } from "../types/toolingManifest.js";
|
|
16
12
|
type ArtifactPayloadMap = {
|
package/dist/io/artifacts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cp, rm, unlink } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { isFileMissingError, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeJsonFile, writeNdjsonFile, writeTextFile, } from "
|
|
3
|
+
import { isFileMissingError, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeJsonFile, writeNdjsonFile, writeTextFile, } from "@audit-tools/shared";
|
|
4
4
|
import { buildToolingManifest } from "./toolingManifest.js";
|
|
5
5
|
function jsonArtifact(fileName, phase) {
|
|
6
6
|
return {
|
package/dist/io/runArtifacts.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { writeJsonFile } from "
|
|
4
|
+
import { writeJsonFile } from "@audit-tools/shared";
|
|
5
5
|
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
6
6
|
const packageRoot = resolve(moduleDir, "..", "..");
|
|
7
7
|
const auditResultSchemaPath = join(packageRoot, "schemas", "audit_result.schema.json");
|
package/dist/mcp/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { spawn } from "node:child_process";
|
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { loadArtifactBundle } from "../io/artifacts.js";
|
|
6
|
-
import { readOptionalTextFile } from "
|
|
6
|
+
import { readOptionalTextFile } from "@audit-tools/shared";
|
|
7
7
|
import { deriveAuditState } from "../orchestrator/state.js";
|
|
8
8
|
import { decideNextStep } from "../orchestrator/nextStep.js";
|
|
9
9
|
import { buildAuditCodeHandoff, } from "../supervisor/operatorHandoff.js";
|
|
@@ -10,6 +10,7 @@ export interface AdvanceAuditOptions {
|
|
|
10
10
|
runtimeValidationUpdates?: RuntimeValidationReport;
|
|
11
11
|
externalAnalyzerResults?: ExternalAnalyzerResults;
|
|
12
12
|
preferredExecutor?: string;
|
|
13
|
+
opentoken?: boolean;
|
|
13
14
|
}
|
|
14
15
|
export interface AdvanceAuditResult {
|
|
15
16
|
audit_state: AuditState;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decideNextStep } from "./nextStep.js";
|
|
1
|
+
import { decideNextStep, findObligation } from "./nextStep.js";
|
|
2
2
|
import { deriveAuditState } from "./state.js";
|
|
3
3
|
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
4
|
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runDesignAssessmentExecutor, runDesignReviewAutoComplete, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
@@ -70,7 +70,9 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
70
70
|
case "runtime_validation_executor":
|
|
71
71
|
if (!options.root)
|
|
72
72
|
throw new Error("advanceAudit runtime_validation_executor requires root");
|
|
73
|
-
run = await runRuntimeValidationExecutor(bundle, options.root
|
|
73
|
+
run = await runRuntimeValidationExecutor(bundle, options.root, {
|
|
74
|
+
opentoken: options.opentoken,
|
|
75
|
+
});
|
|
74
76
|
break;
|
|
75
77
|
case "synthesis_executor":
|
|
76
78
|
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
@@ -95,7 +97,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
95
97
|
throw new Error("advanceAudit syntax_resolution_executor requires root");
|
|
96
98
|
run = runSyntaxResolutionExecutor(bundle, options.root);
|
|
97
99
|
break;
|
|
98
|
-
default:
|
|
100
|
+
default: {
|
|
99
101
|
const state = deriveAuditState(bundle);
|
|
100
102
|
state.last_executor = selectedExecutor;
|
|
101
103
|
state.last_obligation = selectedObligation ?? undefined;
|
|
@@ -109,6 +111,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
109
111
|
next_likely_step: selectedObligation,
|
|
110
112
|
updated_bundle: { ...bundle, audit_state: state },
|
|
111
113
|
};
|
|
114
|
+
}
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
catch (error) {
|
|
@@ -124,7 +127,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
124
127
|
updatedState.last_executor = selectedExecutor;
|
|
125
128
|
updatedState.last_obligation = selectedObligation ?? undefined;
|
|
126
129
|
const finalizedBundle = { ...metadataBundle, audit_state: updatedState };
|
|
127
|
-
const
|
|
130
|
+
const nextObligation = findObligation(updatedState.obligations);
|
|
128
131
|
return {
|
|
129
132
|
audit_state: updatedState,
|
|
130
133
|
selected_obligation: selectedObligation,
|
|
@@ -136,7 +139,7 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
136
139
|
"audit_state.json",
|
|
137
140
|
],
|
|
138
141
|
progress_summary: run.progress_summary,
|
|
139
|
-
next_likely_step:
|
|
142
|
+
next_likely_step: nextObligation?.id ?? null,
|
|
140
143
|
updated_bundle: finalizedBundle,
|
|
141
144
|
};
|
|
142
145
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const LENS_ORDER = [
|
|
2
|
+
"security",
|
|
3
|
+
"correctness",
|
|
4
|
+
"reliability",
|
|
5
|
+
"data_integrity",
|
|
6
|
+
"performance",
|
|
7
|
+
"operability",
|
|
8
|
+
"config_deployment",
|
|
9
|
+
"observability",
|
|
10
|
+
"maintainability",
|
|
11
|
+
"tests",
|
|
12
|
+
];
|
|
13
|
+
export function priorityRank(priority) {
|
|
14
|
+
switch (priority) {
|
|
15
|
+
case "high":
|
|
16
|
+
return 3;
|
|
17
|
+
case "medium":
|
|
18
|
+
return 2;
|
|
19
|
+
case "low":
|
|
20
|
+
default:
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function sortLenses(lenses) {
|
|
25
|
+
const set = new Set(lenses);
|
|
26
|
+
return LENS_ORDER.filter((lens) => set.has(lens));
|
|
27
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
2
|
-
import type { GraphBundle } from "
|
|
2
|
+
import type { GraphBundle } from "@audit-tools/shared";
|
|
3
3
|
export type FileAnchorKind = "boundary" | "import" | "export" | "symbol" | "route" | "keyword" | "graph" | "analyzer_signal";
|
|
4
4
|
export interface FileAnchor {
|
|
5
5
|
kind: FileAnchorKind;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RepoManifest } from "../types.js";
|
|
2
|
+
export interface FileIntegrityResult {
|
|
3
|
+
changed_files: string[];
|
|
4
|
+
missing_files: string[];
|
|
5
|
+
is_clean: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function checkFileIntegrity(root: string, manifest: RepoManifest, scope?: string[]): Promise<FileIntegrityResult>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join, isAbsolute } from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
async function hashFile(absolutePath) {
|
|
6
|
+
const content = await readFile(absolutePath);
|
|
7
|
+
return createHash("sha256").update(content).digest("hex");
|
|
8
|
+
}
|
|
9
|
+
export async function checkFileIntegrity(root, manifest, scope) {
|
|
10
|
+
const changed = [];
|
|
11
|
+
const missing = [];
|
|
12
|
+
const scopeSet = scope ? new Set(scope) : null;
|
|
13
|
+
const files = scopeSet
|
|
14
|
+
? manifest.files.filter((f) => scopeSet.has(f.path))
|
|
15
|
+
: manifest.files;
|
|
16
|
+
for (const record of files) {
|
|
17
|
+
if (!record.hash)
|
|
18
|
+
continue;
|
|
19
|
+
const absolute = isAbsolute(record.path)
|
|
20
|
+
? record.path
|
|
21
|
+
: join(root, record.path);
|
|
22
|
+
if (!existsSync(absolute)) {
|
|
23
|
+
missing.push(record.path);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const currentHash = await hashFile(absolute);
|
|
28
|
+
if (currentHash !== record.hash) {
|
|
29
|
+
changed.push(record.path);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
missing.push(record.path);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
changed_files: changed,
|
|
38
|
+
missing_files: missing,
|
|
39
|
+
is_clean: changed.length === 0 && missing.length === 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { CoverageMatrix } from "../types.js";
|
|
2
2
|
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
3
|
-
import type { CriticalFlowManifest } from "
|
|
3
|
+
import type { CriticalFlowManifest } from "@audit-tools/shared";
|
|
4
4
|
export declare function buildFlowCoverage(criticalFlows: CriticalFlowManifest, coverageMatrix: CoverageMatrix): FlowCoverageManifest;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
2
2
|
import type { AuditTask, CoverageMatrix } from "../types.js";
|
|
3
3
|
import type { FlowCoverageManifest } from "../types/flowCoverage.js";
|
|
4
|
-
import type { CriticalFlowManifest } from "
|
|
4
|
+
import type { CriticalFlowManifest } from "@audit-tools/shared";
|
|
5
5
|
export declare function buildFlowRequeueTasks(criticalFlows: CriticalFlowManifest, flowCoverage: FlowCoverageManifest, coverageMatrix: CoverageMatrix, externalAnalyzerResults?: ExternalAnalyzerResults): AuditTask[];
|
|
@@ -17,7 +17,9 @@ export declare function runDesignAssessmentExecutor(bundle: ArtifactBundle): Exe
|
|
|
17
17
|
export declare function runDesignReviewAutoComplete(bundle: ArtifactBundle): ExecutorRunResult;
|
|
18
18
|
export declare function runPlanningExecutor(bundle: ArtifactBundle, root: string, lineIndex?: Record<string, number>): Promise<ExecutorRunResult>;
|
|
19
19
|
export declare function runResultIngestionExecutor(bundle: ArtifactBundle, results: AuditResult[]): ExecutorRunResult;
|
|
20
|
-
export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, root: string
|
|
20
|
+
export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, root: string, options?: {
|
|
21
|
+
opentoken?: boolean;
|
|
22
|
+
}): Promise<ExecutorRunResult>;
|
|
21
23
|
export declare function runRuntimeValidationUpdateExecutor(bundle: ArtifactBundle, updates: RuntimeValidationReport): ExecutorRunResult;
|
|
22
24
|
export declare function runSynthesisExecutor(bundle: ArtifactBundle, results?: AuditResult[]): ExecutorRunResult;
|
|
23
25
|
export declare function runExternalAnalyzerImportExecutor(bundle: ArtifactBundle, externalResults: ExternalAnalyzerResults): ExecutorRunResult;
|
|
@@ -56,8 +56,21 @@ function appendSelectiveDeepeningTasks(params) {
|
|
|
56
56
|
artifacts: ["audit_tasks.json", "audit_plan_metrics.json", "review_packets.json"],
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
function resolveOpentokenWrap(resolved, platform = process.platform) {
|
|
60
|
+
if (platform === "win32") {
|
|
61
|
+
const shell = process.env.ComSpec ?? "cmd.exe";
|
|
62
|
+
const inner = [resolved.command, ...resolved.args]
|
|
63
|
+
.map((v) => (/^[A-Za-z0-9_./:=@+-]+$/.test(v) ? v : `"${v.replace(/(["^&|<>%])/g, "^$1")}"`))
|
|
64
|
+
.join(" ");
|
|
65
|
+
return { command: shell, args: ["/d", "/s", "/c", `opentoken wrap ${inner}`] };
|
|
66
|
+
}
|
|
67
|
+
return { command: "opentoken", args: ["wrap", resolved.command, ...resolved.args] };
|
|
68
|
+
}
|
|
69
|
+
async function runCommand(command, cwd, options = {}) {
|
|
70
|
+
let spawnCommand = resolveRuntimeValidationSpawnCommand(command);
|
|
71
|
+
if (options.opentoken) {
|
|
72
|
+
spawnCommand = resolveOpentokenWrap(spawnCommand);
|
|
73
|
+
}
|
|
61
74
|
const displayCommand = command.join(" ");
|
|
62
75
|
return await new Promise((resolve) => {
|
|
63
76
|
const child = spawn(spawnCommand.command, spawnCommand.args, {
|
|
@@ -121,7 +134,7 @@ export async function runIntakeExecutor(bundle, root) {
|
|
|
121
134
|
const repoManifest = await buildRepoManifestFromFs({
|
|
122
135
|
root,
|
|
123
136
|
ignore,
|
|
124
|
-
hash_files:
|
|
137
|
+
hash_files: true,
|
|
125
138
|
});
|
|
126
139
|
const disposition = buildFileDisposition(repoManifest);
|
|
127
140
|
const auditableCount = disposition.files.filter((file) => !isAuditExcludedStatus(file.status)).length;
|
|
@@ -192,6 +205,11 @@ export function runDesignAssessmentExecutor(bundle) {
|
|
|
192
205
|
criticalFlows: bundle.critical_flows,
|
|
193
206
|
riskRegister: bundle.risk_register,
|
|
194
207
|
});
|
|
208
|
+
const previous = bundle.design_assessment;
|
|
209
|
+
if (previous?.reviewed) {
|
|
210
|
+
designAssessment.reviewed = true;
|
|
211
|
+
designAssessment.review_findings = previous.review_findings ?? [];
|
|
212
|
+
}
|
|
195
213
|
return {
|
|
196
214
|
updated: {
|
|
197
215
|
...bundle,
|
|
@@ -354,7 +372,7 @@ export function runResultIngestionExecutor(bundle, results) {
|
|
|
354
372
|
: ""),
|
|
355
373
|
};
|
|
356
374
|
}
|
|
357
|
-
export async function runRuntimeValidationExecutor(bundle, root) {
|
|
375
|
+
export async function runRuntimeValidationExecutor(bundle, root, options = {}) {
|
|
358
376
|
if (!bundle.runtime_validation_tasks) {
|
|
359
377
|
throw new Error("Cannot execute runtime validation without runtime_validation_tasks");
|
|
360
378
|
}
|
|
@@ -378,7 +396,7 @@ export async function runRuntimeValidationExecutor(bundle, root) {
|
|
|
378
396
|
continue;
|
|
379
397
|
}
|
|
380
398
|
const signature = task.command.join("\0");
|
|
381
|
-
const outcome = byCommand.get(signature) ?? (await runCommand(task.command, root));
|
|
399
|
+
const outcome = byCommand.get(signature) ?? (await runCommand(task.command, root, { opentoken: options.opentoken }));
|
|
382
400
|
byCommand.set(signature, outcome);
|
|
383
401
|
byTaskId.set(task.id, {
|
|
384
402
|
task_id: task.id,
|