auditor-lambda 0.7.0 → 0.9.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/README.md +0 -21
- package/audit-code-wrapper-lib.mjs +149 -129
- package/dist/adapters/normalizeExternal.js +6 -3
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -6
- package/dist/cli/auditStep.js +7 -1
- package/dist/cli/dispatch.js +3 -2
- package/dist/cli/lineIndex.js +4 -1
- package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
- package/dist/cli/mergeAndIngestCommand.js +219 -0
- package/dist/cli/nextStepCommand.js +5 -1
- package/dist/cli/runToCompletion.d.ts +9 -0
- package/dist/cli/runToCompletion.js +655 -480
- package/dist/cli/statusCommand.d.ts +1 -0
- package/dist/cli/statusCommand.js +113 -0
- package/dist/cli/submitPacketCommand.d.ts +1 -0
- package/dist/cli/submitPacketCommand.js +155 -0
- package/dist/cli/workerResult.d.ts +1 -1
- package/dist/cli/workerRunCommand.d.ts +1 -0
- package/dist/cli/workerRunCommand.js +88 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +14 -565
- package/dist/extractors/analyzers/sql.js +4 -1
- package/dist/extractors/analyzers/treeSitter.js +29 -15
- package/dist/extractors/analyzers/typescript.js +10 -8
- package/dist/extractors/designAssessment.js +43 -24
- package/dist/extractors/graph.js +151 -75
- package/dist/extractors/pathPatterns.js +17 -5
- package/dist/io/artifacts.d.ts +3 -1
- package/dist/io/artifacts.js +18 -2
- package/dist/io/runArtifactTypes.d.ts +18 -0
- package/dist/io/runArtifactTypes.js +1 -0
- package/dist/io/runArtifacts.d.ts +2 -18
- package/dist/io/runArtifacts.js +14 -3
- package/dist/mcp/server.js +9 -0
- package/dist/orchestrator/advance.js +38 -22
- package/dist/orchestrator/artifactFreshness.js +14 -4
- package/dist/orchestrator/autoFixExecutor.d.ts +2 -2
- package/dist/orchestrator/autoFixExecutor.js +26 -8
- package/dist/orchestrator/dependencyMap.d.ts +1 -1
- package/dist/orchestrator/dependencyMap.js +7 -1
- package/dist/orchestrator/executorResult.d.ts +12 -0
- package/dist/orchestrator/executorResult.js +1 -0
- package/dist/orchestrator/fileAnchors.js +14 -3
- package/dist/orchestrator/fileIntegrity.d.ts +1 -0
- package/dist/orchestrator/fileIntegrity.js +12 -3
- package/dist/orchestrator/flowCoverage.js +1 -0
- package/dist/orchestrator/flowRequeue.js +4 -1
- package/dist/orchestrator/graphEnrichmentExecutor.d.ts +1 -1
- package/dist/orchestrator/graphEnrichmentExecutor.js +3 -1
- package/dist/orchestrator/ingestionExecutors.d.ts +11 -0
- package/dist/orchestrator/ingestionExecutors.js +237 -0
- package/dist/orchestrator/intakeExecutors.d.ts +3 -0
- package/dist/orchestrator/intakeExecutors.js +25 -0
- package/dist/orchestrator/planningExecutors.d.ts +4 -0
- package/dist/orchestrator/planningExecutors.js +95 -0
- package/dist/orchestrator/reviewPacketGraph.d.ts +31 -0
- package/dist/orchestrator/reviewPacketGraph.js +691 -0
- package/dist/orchestrator/reviewPackets.d.ts +2 -15
- package/dist/orchestrator/reviewPackets.js +3 -685
- package/dist/orchestrator/runtimeCommand.d.ts +11 -0
- package/dist/orchestrator/runtimeCommand.js +71 -0
- package/dist/orchestrator/scope.js +1 -1
- package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
- package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
- package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
- package/dist/orchestrator/selectiveDeepening/index.js +128 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
- package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
- package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
- package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
- package/dist/orchestrator/selectiveDeepening.js +6 -760
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/structureExecutors.d.ts +5 -0
- package/dist/orchestrator/structureExecutors.js +94 -0
- package/dist/orchestrator/syntaxResolutionExecutor.d.ts +1 -1
- package/dist/orchestrator/synthesisExecutors.d.ts +12 -0
- package/dist/orchestrator/synthesisExecutors.js +90 -0
- package/dist/orchestrator/taskBuilder.d.ts +2 -2
- package/dist/orchestrator/taskBuilder.js +101 -82
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +14 -95
- package/dist/quota/discoveredLimits.d.ts +1 -0
- package/dist/quota/discoveredLimits.js +7 -1
- package/dist/quota/index.d.ts +0 -2
- package/dist/quota/index.js +1 -2
- package/dist/reporting/workBlocks.js +7 -4
- package/dist/types/reviewPlanning.d.ts +23 -16
- package/dist/validation/auditResults.js +97 -95
- package/dist/validation/sessionConfig.d.ts +2 -2
- package/dist/validation/sessionConfig.js +14 -7
- package/docs/development.md +35 -139
- package/docs/history.md +26 -0
- package/docs/product.md +41 -108
- package/package.json +3 -2
- package/schemas/audit_findings.schema.json +6 -5
- package/schemas/critical_flows.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +3 -1
- package/schemas/external_analyzer_results.schema.json +2 -2
- package/schemas/graph_bundle.schema.json +1 -1
- package/schemas/repo_manifest.schema.json +1 -1
- package/schemas/review_packets.schema.json +1 -1
- package/schemas/step_contract.schema.json +80 -0
- package/scripts/postinstall.mjs +19 -2
- package/skills/audit-code/opencode-command-template.txt +3 -3
- package/dist/orchestrator/internalExecutors.d.ts +0 -34
- package/dist/orchestrator/internalExecutors.js +0 -581
- package/dist/providers/localSubprocessProvider.d.ts +0 -9
- package/dist/providers/localSubprocessProvider.js +0 -18
- package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
- package/dist/providers/subprocessTemplateProvider.js +0 -59
- package/dist/providers/vscodeTaskProvider.d.ts +0 -7
- package/dist/providers/vscodeTaskProvider.js +0 -14
- package/dist/quota/probe.d.ts +0 -10
- package/dist/quota/probe.js +0 -18
- package/docs/handoff.md +0 -204
package/dist/io/artifacts.js
CHANGED
|
@@ -79,13 +79,29 @@ export async function loadArtifactBundle(root) {
|
|
|
79
79
|
bundle.tooling_manifest = await buildToolingManifest();
|
|
80
80
|
return bundle;
|
|
81
81
|
}
|
|
82
|
-
export async function writeCoreArtifacts(root, bundle) {
|
|
82
|
+
export async function writeCoreArtifacts(root, bundle, options = {}) {
|
|
83
83
|
const bundleRecord = bundle;
|
|
84
84
|
for (const entry of ARTIFACT_ENTRIES) {
|
|
85
85
|
const [key, definition] = entry;
|
|
86
86
|
const value = bundleRecord[key];
|
|
87
|
+
const path = join(root, definition.fileName);
|
|
87
88
|
if (value !== undefined) {
|
|
88
|
-
await definition.write(
|
|
89
|
+
await definition.write(path, value);
|
|
90
|
+
}
|
|
91
|
+
else if (options.prune) {
|
|
92
|
+
// The bundle is authoritative. An executor that clears an artifact to
|
|
93
|
+
// `undefined` (to force a downstream rebuild — e.g. planning/ingestion
|
|
94
|
+
// reset audit_report) intends the file gone; if it lingers it reloads as a
|
|
95
|
+
// stale "present" artifact with no metadata entry, which deriveAuditState
|
|
96
|
+
// reads as satisfied — masking the invalidation and stranding a stale
|
|
97
|
+
// report. Only callers passing the full accumulated bundle may prune.
|
|
98
|
+
try {
|
|
99
|
+
await unlink(path);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (!isFileMissingError(error))
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
89
105
|
}
|
|
90
106
|
}
|
|
91
107
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface RunPaths {
|
|
2
|
+
runDir: string;
|
|
3
|
+
taskPath: string;
|
|
4
|
+
promptPath: string;
|
|
5
|
+
resultPath: string;
|
|
6
|
+
stdoutPath: string;
|
|
7
|
+
stderrPath: string;
|
|
8
|
+
statusPath: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DispatchBatchRun {
|
|
11
|
+
run_id: string;
|
|
12
|
+
task_path: string;
|
|
13
|
+
prompt_path: string;
|
|
14
|
+
result_path: string;
|
|
15
|
+
status_path: string;
|
|
16
|
+
audit_results_path?: string;
|
|
17
|
+
pending_audit_tasks_path?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
import type { AuditTask } from "../types.js";
|
|
2
2
|
import type { WorkerTask } from "../types/workerSession.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
taskPath: string;
|
|
6
|
-
promptPath: string;
|
|
7
|
-
resultPath: string;
|
|
8
|
-
stdoutPath: string;
|
|
9
|
-
stderrPath: string;
|
|
10
|
-
statusPath: string;
|
|
11
|
-
}
|
|
12
|
-
export interface DispatchBatchRun {
|
|
13
|
-
run_id: string;
|
|
14
|
-
task_path: string;
|
|
15
|
-
prompt_path: string;
|
|
16
|
-
result_path: string;
|
|
17
|
-
status_path: string;
|
|
18
|
-
audit_results_path?: string;
|
|
19
|
-
pending_audit_tasks_path?: string;
|
|
20
|
-
}
|
|
3
|
+
import type { RunPaths, DispatchBatchRun } from "./runArtifactTypes.js";
|
|
4
|
+
export type { RunPaths, DispatchBatchRun } from "./runArtifactTypes.js";
|
|
21
5
|
export declare function buildRunId(obligationId: string | null, index: number, now?: Date): string;
|
|
22
6
|
export declare function getRunPaths(artifactsDir: string, runId: string): RunPaths;
|
|
23
7
|
export declare function ensureSupervisorDirs(artifactsDir: string): Promise<void>;
|
package/dist/io/runArtifacts.js
CHANGED
|
@@ -61,6 +61,10 @@ export async function ensureSupervisorDirs(artifactsDir) {
|
|
|
61
61
|
}
|
|
62
62
|
async function writeDispatchSchemaFiles(artifactsDir) {
|
|
63
63
|
const dispatchDir = join(artifactsDir, "dispatch");
|
|
64
|
+
// Ensure the dispatch dir exists: this is now written before the pointer
|
|
65
|
+
// files (which formerly created it), and parallel-slot dispatch may reach
|
|
66
|
+
// here before the canonical dispatch has run.
|
|
67
|
+
await mkdir(dispatchDir, { recursive: true });
|
|
64
68
|
await writeFile(join(dispatchDir, CURRENT_SCHEMA_FILENAME), await readFile(auditResultSchemaPath, "utf8"), "utf8");
|
|
65
69
|
await writeFile(join(dispatchDir, CURRENT_RESULTS_SCHEMA_FILENAME), await readFile(auditResultsSchemaPath, "utf8"), "utf8");
|
|
66
70
|
await writeFile(join(dispatchDir, CURRENT_FINDING_SCHEMA_FILENAME), await readFile(findingSchemaPath, "utf8"), "utf8");
|
|
@@ -116,15 +120,22 @@ export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, cu
|
|
|
116
120
|
run_id: task.run_id,
|
|
117
121
|
status: "dispatched",
|
|
118
122
|
});
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
// The result schema files are always required by the worker, regardless of
|
|
124
|
+
// whether this run owns the shared "current dispatch" pointer files.
|
|
125
|
+
await writeDispatchSchemaFiles(artifactsDir);
|
|
126
|
+
// Parallel-slot dispatch passes updateDispatch:false so each slot does NOT
|
|
127
|
+
// clobber the shared current-task / current-prompt / current-tasks pointers
|
|
128
|
+
// (only the single canonical dispatch should own them). The default path
|
|
129
|
+
// (updateDispatch unset/true) refreshes those pointers and the single-task
|
|
130
|
+
// fallback.
|
|
131
|
+
const updateDispatch = options.updateDispatch !== false;
|
|
132
|
+
if (!updateDispatch) {
|
|
121
133
|
return;
|
|
122
134
|
}
|
|
123
135
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASK_FILENAME), task);
|
|
124
136
|
await writeFile(join(artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME), prompt, "utf8");
|
|
125
137
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME), currentTasks ?? []);
|
|
126
138
|
await writeSingleTaskFallbackFiles(artifactsDir, task, currentTasks);
|
|
127
|
-
await writeDispatchSchemaFiles(artifactsDir);
|
|
128
139
|
}
|
|
129
140
|
export async function writeDispatchBatchFiles(artifactsDir, runs, currentTasks) {
|
|
130
141
|
const summary = {
|
package/dist/mcp/server.js
CHANGED
|
@@ -125,6 +125,7 @@ async function runWrapperCommand(args, options) {
|
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
|
+
const SUBPROCESS_STDERR_TAIL_CHARS = 2000;
|
|
128
129
|
async function parseCliJson(args, options, allowNonZero = false) {
|
|
129
130
|
const result = await runWrapperCommand(args, options);
|
|
130
131
|
const combined = result.stdout.trim() || result.stderr.trim();
|
|
@@ -134,6 +135,14 @@ async function parseCliJson(args, options, allowNonZero = false) {
|
|
|
134
135
|
if (combined.length === 0) {
|
|
135
136
|
throw new Error("Command completed without JSON output.");
|
|
136
137
|
}
|
|
138
|
+
// On a successful (or tolerated-nonzero) call we parse stdout for the JSON
|
|
139
|
+
// payload and otherwise discard stderr. Surface any captured stderr as a
|
|
140
|
+
// tail so subprocess diagnostics (warnings, structured stderr lines) are not
|
|
141
|
+
// lost when the command still succeeded.
|
|
142
|
+
const stderrTail = result.stderr.trim();
|
|
143
|
+
if (stderrTail.length > 0) {
|
|
144
|
+
process.stderr.write(`[audit-code] mcp: subprocess stderr: ${stderrTail.slice(-SUBPROCESS_STDERR_TAIL_CHARS)}\n`);
|
|
145
|
+
}
|
|
137
146
|
try {
|
|
138
147
|
return JSON.parse(result.stdout);
|
|
139
148
|
}
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { decideNextStep, findObligation } from "./nextStep.js";
|
|
2
2
|
import { deriveAuditState } from "./state.js";
|
|
3
3
|
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
|
-
import { runIntakeExecutor
|
|
4
|
+
import { runIntakeExecutor } from "./intakeExecutors.js";
|
|
5
|
+
import { runStructureExecutor, runDesignAssessmentExecutor, runDesignReviewAutoComplete, } from "./structureExecutors.js";
|
|
6
|
+
import { runPlanningExecutor } from "./planningExecutors.js";
|
|
7
|
+
import { runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runExternalAnalyzerImportExecutor, } from "./ingestionExecutors.js";
|
|
8
|
+
import { runSynthesisExecutor, runSynthesisNarrativeExecutor, } from "./synthesisExecutors.js";
|
|
5
9
|
import { runAutoFixExecutor } from "./autoFixExecutor.js";
|
|
6
10
|
import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
|
|
7
11
|
import { runGraphEnrichmentExecutor } from "./graphEnrichmentExecutor.js";
|
|
8
12
|
import { resolveAuditScope } from "./scope.js";
|
|
9
13
|
import { RunLogger } from "@audit-tools/shared";
|
|
14
|
+
/**
|
|
15
|
+
* Narrow an optional root to a definite string for an executor that requires
|
|
16
|
+
* it, throwing the canonical "advanceAudit <executor> requires root" error
|
|
17
|
+
* otherwise. Replaces the guard previously copy-pasted across every
|
|
18
|
+
* root-dependent executor branch below.
|
|
19
|
+
*/
|
|
20
|
+
function requireRoot(root, executorName) {
|
|
21
|
+
if (!root) {
|
|
22
|
+
throw new Error(`advanceAudit ${executorName} requires root`);
|
|
23
|
+
}
|
|
24
|
+
return root;
|
|
25
|
+
}
|
|
10
26
|
function cloneState(state) {
|
|
11
27
|
return {
|
|
12
28
|
...state,
|
|
@@ -63,11 +79,11 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
63
79
|
});
|
|
64
80
|
try {
|
|
65
81
|
switch (selectedExecutor) {
|
|
66
|
-
case "intake_executor":
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
run = await runIntakeExecutor(bundle, options.root);
|
|
82
|
+
case "intake_executor": {
|
|
83
|
+
const root = requireRoot(options.root, "intake_executor");
|
|
84
|
+
run = await runIntakeExecutor(bundle, root);
|
|
70
85
|
break;
|
|
86
|
+
}
|
|
71
87
|
case "structure_executor":
|
|
72
88
|
run = await runStructureExecutor(bundle, options.root);
|
|
73
89
|
break;
|
|
@@ -85,26 +101,26 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
85
101
|
case "design_review":
|
|
86
102
|
run = runDesignReviewAutoComplete(bundle);
|
|
87
103
|
break;
|
|
88
|
-
case "planning_executor":
|
|
89
|
-
|
|
90
|
-
throw new Error("advanceAudit planning_executor requires root");
|
|
104
|
+
case "planning_executor": {
|
|
105
|
+
const root = requireRoot(options.root, "planning_executor");
|
|
91
106
|
plannedScope = resolveAuditScope({
|
|
92
|
-
root
|
|
107
|
+
root,
|
|
93
108
|
since: options.since,
|
|
94
109
|
bundle,
|
|
95
110
|
});
|
|
96
|
-
run = await runPlanningExecutor(bundle,
|
|
111
|
+
run = await runPlanningExecutor(bundle, root, options.lineIndex ?? {}, options.sizeIndex, plannedScope);
|
|
97
112
|
break;
|
|
113
|
+
}
|
|
98
114
|
case "result_ingestion_executor":
|
|
99
115
|
run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
|
|
100
116
|
break;
|
|
101
|
-
case "runtime_validation_executor":
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
run = await runRuntimeValidationExecutor(bundle, options.root, {
|
|
117
|
+
case "runtime_validation_executor": {
|
|
118
|
+
const root = requireRoot(options.root, "runtime_validation_executor");
|
|
119
|
+
run = await runRuntimeValidationExecutor(bundle, root, {
|
|
105
120
|
opentoken: options.opentoken,
|
|
106
121
|
});
|
|
107
122
|
break;
|
|
123
|
+
}
|
|
108
124
|
case "synthesis_executor":
|
|
109
125
|
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
110
126
|
break;
|
|
@@ -121,16 +137,16 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
121
137
|
throw new Error("advanceAudit external_analyzer_import_executor requires externalAnalyzerResults");
|
|
122
138
|
run = runExternalAnalyzerImportExecutor(bundle, options.externalAnalyzerResults);
|
|
123
139
|
break;
|
|
124
|
-
case "auto_fix_executor":
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
run = runAutoFixExecutor(bundle, options.root);
|
|
140
|
+
case "auto_fix_executor": {
|
|
141
|
+
const root = requireRoot(options.root, "auto_fix_executor");
|
|
142
|
+
run = await runAutoFixExecutor(bundle, root);
|
|
128
143
|
break;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
run = runSyntaxResolutionExecutor(bundle,
|
|
144
|
+
}
|
|
145
|
+
case "syntax_resolution_executor": {
|
|
146
|
+
const root = requireRoot(options.root, "syntax_resolution_executor");
|
|
147
|
+
run = runSyntaxResolutionExecutor(bundle, root);
|
|
133
148
|
break;
|
|
149
|
+
}
|
|
134
150
|
default: {
|
|
135
151
|
const state = deriveAuditState(bundle);
|
|
136
152
|
state.last_executor = selectedExecutor;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { ARTIFACT_DEPENDENTS_MAP } from "./dependencyMap.js";
|
|
3
3
|
export function stableStringify(value) {
|
|
4
4
|
if (value === undefined) {
|
|
5
5
|
return "null";
|
|
@@ -15,9 +15,19 @@ export function stableStringify(value) {
|
|
|
15
15
|
.sort(([a], [b]) => a.localeCompare(b));
|
|
16
16
|
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
|
|
17
17
|
}
|
|
18
|
+
// Artifacts that stamp a wall-clock `generated_at` on every (re)build. The
|
|
19
|
+
// timestamp is provenance, not content: two rebuilds with identical data but
|
|
20
|
+
// different timestamps must hash equal, or the artifact's revision churns every
|
|
21
|
+
// rebuild and perpetually re-stales its downstreams (e.g. audit-report.md
|
|
22
|
+
// depends on design_assessment) — a finalization-oscillation hazard.
|
|
23
|
+
const GENERATED_AT_STRIPPED_ARTIFACTS = new Set([
|
|
24
|
+
"repo_manifest.json",
|
|
25
|
+
"tooling_manifest.json",
|
|
26
|
+
"audit_plan_metrics.json",
|
|
27
|
+
"design_assessment.json",
|
|
28
|
+
]);
|
|
18
29
|
export function normalizeForMetadataHash(artifactName, value) {
|
|
19
|
-
if ((artifactName
|
|
20
|
-
artifactName === "tooling_manifest.json") &&
|
|
30
|
+
if (GENERATED_AT_STRIPPED_ARTIFACTS.has(artifactName) &&
|
|
21
31
|
value &&
|
|
22
32
|
typeof value === "object" &&
|
|
23
33
|
!Array.isArray(value)) {
|
|
@@ -34,7 +44,7 @@ export function hashArtifactValue(artifactName, value) {
|
|
|
34
44
|
}
|
|
35
45
|
export function buildReverseDependencyMap() {
|
|
36
46
|
const reverse = {};
|
|
37
|
-
for (const [upstream, downstreamList] of Object.entries(
|
|
47
|
+
for (const [upstream, downstreamList] of Object.entries(ARTIFACT_DEPENDENTS_MAP)) {
|
|
38
48
|
reverse[upstream] ??= [];
|
|
39
49
|
for (const downstream of downstreamList) {
|
|
40
50
|
reverse[downstream] ??= [];
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
-
import type { ExecutorRunResult } from "./
|
|
3
|
-
export declare function runAutoFixExecutor(bundle: ArtifactBundle, root: string): ExecutorRunResult
|
|
2
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
3
|
+
export declare function runAutoFixExecutor(bundle: ArtifactBundle, root: string): Promise<ExecutorRunResult>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isAuditExcludedStatus } from "../extractors/disposition.js";
|
|
4
4
|
import { resolveNodeTool, runFirstAvailableCommand, } from "./localCommands.js";
|
|
@@ -19,23 +19,31 @@ const PRETTIER_CONFIG_FILES = [
|
|
|
19
19
|
"prettier.config.cjs",
|
|
20
20
|
"prettier.config.mjs",
|
|
21
21
|
];
|
|
22
|
-
function
|
|
23
|
-
|
|
22
|
+
async function pathExists(target) {
|
|
23
|
+
try {
|
|
24
|
+
await access(target);
|
|
24
25
|
return true;
|
|
25
26
|
}
|
|
26
|
-
|
|
27
|
-
if (!existsSync(packageJsonPath)) {
|
|
27
|
+
catch {
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
|
+
}
|
|
31
|
+
async function hasPrettierConfig(root) {
|
|
32
|
+
const configChecks = await Promise.all(PRETTIER_CONFIG_FILES.map((file) => pathExists(join(root, file))));
|
|
33
|
+
if (configChecks.some(Boolean)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
const packageJsonPath = join(root, "package.json");
|
|
30
37
|
try {
|
|
31
|
-
const packageJson = JSON.parse(
|
|
38
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
32
39
|
return packageJson.prettier !== undefined;
|
|
33
40
|
}
|
|
34
41
|
catch {
|
|
42
|
+
// Missing package.json or unparseable JSON => no prettier config.
|
|
35
43
|
return false;
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
|
-
export function runAutoFixExecutor(bundle, root) {
|
|
46
|
+
export async function runAutoFixExecutor(bundle, root) {
|
|
39
47
|
if (!bundle.file_disposition) {
|
|
40
48
|
throw new Error("Cannot run auto fix executor without file_disposition");
|
|
41
49
|
}
|
|
@@ -49,8 +57,9 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
const executedTools = [];
|
|
60
|
+
const toolTimings = [];
|
|
52
61
|
// JS, TS, HTML, CSS, JSON, YAML, MD
|
|
53
|
-
if (hasPrettierConfig(root) &&
|
|
62
|
+
if ((await hasPrettierConfig(root)) &&
|
|
54
63
|
(extensions.has("ts") ||
|
|
55
64
|
extensions.has("js") ||
|
|
56
65
|
extensions.has("tsx") ||
|
|
@@ -61,16 +70,19 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
61
70
|
extensions.has("yml") ||
|
|
62
71
|
extensions.has("yaml") ||
|
|
63
72
|
extensions.has("md"))) {
|
|
73
|
+
const prettierStart = Date.now();
|
|
64
74
|
if (tryRunConfiguredFormatter(root, [
|
|
65
75
|
...resolveNodeTool(root, join("node_modules", "prettier", "bin", "prettier.cjs"), ["--write", "."], "prettier --write ."),
|
|
66
76
|
{ command: "prettier", args: ["--write", "."], display: "prettier --write ." },
|
|
67
77
|
{ command: "npx", args: ["--yes", "prettier", "--write", "."], display: "npx --yes prettier --write ." },
|
|
68
78
|
])) {
|
|
69
79
|
executedTools.push("prettier");
|
|
80
|
+
toolTimings.push({ tool: "prettier", duration_ms: Date.now() - prettierStart });
|
|
70
81
|
}
|
|
71
82
|
}
|
|
72
83
|
// Python
|
|
73
84
|
if (extensions.has("py")) {
|
|
85
|
+
const blackStart = Date.now();
|
|
74
86
|
if (tryRunConfiguredFormatter(root, [
|
|
75
87
|
{ command: "black", args: ["."], display: "black ." },
|
|
76
88
|
{ command: "python", args: ["-m", "black", "."], display: "python -m black ." },
|
|
@@ -78,28 +90,34 @@ export function runAutoFixExecutor(bundle, root) {
|
|
|
78
90
|
{ command: "pipx", args: ["run", "black", "."], display: "pipx run black ." },
|
|
79
91
|
])) {
|
|
80
92
|
executedTools.push("black");
|
|
93
|
+
toolTimings.push({ tool: "black", duration_ms: Date.now() - blackStart });
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
// SQL
|
|
84
97
|
if (extensions.has("sql")) {
|
|
98
|
+
const sqlfluffStart = Date.now();
|
|
85
99
|
if (tryRunConfiguredFormatter(root, [
|
|
86
100
|
{ command: "sqlfluff", args: ["fix", "--force", "."], display: "sqlfluff fix --force ." },
|
|
87
101
|
{ command: "uvx", args: ["sqlfluff", "fix", "--force", "."], display: "uvx sqlfluff fix --force ." },
|
|
88
102
|
{ command: "pipx", args: ["run", "sqlfluff", "fix", "--force", "."], display: "pipx run sqlfluff fix --force ." },
|
|
89
103
|
])) {
|
|
90
104
|
executedTools.push("sqlfluff");
|
|
105
|
+
toolTimings.push({ tool: "sqlfluff", duration_ms: Date.now() - sqlfluffStart });
|
|
91
106
|
}
|
|
92
107
|
}
|
|
93
108
|
// Go
|
|
94
109
|
if (extensions.has("go")) {
|
|
110
|
+
const gofmtStart = Date.now();
|
|
95
111
|
if (tryRunConfiguredFormatter(root, [
|
|
96
112
|
{ command: "gofmt", args: ["-w", "."], display: "gofmt -w ." },
|
|
97
113
|
])) {
|
|
98
114
|
executedTools.push("gofmt");
|
|
115
|
+
toolTimings.push({ tool: "gofmt", duration_ms: Date.now() - gofmtStart });
|
|
99
116
|
}
|
|
100
117
|
}
|
|
101
118
|
const resultsArtifact = {
|
|
102
119
|
executed_tools: executedTools,
|
|
120
|
+
tool_timings: toolTimings,
|
|
103
121
|
timestamp: new Date().toISOString(),
|
|
104
122
|
};
|
|
105
123
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const
|
|
1
|
+
export declare const ARTIFACT_DEPENDENTS_MAP: Record<string, string[]>;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
// Invalidation map keyed by UPSTREAM artifact → the list of DOWNSTREAM
|
|
2
|
+
// artifacts that depend on it (and so become stale when it changes). The name
|
|
3
|
+
// reflects the actual direction: each entry's value is that key's *dependents*.
|
|
4
|
+
// `buildReverseDependencyMap` flips this to the "X depends on Y" view used by
|
|
5
|
+
// computeArtifactMetadata. (Renamed from the misleading ARTIFACT_DEPENDENCY_MAP,
|
|
6
|
+
// which read as "X's dependencies" — the opposite of what it stores.)
|
|
7
|
+
export const ARTIFACT_DEPENDENTS_MAP = {
|
|
2
8
|
"tooling_manifest.json": [
|
|
3
9
|
"repo_manifest.json",
|
|
4
10
|
],
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
+
/**
|
|
3
|
+
* Uniform result of running one audit executor: the updated artifact bundle, the
|
|
4
|
+
* artifact filenames it wrote (which drive metadata/staleness bookkeeping in
|
|
5
|
+
* advanceAudit), and a one-line human progress summary. Shared by every executor
|
|
6
|
+
* module so they need not depend on the internalExecutors barrel.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExecutorRunResult {
|
|
9
|
+
updated: ArtifactBundle;
|
|
10
|
+
artifacts_written: string[];
|
|
11
|
+
progress_summary: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph buckets in `graph_bundle.json` that carry file-to-file edges relevant to
|
|
3
|
+
* large-file anchoring. Named here (rather than inlined as bare strings in the
|
|
4
|
+
* collection loop) so the set of scanned buckets is a single typed source of
|
|
5
|
+
* truth and each bucket key doubles as a typed fallback edge `kind`. `as const`
|
|
6
|
+
* narrows the element type from `string` to the literal union.
|
|
7
|
+
*/
|
|
8
|
+
const GRAPH_EDGE_BUCKETS = ["imports", "calls", "references"];
|
|
1
9
|
const MAX_ANCHORS = 160;
|
|
2
10
|
const KEYWORD_PATTERN = /\b(auth|token|password|secret|permission|role|sql|query|exec|spawn|eval|deserialize|encrypt|decrypt|cache|retry|timeout|transaction|lock|race|TODO|FIXME)\b/i;
|
|
3
11
|
const SYMBOL_PATTERNS = [
|
|
@@ -85,8 +93,11 @@ function collectGraphEdges(graphBundle, path) {
|
|
|
85
93
|
}
|
|
86
94
|
const normalizedPath = normalizePath(path).toLowerCase();
|
|
87
95
|
const edges = [];
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
// Typed as `string` (not the literal union) so the lookup resolves through the
|
|
97
|
+
// `[key: string]: unknown` index signature on `graphs` — the loop body then
|
|
98
|
+
// re-validates each entry's shape, matching the original deterministic parse.
|
|
99
|
+
for (const bucket of GRAPH_EDGE_BUCKETS) {
|
|
100
|
+
const raw = graphBundle.graphs[bucket];
|
|
90
101
|
if (!Array.isArray(raw)) {
|
|
91
102
|
continue;
|
|
92
103
|
}
|
|
@@ -103,7 +114,7 @@ function collectGraphEdges(graphBundle, path) {
|
|
|
103
114
|
edges.push({
|
|
104
115
|
from: record.from,
|
|
105
116
|
to: record.to,
|
|
106
|
-
kind: typeof record.kind === "string" ? record.kind :
|
|
117
|
+
kind: typeof record.kind === "string" ? record.kind : bucket,
|
|
107
118
|
});
|
|
108
119
|
}
|
|
109
120
|
}
|
|
@@ -2,6 +2,7 @@ import type { RepoManifest } from "../types.js";
|
|
|
2
2
|
export interface FileIntegrityResult {
|
|
3
3
|
changed_files: string[];
|
|
4
4
|
missing_files: string[];
|
|
5
|
+
io_errors: string[];
|
|
5
6
|
is_clean: boolean;
|
|
6
7
|
}
|
|
7
8
|
export declare function checkFileIntegrity(root: string, manifest: RepoManifest, scope?: string[]): Promise<FileIntegrityResult>;
|
|
@@ -9,6 +9,7 @@ async function hashFile(absolutePath) {
|
|
|
9
9
|
export async function checkFileIntegrity(root, manifest, scope) {
|
|
10
10
|
const changed = [];
|
|
11
11
|
const missing = [];
|
|
12
|
+
const ioErrors = [];
|
|
12
13
|
const scopeSet = scope ? new Set(scope) : null;
|
|
13
14
|
const files = scopeSet
|
|
14
15
|
? manifest.files.filter((f) => scopeSet.has(f.path))
|
|
@@ -29,13 +30,21 @@ export async function checkFileIntegrity(root, manifest, scope) {
|
|
|
29
30
|
changed.push(record.path);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
catch {
|
|
33
|
-
|
|
33
|
+
catch (err) {
|
|
34
|
+
const code = err.code;
|
|
35
|
+
if (code === "ENOENT") {
|
|
36
|
+
missing.push(record.path);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.warn(`fileIntegrity: I/O error on ${record.path}: ${code ?? String(err)}`);
|
|
40
|
+
ioErrors.push(record.path);
|
|
41
|
+
}
|
|
34
42
|
}
|
|
35
43
|
}
|
|
36
44
|
return {
|
|
37
45
|
changed_files: changed,
|
|
38
46
|
missing_files: missing,
|
|
39
|
-
|
|
47
|
+
io_errors: ioErrors,
|
|
48
|
+
is_clean: changed.length === 0 && missing.length === 0 && ioErrors.length === 0,
|
|
40
49
|
};
|
|
41
50
|
}
|
|
@@ -45,8 +45,11 @@ export function buildFlowRequeueTasks(criticalFlows, flowCoverage, coverageMatri
|
|
|
45
45
|
? flow.paths.filter((path) => typeof path === "string")
|
|
46
46
|
: [];
|
|
47
47
|
for (const lensName of missingLenses) {
|
|
48
|
+
// Skip (rather than throw on) an unsupported lens value, consistent with
|
|
49
|
+
// the filter-based lens guards elsewhere in the orchestrator: a stray
|
|
50
|
+
// non-canonical lens in flow coverage should not abort the whole requeue.
|
|
48
51
|
if (!isLens(lensName)) {
|
|
49
|
-
|
|
52
|
+
continue;
|
|
50
53
|
}
|
|
51
54
|
for (const path of flowPaths) {
|
|
52
55
|
if (!fileStillNeedsLens(coverageByPath, path, lensName)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
-
import type { ExecutorRunResult } from "./
|
|
2
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
3
3
|
import type { AnalyzerSetting } from "@audit-tools/shared";
|
|
4
4
|
import type { LanguageAnalyzer } from "../extractors/analyzers/types.js";
|
|
5
5
|
import { type EdgeReasoningResults } from "./edgeReasoning.js";
|
|
@@ -133,7 +133,9 @@ export async function runGraphEnrichmentExecutor(bundle, options = {}) {
|
|
|
133
133
|
setting,
|
|
134
134
|
edges_added: 0,
|
|
135
135
|
routes_added: 0,
|
|
136
|
-
note:
|
|
136
|
+
note: error instanceof Error
|
|
137
|
+
? `Analyzer failed [${error.name}]: ${error.message}${error.stack ? ` — stack: ${error.stack.split("\n").slice(0, 4).join(" | ")}` : ""}`
|
|
138
|
+
: `Analyzer failed: ${String(error)}.`,
|
|
137
139
|
});
|
|
138
140
|
continue;
|
|
139
141
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
2
|
+
import type { AuditResult } from "../types.js";
|
|
3
|
+
import type { RuntimeValidationReport } from "../types/runtimeValidation.js";
|
|
4
|
+
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
5
|
+
import type { ExecutorRunResult } from "./executorResult.js";
|
|
6
|
+
export declare function runResultIngestionExecutor(bundle: ArtifactBundle, results: AuditResult[]): ExecutorRunResult;
|
|
7
|
+
export declare function runRuntimeValidationExecutor(bundle: ArtifactBundle, root: string, options?: {
|
|
8
|
+
opentoken?: boolean;
|
|
9
|
+
}): Promise<ExecutorRunResult>;
|
|
10
|
+
export declare function runRuntimeValidationUpdateExecutor(bundle: ArtifactBundle, updates: RuntimeValidationReport): ExecutorRunResult;
|
|
11
|
+
export declare function runExternalAnalyzerImportExecutor(bundle: ArtifactBundle, externalResults: ExternalAnalyzerResults): ExecutorRunResult;
|