auditor-lambda 0.3.40 → 0.5.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/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 +532 -0
- package/dist/cli/prompts.d.ts +37 -0
- package/dist/cli/prompts.js +225 -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 +442 -975
- package/dist/extractors/analyzers/css.d.ts +2 -0
- package/dist/extractors/analyzers/css.js +101 -0
- package/dist/extractors/analyzers/html.d.ts +2 -0
- package/dist/extractors/analyzers/html.js +92 -0
- package/dist/extractors/analyzers/merge.d.ts +14 -0
- package/dist/extractors/analyzers/merge.js +85 -0
- package/dist/extractors/analyzers/python.d.ts +2 -0
- package/dist/extractors/analyzers/python.js +104 -0
- package/dist/extractors/analyzers/registry.d.ts +33 -0
- package/dist/extractors/analyzers/registry.js +100 -0
- package/dist/extractors/analyzers/resourceUrl.d.ts +7 -0
- package/dist/extractors/analyzers/resourceUrl.js +25 -0
- package/dist/extractors/analyzers/sql.d.ts +2 -0
- package/dist/extractors/analyzers/sql.js +19 -0
- package/dist/extractors/analyzers/treeSitter.d.ts +34 -0
- package/dist/extractors/analyzers/treeSitter.js +111 -0
- package/dist/extractors/analyzers/types.d.ts +53 -0
- package/dist/extractors/analyzers/typescript.d.ts +2 -0
- package/dist/extractors/analyzers/typescript.js +257 -0
- 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 +11 -1
- package/dist/extractors/flows.d.ts +1 -3
- package/dist/extractors/flows.js +2 -2
- package/dist/extractors/graph.d.ts +2 -2
- package/dist/extractors/graph.js +171 -327
- package/dist/extractors/graphManifestEdges.d.ts +1 -1
- package/dist/extractors/graphPathUtils.d.ts +1 -1
- package/dist/extractors/graphPythonImports.d.ts +18 -0
- package/dist/extractors/graphPythonImports.js +362 -0
- package/dist/extractors/pathPatterns.d.ts +6 -0
- package/dist/extractors/pathPatterns.js +8 -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 +12 -5
- package/dist/io/artifacts.js +13 -1
- package/dist/io/runArtifacts.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/orchestrator/advance.d.ts +21 -0
- package/dist/orchestrator/advance.js +69 -7
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +27 -0
- package/dist/orchestrator/dependencyMap.js +27 -0
- package/dist/orchestrator/edgeReasoning.d.ts +39 -0
- package/dist/orchestrator/edgeReasoning.js +125 -0
- package/dist/orchestrator/executors.js +11 -1
- 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/graphEnrichmentExecutor.d.ts +29 -0
- package/dist/orchestrator/graphEnrichmentExecutor.js +196 -0
- package/dist/orchestrator/internalExecutors.d.ts +13 -2
- package/dist/orchestrator/internalExecutors.js +112 -16
- package/dist/orchestrator/localCommands.js +6 -25
- package/dist/orchestrator/nextStep.d.ts +2 -1
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/planning.d.ts +1 -1
- package/dist/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.d.ts +37 -4
- package/dist/orchestrator/reviewPackets.js +113 -158
- package/dist/orchestrator/runtimeValidation.d.ts +1 -1
- package/dist/orchestrator/runtimeValidation.js +4 -31
- package/dist/orchestrator/scope.d.ts +62 -0
- package/dist/orchestrator/scope.js +227 -0
- package/dist/orchestrator/state.js +2 -0
- 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 +37 -3
- package/dist/reporting/synthesis.js +97 -16
- package/dist/reporting/synthesisNarrativePrompt.d.ts +7 -0
- package/dist/reporting/synthesisNarrativePrompt.js +60 -0
- package/dist/reporting/workBlocks.d.ts +2 -11
- 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 +8 -1
- package/dist/supervisor/sessionConfig.js +22 -3
- package/dist/types/analyzerCapability.d.ts +16 -0
- package/dist/types/auditScope.d.ts +43 -0
- package/dist/types/auditScope.js +14 -0
- package/dist/types/reviewPlanning.d.ts +1 -1
- package/dist/types/synthesisNarrative.d.ts +7 -0
- package/dist/types/synthesisNarrative.js +5 -0
- package/dist/types/workerSession.d.ts +6 -0
- package/dist/types.d.ts +2 -19
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +10 -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 +25 -3
- package/package.json +7 -3
- package/schemas/analyzer_capability.schema.json +47 -0
- package/schemas/audit_findings.schema.json +141 -0
- package/schemas/finding.schema.json +2 -1
- package/schemas/graph_bundle.schema.json +5 -0
- package/schemas/scope.schema.json +46 -0
- 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/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/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
- /package/dist/{providers → extractors/analyzers}/types.js +0 -0
- /package/dist/{quota/quotaSource.js → types/analyzerCapability.js} +0 -0
|
@@ -0,0 +1,362 @@
|
|
|
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
|
+
/**
|
|
283
|
+
* Resolve a single `import <spec>` module specifier to a repo file, or
|
|
284
|
+
* undefined. Shared with the tree-sitter Python analyzer so AST-extracted
|
|
285
|
+
* imports resolve to exactly the same targets as the regex floor.
|
|
286
|
+
*/
|
|
287
|
+
export function resolvePythonImportTarget(fromPath, specifier, pathLookup) {
|
|
288
|
+
if (!isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
return resolvePythonModuleSpecifier(fromPath, specifier, pathLookup);
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Resolve a `from <module> import <names>` statement to repo files. Mirrors the
|
|
295
|
+
* floor: prefer submodule files (`module.name`), else the module itself. Shared
|
|
296
|
+
* with the tree-sitter Python analyzer.
|
|
297
|
+
*/
|
|
298
|
+
export function resolvePythonFromImportTargets(fromPath, moduleSpecifier, importedNames, pathLookup) {
|
|
299
|
+
if (!isPythonModuleSpecifier(moduleSpecifier)) {
|
|
300
|
+
return [];
|
|
301
|
+
}
|
|
302
|
+
const submoduleTargets = importedNames
|
|
303
|
+
.filter((name) => name !== "*" && isPythonIdentifier(name))
|
|
304
|
+
.map((name) => appendPythonImportedSpecifier(moduleSpecifier, name))
|
|
305
|
+
.map((specifier) => ({
|
|
306
|
+
specifier,
|
|
307
|
+
target: resolvePythonModuleSpecifier(fromPath, specifier, pathLookup),
|
|
308
|
+
}))
|
|
309
|
+
.filter((item) => item.target !== undefined && item.target !== fromPath);
|
|
310
|
+
if (submoduleTargets.length > 0) {
|
|
311
|
+
return submoduleTargets;
|
|
312
|
+
}
|
|
313
|
+
const moduleTarget = resolvePythonModuleSpecifier(fromPath, moduleSpecifier, pathLookup);
|
|
314
|
+
return moduleTarget && moduleTarget !== fromPath
|
|
315
|
+
? [{ specifier: moduleSpecifier, target: moduleTarget }]
|
|
316
|
+
: [];
|
|
317
|
+
}
|
|
318
|
+
export function extractPythonImportEdges(fromPath, content, pathLookup) {
|
|
319
|
+
if (!isPythonSourcePath(fromPath)) {
|
|
320
|
+
return [];
|
|
321
|
+
}
|
|
322
|
+
const edges = [];
|
|
323
|
+
for (const line of pythonLogicalLines(content)) {
|
|
324
|
+
const importMatch = /^import\s+(.+)$/i.exec(line);
|
|
325
|
+
if (importMatch) {
|
|
326
|
+
for (const rawSpecifier of splitPythonImportList(importMatch[1] ?? "")) {
|
|
327
|
+
const specifier = stripPythonAlias(rawSpecifier);
|
|
328
|
+
if (!isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, specifier, pathLookup), "python-import", specifier);
|
|
332
|
+
}
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const fromImportMatch = /^from\s+([.\w]+)\s+import\s+(.+)$/i.exec(line);
|
|
336
|
+
if (!fromImportMatch) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const moduleSpecifier = fromImportMatch[1] ?? "";
|
|
340
|
+
if (!isPythonModuleSpecifier(moduleSpecifier)) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
const importedNames = splitPythonImportList(fromImportMatch[2] ?? "")
|
|
344
|
+
.map(stripPythonAlias)
|
|
345
|
+
.filter((name) => name !== "*" && isPythonIdentifier(name));
|
|
346
|
+
const submoduleTargets = importedNames
|
|
347
|
+
.map((name) => appendPythonImportedSpecifier(moduleSpecifier, name))
|
|
348
|
+
.map((specifier) => ({
|
|
349
|
+
specifier,
|
|
350
|
+
target: resolvePythonModuleSpecifier(fromPath, specifier, pathLookup),
|
|
351
|
+
}))
|
|
352
|
+
.filter((item) => item.target);
|
|
353
|
+
if (submoduleTargets.length > 0) {
|
|
354
|
+
for (const { specifier, target } of submoduleTargets) {
|
|
355
|
+
addPythonImportEdge(edges, fromPath, target, "python-from-import", specifier);
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, moduleSpecifier, pathLookup), "python-from-import", moduleSpecifier);
|
|
360
|
+
}
|
|
361
|
+
return edges;
|
|
362
|
+
}
|
|
@@ -8,6 +8,12 @@ export declare const EXTRACTOR_HEURISTIC_NOTE = "Heuristic path classification n
|
|
|
8
8
|
export declare function normalizeExtractorPath(path: string): string;
|
|
9
9
|
export declare function pathTokens(normalized: string): string[];
|
|
10
10
|
export declare function isNodeModulesOrGit(normalized: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* `.tmp/` holds transient scratch and bundled tool copies (e.g. a vendored
|
|
13
|
+
* `.tmp/opentoken`). These are not the audited project's source — excluding
|
|
14
|
+
* them keeps the self-audit from auditing its own bundled dependencies.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isTmpPath(normalized: string): boolean;
|
|
11
17
|
export declare function isBuildOutput(normalized: string): boolean;
|
|
12
18
|
export declare function isVendorPath(normalized: string): boolean;
|
|
13
19
|
export declare function isBinaryArtifact(normalized: string): boolean;
|
|
@@ -156,6 +156,14 @@ function hasToken(normalized, values) {
|
|
|
156
156
|
export function isNodeModulesOrGit(normalized) {
|
|
157
157
|
return hasSegment(normalized, "node_modules") || hasSegment(normalized, ".git");
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* `.tmp/` holds transient scratch and bundled tool copies (e.g. a vendored
|
|
161
|
+
* `.tmp/opentoken`). These are not the audited project's source — excluding
|
|
162
|
+
* them keeps the self-audit from auditing its own bundled dependencies.
|
|
163
|
+
*/
|
|
164
|
+
export function isTmpPath(normalized) {
|
|
165
|
+
return hasSegment(normalized, ".tmp");
|
|
166
|
+
}
|
|
159
167
|
export function isBuildOutput(normalized) {
|
|
160
168
|
return hasSegment(normalized, "dist") || hasSegment(normalized, "build");
|
|
161
169
|
}
|
|
@@ -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,16 +2,15 @@ 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 { AuditFindingsReport, FileDisposition, CriticalFlowManifest, GraphBundle, RiskRegister, SurfaceManifest } from "@audit-tools/shared";
|
|
6
|
+
import type { SynthesisNarrativeRecord } from "../types/synthesisNarrative.js";
|
|
6
7
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
7
8
|
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
9
|
import type { AuditPlanMetrics, ReviewPacket } from "../types/reviewPlanning.js";
|
|
12
10
|
import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
|
|
13
|
-
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
14
11
|
import type { DesignAssessment } from "../types/designAssessment.js";
|
|
12
|
+
import type { AnalyzerCapabilityRecord } from "../types/analyzerCapability.js";
|
|
13
|
+
import type { AuditScopeManifest } from "../types/auditScope.js";
|
|
15
14
|
import type { ToolingManifest } from "../types/toolingManifest.js";
|
|
16
15
|
type ArtifactPayloadMap = {
|
|
17
16
|
repo_manifest: RepoManifest;
|
|
@@ -24,6 +23,8 @@ type ArtifactPayloadMap = {
|
|
|
24
23
|
flow_coverage: FlowCoverageManifest;
|
|
25
24
|
risk_register: RiskRegister;
|
|
26
25
|
design_assessment: DesignAssessment;
|
|
26
|
+
analyzer_capability: AnalyzerCapabilityRecord;
|
|
27
|
+
scope: AuditScopeManifest;
|
|
27
28
|
coverage_matrix: CoverageMatrix;
|
|
28
29
|
runtime_validation_tasks: RuntimeValidationTaskManifest;
|
|
29
30
|
runtime_validation_report: RuntimeValidationReport;
|
|
@@ -35,6 +36,8 @@ type ArtifactPayloadMap = {
|
|
|
35
36
|
review_packets: ReviewPacket[];
|
|
36
37
|
requeue_tasks: AuditTask[];
|
|
37
38
|
audit_report: string;
|
|
39
|
+
audit_findings: AuditFindingsReport;
|
|
40
|
+
synthesis_narrative: SynthesisNarrativeRecord;
|
|
38
41
|
audit_state: AuditState;
|
|
39
42
|
artifact_metadata: ArtifactMetadataManifest;
|
|
40
43
|
tooling_manifest: ToolingManifest;
|
|
@@ -63,6 +66,8 @@ export declare const ARTIFACT_DEFINITIONS: {
|
|
|
63
66
|
readonly flow_coverage: ArtifactDefinition<"flow_coverage">;
|
|
64
67
|
readonly risk_register: ArtifactDefinition<"risk_register">;
|
|
65
68
|
readonly design_assessment: ArtifactDefinition<"design_assessment">;
|
|
69
|
+
readonly analyzer_capability: ArtifactDefinition<"analyzer_capability">;
|
|
70
|
+
readonly scope: ArtifactDefinition<"scope">;
|
|
66
71
|
readonly coverage_matrix: ArtifactDefinition<"coverage_matrix">;
|
|
67
72
|
readonly runtime_validation_tasks: ArtifactDefinition<"runtime_validation_tasks">;
|
|
68
73
|
readonly runtime_validation_report: ArtifactDefinition<"runtime_validation_report">;
|
|
@@ -74,6 +79,8 @@ export declare const ARTIFACT_DEFINITIONS: {
|
|
|
74
79
|
readonly review_packets: ArtifactDefinition<"review_packets">;
|
|
75
80
|
readonly requeue_tasks: ArtifactDefinition<"requeue_tasks">;
|
|
76
81
|
readonly audit_report: ArtifactDefinition<"audit_report">;
|
|
82
|
+
readonly audit_findings: ArtifactDefinition<"audit_findings">;
|
|
83
|
+
readonly synthesis_narrative: ArtifactDefinition<"synthesis_narrative">;
|
|
77
84
|
readonly audit_state: ArtifactDefinition<"audit_state">;
|
|
78
85
|
readonly artifact_metadata: ArtifactDefinition<"artifact_metadata">;
|
|
79
86
|
readonly tooling_manifest: ArtifactDefinition<"tooling_manifest">;
|
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 {
|
|
@@ -37,6 +37,8 @@ export const ARTIFACT_DEFINITIONS = {
|
|
|
37
37
|
flow_coverage: jsonArtifact("flow_coverage.json", "analysis"),
|
|
38
38
|
risk_register: jsonArtifact("risk_register.json", "analysis"),
|
|
39
39
|
design_assessment: jsonArtifact("design_assessment.json", "analysis"),
|
|
40
|
+
analyzer_capability: jsonArtifact("analyzer_capability.json", "analysis"),
|
|
41
|
+
scope: jsonArtifact("scope.json", "execution"),
|
|
40
42
|
coverage_matrix: jsonArtifact("coverage_matrix.json", "execution"),
|
|
41
43
|
runtime_validation_tasks: jsonArtifact("runtime_validation_tasks.json", "execution"),
|
|
42
44
|
runtime_validation_report: jsonArtifact("runtime_validation_report.json", "execution"),
|
|
@@ -48,6 +50,8 @@ export const ARTIFACT_DEFINITIONS = {
|
|
|
48
50
|
review_packets: jsonArtifact("review_packets.json", "execution"),
|
|
49
51
|
requeue_tasks: jsonArtifact("requeue_tasks.json", "execution"),
|
|
50
52
|
audit_report: textArtifact("audit-report.md", "reporting"),
|
|
53
|
+
audit_findings: jsonArtifact("audit-findings.json", "reporting"),
|
|
54
|
+
synthesis_narrative: jsonArtifact("synthesis-narrative.json", "reporting"),
|
|
51
55
|
audit_state: jsonArtifact("audit_state.json", "supervisor"),
|
|
52
56
|
artifact_metadata: jsonArtifact("artifact_metadata.json", "supervisor"),
|
|
53
57
|
tooling_manifest: jsonArtifact("tooling_manifest.json", "supervisor"),
|
|
@@ -113,6 +117,14 @@ export async function promoteFinalAuditReport(params, options = {}) {
|
|
|
113
117
|
warn(warning);
|
|
114
118
|
return { promoted: false, cleaned: false, warning };
|
|
115
119
|
}
|
|
120
|
+
// Promote the canonical machine contract alongside the human report. Missing
|
|
121
|
+
// (e.g. legacy bundle) or unreadable: best-effort, never blocks completion.
|
|
122
|
+
try {
|
|
123
|
+
await copy(join(params.artifactsDir, "audit-findings.json"), join(params.repoRoot, "audit-findings.json"), { force: true });
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// audit-findings.json is optional output; absence must not fail promotion.
|
|
127
|
+
}
|
|
116
128
|
try {
|
|
117
129
|
await remove(params.artifactsDir, { recursive: true, force: true });
|
|
118
130
|
return { promoted: true, cleaned: true };
|
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";
|
|
@@ -3,13 +3,34 @@ import type { AuditState } from "../types/auditState.js";
|
|
|
3
3
|
import type { AuditResult } from "../types.js";
|
|
4
4
|
import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
|
|
5
5
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
6
|
+
import { RunLogger } from "@audit-tools/shared";
|
|
7
|
+
import type { AnalyzerSetting, SynthesisNarrative } from "@audit-tools/shared";
|
|
8
|
+
import type { EdgeReasoningResults } from "./edgeReasoning.js";
|
|
6
9
|
export interface AdvanceAuditOptions {
|
|
7
10
|
root?: string;
|
|
8
11
|
lineIndex?: Record<string, number>;
|
|
12
|
+
/** Path → size_bytes (from the repo manifest); drives byte-based packet token sizing. */
|
|
13
|
+
sizeIndex?: Record<string, number>;
|
|
9
14
|
auditResults?: AuditResult[];
|
|
10
15
|
runtimeValidationUpdates?: RuntimeValidationReport;
|
|
11
16
|
externalAnalyzerResults?: ExternalAnalyzerResults;
|
|
17
|
+
/** Host/provider-supplied synthesis narrative; merged by synthesis_narrative_executor. */
|
|
18
|
+
narrativeResults?: SynthesisNarrative;
|
|
19
|
+
/** Per-analyzer resolution policy for the optional graph-enrichment pass. */
|
|
20
|
+
analyzers?: Record<string, AnalyzerSetting>;
|
|
21
|
+
/** Phase 4B gate (session-config `graph.llm_edge_reasoning`); default off. */
|
|
22
|
+
graphLlmEdgeReasoning?: boolean;
|
|
23
|
+
/** Phase 4B host-supplied reason rewrites for low-confidence graph edges. */
|
|
24
|
+
edgeReasoningResults?: EdgeReasoningResults;
|
|
25
|
+
/**
|
|
26
|
+
* Git ref for Phase 3 delta mode (the `--since` flag). When set and resolvable
|
|
27
|
+
* against a git repo, planning scopes coverage to the changed files and their
|
|
28
|
+
* graph neighbours; otherwise the run is a full audit.
|
|
29
|
+
*/
|
|
30
|
+
since?: string;
|
|
12
31
|
preferredExecutor?: string;
|
|
32
|
+
opentoken?: boolean;
|
|
33
|
+
runLogger?: RunLogger;
|
|
13
34
|
}
|
|
14
35
|
export interface AdvanceAuditResult {
|
|
15
36
|
audit_state: AuditState;
|