auditor-lambda 0.2.12 → 0.2.13
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 +6 -6
- package/dist/extractors/disposition.js +8 -1
- package/dist/extractors/pathPatterns.d.ts +1 -0
- package/dist/extractors/pathPatterns.js +3 -0
- package/dist/io/artifacts.d.ts +3 -0
- package/dist/io/artifacts.js +3 -0
- package/dist/io/toolingManifest.d.ts +2 -0
- package/dist/io/toolingManifest.js +75 -0
- package/dist/orchestrator/advance.js +6 -2
- package/dist/orchestrator/artifactMetadata.d.ts +1 -1
- package/dist/orchestrator/artifactMetadata.js +15 -2
- package/dist/orchestrator/dependencyMap.js +3 -0
- package/dist/orchestrator/internalExecutors.js +16 -0
- package/dist/orchestrator/staleness.js +48 -1
- package/dist/types/toolingManifest.d.ts +7 -0
- package/dist/types/toolingManifest.js +1 -0
- package/dist/validation/artifacts.js +3 -0
- package/package.json +1 -1
- package/skills/audit-code/SKILL.md +9 -0
- package/skills/audit-code/audit-code.prompt.md +1 -1
package/dist/cli.js
CHANGED
|
@@ -400,7 +400,7 @@ async function ingestBatchAuditResults(options) {
|
|
|
400
400
|
}
|
|
401
401
|
const bundle = lastStep?.updated_bundle ??
|
|
402
402
|
(await loadArtifactBundle(options.artifactsDir));
|
|
403
|
-
const state =
|
|
403
|
+
const state = deriveAuditState(bundle);
|
|
404
404
|
const decision = decideNextStep(bundle);
|
|
405
405
|
return {
|
|
406
406
|
batchFiles,
|
|
@@ -720,7 +720,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
720
720
|
if (preferredExecutor === "agent" && provider.name === LOCAL_SUBPROCESS_PROVIDER_NAME) {
|
|
721
721
|
const blocker = buildManualReviewBlocker(provider.name);
|
|
722
722
|
const blockedState = buildBlockedAuditState({
|
|
723
|
-
state:
|
|
723
|
+
state: decision.state,
|
|
724
724
|
obligationId,
|
|
725
725
|
executor: preferredExecutor,
|
|
726
726
|
blocker,
|
|
@@ -784,7 +784,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
784
784
|
return;
|
|
785
785
|
}
|
|
786
786
|
if (!preferredExecutor) {
|
|
787
|
-
const state =
|
|
787
|
+
const state = decision.state;
|
|
788
788
|
await clearDispatchFiles(artifactsDir);
|
|
789
789
|
await emitEnvelope({
|
|
790
790
|
root,
|
|
@@ -1251,12 +1251,12 @@ async function cmdRunToCompletion(argv) {
|
|
|
1251
1251
|
const shouldBlock = workerResult.status === "failed" || workerResult.status === "blocked";
|
|
1252
1252
|
const state = shouldBlock
|
|
1253
1253
|
? buildBlockedAuditState({
|
|
1254
|
-
state:
|
|
1254
|
+
state: deriveAuditState(bundleAfter),
|
|
1255
1255
|
obligationId: workerResult.obligation_id,
|
|
1256
1256
|
executor: workerResult.selected_executor,
|
|
1257
1257
|
blocker: buildWorkerFailureBlocker(workerResult),
|
|
1258
1258
|
})
|
|
1259
|
-
:
|
|
1259
|
+
: deriveAuditState(bundleAfter);
|
|
1260
1260
|
if (shouldBlock) {
|
|
1261
1261
|
await writeCoreArtifacts(artifactsDir, {
|
|
1262
1262
|
...bundleAfter,
|
|
@@ -1285,7 +1285,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1285
1285
|
}
|
|
1286
1286
|
const bundle = await loadArtifactBundle(artifactsDir);
|
|
1287
1287
|
const decision = decideNextStep(bundle);
|
|
1288
|
-
const state =
|
|
1288
|
+
const state = decision.state;
|
|
1289
1289
|
if (state.status === "complete") {
|
|
1290
1290
|
await clearDispatchFiles(artifactsDir);
|
|
1291
1291
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isGeneratedInstallArtifactPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isAuditArtifactPath, isGeneratedInstallArtifactPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
3
|
const normalized = normalizeExtractorPath(path);
|
|
4
4
|
if (isNodeModulesOrGit(normalized)) {
|
|
@@ -26,6 +26,13 @@ function inferDisposition(path) {
|
|
|
26
26
|
if (isLockfilePath(normalized)) {
|
|
27
27
|
return { path, status: "generated", reason: "Lockfile excluded from code audit scope." };
|
|
28
28
|
}
|
|
29
|
+
if (isAuditArtifactPath(normalized)) {
|
|
30
|
+
return {
|
|
31
|
+
path,
|
|
32
|
+
status: "generated",
|
|
33
|
+
reason: "Generated audit artifact.",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
29
36
|
if (isDocPath(normalized)) {
|
|
30
37
|
return { path, status: "doc_only", reason: "Documentation artifact." };
|
|
31
38
|
}
|
|
@@ -14,6 +14,7 @@ export declare function isLicensePath(normalized: string): boolean;
|
|
|
14
14
|
export declare function isLockfilePath(normalized: string): boolean;
|
|
15
15
|
export declare function isDocPath(normalized: string): boolean;
|
|
16
16
|
export declare function isGeneratedInstallArtifactPath(normalized: string): boolean;
|
|
17
|
+
export declare function isAuditArtifactPath(normalized: string): boolean;
|
|
17
18
|
export declare function isTestPath(normalized: string): boolean;
|
|
18
19
|
export declare function isInterfacePath(normalized: string): boolean;
|
|
19
20
|
export declare function isDataLayerPath(normalized: string): boolean;
|
|
@@ -103,6 +103,9 @@ export function isDocPath(normalized) {
|
|
|
103
103
|
export function isGeneratedInstallArtifactPath(normalized) {
|
|
104
104
|
return normalized.startsWith(".audit-code/install/");
|
|
105
105
|
}
|
|
106
|
+
export function isAuditArtifactPath(normalized) {
|
|
107
|
+
return splitSegments(normalized).some((segment) => segment.startsWith(".audit-artifacts"));
|
|
108
|
+
}
|
|
106
109
|
export function isTestPath(normalized) {
|
|
107
110
|
return includesAny(normalized, TEST_KEYWORDS);
|
|
108
111
|
}
|
package/dist/io/artifacts.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { GraphBundle } from "../types/graph.js";
|
|
|
9
9
|
import type { RiskRegister } from "../types/risk.js";
|
|
10
10
|
import type { RuntimeValidationReport, RuntimeValidationTaskManifest } from "../types/runtimeValidation.js";
|
|
11
11
|
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
12
|
+
import type { ToolingManifest } from "../types/toolingManifest.js";
|
|
12
13
|
type ArtifactPayloadMap = {
|
|
13
14
|
repo_manifest: RepoManifest;
|
|
14
15
|
file_disposition: FileDisposition;
|
|
@@ -29,6 +30,7 @@ type ArtifactPayloadMap = {
|
|
|
29
30
|
audit_report: string;
|
|
30
31
|
audit_state: AuditState;
|
|
31
32
|
artifact_metadata: ArtifactMetadataManifest;
|
|
33
|
+
tooling_manifest: ToolingManifest;
|
|
32
34
|
};
|
|
33
35
|
/**
|
|
34
36
|
* Audit artifacts accumulate phase-by-phase as the orchestrator advances.
|
|
@@ -63,6 +65,7 @@ export declare const ARTIFACT_DEFINITIONS: {
|
|
|
63
65
|
readonly audit_report: ArtifactDefinition<"audit_report">;
|
|
64
66
|
readonly audit_state: ArtifactDefinition<"audit_state">;
|
|
65
67
|
readonly artifact_metadata: ArtifactDefinition<"artifact_metadata">;
|
|
68
|
+
readonly tooling_manifest: ArtifactDefinition<"tooling_manifest">;
|
|
66
69
|
};
|
|
67
70
|
export declare const ARTIFACT_FILE_TO_BUNDLE_KEY: Record<string, ArtifactBundleKey>;
|
|
68
71
|
export declare function getArtifactValue(bundle: ArtifactBundle, artifactName: string): unknown;
|
package/dist/io/artifacts.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { cp, rm, unlink } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isFileMissingError, readOptionalJsonFile, readOptionalNdjsonFile, readOptionalTextFile, writeJsonFile, writeNdjsonFile, writeTextFile, } from "./json.js";
|
|
4
|
+
import { buildToolingManifest } from "./toolingManifest.js";
|
|
4
5
|
function jsonArtifact(fileName, phase) {
|
|
5
6
|
return {
|
|
6
7
|
fileName,
|
|
@@ -45,6 +46,7 @@ export const ARTIFACT_DEFINITIONS = {
|
|
|
45
46
|
audit_report: textArtifact("audit-report.md", "reporting"),
|
|
46
47
|
audit_state: jsonArtifact("audit_state.json", "supervisor"),
|
|
47
48
|
artifact_metadata: jsonArtifact("artifact_metadata.json", "supervisor"),
|
|
49
|
+
tooling_manifest: jsonArtifact("tooling_manifest.json", "supervisor"),
|
|
48
50
|
};
|
|
49
51
|
const ARTIFACT_ENTRIES = Object.entries(ARTIFACT_DEFINITIONS);
|
|
50
52
|
export const ARTIFACT_FILE_TO_BUNDLE_KEY = Object.fromEntries(ARTIFACT_ENTRIES.map(([key, definition]) => [definition.fileName, key]));
|
|
@@ -62,6 +64,7 @@ export async function loadArtifactBundle(root) {
|
|
|
62
64
|
bundleRecord[key] = value;
|
|
63
65
|
}
|
|
64
66
|
}
|
|
67
|
+
bundle.tooling_manifest = await buildToolingManifest();
|
|
65
68
|
return bundle;
|
|
66
69
|
}
|
|
67
70
|
export async function writeCoreArtifacts(root, bundle) {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
6
|
+
const TOOLING_INPUTS = [
|
|
7
|
+
"audit-code.mjs",
|
|
8
|
+
"audit-code-wrapper-lib.mjs",
|
|
9
|
+
"package.json",
|
|
10
|
+
"dist",
|
|
11
|
+
"schemas",
|
|
12
|
+
"skills/audit-code",
|
|
13
|
+
];
|
|
14
|
+
async function pathExists(path) {
|
|
15
|
+
try {
|
|
16
|
+
await stat(path);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function collectFiles(path) {
|
|
24
|
+
const info = await stat(path);
|
|
25
|
+
if (info.isFile()) {
|
|
26
|
+
return [path];
|
|
27
|
+
}
|
|
28
|
+
if (!info.isDirectory()) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const entries = await readdir(path, { withFileTypes: true });
|
|
32
|
+
const files = [];
|
|
33
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
34
|
+
files.push(...(await collectFiles(join(path, entry.name))));
|
|
35
|
+
}
|
|
36
|
+
return files;
|
|
37
|
+
}
|
|
38
|
+
async function readPackageVersion() {
|
|
39
|
+
const packageJsonPath = join(PACKAGE_ROOT, "package.json");
|
|
40
|
+
if (!(await pathExists(packageJsonPath))) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
45
|
+
return typeof packageJson.version === "string" ? packageJson.version : null;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function buildToolingManifest() {
|
|
52
|
+
const hash = createHash("sha256");
|
|
53
|
+
const existingInputs = [];
|
|
54
|
+
for (const input of TOOLING_INPUTS) {
|
|
55
|
+
const absolute = join(PACKAGE_ROOT, input);
|
|
56
|
+
if (!(await pathExists(absolute))) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
existingInputs.push(input);
|
|
60
|
+
const files = await collectFiles(absolute);
|
|
61
|
+
for (const file of files.sort((a, b) => a.localeCompare(b))) {
|
|
62
|
+
hash.update(relative(PACKAGE_ROOT, file).replace(/\\/g, "/"));
|
|
63
|
+
hash.update("\n");
|
|
64
|
+
hash.update(await readFile(file));
|
|
65
|
+
hash.update("\n");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
generated_at: new Date().toISOString(),
|
|
70
|
+
package_root: PACKAGE_ROOT,
|
|
71
|
+
package_version: await readPackageVersion(),
|
|
72
|
+
implementation_hash: hash.digest("hex"),
|
|
73
|
+
inputs: existingInputs,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -108,8 +108,12 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
108
108
|
catch (error) {
|
|
109
109
|
throw formatExecutorFailure(selectedExecutor, selectedObligation, error);
|
|
110
110
|
}
|
|
111
|
-
const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata);
|
|
112
|
-
const metadataBundle = {
|
|
111
|
+
const metadata = computeArtifactMetadata(run.updated, bundle.artifact_metadata, [...run.artifacts_written, "tooling_manifest.json"]);
|
|
112
|
+
const metadataBundle = {
|
|
113
|
+
...run.updated,
|
|
114
|
+
tooling_manifest: bundle.tooling_manifest,
|
|
115
|
+
artifact_metadata: metadata,
|
|
116
|
+
};
|
|
113
117
|
const updatedState = deriveAuditState(metadataBundle);
|
|
114
118
|
updatedState.last_executor = selectedExecutor;
|
|
115
119
|
updatedState.last_obligation = selectedObligation ?? undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ArtifactMetadataManifest } from "../types/artifactMetadata.js";
|
|
2
2
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
3
3
|
export declare function present(bundle: ArtifactBundle, artifactName: string): boolean;
|
|
4
|
-
export declare function computeArtifactMetadata(bundle: ArtifactBundle, previous?: ArtifactMetadataManifest): ArtifactMetadataManifest;
|
|
4
|
+
export declare function computeArtifactMetadata(bundle: ArtifactBundle, previous?: ArtifactMetadataManifest, updatedArtifacts?: Iterable<string>): ArtifactMetadataManifest;
|
|
@@ -28,6 +28,14 @@ function normalizeForMetadataHash(artifactName, value) {
|
|
|
28
28
|
const { generated_at: _generatedAt, ...rest } = record;
|
|
29
29
|
return rest;
|
|
30
30
|
}
|
|
31
|
+
if (artifactName === "tooling_manifest.json" &&
|
|
32
|
+
value &&
|
|
33
|
+
typeof value === "object" &&
|
|
34
|
+
!Array.isArray(value)) {
|
|
35
|
+
const record = value;
|
|
36
|
+
const { generated_at: _generatedAt, ...rest } = record;
|
|
37
|
+
return rest;
|
|
38
|
+
}
|
|
31
39
|
return value;
|
|
32
40
|
}
|
|
33
41
|
function buildReverseDependencyMap() {
|
|
@@ -72,8 +80,9 @@ export function present(bundle, artifactName) {
|
|
|
72
80
|
const value = getArtifactValue(bundle, artifactName);
|
|
73
81
|
return value !== undefined && value !== null;
|
|
74
82
|
}
|
|
75
|
-
export function computeArtifactMetadata(bundle, previous) {
|
|
83
|
+
export function computeArtifactMetadata(bundle, previous, updatedArtifacts = []) {
|
|
76
84
|
const artifacts = {};
|
|
85
|
+
const updated = new Set(updatedArtifacts);
|
|
77
86
|
const presentArtifacts = Object.keys(REVERSE_DEPENDENCY_MAP).filter((artifactName) => artifactName !== "artifact_metadata.json" &&
|
|
78
87
|
present(bundle, artifactName));
|
|
79
88
|
const orderedArtifacts = computeDependencyFirstOrder(presentArtifacts);
|
|
@@ -83,8 +92,12 @@ export function computeArtifactMetadata(bundle, previous) {
|
|
|
83
92
|
const value = getArtifactValue(bundle, artifactName);
|
|
84
93
|
if (value === undefined || value === null)
|
|
85
94
|
continue;
|
|
86
|
-
const contentHash = hashValue(normalizeForMetadataHash(artifactName, value));
|
|
87
95
|
const previousEntry = previous?.artifacts[artifactName];
|
|
96
|
+
if (previousEntry && !updated.has(artifactName)) {
|
|
97
|
+
artifacts[artifactName] = previousEntry;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const contentHash = hashValue(normalizeForMetadataHash(artifactName, value));
|
|
88
101
|
const dependencyRevisions = Object.fromEntries((REVERSE_DEPENDENCY_MAP[artifactName] ?? [])
|
|
89
102
|
.filter((dependencyName) => dependencyName !== "artifact_metadata.json")
|
|
90
103
|
.sort()
|
|
@@ -174,6 +174,18 @@ export function runResultIngestionExecutor(bundle, results) {
|
|
|
174
174
|
const flowCoverage = bundle.critical_flows
|
|
175
175
|
? buildFlowCoverage(bundle.critical_flows, updatedCoverageMatrix)
|
|
176
176
|
: bundle.flow_coverage;
|
|
177
|
+
const runtimeCommand = bundle.runtime_validation_tasks?.tasks.find((task) => task.command && task.command.length > 0)?.command;
|
|
178
|
+
const runtimeValidationTasks = bundle.unit_manifest && flowCoverage
|
|
179
|
+
? buildRuntimeValidationTasks({
|
|
180
|
+
unitManifest: bundle.unit_manifest,
|
|
181
|
+
criticalFlows: bundle.critical_flows,
|
|
182
|
+
flowCoverage,
|
|
183
|
+
command: runtimeCommand,
|
|
184
|
+
})
|
|
185
|
+
: bundle.runtime_validation_tasks;
|
|
186
|
+
const runtimeValidationReport = runtimeValidationTasks
|
|
187
|
+
? mergeRuntimeValidationReport(runtimeValidationTasks, bundle.runtime_validation_report)
|
|
188
|
+
: bundle.runtime_validation_report;
|
|
177
189
|
const requeuePayload = buildRequeuePayload(updatedCoverageMatrix, bundle.critical_flows, flowCoverage, bundle.external_analyzer_results);
|
|
178
190
|
const mergedResults = [...(bundle.audit_results ?? []), ...results];
|
|
179
191
|
const updatedAuditTasks = updateAuditTaskStatuses(bundle.audit_tasks, mergedResults);
|
|
@@ -182,6 +194,8 @@ export function runResultIngestionExecutor(bundle, results) {
|
|
|
182
194
|
...bundle,
|
|
183
195
|
coverage_matrix: updatedCoverageMatrix,
|
|
184
196
|
flow_coverage: flowCoverage,
|
|
197
|
+
runtime_validation_tasks: runtimeValidationTasks,
|
|
198
|
+
runtime_validation_report: runtimeValidationReport,
|
|
185
199
|
audit_results: mergedResults,
|
|
186
200
|
audit_tasks: updatedAuditTasks,
|
|
187
201
|
requeue_tasks: requeuePayload.tasks,
|
|
@@ -190,6 +204,8 @@ export function runResultIngestionExecutor(bundle, results) {
|
|
|
190
204
|
artifacts_written: [
|
|
191
205
|
"coverage_matrix.json",
|
|
192
206
|
"flow_coverage.json",
|
|
207
|
+
...(runtimeValidationTasks ? ["runtime_validation_tasks.json"] : []),
|
|
208
|
+
...(runtimeValidationReport ? ["runtime_validation_report.json"] : []),
|
|
193
209
|
"audit_results.jsonl",
|
|
194
210
|
"audit_tasks.json",
|
|
195
211
|
"requeue_tasks.json",
|
|
@@ -23,6 +23,14 @@ function normalizeForMetadataHash(artifactName, value) {
|
|
|
23
23
|
const { generated_at: _generatedAt, ...rest } = record;
|
|
24
24
|
return rest;
|
|
25
25
|
}
|
|
26
|
+
if (artifactName === "tooling_manifest.json" &&
|
|
27
|
+
value &&
|
|
28
|
+
typeof value === "object" &&
|
|
29
|
+
!Array.isArray(value)) {
|
|
30
|
+
const record = value;
|
|
31
|
+
const { generated_at: _generatedAt, ...rest } = record;
|
|
32
|
+
return rest;
|
|
33
|
+
}
|
|
26
34
|
return value;
|
|
27
35
|
}
|
|
28
36
|
function computeContentHash(artifactName, bundle) {
|
|
@@ -33,6 +41,18 @@ function computeContentHash(artifactName, bundle) {
|
|
|
33
41
|
.update(stableStringify(normalizeForMetadataHash(artifactName, value)))
|
|
34
42
|
.digest("hex");
|
|
35
43
|
}
|
|
44
|
+
function buildReverseDependencyMap() {
|
|
45
|
+
const reverse = {};
|
|
46
|
+
for (const [upstream, downstreamList] of Object.entries(ARTIFACT_DEPENDENCY_MAP)) {
|
|
47
|
+
reverse[upstream] ??= [];
|
|
48
|
+
for (const downstream of downstreamList) {
|
|
49
|
+
reverse[downstream] ??= [];
|
|
50
|
+
reverse[downstream].push(upstream);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return reverse;
|
|
54
|
+
}
|
|
55
|
+
const REVERSE_DEPENDENCY_MAP = buildReverseDependencyMap();
|
|
36
56
|
export function computeStaleArtifacts(bundle) {
|
|
37
57
|
const stale = new Set();
|
|
38
58
|
const metadata = bundle.artifact_metadata;
|
|
@@ -40,6 +60,15 @@ export function computeStaleArtifacts(bundle) {
|
|
|
40
60
|
for (const [artifactName, entry] of Object.entries(metadata.artifacts)) {
|
|
41
61
|
if (!present(bundle, artifactName))
|
|
42
62
|
continue;
|
|
63
|
+
const expectedDependencies = [...(REVERSE_DEPENDENCY_MAP[artifactName] ?? [])]
|
|
64
|
+
.filter((dependencyName) => dependencyName !== "artifact_metadata.json")
|
|
65
|
+
.sort();
|
|
66
|
+
const recordedDependencies = Object.keys(entry.dependency_revisions).sort();
|
|
67
|
+
if (stableStringify(expectedDependencies) !==
|
|
68
|
+
stableStringify(recordedDependencies)) {
|
|
69
|
+
stale.add(artifactName);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
43
72
|
let isStale = false;
|
|
44
73
|
for (const [dependencyName, recordedRevision] of Object.entries(entry.dependency_revisions)) {
|
|
45
74
|
if (!present(bundle, dependencyName)) {
|
|
@@ -51,7 +80,7 @@ export function computeStaleArtifacts(bundle) {
|
|
|
51
80
|
}
|
|
52
81
|
const dependencyEntry = metadata.artifacts[dependencyName];
|
|
53
82
|
if (!dependencyEntry) {
|
|
54
|
-
if (recordedRevision > 0) {
|
|
83
|
+
if (present(bundle, dependencyName) || recordedRevision > 0) {
|
|
55
84
|
isStale = true;
|
|
56
85
|
break;
|
|
57
86
|
}
|
|
@@ -70,6 +99,9 @@ export function computeStaleArtifacts(bundle) {
|
|
|
70
99
|
}
|
|
71
100
|
}
|
|
72
101
|
for (const [upstream, downstreamList] of Object.entries(ARTIFACT_DEPENDENCY_MAP)) {
|
|
102
|
+
if (upstream === "tooling_manifest.json" && !present(bundle, upstream)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
73
105
|
if (!present(bundle, upstream)) {
|
|
74
106
|
for (const downstream of downstreamList) {
|
|
75
107
|
const hasMetadataEntry = Boolean(metadata?.artifacts[downstream]);
|
|
@@ -79,5 +111,20 @@ export function computeStaleArtifacts(bundle) {
|
|
|
79
111
|
}
|
|
80
112
|
}
|
|
81
113
|
}
|
|
114
|
+
let changed = true;
|
|
115
|
+
while (changed) {
|
|
116
|
+
changed = false;
|
|
117
|
+
for (const [upstream, downstreamList] of Object.entries(ARTIFACT_DEPENDENCY_MAP)) {
|
|
118
|
+
if (!stale.has(upstream)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
for (const downstream of downstreamList) {
|
|
122
|
+
if (present(bundle, downstream) && !stale.has(downstream)) {
|
|
123
|
+
stale.add(downstream);
|
|
124
|
+
changed = true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
82
129
|
return stale;
|
|
83
130
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -40,6 +40,9 @@ export function validateArtifactBundle(bundle) {
|
|
|
40
40
|
if (bundle.external_analyzer_results) {
|
|
41
41
|
issues.push(...requireKeys(bundle.external_analyzer_results, "external_analyzer_results", ["tool", "results"]));
|
|
42
42
|
}
|
|
43
|
+
if (bundle.tooling_manifest) {
|
|
44
|
+
issues.push(...requireKeys(bundle.tooling_manifest, "tooling_manifest", ["generated_at", "package_root", "implementation_hash", "inputs"]));
|
|
45
|
+
}
|
|
43
46
|
const repoManifestFiles = asArray(bundle.repo_manifest?.files);
|
|
44
47
|
const fileDispositionEntries = asArray(bundle.file_disposition?.files);
|
|
45
48
|
const unitManifestUnits = asArray(bundle.unit_manifest?.units);
|
package/package.json
CHANGED
|
@@ -46,6 +46,15 @@ audit-code
|
|
|
46
46
|
|
|
47
47
|
from the target repository root.
|
|
48
48
|
|
|
49
|
+
When developing inside the `auditor-lambda` repository itself, prefer:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node audit-code.mjs
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
That keeps the run pinned to the local wrapper and local `dist/` output instead
|
|
56
|
+
of whichever global `audit-code` binary happens to be on `PATH`.
|
|
57
|
+
|
|
49
58
|
Debug one-step mode:
|
|
50
59
|
|
|
51
60
|
```bash
|
|
@@ -18,7 +18,7 @@ To move the state machine forward, execute the backend framework using your term
|
|
|
18
18
|
audit-code
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
_(If the wrapper is only available as a package dependency in the current repository, `npx audit-code` is equivalent. If developing
|
|
21
|
+
_(If the wrapper is only available as a package dependency in the current repository, `npx audit-code` is equivalent. If you are developing inside the `auditor-lambda` repository itself, prefer `node audit-code.mjs` so the run uses the local wrapper and local `dist/` output instead of a potentially stale global install.)_
|
|
22
22
|
|
|
23
23
|
## Step 2: Handle Blockages (The "Thinking" Phase)
|
|
24
24
|
|