auditor-lambda 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +11 -3
- package/dist/extractors/disposition.js +4 -1
- package/dist/extractors/flows.js +10 -2
- package/dist/extractors/pathPatterns.d.ts +2 -0
- package/dist/extractors/pathPatterns.js +23 -2
- package/dist/io/runArtifacts.js +11 -3
- package/dist/orchestrator/localCommands.js +16 -2
- package/dist/orchestrator/unitBuilder.js +31 -17
- package/dist/prompts/renderWorkerPrompt.js +7 -4
- package/dist/types.d.ts +1 -0
- package/dist/validation/auditResults.js +3 -3
- package/package.json +1 -1
- package/schemas/audit_result.schema.json +1 -1
- package/schemas/audit_task.schema.json +7 -0
package/dist/cli.js
CHANGED
|
@@ -287,6 +287,13 @@ function buildPendingAuditTasks(bundle) {
|
|
|
287
287
|
const completedTaskIds = new Set((bundle.audit_results ?? []).map((result) => result.task_id));
|
|
288
288
|
return (bundle.audit_tasks ?? []).filter((task) => task.status !== "complete" && !completedTaskIds.has(task.task_id));
|
|
289
289
|
}
|
|
290
|
+
async function addFileLineCountHints(root, tasks) {
|
|
291
|
+
const lineIndex = await buildLineIndexForPaths(root, tasks.flatMap((task) => task.file_paths));
|
|
292
|
+
return tasks.map((task) => ({
|
|
293
|
+
...task,
|
|
294
|
+
file_line_counts: Object.fromEntries(task.file_paths.map((path) => [path, lineIndex[path] ?? 0])),
|
|
295
|
+
}));
|
|
296
|
+
}
|
|
290
297
|
function formatAuditResultValidationError(issues) {
|
|
291
298
|
return (`audit-results validation failed with ${issues.length} error(s):\n` +
|
|
292
299
|
formatAuditResultIssues(issues));
|
|
@@ -731,7 +738,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
731
738
|
});
|
|
732
739
|
const blockRunId = buildRunId(obligationId, runCount + 1);
|
|
733
740
|
const blockPaths = getRunPaths(artifactsDir, blockRunId);
|
|
734
|
-
const blockPendingTasks = buildPendingAuditTasks(bundle).slice(0, agentBatchSize);
|
|
741
|
+
const blockPendingTasks = await addFileLineCountHints(root, buildPendingAuditTasks(bundle).slice(0, agentBatchSize));
|
|
735
742
|
const blockPendingTasksPath = join(blockPaths.runDir, "pending-audit-tasks.json");
|
|
736
743
|
const blockAuditResultsPath = join(blockPaths.runDir, "audit-results.json");
|
|
737
744
|
const blockTask = {
|
|
@@ -814,7 +821,8 @@ async function cmdRunToCompletion(argv) {
|
|
|
814
821
|
const allPendingTasks = buildPendingAuditTasks(bundle);
|
|
815
822
|
const taskGroups = chunkArray(allPendingTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
816
823
|
const workerSlots = [];
|
|
817
|
-
for (const
|
|
824
|
+
for (const rawGroup of taskGroups) {
|
|
825
|
+
const group = await addFileLineCountHints(root, rawGroup);
|
|
818
826
|
runCount += 1;
|
|
819
827
|
const slotRunId = buildRunId(obligationId, runCount);
|
|
820
828
|
const slotPaths = getRunPaths(artifactsDir, slotRunId);
|
|
@@ -1131,7 +1139,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1131
1139
|
continue;
|
|
1132
1140
|
}
|
|
1133
1141
|
const pendingAuditTasks = preferredExecutor === "agent"
|
|
1134
|
-
? buildPendingAuditTasks(bundle).slice(0, agentBatchSize)
|
|
1142
|
+
? await addFileLineCountHints(root, buildPendingAuditTasks(bundle).slice(0, agentBatchSize))
|
|
1135
1143
|
: undefined;
|
|
1136
1144
|
const pendingAuditTasksPath = preferredExecutor === "agent"
|
|
1137
1145
|
? join(paths.runDir, "pending-audit-tasks.json")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isAuditArtifactPath, isGeneratedInstallArtifactPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isAuditArtifactPath, isGeneratedInstallArtifactPath, isExamplesOrFixturesPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
3
|
const normalized = normalizeExtractorPath(path);
|
|
4
4
|
if (isNodeModulesOrGit(normalized)) {
|
|
@@ -43,6 +43,9 @@ function inferDisposition(path) {
|
|
|
43
43
|
reason: "Generated install/bootstrap artifact.",
|
|
44
44
|
};
|
|
45
45
|
}
|
|
46
|
+
if (isExamplesOrFixturesPath(normalized)) {
|
|
47
|
+
return { path, status: "doc_only", reason: "Examples and fixtures are support artifacts, not auditable code." };
|
|
48
|
+
}
|
|
46
49
|
return {
|
|
47
50
|
path,
|
|
48
51
|
status: "included",
|
package/dist/extractors/flows.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
-
import { EXTRACTOR_HEURISTIC_NOTE, isAsyncTaskPath, isBillingPath, isIdentityPath, isSecuritySensitivePath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
|
+
import { EXTRACTOR_HEURISTIC_NOTE, isAsyncTaskPath, isBillingPath, isIdentityPath, isSecuritySensitivePath, isTestPath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
3
3
|
function inferConcerns(paths) {
|
|
4
4
|
const concerns = new Set();
|
|
5
5
|
for (const path of paths) {
|
|
@@ -15,6 +15,12 @@ function inferConcerns(paths) {
|
|
|
15
15
|
}
|
|
16
16
|
return concerns.size > 0 ? [...concerns] : ["correctness"];
|
|
17
17
|
}
|
|
18
|
+
function isSchemaContractPath(normalized) {
|
|
19
|
+
return normalized.endsWith(".schema.json");
|
|
20
|
+
}
|
|
21
|
+
function isSupportArtifactPath(normalized) {
|
|
22
|
+
return isTestPath(normalized) || normalized.startsWith("examples/");
|
|
23
|
+
}
|
|
18
24
|
function relatedPaths(entry, availablePaths) {
|
|
19
25
|
const normalized = normalizeExtractorPath(entry);
|
|
20
26
|
const linked = new Set([entry]);
|
|
@@ -82,7 +88,9 @@ export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposi
|
|
|
82
88
|
}
|
|
83
89
|
for (const path of availablePaths) {
|
|
84
90
|
const normalized = normalizeExtractorPath(path);
|
|
85
|
-
if (isDataLayerPath(normalized)
|
|
91
|
+
if (isDataLayerPath(normalized) &&
|
|
92
|
+
!isSchemaContractPath(normalized) &&
|
|
93
|
+
!isSupportArtifactPath(normalized)) {
|
|
86
94
|
flows.push({
|
|
87
95
|
id: `flow:data:${path.replace(/[^a-zA-Z0-9:_-]/g, "-")}`,
|
|
88
96
|
name: `data evolution flow for ${path}`,
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare const EXTRACTOR_HEURISTIC_NOTE = "Heuristic path classification normalizes case and path separators, then matches conservative keyword groups; confirm unusual repo layouts manually.";
|
|
7
7
|
export declare function normalizeExtractorPath(path: string): string;
|
|
8
|
+
export declare function pathTokens(normalized: string): string[];
|
|
8
9
|
export declare function isNodeModulesOrGit(normalized: string): boolean;
|
|
9
10
|
export declare function isBuildOutput(normalized: string): boolean;
|
|
10
11
|
export declare function isVendorPath(normalized: string): boolean;
|
|
@@ -20,6 +21,7 @@ export declare function isInterfacePath(normalized: string): boolean;
|
|
|
20
21
|
export declare function isDataLayerPath(normalized: string): boolean;
|
|
21
22
|
export declare function isSecuritySensitivePath(normalized: string): boolean;
|
|
22
23
|
export declare function isConcurrencyPath(normalized: string): boolean;
|
|
24
|
+
export declare function isExamplesOrFixturesPath(normalized: string): boolean;
|
|
23
25
|
export declare function isScriptPath(normalized: string): boolean;
|
|
24
26
|
export declare function isDeploymentConfigPath(normalized: string): boolean;
|
|
25
27
|
export declare function isGeneratedPath(normalized: string): boolean;
|
|
@@ -32,11 +32,17 @@ const SECURITY_KEYWORDS = [
|
|
|
32
32
|
];
|
|
33
33
|
const CONCURRENCY_KEYWORDS = [
|
|
34
34
|
"queue",
|
|
35
|
+
"queues",
|
|
35
36
|
"worker",
|
|
37
|
+
"workers",
|
|
36
38
|
"job",
|
|
39
|
+
"jobs",
|
|
37
40
|
"cache",
|
|
41
|
+
"caches",
|
|
38
42
|
"retry",
|
|
43
|
+
"retries",
|
|
39
44
|
"lock",
|
|
45
|
+
"locks",
|
|
40
46
|
];
|
|
41
47
|
const SCRIPT_KEYWORDS = ["script"];
|
|
42
48
|
const DEPLOYMENT_KEYWORDS = [
|
|
@@ -75,6 +81,13 @@ function baseName(normalized) {
|
|
|
75
81
|
const segments = splitSegments(normalized);
|
|
76
82
|
return segments.at(-1) ?? normalized;
|
|
77
83
|
}
|
|
84
|
+
export function pathTokens(normalized) {
|
|
85
|
+
return normalized.split(/[^a-z0-9]+/).filter(Boolean);
|
|
86
|
+
}
|
|
87
|
+
function hasToken(normalized, values) {
|
|
88
|
+
const tokens = new Set(pathTokens(normalized));
|
|
89
|
+
return values.some((value) => tokens.has(value));
|
|
90
|
+
}
|
|
78
91
|
export function isNodeModulesOrGit(normalized) {
|
|
79
92
|
return hasSegment(normalized, "node_modules") || hasSegment(normalized, ".git");
|
|
80
93
|
}
|
|
@@ -113,13 +126,21 @@ export function isInterfacePath(normalized) {
|
|
|
113
126
|
return includesAny(normalized, INTERFACE_KEYWORDS) || hasSegment(normalized, "api");
|
|
114
127
|
}
|
|
115
128
|
export function isDataLayerPath(normalized) {
|
|
116
|
-
return
|
|
129
|
+
return (hasToken(normalized, DATA_LAYER_KEYWORDS) ||
|
|
130
|
+
hasSegment(normalized, "models") ||
|
|
131
|
+
hasSegment(normalized, "schemas") ||
|
|
132
|
+
hasSegment(normalized, "migrations") ||
|
|
133
|
+
hasSegment(normalized, "seeds") ||
|
|
134
|
+
hasSegment(normalized, "db"));
|
|
117
135
|
}
|
|
118
136
|
export function isSecuritySensitivePath(normalized) {
|
|
119
137
|
return includesAny(normalized, SECURITY_KEYWORDS);
|
|
120
138
|
}
|
|
121
139
|
export function isConcurrencyPath(normalized) {
|
|
122
|
-
return
|
|
140
|
+
return hasToken(normalized, CONCURRENCY_KEYWORDS);
|
|
141
|
+
}
|
|
142
|
+
export function isExamplesOrFixturesPath(normalized) {
|
|
143
|
+
return hasSegment(normalized, "examples") || hasSegment(normalized, "fixtures");
|
|
123
144
|
}
|
|
124
145
|
export function isScriptPath(normalized) {
|
|
125
146
|
return (includesAny(normalized, SCRIPT_KEYWORDS) ||
|
package/dist/io/runArtifacts.js
CHANGED
|
@@ -5,10 +5,12 @@ import { writeJsonFile } from "./json.js";
|
|
|
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");
|
|
8
|
+
const findingSchemaPath = join(packageRoot, "schemas", "finding.schema.json");
|
|
8
9
|
const CURRENT_TASK_FILENAME = "current-task.json";
|
|
9
10
|
const CURRENT_PROMPT_FILENAME = "current-prompt.md";
|
|
10
11
|
const CURRENT_TASKS_FILENAME = "current-tasks.json";
|
|
11
12
|
const CURRENT_SCHEMA_FILENAME = "audit-result.schema.json";
|
|
13
|
+
const CURRENT_FINDING_SCHEMA_FILENAME = "finding.schema.json";
|
|
12
14
|
function pad(value, size = 2) {
|
|
13
15
|
return String(value).padStart(size, "0");
|
|
14
16
|
}
|
|
@@ -53,6 +55,11 @@ export async function ensureSupervisorDirs(artifactsDir) {
|
|
|
53
55
|
await mkdir(join(artifactsDir, "dispatch"), { recursive: true });
|
|
54
56
|
await mkdir(join(artifactsDir, "runs"), { recursive: true });
|
|
55
57
|
}
|
|
58
|
+
async function writeDispatchSchemaFiles(artifactsDir) {
|
|
59
|
+
const dispatchDir = join(artifactsDir, "dispatch");
|
|
60
|
+
await writeFile(join(dispatchDir, CURRENT_SCHEMA_FILENAME), await readFile(auditResultSchemaPath, "utf8"), "utf8");
|
|
61
|
+
await writeFile(join(dispatchDir, CURRENT_FINDING_SCHEMA_FILENAME), await readFile(findingSchemaPath, "utf8"), "utf8");
|
|
62
|
+
}
|
|
56
63
|
export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, currentTasks, options = {}) {
|
|
57
64
|
await mkdir(paths.runDir, { recursive: true });
|
|
58
65
|
await writeJsonFile(paths.taskPath, task);
|
|
@@ -62,13 +69,13 @@ export async function writeWorkerTaskFiles(task, prompt, paths, artifactsDir, cu
|
|
|
62
69
|
status: "dispatched",
|
|
63
70
|
});
|
|
64
71
|
if (options.updateDispatch === false) {
|
|
65
|
-
await
|
|
72
|
+
await writeDispatchSchemaFiles(artifactsDir);
|
|
66
73
|
return;
|
|
67
74
|
}
|
|
68
75
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASK_FILENAME), task);
|
|
69
76
|
await writeFile(join(artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME), prompt, "utf8");
|
|
70
77
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME), currentTasks ?? []);
|
|
71
|
-
await
|
|
78
|
+
await writeDispatchSchemaFiles(artifactsDir);
|
|
72
79
|
}
|
|
73
80
|
export async function writeDispatchBatchFiles(artifactsDir, runs, currentTasks) {
|
|
74
81
|
const summary = {
|
|
@@ -104,7 +111,7 @@ export async function writeDispatchBatchFiles(artifactsDir, runs, currentTasks)
|
|
|
104
111
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASK_FILENAME), summary);
|
|
105
112
|
await writeFile(join(artifactsDir, "dispatch", CURRENT_PROMPT_FILENAME), promptLines.join("\n"), "utf8");
|
|
106
113
|
await writeJsonFile(join(artifactsDir, "dispatch", CURRENT_TASKS_FILENAME), currentTasks);
|
|
107
|
-
await
|
|
114
|
+
await writeDispatchSchemaFiles(artifactsDir);
|
|
108
115
|
}
|
|
109
116
|
export async function clearDispatchFiles(artifactsDir) {
|
|
110
117
|
const targets = [
|
|
@@ -112,6 +119,7 @@ export async function clearDispatchFiles(artifactsDir) {
|
|
|
112
119
|
CURRENT_PROMPT_FILENAME,
|
|
113
120
|
CURRENT_TASKS_FILENAME,
|
|
114
121
|
CURRENT_SCHEMA_FILENAME,
|
|
122
|
+
CURRENT_FINDING_SCHEMA_FILENAME,
|
|
115
123
|
];
|
|
116
124
|
for (const name of targets) {
|
|
117
125
|
await rm(join(artifactsDir, "dispatch", name), { force: true });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { delimiter, isAbsolute, join } from "node:path";
|
|
3
|
+
import { delimiter, extname, isAbsolute, join } from "node:path";
|
|
4
4
|
function isWindowsBatchCommand(path) {
|
|
5
5
|
return process.platform === "win32" && /\.(cmd|bat)$/i.test(path);
|
|
6
6
|
}
|
|
@@ -45,10 +45,24 @@ function resolveFromPath(command) {
|
|
|
45
45
|
const extensions = process.platform === "win32"
|
|
46
46
|
? (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
|
|
47
47
|
.split(";")
|
|
48
|
-
.map((ext) => ext.toLowerCase())
|
|
48
|
+
.map((ext) => ext.trim().toLowerCase())
|
|
49
|
+
.filter((ext) => ext.length > 0)
|
|
50
|
+
.map((ext) => (ext.startsWith(".") ? ext : `.${ext}`))
|
|
49
51
|
: [""];
|
|
50
52
|
for (const dir of pathEntries) {
|
|
51
53
|
const directPath = join(dir, command);
|
|
54
|
+
if (process.platform === "win32" && extname(command).length === 0) {
|
|
55
|
+
for (const ext of extensions) {
|
|
56
|
+
const candidatePath = join(dir, `${command}${ext}`);
|
|
57
|
+
if (existsSync(candidatePath)) {
|
|
58
|
+
return candidatePath;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (existsSync(directPath)) {
|
|
62
|
+
return directPath;
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
52
66
|
if (existsSync(directPath)) {
|
|
53
67
|
return directPath;
|
|
54
68
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { bucketFile } from "../extractors/bucketing.js";
|
|
2
2
|
import { isAuditExcludedStatus } from "../extractors/disposition.js";
|
|
3
|
+
import { pathTokens, normalizeExtractorPath } from "../extractors/pathPatterns.js";
|
|
3
4
|
const LENS_MAP = {
|
|
4
5
|
runtime: ["correctness", "maintainability", "tests"],
|
|
5
6
|
interface: ["correctness", "security", "reliability", "tests"],
|
|
@@ -50,13 +51,20 @@ function inferUnitId(path, kind) {
|
|
|
50
51
|
if ((parts[0] === "tests" || parts[0] === "test") && parts.length >= 2) {
|
|
51
52
|
return `tests-${parts[1]}`.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
52
53
|
}
|
|
53
|
-
if (parts.length >=
|
|
54
|
+
if (parts.length >= 3) {
|
|
54
55
|
return `${parts[0]}-${parts[1]}`.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
55
56
|
}
|
|
56
|
-
if (
|
|
57
|
+
if (parts.length === 2) {
|
|
58
|
+
return parts[0].replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
59
|
+
}
|
|
60
|
+
if (normalized.endsWith(".json") ||
|
|
61
|
+
normalized.endsWith(".yaml") ||
|
|
57
62
|
normalized.endsWith(".yml") ||
|
|
58
|
-
normalized.endsWith(".
|
|
59
|
-
|
|
63
|
+
normalized.endsWith(".toml") ||
|
|
64
|
+
normalized.endsWith(".sh") ||
|
|
65
|
+
normalized.includes("docker") ||
|
|
66
|
+
normalized.startsWith(".")) {
|
|
67
|
+
return "root-config";
|
|
60
68
|
}
|
|
61
69
|
return `${kind}-${path.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
|
|
62
70
|
}
|
|
@@ -75,6 +83,16 @@ function sortLenses(lenses) {
|
|
|
75
83
|
const set = new Set(lenses);
|
|
76
84
|
return LENS_ORDER.filter((lens) => set.has(lens));
|
|
77
85
|
}
|
|
86
|
+
function applyExtensionLensGuards(path, lenses) {
|
|
87
|
+
const n = path.toLowerCase();
|
|
88
|
+
if (n.endsWith(".schema.json") || n.endsWith(".schema.ts")) {
|
|
89
|
+
return lenses.filter((l) => l === "data_integrity");
|
|
90
|
+
}
|
|
91
|
+
if (n.endsWith(".json") || n.endsWith(".yaml") || n.endsWith(".yml")) {
|
|
92
|
+
return lenses.filter((l) => l !== "tests" && l !== "performance");
|
|
93
|
+
}
|
|
94
|
+
return lenses;
|
|
95
|
+
}
|
|
78
96
|
export function deriveRequiredLensesForPath(path) {
|
|
79
97
|
const assignment = bucketFile(path);
|
|
80
98
|
const required = new Set();
|
|
@@ -83,29 +101,25 @@ export function deriveRequiredLensesForPath(path) {
|
|
|
83
101
|
required.add(lens);
|
|
84
102
|
}
|
|
85
103
|
}
|
|
86
|
-
return sortLenses(required);
|
|
104
|
+
return applyExtensionLensGuards(path, sortLenses(required));
|
|
87
105
|
}
|
|
88
106
|
function inferCriticalFlows(files, requiredLenses) {
|
|
89
107
|
const flows = new Set();
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
combined.includes("session") ||
|
|
93
|
-
combined.includes("token")) {
|
|
108
|
+
const tokens = new Set(files.flatMap((f) => pathTokens(normalizeExtractorPath(f))));
|
|
109
|
+
if (tokens.has("auth") || tokens.has("session") || tokens.has("token")) {
|
|
94
110
|
flows.add("auth-session");
|
|
95
111
|
}
|
|
96
|
-
if (
|
|
97
|
-
combined.includes("invoice") ||
|
|
98
|
-
combined.includes("payment")) {
|
|
112
|
+
if (tokens.has("billing") || tokens.has("invoice") || tokens.has("payment")) {
|
|
99
113
|
flows.add("billing-payment");
|
|
100
114
|
}
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
115
|
+
if (tokens.has("queue") ||
|
|
116
|
+
tokens.has("worker") ||
|
|
117
|
+
tokens.has("job") ||
|
|
104
118
|
requiredLenses.includes("reliability")) {
|
|
105
119
|
flows.add("async-processing");
|
|
106
120
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
121
|
+
if (tokens.has("deploy") ||
|
|
122
|
+
tokens.has("docker") ||
|
|
109
123
|
requiredLenses.includes("config_deployment")) {
|
|
110
124
|
flows.add("deployment-config");
|
|
111
125
|
}
|
|
@@ -8,7 +8,7 @@ export function renderWorkerPrompt(task) {
|
|
|
8
8
|
const tasksPath = task.pending_audit_tasks_path ??
|
|
9
9
|
`${task.artifacts_dir}/audit_tasks.json`;
|
|
10
10
|
const lines = [
|
|
11
|
-
"You are executing one bounded audit
|
|
11
|
+
"You are executing one bounded audit run for audit-code.",
|
|
12
12
|
`Run ID: ${task.run_id}`,
|
|
13
13
|
`Repository root: ${task.repo_root}`,
|
|
14
14
|
"",
|
|
@@ -23,17 +23,20 @@ export function renderWorkerPrompt(task) {
|
|
|
23
23
|
" task_id, unit_id, pass_id, lens",
|
|
24
24
|
" file_coverage: [{path, total_lines}] for every assigned file you reviewed",
|
|
25
25
|
" findings: array (empty if nothing found)",
|
|
26
|
+
" If the task includes file_line_counts, use those values for file_coverage.total_lines.",
|
|
26
27
|
" total_lines must match the file's current total line count.",
|
|
27
28
|
" Each finding must include:",
|
|
28
|
-
" id, title, category, severity, confidence, lens, summary
|
|
29
|
-
"
|
|
29
|
+
" id, title, category, severity, confidence, lens, summary",
|
|
30
|
+
" affected_files: [{path, line_start?, line_end?, symbol?}] — path is repo-relative, NOT a plain string",
|
|
31
|
+
" evidence: array of plain strings only, at least one excerpt or line reference from the file you read",
|
|
30
32
|
" Example evidence entry: src/foo.ts:42 - variable overwritten before use",
|
|
33
|
+
" Example affected_files entry: {\"path\": \"src/foo.ts\", \"line_start\": 42, \"line_end\": 55, \"symbol\": \"myFunction\"}",
|
|
31
34
|
" Optional finding fields: impact, likelihood, reproduction, systemic, related_findings",
|
|
32
35
|
" Low-priority tasks still require a real review. Use findings: [] only when you genuinely found nothing notable.",
|
|
33
36
|
task.timeout_ms
|
|
34
37
|
? ` Time budget for this task: ${task.timeout_ms} ms.`
|
|
35
38
|
: " Keep the task bounded to the assigned files only.",
|
|
36
|
-
`Reference
|
|
39
|
+
`Reference schemas: ${task.artifacts_dir}/dispatch/audit-result.schema.json and ${task.artifacts_dir}/dispatch/finding.schema.json`,
|
|
37
40
|
`Write the AuditResult[] JSON array to: ${task.audit_results_path}`,
|
|
38
41
|
];
|
|
39
42
|
if (usesDeferredWorkerCommand(task)) {
|
package/dist/types.d.ts
CHANGED
|
@@ -306,12 +306,12 @@ export function validateAuditResults(results, tasks, options = {}) {
|
|
|
306
306
|
});
|
|
307
307
|
}
|
|
308
308
|
if (Number.isInteger(entry.total_lines) &&
|
|
309
|
-
Number(entry.total_lines)
|
|
309
|
+
Number(entry.total_lines) < 0) {
|
|
310
310
|
pushIssue(issues, {
|
|
311
311
|
result_index: i,
|
|
312
312
|
task_id: taskId,
|
|
313
313
|
field: `file_coverage[${j}].total_lines`,
|
|
314
|
-
message: "file_coverage total_lines must be
|
|
314
|
+
message: "file_coverage total_lines must be zero or greater.",
|
|
315
315
|
});
|
|
316
316
|
}
|
|
317
317
|
const expectedLineCount = typeof entry.path === "string"
|
|
@@ -330,7 +330,7 @@ export function validateAuditResults(results, tasks, options = {}) {
|
|
|
330
330
|
}
|
|
331
331
|
if (isNonEmptyString(entry.path) &&
|
|
332
332
|
Number.isInteger(entry.total_lines) &&
|
|
333
|
-
Number(entry.total_lines)
|
|
333
|
+
Number(entry.total_lines) >= 0) {
|
|
334
334
|
normalizedFileCoverage.push({
|
|
335
335
|
path: entry.path,
|
|
336
336
|
total_lines: Number(entry.total_lines),
|
package/package.json
CHANGED