auditor-lambda 0.10.3 → 0.10.7
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-build.mjs +198 -0
- package/audit-code-wrapper-install-hosts.mjs +1140 -0
- package/audit-code-wrapper-io.mjs +155 -0
- package/audit-code-wrapper-legacy.mjs +125 -0
- package/audit-code-wrapper-lib.mjs +17 -1801
- package/audit-code-wrapper-opencode.mjs +256 -0
- package/dispatch/merge-results.mjs +5 -3
- package/dispatch/validate-result.mjs +2 -2
- package/dist/adapters/coverageSummary.js +6 -2
- package/dist/adapters/normalizeExternal.js +16 -1
- package/dist/adapters/npmAudit.js +20 -9
- package/dist/adapters/semgrep.js +26 -1
- package/dist/cli/advanceAuditCommand.d.ts +1 -0
- package/dist/cli/advanceAuditCommand.js +95 -0
- package/dist/cli/args.js +1 -2
- package/dist/cli/auditStep.js +2 -2
- package/dist/cli/cleanup.d.ts +11 -1
- package/dist/cli/cleanup.js +25 -5
- package/dist/cli/cleanupCommand.d.ts +1 -0
- package/dist/cli/cleanupCommand.js +24 -0
- package/dist/cli/dispatch.d.ts +55 -31
- package/dist/cli/dispatch.js +298 -241
- package/dist/cli/dispatchStatusCommand.d.ts +1 -0
- package/dist/cli/dispatchStatusCommand.js +68 -0
- package/dist/cli/explainTaskCommand.d.ts +1 -0
- package/dist/cli/explainTaskCommand.js +33 -0
- package/dist/cli/importExternalAnalyzerCommand.d.ts +1 -0
- package/dist/cli/importExternalAnalyzerCommand.js +20 -0
- package/dist/cli/ingestResultsCommand.d.ts +1 -0
- package/dist/cli/ingestResultsCommand.js +34 -0
- package/dist/cli/intakeCommand.d.ts +1 -0
- package/dist/cli/intakeCommand.js +17 -0
- package/dist/cli/lineIndex.js +19 -12
- package/dist/cli/nextStepCommand.d.ts +139 -0
- package/dist/cli/nextStepCommand.js +281 -232
- package/dist/cli/planCommand.d.ts +1 -0
- package/dist/cli/planCommand.js +16 -0
- package/dist/cli/prepareDispatchCommand.d.ts +1 -0
- package/dist/cli/prepareDispatchCommand.js +25 -0
- package/dist/cli/quotaCommand.d.ts +1 -0
- package/dist/cli/quotaCommand.js +56 -0
- package/dist/cli/requeueCommand.d.ts +1 -0
- package/dist/cli/requeueCommand.js +10 -0
- package/dist/cli/runToCompletion.js +451 -412
- package/dist/cli/sampleRunCommand.d.ts +1 -0
- package/dist/cli/sampleRunCommand.js +93 -0
- package/dist/cli/statusCommand.js +1 -1
- package/dist/cli/steps.js +4 -1
- package/dist/cli/submitPacketCommand.js +16 -15
- package/dist/cli/synthesizeCommand.d.ts +1 -0
- package/dist/cli/synthesizeCommand.js +15 -0
- package/dist/cli/updateRuntimeValidationCommand.d.ts +1 -0
- package/dist/cli/updateRuntimeValidationCommand.js +16 -0
- package/dist/cli/validateCommand.d.ts +1 -0
- package/dist/cli/validateCommand.js +41 -0
- package/dist/cli/validateResultCommand.d.ts +1 -0
- package/dist/cli/validateResultCommand.js +63 -0
- package/dist/cli/validateResultsCommand.d.ts +1 -0
- package/dist/cli/validateResultsCommand.js +31 -0
- package/dist/cli/workerRunCommand.d.ts +15 -1
- package/dist/cli/workerRunCommand.js +40 -4
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +21 -628
- package/dist/coverage.js +7 -3
- package/dist/extractors/analyzers/css.js +2 -2
- package/dist/extractors/analyzers/html.js +2 -2
- package/dist/extractors/analyzers/python.js +2 -2
- package/dist/extractors/analyzers/registry.js +17 -36
- package/dist/extractors/analyzers/treeSitter.d.ts +10 -1
- package/dist/extractors/analyzers/treeSitter.js +28 -6
- package/dist/extractors/analyzers/typescript.js +104 -85
- package/dist/extractors/browserExtension.js +4 -1
- package/dist/extractors/designAssessment.js +21 -21
- package/dist/extractors/fsIntake.js +34 -10
- package/dist/extractors/graph.js +17 -7
- package/dist/extractors/graphManifestEdges/cargo.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/cargo.js +107 -0
- package/dist/extractors/graphManifestEdges/go.d.ts +5 -0
- package/dist/extractors/graphManifestEdges/go.js +151 -0
- package/dist/extractors/graphManifestEdges/index.d.ts +8 -0
- package/dist/extractors/graphManifestEdges/index.js +11 -0
- package/dist/extractors/graphManifestEdges/jsonc.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/jsonc.js +97 -0
- package/dist/extractors/graphManifestEdges/maven.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/maven.js +73 -0
- package/dist/extractors/graphManifestEdges/packageJson.d.ts +19 -0
- package/dist/extractors/graphManifestEdges/packageJson.js +204 -0
- package/dist/extractors/graphManifestEdges/pnpm.d.ts +2 -0
- package/dist/extractors/graphManifestEdges/pnpm.js +42 -0
- package/dist/extractors/graphManifestEdges/pyproject.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/pyproject.js +83 -0
- package/dist/extractors/graphManifestEdges/toml.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/toml.js +68 -0
- package/dist/extractors/graphManifestEdges/typescript.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/typescript.js +56 -0
- package/dist/extractors/graphManifestEdges/workspace.d.ts +10 -0
- package/dist/extractors/graphManifestEdges/workspace.js +72 -0
- package/dist/extractors/graphManifestEdges/yaml.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/yaml.js +59 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.js +89 -0
- package/dist/extractors/graphPythonImports.js +4 -20
- package/dist/extractors/pathPatterns.js +3 -13
- package/dist/io/artifacts.d.ts +1 -1
- package/dist/io/artifacts.js +4 -1
- package/dist/io/runArtifacts.d.ts +8 -2
- package/dist/io/runArtifacts.js +103 -69
- package/dist/io/toolingManifest.js +2 -1
- package/dist/orchestrator/advance.js +36 -0
- package/dist/orchestrator/artifactFreshness.d.ts +1 -1
- package/dist/orchestrator/artifactFreshness.js +1 -1
- package/dist/orchestrator/artifactMetadata.js +5 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +8 -12
- package/dist/orchestrator/autoFixExecutor.js +40 -26
- package/dist/orchestrator/dependencyMap.js +1 -1
- package/dist/orchestrator/executorResult.d.ts +33 -0
- package/dist/orchestrator/executors.d.ts +7 -0
- package/dist/orchestrator/executors.js +24 -0
- package/dist/orchestrator/fileAnchors.js +42 -29
- package/dist/orchestrator/fileIntegrity.js +6 -1
- package/dist/orchestrator/flowCoverage.js +1 -2
- package/dist/orchestrator/flowPlanning.js +8 -4
- package/dist/orchestrator/graphEnrichmentExecutor.js +67 -45
- package/dist/orchestrator/ingestionExecutors.js +9 -1
- package/dist/orchestrator/intakeExecutors.d.ts +0 -4
- package/dist/orchestrator/intakeExecutors.js +24 -14
- package/dist/orchestrator/localCommands.d.ts +1 -0
- package/dist/orchestrator/localCommands.js +10 -17
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/requeueCommand.js +4 -0
- package/dist/orchestrator/reviewPacketGraph.js +50 -18
- package/dist/orchestrator/reviewPackets.js +10 -8
- package/dist/orchestrator/runtimeCommand.js +35 -7
- package/dist/orchestrator/runtimeValidationUpdate.js +6 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +3 -2
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +44 -18
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/state.js +1 -1
- package/dist/orchestrator/syntaxResolutionExecutor.js +17 -24
- package/dist/orchestrator/synthesisExecutors.js +1 -0
- package/dist/orchestrator/taskBuilder.js +5 -4
- package/dist/providers/claudeCodeProvider.js +4 -1
- package/dist/providers/opencodeProvider.js +4 -1
- package/dist/quota/discoveredLimits.js +3 -3
- package/dist/quota/headerExtraction.js +5 -2
- package/dist/quota/headerExtractors/claudeCodeHeaderExtractor.js +3 -0
- package/dist/quota/headerExtractors/index.js +3 -3
- package/dist/quota/index.d.ts +3 -1
- package/dist/quota/index.js +3 -0
- package/dist/reporting/findingRanks.d.ts +3 -0
- package/dist/reporting/findingRanks.js +24 -0
- package/dist/reporting/mergeFindings.js +1 -24
- package/dist/reporting/synthesis.d.ts +3 -1
- package/dist/reporting/synthesis.js +30 -6
- package/dist/reporting/synthesisNarrativePrompt.js +3 -0
- package/dist/reporting/workBlocks.js +1 -14
- package/dist/supervisor/operatorHandoff.js +2 -6
- package/dist/supervisor/runLedger.js +30 -41
- package/dist/types/activeDispatch.d.ts +31 -0
- package/dist/types/activeDispatch.js +2 -0
- package/dist/types.d.ts +21 -4
- package/dist/types.js +24 -16
- package/dist/validation/artifacts.js +3 -0
- package/dist/validation/auditResults.js +8 -2
- package/package.json +2 -2
- package/schemas/audit_findings.schema.json +5 -1
- package/schemas/audit_plan_metrics.schema.json +1 -1
- package/schemas/audit_result.schema.json +5 -6
- package/schemas/audit_task.schema.json +1 -4
- package/schemas/blind_spot_register.schema.json +1 -1
- package/schemas/coverage_matrix.schema.json +2 -8
- package/schemas/finding.schema.json +1 -16
- package/schemas/flow_coverage.schema.json +2 -8
- package/schemas/graph_bundle.schema.json +31 -0
- package/schemas/lens.schema.json +7 -0
- package/schemas/review_packets.schema.json +6 -17
- package/schemas/step_contract.schema.json +8 -2
- package/schemas/unit_manifest.schema.json +1 -4
- package/scripts/postinstall.mjs +3 -1
- package/skills/audit-code/audit-code.prompt.md +2 -3
- package/dist/extractors/graphManifestEdges.d.ts +0 -12
- package/dist/extractors/graphManifestEdges.js +0 -1135
package/dist/extractors/graph.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isAbsolute, relative, resolve } from "node:path";
|
|
|
3
3
|
import { posix } from "node:path";
|
|
4
4
|
import { buildDispositionMap, isAuditExcludedStatus } from "./disposition.js";
|
|
5
5
|
import { extractChromeExtensionManifestEdges, extractHtmlResourceEdges, } from "./browserExtension.js";
|
|
6
|
-
import { extractCargoWorkspaceMemberEdges, extractGoWorkspaceModuleEdges, extractMavenModuleEdges, extractPackageEntrypointEdges, extractPackageScriptEdges, extractPyprojectTestpathLinks, extractTypescriptProjectReferenceEdges, extractWorkspacePackageEdges, extractYamlPathReferenceEdges, isCargoManifestPath, isGoWorkspaceManifestPath, isMavenPomPath, isPyprojectPath, } from "./graphManifestEdges.js";
|
|
6
|
+
import { extractCargoWorkspaceMemberEdges, extractGoWorkspaceModuleEdges, extractMavenModuleEdges, extractPackageEntrypointEdges, extractPackageScriptEdges, extractPyprojectTestpathLinks, extractTypescriptProjectReferenceEdges, extractWorkspacePackageEdges, extractYamlPathReferenceEdges, isCargoManifestPath, isGoWorkspaceManifestPath, isMavenPomPath, isPyprojectPath, } from "./graphManifestEdges/index.js";
|
|
7
7
|
import { graphEdge, graphLookupKey, isPytestConftestPath, normalizeGraphPath, resolveCandidate, resolveReferenceLiteral, resolveSpecifier, SOURCE_EXTENSIONS, STRING_LITERAL_PATTERN, } from "./graphPathUtils.js";
|
|
8
8
|
import { extractPythonImportEdges } from "./graphPythonImports.js";
|
|
9
9
|
import { isTestPath, normalizeExtractorPath } from "./pathPatterns.js";
|
|
@@ -307,12 +307,13 @@ export async function buildGraphBundleFromFs(repoManifest, root, disposition, op
|
|
|
307
307
|
* its top-two-segment module root, suggesting shared module ownership.
|
|
308
308
|
*/
|
|
309
309
|
function extractHeuristicContainerEdges(filePath) {
|
|
310
|
-
const
|
|
310
|
+
const normalizedPath = normalizeGraphPath(filePath);
|
|
311
|
+
const parts = normalizedPath.split("/");
|
|
311
312
|
if (parts.length <= 2)
|
|
312
313
|
return [];
|
|
313
314
|
return [
|
|
314
315
|
graphEdge({
|
|
315
|
-
from:
|
|
316
|
+
from: normalizedPath,
|
|
316
317
|
to: `${parts[0]}/${parts[1]}`,
|
|
317
318
|
kind: EDGE_KIND.heuristicContainer,
|
|
318
319
|
direction: "undirected",
|
|
@@ -389,9 +390,15 @@ function logGraphExtractionMetric(graphs) {
|
|
|
389
390
|
const edgeCount = graphs.imports.length +
|
|
390
391
|
graphs.calls.length +
|
|
391
392
|
graphs.references.length +
|
|
392
|
-
graphs.routes.length
|
|
393
|
+
graphs.routes.length +
|
|
394
|
+
graphs.heuristics.length;
|
|
393
395
|
const nodes = new Set();
|
|
394
|
-
for (const edge of [
|
|
396
|
+
for (const edge of [
|
|
397
|
+
...graphs.imports,
|
|
398
|
+
...graphs.calls,
|
|
399
|
+
...graphs.references,
|
|
400
|
+
...graphs.heuristics,
|
|
401
|
+
]) {
|
|
395
402
|
nodes.add(edge.from);
|
|
396
403
|
nodes.add(edge.to);
|
|
397
404
|
}
|
|
@@ -404,6 +411,7 @@ function logGraphExtractionMetric(graphs) {
|
|
|
404
411
|
graphs.calls,
|
|
405
412
|
graphs.references,
|
|
406
413
|
graphs.routes,
|
|
414
|
+
graphs.heuristics,
|
|
407
415
|
].filter((edges) => edges.length > 0).length;
|
|
408
416
|
process.stderr.write(`[audit-code] graph: built bundle — ${nodes.size} nodes, ${edgeCount} edges across ${graphTypeCount} graph type(s)\n`);
|
|
409
417
|
}
|
|
@@ -413,6 +421,7 @@ export function buildGraphBundle(repoManifest, disposition, options = {}) {
|
|
|
413
421
|
calls: [],
|
|
414
422
|
references: [],
|
|
415
423
|
routes: [],
|
|
424
|
+
heuristics: [],
|
|
416
425
|
};
|
|
417
426
|
const dispositionMap = buildDispositionMap(disposition);
|
|
418
427
|
const pathLookup = buildPathLookup(repoManifest, dispositionMap);
|
|
@@ -421,8 +430,8 @@ export function buildGraphBundle(repoManifest, disposition, options = {}) {
|
|
|
421
430
|
if (file.excluded || (status && isAuditExcludedStatus(status))) {
|
|
422
431
|
continue;
|
|
423
432
|
}
|
|
424
|
-
acc.
|
|
425
|
-
acc.
|
|
433
|
+
acc.heuristics.push(...extractHeuristicContainerEdges(file.path));
|
|
434
|
+
acc.heuristics.push(...extractHeuristicAuthSessionEdges(file.path, repoManifest, dispositionMap));
|
|
426
435
|
const content = options.fileContents?.[file.path];
|
|
427
436
|
const fileRoutes = [];
|
|
428
437
|
if (content) {
|
|
@@ -446,6 +455,7 @@ export function buildGraphBundle(repoManifest, disposition, options = {}) {
|
|
|
446
455
|
calls: uniqueSortedEdges(acc.calls),
|
|
447
456
|
references: uniqueSortedEdges(acc.references),
|
|
448
457
|
routes: uniqueSortedRoutes(acc.routes),
|
|
458
|
+
heuristics: uniqueSortedEdges(acc.heuristics),
|
|
449
459
|
};
|
|
450
460
|
logGraphExtractionMetric(graphs);
|
|
451
461
|
return { graphs };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
import { WorkspacePattern } from "./workspace.js";
|
|
3
|
+
export declare function cargoWorkspacePatterns(content: string): WorkspacePattern[];
|
|
4
|
+
export declare function extractCargoWorkspaceMemberEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { graphEdge, isCargoManifestPath } from "../graphPathUtils.js";
|
|
2
|
+
import { addWorkspacePattern, normalizeWorkspacePattern, workspacePatternMatchesManifest } from "./workspace.js";
|
|
3
|
+
import { stripTomlComment, tomlArrayIsClosed, tomlStringArrayValues } from "./toml.js";
|
|
4
|
+
const CARGO_WORKSPACE_MEMBER_EDGE_CONFIDENCE = 0.87;
|
|
5
|
+
export function cargoWorkspacePatterns(content) {
|
|
6
|
+
const patterns = [];
|
|
7
|
+
let currentSection;
|
|
8
|
+
let collectingKey;
|
|
9
|
+
let collectedValue = "";
|
|
10
|
+
const flushCollectedValue = () => {
|
|
11
|
+
if (!collectingKey) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const value of tomlStringArrayValues(collectedValue)) {
|
|
15
|
+
addWorkspacePattern(patterns, collectingKey === "exclude" ? `!${value}` : value);
|
|
16
|
+
}
|
|
17
|
+
collectingKey = undefined;
|
|
18
|
+
collectedValue = "";
|
|
19
|
+
};
|
|
20
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
21
|
+
const withoutComment = stripTomlComment(rawLine);
|
|
22
|
+
const trimmed = withoutComment.trim();
|
|
23
|
+
if (trimmed.length === 0) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const sectionMatch = /^\[([^\]]+)\]\s*$/.exec(trimmed);
|
|
27
|
+
if (sectionMatch?.[1]) {
|
|
28
|
+
if (collectingKey) {
|
|
29
|
+
flushCollectedValue();
|
|
30
|
+
}
|
|
31
|
+
currentSection = sectionMatch[1].trim();
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (collectingKey) {
|
|
35
|
+
collectedValue = `${collectedValue}\n${trimmed}`;
|
|
36
|
+
if (tomlArrayIsClosed(collectedValue)) {
|
|
37
|
+
flushCollectedValue();
|
|
38
|
+
}
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (currentSection !== "workspace") {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const arrayMatch = /^(members|exclude)\s*=\s*(.+)$/.exec(trimmed);
|
|
45
|
+
if (!arrayMatch?.[1] || !arrayMatch[2]) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const value = arrayMatch[2].trim();
|
|
49
|
+
if (!value.startsWith("[")) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
collectingKey = arrayMatch[1];
|
|
53
|
+
collectedValue = value;
|
|
54
|
+
if (tomlArrayIsClosed(collectedValue)) {
|
|
55
|
+
flushCollectedValue();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (collectingKey) {
|
|
59
|
+
flushCollectedValue();
|
|
60
|
+
}
|
|
61
|
+
return patterns;
|
|
62
|
+
}
|
|
63
|
+
export function extractCargoWorkspaceMemberEdges(fromPath, content, pathLookup) {
|
|
64
|
+
if (!isCargoManifestPath(fromPath)) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const rawPatterns = cargoWorkspacePatterns(content);
|
|
68
|
+
if (rawPatterns.length === 0) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const positivePatterns = [];
|
|
72
|
+
const negativePatterns = [];
|
|
73
|
+
for (const { pattern, negated } of rawPatterns) {
|
|
74
|
+
const normalized = normalizeWorkspacePattern(fromPath, pattern);
|
|
75
|
+
if (!normalized) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (negated) {
|
|
79
|
+
negativePatterns.push(normalized);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
positivePatterns.push(normalized);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const edges = [];
|
|
86
|
+
for (const pattern of positivePatterns) {
|
|
87
|
+
for (const target of pathLookup.values()) {
|
|
88
|
+
if (target === fromPath || !isCargoManifestPath(target)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (!workspacePatternMatchesManifest(pattern, target, "Cargo.toml")) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (negativePatterns.some((negativePattern) => workspacePatternMatchesManifest(negativePattern, target, "Cargo.toml"))) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
edges.push(graphEdge({
|
|
98
|
+
from: fromPath,
|
|
99
|
+
to: target,
|
|
100
|
+
kind: "cargo-workspace-member-link",
|
|
101
|
+
confidence: CARGO_WORKSPACE_MEMBER_EDGE_CONFIDENCE,
|
|
102
|
+
reason: `Cargo workspace pattern '${pattern}' includes member manifest '${target}'.`,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return edges;
|
|
107
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
export declare const GO_WORKSPACE_MODULE_EDGE_CONFIDENCE = 0.87;
|
|
3
|
+
export declare function stripGoLineComment(line: string): string;
|
|
4
|
+
export declare function splitGoWorkspaceSpecifiers(value: string): string[];
|
|
5
|
+
export declare function extractGoWorkspaceModuleEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { scanStringAware } from "@audit-tools/shared";
|
|
3
|
+
import { graphEdge, normalizeGraphPath, isGoModuleManifestPath, isGoWorkspaceManifestPath } from "../graphPathUtils.js";
|
|
4
|
+
export const GO_WORKSPACE_MODULE_EDGE_CONFIDENCE = 0.87;
|
|
5
|
+
const GO_SCAN_OPTIONS = {
|
|
6
|
+
quoteChars: ['"', "`"],
|
|
7
|
+
// Backtick raw strings do not honour backslash escapes.
|
|
8
|
+
escapedQuotes: ['"'],
|
|
9
|
+
};
|
|
10
|
+
export function stripGoLineComment(line) {
|
|
11
|
+
let commentIndex;
|
|
12
|
+
scanStringAware(line, GO_SCAN_OPTIONS, {
|
|
13
|
+
onUnquoted(char, i) {
|
|
14
|
+
if (char === "/" && line[i + 1] === "/") {
|
|
15
|
+
commentIndex = i;
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
return commentIndex !== undefined ? line.slice(0, commentIndex) : line;
|
|
21
|
+
}
|
|
22
|
+
function unquoteGoWorkspaceSpecifier(value) {
|
|
23
|
+
const trimmed = value.trim();
|
|
24
|
+
if (trimmed.length < 2) {
|
|
25
|
+
return trimmed;
|
|
26
|
+
}
|
|
27
|
+
if (trimmed[0] === '"' && trimmed.at(-1) === '"') {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(trimmed);
|
|
30
|
+
return typeof parsed === "string" ? parsed.trim() : trimmed;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return trimmed.slice(1, -1).trim();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (trimmed[0] === "`" && trimmed.at(-1) === "`") {
|
|
37
|
+
return trimmed.slice(1, -1).trim();
|
|
38
|
+
}
|
|
39
|
+
return trimmed;
|
|
40
|
+
}
|
|
41
|
+
export function splitGoWorkspaceSpecifiers(value) {
|
|
42
|
+
const specifiers = [];
|
|
43
|
+
let tokenStart;
|
|
44
|
+
// Use scanStringAware to correctly skip over quoted string content, and
|
|
45
|
+
// detect whitespace-delimited token boundaries in unquoted regions.
|
|
46
|
+
// Quoted tokens are captured from the opening quote (tokenStart) through
|
|
47
|
+
// the closing quote (flushed on the next whitespace event), so that
|
|
48
|
+
// unquoteGoWorkspaceSpecifier sees the delimiters and can strip them.
|
|
49
|
+
scanStringAware(value, GO_SCAN_OPTIONS, {
|
|
50
|
+
onQuoteOpen(_q, i) {
|
|
51
|
+
tokenStart ??= i; // quoted token begins at the opening quote
|
|
52
|
+
},
|
|
53
|
+
onUnquoted(char, i) {
|
|
54
|
+
if (/\s/.test(char)) {
|
|
55
|
+
if (tokenStart !== undefined) {
|
|
56
|
+
const specifier = unquoteGoWorkspaceSpecifier(value.slice(tokenStart, i));
|
|
57
|
+
if (specifier.length > 0) {
|
|
58
|
+
specifiers.push(specifier);
|
|
59
|
+
}
|
|
60
|
+
tokenStart = undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
tokenStart ??= i;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
// Flush final token (no trailing whitespace).
|
|
69
|
+
if (tokenStart !== undefined) {
|
|
70
|
+
const specifier = unquoteGoWorkspaceSpecifier(value.slice(tokenStart));
|
|
71
|
+
if (specifier.length > 0) {
|
|
72
|
+
specifiers.push(specifier);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return specifiers;
|
|
76
|
+
}
|
|
77
|
+
function goWorkspaceUseSpecifiers(content) {
|
|
78
|
+
const specifiers = [];
|
|
79
|
+
let inUseBlock = false;
|
|
80
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
81
|
+
const trimmed = stripGoLineComment(rawLine).trim();
|
|
82
|
+
if (trimmed.length === 0) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (inUseBlock) {
|
|
86
|
+
const closeIndex = trimmed.indexOf(")");
|
|
87
|
+
const body = closeIndex >= 0 ? trimmed.slice(0, closeIndex).trim() : trimmed;
|
|
88
|
+
specifiers.push(...splitGoWorkspaceSpecifiers(body));
|
|
89
|
+
if (closeIndex >= 0) {
|
|
90
|
+
inUseBlock = false;
|
|
91
|
+
}
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const useMatch = /^use(?:\s+(.+)|\s*)$/.exec(trimmed);
|
|
95
|
+
if (!useMatch) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
let body = useMatch[1]?.trim() ?? "";
|
|
99
|
+
if (!body.startsWith("(")) {
|
|
100
|
+
specifiers.push(...splitGoWorkspaceSpecifiers(body));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
body = body.slice(1).trim();
|
|
104
|
+
const closeIndex = body.indexOf(")");
|
|
105
|
+
if (closeIndex >= 0) {
|
|
106
|
+
specifiers.push(...splitGoWorkspaceSpecifiers(body.slice(0, closeIndex).trim()));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
specifiers.push(...splitGoWorkspaceSpecifiers(body));
|
|
110
|
+
inUseBlock = true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return specifiers;
|
|
114
|
+
}
|
|
115
|
+
function resolveGoWorkspaceModuleReference(fromPath, specifier, pathLookup) {
|
|
116
|
+
const normalizedSpecifier = normalizeGraphPath(specifier);
|
|
117
|
+
if (normalizedSpecifier.length === 0 ||
|
|
118
|
+
normalizedSpecifier.startsWith("/") ||
|
|
119
|
+
/^[a-z][a-z0-9+.-]*:/i.test(normalizedSpecifier)) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const workspaceDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
123
|
+
const target = workspaceDir === "."
|
|
124
|
+
? normalizedSpecifier
|
|
125
|
+
: posix.join(workspaceDir, normalizedSpecifier);
|
|
126
|
+
const direct = pathLookup.get(target.toLowerCase());
|
|
127
|
+
if (direct && isGoModuleManifestPath(direct)) {
|
|
128
|
+
return direct;
|
|
129
|
+
}
|
|
130
|
+
return pathLookup.get(posix.join(target, "go.mod").toLowerCase());
|
|
131
|
+
}
|
|
132
|
+
export function extractGoWorkspaceModuleEdges(fromPath, content, pathLookup) {
|
|
133
|
+
if (!isGoWorkspaceManifestPath(fromPath)) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const edges = [];
|
|
137
|
+
for (const specifier of goWorkspaceUseSpecifiers(content)) {
|
|
138
|
+
const target = resolveGoWorkspaceModuleReference(fromPath, specifier, pathLookup);
|
|
139
|
+
if (!target) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
edges.push(graphEdge({
|
|
143
|
+
from: fromPath,
|
|
144
|
+
to: target,
|
|
145
|
+
kind: "go-workspace-module-link",
|
|
146
|
+
confidence: GO_WORKSPACE_MODULE_EDGE_CONFIDENCE,
|
|
147
|
+
reason: `Go workspace use directive '${specifier}' resolves to module '${target}'.`,
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
return edges;
|
|
151
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { isCargoManifestPath, isGoWorkspaceManifestPath, isMavenPomPath, isPyprojectPath, } from "../graphPathUtils.js";
|
|
2
|
+
export { extractPackageEntrypointEdges, extractPackageScriptEdges, extractWorkspacePackageEdges } from "./packageJson.js";
|
|
3
|
+
export { extractCargoWorkspaceMemberEdges } from "./cargo.js";
|
|
4
|
+
export { extractTypescriptProjectReferenceEdges } from "./typescript.js";
|
|
5
|
+
export { extractGoWorkspaceModuleEdges } from "./go.js";
|
|
6
|
+
export { extractMavenModuleEdges } from "./maven.js";
|
|
7
|
+
export { extractPyprojectTestpathLinks } from "./pyproject.js";
|
|
8
|
+
export { extractYamlPathReferenceEdges } from "./yamlPaths.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Re-exported for the graph builder, which imports these manifest predicates
|
|
2
|
+
// from here for historical reasons; the canonical definitions live in
|
|
3
|
+
// graphPathUtils.
|
|
4
|
+
export { isCargoManifestPath, isGoWorkspaceManifestPath, isMavenPomPath, isPyprojectPath, } from "../graphPathUtils.js";
|
|
5
|
+
export { extractPackageEntrypointEdges, extractPackageScriptEdges, extractWorkspacePackageEdges } from "./packageJson.js";
|
|
6
|
+
export { extractCargoWorkspaceMemberEdges } from "./cargo.js";
|
|
7
|
+
export { extractTypescriptProjectReferenceEdges } from "./typescript.js";
|
|
8
|
+
export { extractGoWorkspaceModuleEdges } from "./go.js";
|
|
9
|
+
export { extractMavenModuleEdges } from "./maven.js";
|
|
10
|
+
export { extractPyprojectTestpathLinks } from "./pyproject.js";
|
|
11
|
+
export { extractYamlPathReferenceEdges } from "./yamlPaths.js";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { scanStringAware } from "@audit-tools/shared";
|
|
2
|
+
const JSON_SCAN_OPTIONS = { quoteChars: ['"'], escapedQuotes: ['"'] };
|
|
3
|
+
export function stripJsonComments(content) {
|
|
4
|
+
let result = "";
|
|
5
|
+
let inString = false;
|
|
6
|
+
let escaped = false;
|
|
7
|
+
for (let index = 0; index < content.length; index++) {
|
|
8
|
+
const char = content[index];
|
|
9
|
+
const next = content[index + 1];
|
|
10
|
+
if (inString) {
|
|
11
|
+
result += char;
|
|
12
|
+
if (escaped) {
|
|
13
|
+
escaped = false;
|
|
14
|
+
}
|
|
15
|
+
else if (char === "\\") {
|
|
16
|
+
escaped = true;
|
|
17
|
+
}
|
|
18
|
+
else if (char === '"') {
|
|
19
|
+
inString = false;
|
|
20
|
+
}
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (char === '"') {
|
|
24
|
+
inString = true;
|
|
25
|
+
result += char;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (char === "/" && next === "/") {
|
|
29
|
+
while (index < content.length && content[index] !== "\n") {
|
|
30
|
+
index++;
|
|
31
|
+
}
|
|
32
|
+
if (index < content.length) {
|
|
33
|
+
result += content[index];
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (char === "/" && next === "*") {
|
|
38
|
+
index += 2;
|
|
39
|
+
while (index < content.length &&
|
|
40
|
+
!(content[index] === "*" && content[index + 1] === "/")) {
|
|
41
|
+
if (content[index] === "\n") {
|
|
42
|
+
result += "\n";
|
|
43
|
+
}
|
|
44
|
+
index++;
|
|
45
|
+
}
|
|
46
|
+
if (index < content.length) {
|
|
47
|
+
index++;
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
result += char;
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
export function removeTrailingJsonCommas(content) {
|
|
56
|
+
let result = "";
|
|
57
|
+
let pos = 0;
|
|
58
|
+
scanStringAware(content, JSON_SCAN_OPTIONS, {
|
|
59
|
+
onQuoteOpen(_q, i) {
|
|
60
|
+
result += content.slice(pos, i + 1);
|
|
61
|
+
pos = i + 1;
|
|
62
|
+
},
|
|
63
|
+
onQuoteClose(_q, i) {
|
|
64
|
+
result += content.slice(pos, i + 1);
|
|
65
|
+
pos = i + 1;
|
|
66
|
+
},
|
|
67
|
+
onUnquoted(char, i) {
|
|
68
|
+
if (char === ",") {
|
|
69
|
+
let lookahead = i + 1;
|
|
70
|
+
while (/\s/.test(content[lookahead] ?? "")) {
|
|
71
|
+
lookahead++;
|
|
72
|
+
}
|
|
73
|
+
if (content[lookahead] === "}" || content[lookahead] === "]") {
|
|
74
|
+
// Flush up to (not including) the comma; skip it.
|
|
75
|
+
result += content.slice(pos, i);
|
|
76
|
+
pos = i + 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
// Flush anything after the last event.
|
|
82
|
+
result += content.slice(pos);
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
export function parseJsoncObject(content) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(removeTrailingJsonCommas(stripJsonComments(content)));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return parsed;
|
|
97
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { graphEdge, normalizeGraphPath, isMavenPomPath } from "../graphPathUtils.js";
|
|
3
|
+
export const MAVEN_MODULE_EDGE_CONFIDENCE = 0.87;
|
|
4
|
+
function stripXmlComments(content) {
|
|
5
|
+
return content.replace(/<!--[\s\S]*?-->/g, "");
|
|
6
|
+
}
|
|
7
|
+
function decodeXmlText(value) {
|
|
8
|
+
return value
|
|
9
|
+
.replace(/</g, "<")
|
|
10
|
+
.replace(/>/g, ">")
|
|
11
|
+
.replace(/"/g, "\"")
|
|
12
|
+
.replace(/'/g, "'")
|
|
13
|
+
.replace(/&/g, "&");
|
|
14
|
+
}
|
|
15
|
+
function mavenModuleSpecifiers(content) {
|
|
16
|
+
const specifiers = [];
|
|
17
|
+
const withoutComments = stripXmlComments(content);
|
|
18
|
+
const modulesPattern = /<modules(?:\s[^>]*)?>([\s\S]*?)<\/modules>/gi;
|
|
19
|
+
let modulesMatch;
|
|
20
|
+
while ((modulesMatch = modulesPattern.exec(withoutComments))) {
|
|
21
|
+
const body = modulesMatch[1] ?? "";
|
|
22
|
+
const modulePattern = /<module(?:\s[^>]*)?>([\s\S]*?)<\/module>/gi;
|
|
23
|
+
let moduleMatch;
|
|
24
|
+
while ((moduleMatch = modulePattern.exec(body))) {
|
|
25
|
+
const specifier = decodeXmlText(moduleMatch[1] ?? "").trim();
|
|
26
|
+
if (specifier.length > 0) {
|
|
27
|
+
specifiers.push(specifier);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return specifiers;
|
|
32
|
+
}
|
|
33
|
+
function resolveMavenModuleReference(fromPath, specifier, pathLookup) {
|
|
34
|
+
const normalizedSpecifier = normalizeGraphPath(specifier);
|
|
35
|
+
if (normalizedSpecifier.length === 0 ||
|
|
36
|
+
normalizedSpecifier.startsWith("/") ||
|
|
37
|
+
/^[a-z][a-z0-9+.-]*:/i.test(normalizedSpecifier)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const manifestDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
41
|
+
const target = manifestDir === "."
|
|
42
|
+
? normalizedSpecifier
|
|
43
|
+
: posix.join(manifestDir, normalizedSpecifier);
|
|
44
|
+
const normalizedTarget = normalizeGraphPath(target);
|
|
45
|
+
if (normalizedTarget === ".." || normalizedTarget.startsWith("../")) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const direct = pathLookup.get(normalizedTarget.toLowerCase());
|
|
49
|
+
if (direct && isMavenPomPath(direct)) {
|
|
50
|
+
return direct;
|
|
51
|
+
}
|
|
52
|
+
return pathLookup.get(posix.join(normalizedTarget, "pom.xml").toLowerCase());
|
|
53
|
+
}
|
|
54
|
+
export function extractMavenModuleEdges(fromPath, content, pathLookup) {
|
|
55
|
+
if (!isMavenPomPath(fromPath)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const edges = [];
|
|
59
|
+
for (const specifier of mavenModuleSpecifiers(content)) {
|
|
60
|
+
const target = resolveMavenModuleReference(fromPath, specifier, pathLookup);
|
|
61
|
+
if (!target || target === fromPath) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
edges.push(graphEdge({
|
|
65
|
+
from: fromPath,
|
|
66
|
+
to: target,
|
|
67
|
+
kind: "maven-module-link",
|
|
68
|
+
confidence: MAVEN_MODULE_EDGE_CONFIDENCE,
|
|
69
|
+
reason: `Maven module '${specifier}' resolves to module manifest '${target}'.`,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
return edges;
|
|
73
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
import { WorkspacePattern } from "./workspace.js";
|
|
3
|
+
export declare const PACKAGE_ENTRYPOINT_EDGE_CONFIDENCE = 0.9;
|
|
4
|
+
export declare const PACKAGE_SCRIPT_EDGE_CONFIDENCE = 0.88;
|
|
5
|
+
export declare const WORKSPACE_PACKAGE_EDGE_CONFIDENCE = 0.86;
|
|
6
|
+
export declare const PACKAGE_SCRIPT_REFERENCE_PATTERN: RegExp;
|
|
7
|
+
export declare function packageEntrypointCandidates(content: string): Array<{
|
|
8
|
+
field: string;
|
|
9
|
+
specifier: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function resolvePackageEntrypoint(packagePath: string, specifier: string, pathLookup: Map<string, string>): string | undefined;
|
|
12
|
+
export declare function extractPackageEntrypointEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
13
|
+
export declare function packageScriptCandidates(content: string): Array<{
|
|
14
|
+
script: string;
|
|
15
|
+
specifier: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare function extractPackageScriptEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
18
|
+
export declare function packageWorkspacePatterns(content: string): WorkspacePattern[];
|
|
19
|
+
export declare function extractWorkspacePackageEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|