auditor-lambda 0.8.0 → 0.9.1
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 +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/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.js +14 -563
- 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 +139 -73
- package/dist/extractors/pathPatterns.js +17 -5
- 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 +37 -22
- package/dist/orchestrator/artifactFreshness.js +2 -2
- package/dist/orchestrator/autoFixExecutor.d.ts +1 -1
- package/dist/orchestrator/autoFixExecutor.js +16 -8
- package/dist/orchestrator/dependencyMap.d.ts +1 -1
- package/dist/orchestrator/dependencyMap.js +7 -1
- package/dist/orchestrator/fileAnchors.js +14 -3
- package/dist/orchestrator/flowCoverage.js +1 -0
- package/dist/orchestrator/flowRequeue.js +4 -1
- package/dist/orchestrator/{internalExecutors.d.ts → ingestionExecutors.d.ts} +0 -6
- 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/runtimeCommand.js +7 -15
- 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/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/package.json +4 -3
- package/schemas/audit_findings.schema.json +3 -3
- package/schemas/critical_flows.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +1 -1
- package/schemas/graph_bundle.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.js +0 -424
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describeValue, formatValidationIssues, isRecord, } from "@audit-tools/shared";
|
|
1
|
+
import { describeValue, formatValidationIssues, isRecord, VALID_LENSES, VALID_SEVERITIES, VALID_CONFIDENCES, } from "@audit-tools/shared";
|
|
2
2
|
export function normalizeCoveragePath(path) {
|
|
3
3
|
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4
4
|
}
|
|
@@ -11,23 +11,11 @@ const REQUIRED_FINDING_FIELDS = [
|
|
|
11
11
|
"lens",
|
|
12
12
|
"summary",
|
|
13
13
|
];
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// Severity / confidence / lens validity now come from the canonical shared
|
|
15
|
+
// vocabulary (`@audit-tools/shared`); previously each was re-defined here and
|
|
16
|
+
// drifted from the shared Lens / FindingSeverity / FindingConfidence types.
|
|
16
17
|
const VALID_PRIORITIES = new Set(["high", "medium", "low"]);
|
|
17
18
|
const LENS_VERIFICATION_TAG = "lens_verification";
|
|
18
|
-
const VALID_LENSES = new Set([
|
|
19
|
-
"correctness",
|
|
20
|
-
"architecture",
|
|
21
|
-
"maintainability",
|
|
22
|
-
"security",
|
|
23
|
-
"reliability",
|
|
24
|
-
"performance",
|
|
25
|
-
"data_integrity",
|
|
26
|
-
"tests",
|
|
27
|
-
"operability",
|
|
28
|
-
"config_deployment",
|
|
29
|
-
"observability",
|
|
30
|
-
]);
|
|
31
19
|
function pushIssue(issues, params) {
|
|
32
20
|
issues.push({
|
|
33
21
|
...params,
|
|
@@ -77,20 +65,12 @@ function validateExpectedStringField(value, label, expected, taskId, resultIndex
|
|
|
77
65
|
});
|
|
78
66
|
}
|
|
79
67
|
}
|
|
80
|
-
function
|
|
81
|
-
const issues = [];
|
|
82
|
-
if (!isRecord(finding)) {
|
|
83
|
-
pushIssue(issues, {
|
|
84
|
-
result_index: resultIndex,
|
|
85
|
-
task_id: taskId,
|
|
86
|
-
field: label,
|
|
87
|
-
message: `${label} must be an object, got ${describeValue(finding)}.`,
|
|
88
|
-
});
|
|
89
|
-
return issues;
|
|
90
|
-
}
|
|
68
|
+
function validateFindingRequiredFields(finding, label, taskId, resultIndex, issues) {
|
|
91
69
|
for (const field of REQUIRED_FINDING_FIELDS) {
|
|
92
70
|
validateRequiredStringField(finding[field], `${label}.${field}`, taskId, resultIndex, issues);
|
|
93
71
|
}
|
|
72
|
+
}
|
|
73
|
+
function validateFindingEnums(finding, label, taskId, resultIndex, issues) {
|
|
94
74
|
if (typeof finding.severity === "string" &&
|
|
95
75
|
!VALID_SEVERITIES.has(finding.severity)) {
|
|
96
76
|
pushIssue(issues, {
|
|
@@ -117,6 +97,8 @@ function validateFinding(finding, label, taskId, resultIndex) {
|
|
|
117
97
|
message: `Invalid lens '${finding.lens}'. Must be one of: ${[...VALID_LENSES].join(", ")}.`,
|
|
118
98
|
});
|
|
119
99
|
}
|
|
100
|
+
}
|
|
101
|
+
function validateAffectedFiles(finding, label, taskId, resultIndex, issues) {
|
|
120
102
|
const affectedFiles = finding.affected_files;
|
|
121
103
|
if (!Array.isArray(affectedFiles) || affectedFiles.length === 0) {
|
|
122
104
|
pushIssue(issues, {
|
|
@@ -125,57 +107,58 @@ function validateFinding(finding, label, taskId, resultIndex) {
|
|
|
125
107
|
field: `${label}.affected_files`,
|
|
126
108
|
message: "affected_files must be a non-empty array.",
|
|
127
109
|
});
|
|
110
|
+
return;
|
|
128
111
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
});
|
|
176
|
-
}
|
|
112
|
+
for (let k = 0; k < affectedFiles.length; k++) {
|
|
113
|
+
const item = affectedFiles[k];
|
|
114
|
+
if (!isRecord(item)) {
|
|
115
|
+
pushIssue(issues, {
|
|
116
|
+
result_index: resultIndex,
|
|
117
|
+
task_id: taskId,
|
|
118
|
+
field: `${label}.affected_files[${k}]`,
|
|
119
|
+
message: `affected_files[${k}] must be an object, got ${describeValue(item)}.`,
|
|
120
|
+
});
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (!isNonEmptyString(item.path)) {
|
|
124
|
+
pushIssue(issues, {
|
|
125
|
+
result_index: resultIndex,
|
|
126
|
+
task_id: taskId,
|
|
127
|
+
field: `${label}.affected_files[${k}].path`,
|
|
128
|
+
message: "affected_files entry has an empty path.",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (item.line_start !== undefined &&
|
|
132
|
+
!Number.isInteger(item.line_start)) {
|
|
133
|
+
pushIssue(issues, {
|
|
134
|
+
result_index: resultIndex,
|
|
135
|
+
task_id: taskId,
|
|
136
|
+
field: `${label}.affected_files[${k}].line_start`,
|
|
137
|
+
message: `affected_files[${k}].line_start must be an integer, got ${describeValue(item.line_start)}.`,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (item.line_end !== undefined &&
|
|
141
|
+
!Number.isInteger(item.line_end)) {
|
|
142
|
+
pushIssue(issues, {
|
|
143
|
+
result_index: resultIndex,
|
|
144
|
+
task_id: taskId,
|
|
145
|
+
field: `${label}.affected_files[${k}].line_end`,
|
|
146
|
+
message: `affected_files[${k}].line_end must be an integer, got ${describeValue(item.line_end)}.`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
if (Number.isInteger(item.line_start) &&
|
|
150
|
+
Number.isInteger(item.line_end) &&
|
|
151
|
+
Number(item.line_start) > Number(item.line_end)) {
|
|
152
|
+
pushIssue(issues, {
|
|
153
|
+
result_index: resultIndex,
|
|
154
|
+
task_id: taskId,
|
|
155
|
+
field: `${label}.affected_files[${k}]`,
|
|
156
|
+
message: "affected_files line_start must be less than or equal to line_end.",
|
|
157
|
+
});
|
|
177
158
|
}
|
|
178
159
|
}
|
|
160
|
+
}
|
|
161
|
+
function validateEvidence(finding, label, taskId, resultIndex, issues) {
|
|
179
162
|
const evidence = finding.evidence;
|
|
180
163
|
if (!Array.isArray(evidence) || evidence.length === 0) {
|
|
181
164
|
pushIssue(issues, {
|
|
@@ -184,33 +167,52 @@ function validateFinding(finding, label, taskId, resultIndex) {
|
|
|
184
167
|
field: `${label}.evidence`,
|
|
185
168
|
message: "evidence is empty — provide an array of plain strings such as \"src/foo.ts:42 - variable overwritten before use\".",
|
|
186
169
|
});
|
|
170
|
+
return;
|
|
187
171
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (typeof entry !== "string") {
|
|
193
|
-
pushIssue(issues, {
|
|
194
|
-
result_index: resultIndex,
|
|
195
|
-
task_id: taskId,
|
|
196
|
-
field: `${label}.evidence[${k}]`,
|
|
197
|
-
message: `evidence[${k}] must be a string, got ${describeValue(entry)}.`,
|
|
198
|
-
});
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (entry.trim().length > 0) {
|
|
202
|
-
hasSubstantiveEntry = true;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
if (!hasSubstantiveEntry) {
|
|
172
|
+
let hasSubstantiveEntry = false;
|
|
173
|
+
for (let k = 0; k < evidence.length; k++) {
|
|
174
|
+
const entry = evidence[k];
|
|
175
|
+
if (typeof entry !== "string") {
|
|
206
176
|
pushIssue(issues, {
|
|
207
177
|
result_index: resultIndex,
|
|
208
178
|
task_id: taskId,
|
|
209
|
-
field: `${label}.evidence`,
|
|
210
|
-
message:
|
|
179
|
+
field: `${label}.evidence[${k}]`,
|
|
180
|
+
message: `evidence[${k}] must be a string, got ${describeValue(entry)}.`,
|
|
211
181
|
});
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (entry.trim().length > 0) {
|
|
185
|
+
hasSubstantiveEntry = true;
|
|
212
186
|
}
|
|
213
187
|
}
|
|
188
|
+
if (!hasSubstantiveEntry) {
|
|
189
|
+
pushIssue(issues, {
|
|
190
|
+
result_index: resultIndex,
|
|
191
|
+
task_id: taskId,
|
|
192
|
+
field: `${label}.evidence`,
|
|
193
|
+
message: "All evidence entries are empty strings.",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// Thin orchestrator: validates one finding by delegating to the per-concern
|
|
198
|
+
// validators (object-shape, required strings, enums, affected_files, evidence),
|
|
199
|
+
// each of which pushes into the shared issues array. Behavior and messages are
|
|
200
|
+
// identical to the former single 165-line function.
|
|
201
|
+
function validateFinding(finding, label, taskId, resultIndex) {
|
|
202
|
+
const issues = [];
|
|
203
|
+
if (!isRecord(finding)) {
|
|
204
|
+
pushIssue(issues, {
|
|
205
|
+
result_index: resultIndex,
|
|
206
|
+
task_id: taskId,
|
|
207
|
+
field: label,
|
|
208
|
+
message: `${label} must be an object, got ${describeValue(finding)}.`,
|
|
209
|
+
});
|
|
210
|
+
return issues;
|
|
211
|
+
}
|
|
212
|
+
validateFindingRequiredFields(finding, label, taskId, resultIndex, issues);
|
|
213
|
+
validateFindingEnums(finding, label, taskId, resultIndex, issues);
|
|
214
|
+
validateAffectedFiles(finding, label, taskId, resultIndex, issues);
|
|
215
|
+
validateEvidence(finding, label, taskId, resultIndex, issues);
|
|
214
216
|
return issues;
|
|
215
217
|
}
|
|
216
218
|
function validateOptionalStringArray(value, label, taskId, resultIndex, issues) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SessionConfig, type ValidationIssue } from "@audit-tools/shared";
|
|
2
2
|
export declare function validateSessionConfig(value: unknown): ValidationIssue[];
|
|
3
3
|
export declare function validateConfiguredProviderEnvironment(sessionConfig: SessionConfig, options?: {
|
|
4
|
-
commandExists?: (command: string) => boolean
|
|
4
|
+
commandExists?: (command: string) => Promise<boolean>;
|
|
5
5
|
pathExists?: (commandPath: string) => boolean;
|
|
6
|
-
}): ValidationIssue[]
|
|
6
|
+
}): Promise<ValidationIssue[]>;
|
|
7
7
|
export { formatValidationIssues } from "@audit-tools/shared";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
2
|
import { accessSync, constants } from "node:fs";
|
|
3
|
+
import { promisify } from "node:util";
|
|
3
4
|
import { ANALYZER_SETTINGS, PROVIDER_NAMES, SESSION_UI_MODES, isRecord, pushValidationIssue, } from "@audit-tools/shared";
|
|
5
|
+
const execAsync = promisify(exec);
|
|
4
6
|
const VALID_PROVIDERS = new Set(PROVIDER_NAMES);
|
|
5
7
|
const VALID_UI_MODES = new Set(SESSION_UI_MODES);
|
|
6
8
|
const VALID_ANALYZER_SETTINGS = new Set(ANALYZER_SETTINGS);
|
|
@@ -80,10 +82,15 @@ function validateAgentProviderSection(value, path, issues) {
|
|
|
80
82
|
pushIssue(issues, `${path}.dangerously_skip_permissions`, "dangerously_skip_permissions must be a boolean when provided.");
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
|
-
function commandExists(command) {
|
|
85
|
+
async function commandExists(command) {
|
|
84
86
|
const lookupCommand = process.platform === "win32" ? "where" : "which";
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
try {
|
|
88
|
+
await execAsync(`${lookupCommand} ${command}`);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
87
94
|
}
|
|
88
95
|
function configuredPathExists(commandPath) {
|
|
89
96
|
try {
|
|
@@ -183,14 +190,14 @@ export function validateSessionConfig(value) {
|
|
|
183
190
|
}
|
|
184
191
|
return issues;
|
|
185
192
|
}
|
|
186
|
-
export function validateConfiguredProviderEnvironment(sessionConfig, options = {}) {
|
|
193
|
+
export async function validateConfiguredProviderEnvironment(sessionConfig, options = {}) {
|
|
187
194
|
const issues = [];
|
|
188
195
|
const lookupCommand = options.commandExists ?? commandExists;
|
|
189
196
|
const lookupPath = options.pathExists ?? configuredPathExists;
|
|
190
197
|
const provider = sessionConfig.provider ?? "local-subprocess";
|
|
191
198
|
if (provider === "claude-code") {
|
|
192
199
|
const command = sessionConfig.claude_code?.command ?? "claude";
|
|
193
|
-
if (isBareExecutableName(command) && !lookupCommand(command)) {
|
|
200
|
+
if (isBareExecutableName(command) && !(await lookupCommand(command))) {
|
|
194
201
|
pushIssue(issues, "claude_code.command", `Configured claude-code executable was not found on PATH: ${command}.`);
|
|
195
202
|
}
|
|
196
203
|
else if (isDirectExecutablePath(command) && !lookupPath(command)) {
|
|
@@ -202,7 +209,7 @@ export function validateConfiguredProviderEnvironment(sessionConfig, options = {
|
|
|
202
209
|
}
|
|
203
210
|
if (provider === "opencode") {
|
|
204
211
|
const command = sessionConfig.opencode?.command ?? "opencode";
|
|
205
|
-
if (isBareExecutableName(command) && !lookupCommand(command)) {
|
|
212
|
+
if (isBareExecutableName(command) && !(await lookupCommand(command))) {
|
|
206
213
|
pushIssue(issues, "opencode.command", `Configured opencode executable was not found on PATH: ${command}.`);
|
|
207
214
|
}
|
|
208
215
|
else if (isDirectExecutablePath(command) && !lookupPath(command)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auditor-lambda",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Portable hybrid code-auditing framework for arbitrary repositories.",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"update-languages": "node scripts/update-languages.mjs",
|
|
24
24
|
"build": "tsc -p tsconfig.json",
|
|
25
25
|
"check": "tsc -p tsconfig.json --noEmit",
|
|
26
|
-
"test": "npm run build && node --test tests/*.test.mjs",
|
|
26
|
+
"test": "npm run build && node --import tsx/esm --test tests/*.test.mjs",
|
|
27
27
|
"release:patch": "node scripts/release-and-publish.mjs patch --bump-only",
|
|
28
28
|
"release:minor": "node scripts/release-and-publish.mjs minor --bump-only",
|
|
29
29
|
"release:major": "node scripts/release-and-publish.mjs major --bump-only",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"publishConfig": {
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
|
-
"homepage": "https://github.com/OhOkThisIsFine/audit-tools/tree/
|
|
56
|
+
"homepage": "https://github.com/OhOkThisIsFine/audit-tools/tree/main/packages/audit-code#readme",
|
|
57
57
|
"bugs": {
|
|
58
58
|
"url": "https://github.com/OhOkThisIsFine/audit-tools/issues"
|
|
59
59
|
},
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"ajv": "^8.17.1",
|
|
74
74
|
"linguist-languages": "^9.3.2",
|
|
75
75
|
"tree-sitter-wasms": "^0.1.13",
|
|
76
|
+
"tsx": "^4.19.0",
|
|
76
77
|
"typescript": "^5.9.2",
|
|
77
78
|
"web-tree-sitter": "^0.25.10"
|
|
78
79
|
}
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"enum": ["critical", "high", "medium", "low", "info"]
|
|
58
58
|
},
|
|
59
59
|
"confidence": { "type": "string", "enum": ["high", "medium", "low"] },
|
|
60
|
-
"lens": { "type": "string", "
|
|
60
|
+
"lens": { "type": "string", "enum": ["correctness", "architecture", "maintainability", "security", "reliability", "performance", "data_integrity", "tests", "operability", "config_deployment", "observability"] },
|
|
61
61
|
"summary": { "type": "string" },
|
|
62
62
|
"affected_files": {
|
|
63
63
|
"type": "array",
|
|
@@ -78,9 +78,9 @@
|
|
|
78
78
|
"impact": { "type": "string" },
|
|
79
79
|
"likelihood": { "type": "string" },
|
|
80
80
|
"evidence": { "type": "array", "minItems": 1, "items": { "type": "string" } },
|
|
81
|
-
"reproduction": { "type": "array", "items": { "type": "string" } },
|
|
81
|
+
"reproduction": { "type": "array", "minItems": 1, "items": { "type": "string" } },
|
|
82
82
|
"systemic": { "type": "boolean" },
|
|
83
|
-
"related_findings": { "type": "array", "items": { "type": "string" } },
|
|
83
|
+
"related_findings": { "type": "array", "minItems": 1, "items": { "type": "string" } },
|
|
84
84
|
"theme_id": { "type": "string" }
|
|
85
85
|
},
|
|
86
86
|
"additionalProperties": false
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "audit-code-dispatch-quota/v1alpha2",
|
|
4
4
|
"title": "DispatchQuota",
|
|
5
5
|
"description": "Quota schedule for a prepare-dispatch run. Written beside dispatch-plan.json. Hosts must launch at most wave_size packets per wave, then re-read this file before the next wave to pick up any updated limits.",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "step_contract.schema.json",
|
|
4
|
+
"title": "Audit Code Step Contract",
|
|
5
|
+
"description": "The step contract written to steps/current-step.json by audit-code. Describes one bounded step for the host agent to execute.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"contract_version",
|
|
9
|
+
"step_kind",
|
|
10
|
+
"prompt_path",
|
|
11
|
+
"status",
|
|
12
|
+
"run_id",
|
|
13
|
+
"allowed_commands",
|
|
14
|
+
"stop_condition",
|
|
15
|
+
"repo_root",
|
|
16
|
+
"artifacts_dir",
|
|
17
|
+
"artifact_paths"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"contract_version": { "const": "audit-code-step/v1alpha1" },
|
|
21
|
+
"step_kind": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"enum": [
|
|
24
|
+
"dispatch_review",
|
|
25
|
+
"single_task_fallback",
|
|
26
|
+
"design_review",
|
|
27
|
+
"analyzer_install",
|
|
28
|
+
"edge_reasoning",
|
|
29
|
+
"edge_reasoning_dispatch",
|
|
30
|
+
"synthesis_narrative",
|
|
31
|
+
"present_report",
|
|
32
|
+
"blocked"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"status": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": ["ready", "blocked", "complete"]
|
|
38
|
+
},
|
|
39
|
+
"prompt_path": { "type": "string" },
|
|
40
|
+
"run_id": { "type": ["string", "null"] },
|
|
41
|
+
"progress": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"required": ["summary"],
|
|
44
|
+
"properties": {
|
|
45
|
+
"summary": { "type": "string" },
|
|
46
|
+
"pending_packets": { "type": "integer" },
|
|
47
|
+
"pending_tasks": { "type": "integer" },
|
|
48
|
+
"completed_tasks": { "type": "integer" },
|
|
49
|
+
"wave_size": { "type": "integer" }
|
|
50
|
+
},
|
|
51
|
+
"additionalProperties": false
|
|
52
|
+
},
|
|
53
|
+
"allowed_commands": {
|
|
54
|
+
"type": "array",
|
|
55
|
+
"items": { "type": "string" }
|
|
56
|
+
},
|
|
57
|
+
"allowed_mcp_tools": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": { "type": "string" }
|
|
60
|
+
},
|
|
61
|
+
"stop_condition": { "type": "string" },
|
|
62
|
+
"repo_root": { "type": "string" },
|
|
63
|
+
"artifacts_dir": { "type": "string" },
|
|
64
|
+
"artifact_paths": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": { "type": ["string", "null"] }
|
|
67
|
+
},
|
|
68
|
+
"access": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["read_paths", "write_paths"],
|
|
71
|
+
"properties": {
|
|
72
|
+
"read_paths": { "type": "array", "items": { "type": "string" } },
|
|
73
|
+
"write_paths": { "type": "array", "items": { "type": "string" } },
|
|
74
|
+
"forbidden_patterns": { "type": "array", "items": { "type": "string" } }
|
|
75
|
+
},
|
|
76
|
+
"additionalProperties": false
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"additionalProperties": false
|
|
80
|
+
}
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -284,7 +284,6 @@ function mergeOpenCodeGlobalConfig(existing) {
|
|
|
284
284
|
const parsed = existing ? JSON.parse(existing) : {};
|
|
285
285
|
const auditPermission = renderOpenCodePermissionConfig();
|
|
286
286
|
const existingAuditor = objectValue(objectValue(parsed.agent).auditor);
|
|
287
|
-
const nodeExecPath = replaceBackslashes(process.execPath);
|
|
288
287
|
const pkgEntrypoint = replaceBackslashes(join(pkgRoot, 'audit-code.mjs'));
|
|
289
288
|
return {
|
|
290
289
|
...parsed,
|
|
@@ -303,7 +302,7 @@ function mergeOpenCodeGlobalConfig(existing) {
|
|
|
303
302
|
...objectValue(parsed.mcp),
|
|
304
303
|
auditor: {
|
|
305
304
|
type: 'local',
|
|
306
|
-
command: [
|
|
305
|
+
command: ['node', pkgEntrypoint, 'mcp'],
|
|
307
306
|
enabled: true,
|
|
308
307
|
timeout: 10000,
|
|
309
308
|
},
|
|
@@ -380,6 +379,10 @@ if (!promptSource || !skillSource) {
|
|
|
380
379
|
|
|
381
380
|
const codexOpenAiAgentSource = readOptionalSource(codexOpenAiAgentSourceFile, 'Codex skill UI metadata');
|
|
382
381
|
|
|
382
|
+
const postinstallStart = Date.now();
|
|
383
|
+
let succeeded = 0;
|
|
384
|
+
let failed = 0;
|
|
385
|
+
|
|
383
386
|
const installs = [
|
|
384
387
|
{
|
|
385
388
|
label: 'Claude command',
|
|
@@ -415,12 +418,14 @@ for (const install of installs) {
|
|
|
415
418
|
try {
|
|
416
419
|
const action = writeGeneratedFile(install.path, install.content);
|
|
417
420
|
console.log(`audit-code: ${action} global ${install.label} at ${install.path}`);
|
|
421
|
+
succeeded++;
|
|
418
422
|
} catch (err) {
|
|
419
423
|
console.warn(`audit-code: could not install global ${install.label} (${err.message})`);
|
|
420
424
|
console.warn(` To install manually, copy from:`);
|
|
421
425
|
console.warn(` ${install.sourcePath}`);
|
|
422
426
|
console.warn(` to:`);
|
|
423
427
|
console.warn(` ${install.path}`);
|
|
428
|
+
failed++;
|
|
424
429
|
}
|
|
425
430
|
}
|
|
426
431
|
|
|
@@ -429,8 +434,10 @@ const globalMcpLauncherPath = join(homedir(), '.audit-code', 'run-mcp-server.mjs
|
|
|
429
434
|
try {
|
|
430
435
|
const action = writeGeneratedFile(globalMcpLauncherPath, Buffer.from(renderGlobalMcpLauncher(pkgRoot)));
|
|
431
436
|
console.log(`audit-code: ${action} global MCP launcher at ${globalMcpLauncherPath}`);
|
|
437
|
+
succeeded++;
|
|
432
438
|
} catch (err) {
|
|
433
439
|
console.warn(`audit-code: could not install global MCP launcher (${err.message})`);
|
|
440
|
+
failed++;
|
|
434
441
|
}
|
|
435
442
|
|
|
436
443
|
// Install OpenCode global command and MCP via merged config
|
|
@@ -440,10 +447,12 @@ try {
|
|
|
440
447
|
mergeOpenCodeGlobalConfig(existing),
|
|
441
448
|
);
|
|
442
449
|
console.log(`audit-code: ${action} global OpenCode config in ${opencodeGlobalConfig}`);
|
|
450
|
+
succeeded++;
|
|
443
451
|
} catch (err) {
|
|
444
452
|
console.warn(`audit-code: could not install global OpenCode config (${err.message})`);
|
|
445
453
|
console.warn(` To install manually, add the mcp.auditor and command["audit-code"] entries to:`);
|
|
446
454
|
console.warn(` ${opencodeGlobalConfig}`);
|
|
455
|
+
failed++;
|
|
447
456
|
}
|
|
448
457
|
|
|
449
458
|
// Install Antigravity plugin (global skill for Gemini IDE / Antigravity Hub)
|
|
@@ -460,8 +469,10 @@ try {
|
|
|
460
469
|
|
|
461
470
|
const skillAction = writeGeneratedFile(antigravityPluginSkillPath, skillSource);
|
|
462
471
|
console.log(`audit-code: ${skillAction} Antigravity plugin skill at ${antigravityPluginSkillPath}`);
|
|
472
|
+
succeeded++;
|
|
463
473
|
} catch (err) {
|
|
464
474
|
console.warn(`audit-code: could not install Antigravity plugin (${err.message})`);
|
|
475
|
+
failed++;
|
|
465
476
|
}
|
|
466
477
|
|
|
467
478
|
// Install Claude Desktop plugin so /audit-code appears in the slash-command menu
|
|
@@ -497,9 +508,11 @@ try {
|
|
|
497
508
|
console.log(`audit-code: ${skillAction} Claude Desktop plugin skill at ${claudePluginSkillPath}`);
|
|
498
509
|
|
|
499
510
|
console.log(`audit-code: restart Claude Desktop for /audit-code to appear in the slash-command menu`);
|
|
511
|
+
succeeded++;
|
|
500
512
|
} catch (err) {
|
|
501
513
|
console.warn(`audit-code: could not install Claude Desktop plugin (${err.message})`);
|
|
502
514
|
console.warn(` Plugin directory: ${claudePluginDir}`);
|
|
515
|
+
failed++;
|
|
503
516
|
}
|
|
504
517
|
|
|
505
518
|
// Register auditor MCP server with Claude Desktop so /audit-code appears in its slash-command menu
|
|
@@ -511,9 +524,13 @@ try {
|
|
|
511
524
|
console.log(`audit-code: ${action} Claude Desktop MCP server entry in ${claudeDesktopConfig}`);
|
|
512
525
|
console.log(`audit-code: restart Claude Desktop for /audit-code to appear`);
|
|
513
526
|
console.log(`audit-code: to target a specific repo, set AUDIT_CODE_REPO_ROOT in Claude Desktop's MCP env settings`);
|
|
527
|
+
succeeded++;
|
|
514
528
|
} catch (err) {
|
|
515
529
|
console.warn(`audit-code: could not update Claude Desktop config (${err.message})`);
|
|
516
530
|
console.warn(` To register manually, add "mcpServers.auditor" to:`);
|
|
517
531
|
console.warn(` ${claudeDesktopConfig}`);
|
|
518
532
|
console.warn(` with command "node" and args ["${replaceBackslashes(globalMcpLauncherPath)}"]`);
|
|
533
|
+
failed++;
|
|
519
534
|
}
|
|
535
|
+
|
|
536
|
+
console.log(`audit-code: postinstall complete — ${succeeded} succeeded, ${failed} failed (${Date.now() - postinstallStart}ms)`);
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Use `audit-code next-step` as the primary interface to the audit workflow.
|
|
4
4
|
|
|
5
5
|
1. Run `audit-code next-step` directly when shell access is available.
|
|
6
|
-
2. If MCP is your only available interface, call `
|
|
6
|
+
2. If MCP is your only available interface, call `start_audit` or `continue_audit`; both return the same one-step contract.
|
|
7
7
|
3. Read `prompt_content` in the response and follow it.
|
|
8
|
-
4. When a step completes (not blocked), run `audit-code next-step` again or call `
|
|
8
|
+
4. When a step completes (not blocked), run `audit-code next-step` again or call `continue_audit` as the compatibility adapter.
|
|
9
9
|
5. Stop when the step instructions say to stop.
|
|
10
10
|
|
|
11
11
|
Use the `task` tool or equivalent for subagent dispatch when the step tells you to fan out review work.
|
|
12
12
|
|
|
13
|
-
If neither shell access nor `
|
|
13
|
+
If neither shell access nor `start_audit` is available, stop and report that no next-step interface is connected.
|