auditor-lambda 0.10.3 → 0.10.8
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 +22 -1806
- package/audit-code-wrapper-opencode.mjs +255 -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 +2 -3
- 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 -234
- 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 +35 -11
- 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 -2
- package/dist/io/artifacts.js +8 -4
- 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 +5 -2
- 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 +4 -3
- package/skills/audit-code/audit-code.prompt.md +3 -4
- package/dist/extractors/graphManifestEdges.d.ts +0 -12
- package/dist/extractors/graphManifestEdges.js +0 -1135
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { graphEdge, normalizeGraphPath, resolveCandidate, isPackageManifestPath } from "../graphPathUtils.js";
|
|
3
|
+
import { collectWorkspacePatternValues, normalizeWorkspacePattern, workspacePatternMatchesPackage, } from "./workspace.js";
|
|
4
|
+
import { pnpmWorkspacePatterns } from "./pnpm.js";
|
|
5
|
+
import { isPnpmWorkspaceManifestPath } from "../graphPathUtils.js";
|
|
6
|
+
export const PACKAGE_ENTRYPOINT_EDGE_CONFIDENCE = 0.9;
|
|
7
|
+
export const PACKAGE_SCRIPT_EDGE_CONFIDENCE = 0.88;
|
|
8
|
+
export const WORKSPACE_PACKAGE_EDGE_CONFIDENCE = 0.86;
|
|
9
|
+
export const PACKAGE_SCRIPT_REFERENCE_PATTERN = /(?:^|[\s"'`])((?:\.{1,2}\/)?(?:[\w.-]+\/)*[\w.-]+\.(?:cjs|cts|js|jsx|mjs|mts|ts|tsx))(?:$|[\s"'`])/gi;
|
|
10
|
+
function collectPackageEntrypointValues(value, fieldPath, entries) {
|
|
11
|
+
if (typeof value === "string") {
|
|
12
|
+
if (value.trim().length > 0) {
|
|
13
|
+
entries.push({ field: fieldPath, specifier: value });
|
|
14
|
+
}
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(value)) {
|
|
18
|
+
value.forEach((item, index) => collectPackageEntrypointValues(item, `${fieldPath}.${index}`, entries));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (value === null || typeof value !== "object") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
for (const [key, item] of Object.entries(value)) {
|
|
25
|
+
collectPackageEntrypointValues(item, `${fieldPath}.${key}`, entries);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function packageEntrypointCandidates(content) {
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(content);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const record = parsed;
|
|
40
|
+
const entries = [];
|
|
41
|
+
for (const field of ["main", "module", "types", "typings", "browser"]) {
|
|
42
|
+
collectPackageEntrypointValues(record[field], field, entries);
|
|
43
|
+
}
|
|
44
|
+
collectPackageEntrypointValues(record.bin, "bin", entries);
|
|
45
|
+
collectPackageEntrypointValues(record.exports, "exports", entries);
|
|
46
|
+
return entries;
|
|
47
|
+
}
|
|
48
|
+
export function resolvePackageEntrypoint(packagePath, specifier, pathLookup) {
|
|
49
|
+
const normalizedSpecifier = normalizeGraphPath(specifier);
|
|
50
|
+
if (normalizedSpecifier.length === 0 ||
|
|
51
|
+
normalizedSpecifier.startsWith("/") ||
|
|
52
|
+
/^[a-z][a-z0-9+.-]*:/i.test(normalizedSpecifier)) {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
const packageDir = posix.dirname(normalizeGraphPath(packagePath));
|
|
56
|
+
const packageRelative = packageDir === "."
|
|
57
|
+
? normalizedSpecifier
|
|
58
|
+
: posix.join(packageDir, normalizedSpecifier);
|
|
59
|
+
return resolveCandidate(packageRelative, pathLookup);
|
|
60
|
+
}
|
|
61
|
+
export function extractPackageEntrypointEdges(fromPath, content, pathLookup) {
|
|
62
|
+
if (!isPackageManifestPath(fromPath)) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
const edges = [];
|
|
66
|
+
for (const { field, specifier } of packageEntrypointCandidates(content)) {
|
|
67
|
+
const target = resolvePackageEntrypoint(fromPath, specifier, pathLookup);
|
|
68
|
+
if (!target) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
edges.push(graphEdge({
|
|
72
|
+
from: fromPath,
|
|
73
|
+
to: target,
|
|
74
|
+
kind: "package-entrypoint-link",
|
|
75
|
+
confidence: PACKAGE_ENTRYPOINT_EDGE_CONFIDENCE,
|
|
76
|
+
reason: `Package manifest field '${field}' points to '${specifier}'.`,
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
return edges;
|
|
80
|
+
}
|
|
81
|
+
export function packageScriptCandidates(content) {
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = JSON.parse(content);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
const scripts = parsed.scripts;
|
|
93
|
+
if (scripts === null ||
|
|
94
|
+
typeof scripts !== "object" ||
|
|
95
|
+
Array.isArray(scripts)) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const entries = [];
|
|
99
|
+
for (const [script, command] of Object.entries(scripts)) {
|
|
100
|
+
if (typeof command !== "string") {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
PACKAGE_SCRIPT_REFERENCE_PATTERN.lastIndex = 0;
|
|
104
|
+
for (const match of command.matchAll(PACKAGE_SCRIPT_REFERENCE_PATTERN)) {
|
|
105
|
+
const specifier = match[1]?.trim();
|
|
106
|
+
if (specifier) {
|
|
107
|
+
entries.push({ script, specifier });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
export function extractPackageScriptEdges(fromPath, content, pathLookup) {
|
|
114
|
+
if (!isPackageManifestPath(fromPath)) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const edges = [];
|
|
118
|
+
for (const { script, specifier } of packageScriptCandidates(content)) {
|
|
119
|
+
const target = resolvePackageEntrypoint(fromPath, specifier, pathLookup);
|
|
120
|
+
if (!target) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
edges.push(graphEdge({
|
|
124
|
+
from: fromPath,
|
|
125
|
+
to: target,
|
|
126
|
+
kind: "package-script-link",
|
|
127
|
+
confidence: PACKAGE_SCRIPT_EDGE_CONFIDENCE,
|
|
128
|
+
reason: `Package script '${script}' references '${specifier}'.`,
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
return edges;
|
|
132
|
+
}
|
|
133
|
+
export function packageWorkspacePatterns(content) {
|
|
134
|
+
let parsed;
|
|
135
|
+
try {
|
|
136
|
+
parsed = JSON.parse(content);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const record = parsed;
|
|
145
|
+
const patterns = [];
|
|
146
|
+
collectWorkspacePatternValues(record.workspaces, patterns);
|
|
147
|
+
if (record.workspaces !== null &&
|
|
148
|
+
typeof record.workspaces === "object" &&
|
|
149
|
+
!Array.isArray(record.workspaces)) {
|
|
150
|
+
collectWorkspacePatternValues(record.workspaces.packages, patterns);
|
|
151
|
+
}
|
|
152
|
+
return patterns;
|
|
153
|
+
}
|
|
154
|
+
function workspacePatternsForFile(path, content) {
|
|
155
|
+
if (isPackageManifestPath(path)) {
|
|
156
|
+
return packageWorkspacePatterns(content);
|
|
157
|
+
}
|
|
158
|
+
if (isPnpmWorkspaceManifestPath(path)) {
|
|
159
|
+
return pnpmWorkspacePatterns(content);
|
|
160
|
+
}
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
export function extractWorkspacePackageEdges(fromPath, content, pathLookup) {
|
|
164
|
+
const rawPatterns = workspacePatternsForFile(fromPath, content);
|
|
165
|
+
if (rawPatterns.length === 0) {
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
const positivePatterns = [];
|
|
169
|
+
const negativePatterns = [];
|
|
170
|
+
for (const { pattern, negated } of rawPatterns) {
|
|
171
|
+
const normalized = normalizeWorkspacePattern(fromPath, pattern);
|
|
172
|
+
if (!normalized) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (negated) {
|
|
176
|
+
negativePatterns.push(normalized);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
positivePatterns.push(normalized);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const edges = [];
|
|
183
|
+
for (const pattern of positivePatterns) {
|
|
184
|
+
for (const target of pathLookup.values()) {
|
|
185
|
+
if (target === fromPath || !isPackageManifestPath(target)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (!workspacePatternMatchesPackage(pattern, target)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (negativePatterns.some((negativePattern) => workspacePatternMatchesPackage(negativePattern, target))) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
edges.push(graphEdge({
|
|
195
|
+
from: fromPath,
|
|
196
|
+
to: target,
|
|
197
|
+
kind: "workspace-package-link",
|
|
198
|
+
confidence: WORKSPACE_PACKAGE_EDGE_CONFIDENCE,
|
|
199
|
+
reason: `Workspace pattern '${pattern}' includes package manifest '${target}'.`,
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return edges;
|
|
204
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { addWorkspacePattern } from "./workspace.js";
|
|
2
|
+
import { stripYamlComment, unquoteYamlScalar, splitYamlInlineList } from "./yaml.js";
|
|
3
|
+
export function pnpmWorkspacePatterns(content) {
|
|
4
|
+
const patterns = [];
|
|
5
|
+
const lines = content.split(/\r?\n/);
|
|
6
|
+
let inPackagesList = false;
|
|
7
|
+
let packagesIndent = 0;
|
|
8
|
+
for (const line of lines) {
|
|
9
|
+
const withoutComment = stripYamlComment(line);
|
|
10
|
+
if (withoutComment.trim().length === 0) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const indent = withoutComment.match(/^\s*/)?.[0].length ?? 0;
|
|
14
|
+
const trimmed = withoutComment.trim();
|
|
15
|
+
if (inPackagesList) {
|
|
16
|
+
if (indent <= packagesIndent) {
|
|
17
|
+
inPackagesList = false;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const itemMatch = /^-\s+(.+)$/.exec(trimmed);
|
|
21
|
+
if (itemMatch?.[1]) {
|
|
22
|
+
addWorkspacePattern(patterns, unquoteYamlScalar(itemMatch[1]));
|
|
23
|
+
}
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const packagesMatch = /^packages\s*:\s*(.*)$/.exec(trimmed);
|
|
28
|
+
if (!packagesMatch || indent !== 0) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const inlineValue = packagesMatch[1]?.trim() ?? "";
|
|
32
|
+
if (inlineValue.length === 0) {
|
|
33
|
+
inPackagesList = true;
|
|
34
|
+
packagesIndent = indent;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
for (const pattern of splitYamlInlineList(inlineValue)) {
|
|
38
|
+
addWorkspacePattern(patterns, pattern);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return patterns;
|
|
42
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { graphEdge, normalizeGraphPath, isPyprojectPath } from "../graphPathUtils.js";
|
|
3
|
+
import { stripTomlComment, tomlArrayIsClosed, tomlStringArrayValues } from "./toml.js";
|
|
4
|
+
export const PYPROJECT_TESTPATHS_LINK_CONFIDENCE = 0.85;
|
|
5
|
+
function pyprojectTestpaths(content) {
|
|
6
|
+
const values = [];
|
|
7
|
+
let currentSection = "";
|
|
8
|
+
let collectingKey;
|
|
9
|
+
let collectedValue = "";
|
|
10
|
+
const flush = () => {
|
|
11
|
+
if (!collectingKey)
|
|
12
|
+
return;
|
|
13
|
+
for (const v of tomlStringArrayValues(collectedValue)) {
|
|
14
|
+
values.push(v);
|
|
15
|
+
}
|
|
16
|
+
collectingKey = undefined;
|
|
17
|
+
collectedValue = "";
|
|
18
|
+
};
|
|
19
|
+
for (const rawLine of content.split(/\r?\n/)) {
|
|
20
|
+
const withoutComment = stripTomlComment(rawLine);
|
|
21
|
+
const trimmed = withoutComment.trim();
|
|
22
|
+
if (trimmed.length === 0)
|
|
23
|
+
continue;
|
|
24
|
+
const sectionMatch = /^\[([^\]]+)\]\s*$/.exec(trimmed);
|
|
25
|
+
if (sectionMatch?.[1]) {
|
|
26
|
+
flush();
|
|
27
|
+
currentSection = sectionMatch[1].trim();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (collectingKey) {
|
|
31
|
+
collectedValue = `${collectedValue}\n${trimmed}`;
|
|
32
|
+
if (tomlArrayIsClosed(collectedValue)) {
|
|
33
|
+
flush();
|
|
34
|
+
}
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (currentSection !== "tool.pytest.ini_options")
|
|
38
|
+
continue;
|
|
39
|
+
const keyMatch = /^testpaths\s*=\s*(.+)$/.exec(trimmed);
|
|
40
|
+
if (!keyMatch?.[1])
|
|
41
|
+
continue;
|
|
42
|
+
const value = keyMatch[1].trim();
|
|
43
|
+
if (!value.startsWith("[")) {
|
|
44
|
+
const bare = value.replace(/^["']|["']$/g, "").trim();
|
|
45
|
+
if (bare.length > 0)
|
|
46
|
+
values.push(bare);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
collectingKey = "testpaths";
|
|
50
|
+
collectedValue = value;
|
|
51
|
+
if (tomlArrayIsClosed(collectedValue)) {
|
|
52
|
+
flush();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
flush();
|
|
56
|
+
return values;
|
|
57
|
+
}
|
|
58
|
+
export function extractPyprojectTestpathLinks(fromPath, content, pathLookup) {
|
|
59
|
+
if (!isPyprojectPath(fromPath)) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
const testpaths = pyprojectTestpaths(content);
|
|
63
|
+
if (testpaths.length === 0) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const pyprojectDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
67
|
+
const edges = [];
|
|
68
|
+
for (const testpath of testpaths) {
|
|
69
|
+
const resolvedTestpath = pyprojectDir === "." ? testpath : posix.join(pyprojectDir, testpath);
|
|
70
|
+
const conftestKey = posix.join(resolvedTestpath, "conftest.py").toLowerCase();
|
|
71
|
+
const conftestTarget = pathLookup.get(conftestKey);
|
|
72
|
+
if (!conftestTarget || conftestTarget === fromPath)
|
|
73
|
+
continue;
|
|
74
|
+
edges.push(graphEdge({
|
|
75
|
+
from: fromPath,
|
|
76
|
+
to: conftestTarget,
|
|
77
|
+
kind: "pyproject-testpaths-link",
|
|
78
|
+
confidence: PYPROJECT_TESTPATHS_LINK_CONFIDENCE,
|
|
79
|
+
reason: `pyproject.toml testpaths entry '${testpath}' resolves to '${conftestTarget}'.`,
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
return edges;
|
|
83
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function stripTomlComment(line: string): string;
|
|
2
|
+
export declare function tomlArrayIsClosed(value: string): boolean;
|
|
3
|
+
export declare function unquoteTomlString(value: string, quote: '"' | "'"): string;
|
|
4
|
+
export declare function tomlStringArrayValues(value: string): string[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { scanStringAware } from "@audit-tools/shared";
|
|
2
|
+
const TOML_SCAN_OPTIONS = {
|
|
3
|
+
quoteChars: ['"', "'"],
|
|
4
|
+
// Only double-quoted strings honour backslash escapes in TOML.
|
|
5
|
+
escapedQuotes: ['"'],
|
|
6
|
+
};
|
|
7
|
+
export function stripTomlComment(line) {
|
|
8
|
+
let commentIndex;
|
|
9
|
+
scanStringAware(line, TOML_SCAN_OPTIONS, {
|
|
10
|
+
onUnquoted(char, i) {
|
|
11
|
+
if (char === "#") {
|
|
12
|
+
commentIndex = i;
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
return commentIndex !== undefined ? line.slice(0, commentIndex) : line;
|
|
18
|
+
}
|
|
19
|
+
export function tomlArrayIsClosed(value) {
|
|
20
|
+
let depth = 0;
|
|
21
|
+
let found = false;
|
|
22
|
+
scanStringAware(value, TOML_SCAN_OPTIONS, {
|
|
23
|
+
onUnquoted(char) {
|
|
24
|
+
if (char === "[") {
|
|
25
|
+
depth += 1;
|
|
26
|
+
}
|
|
27
|
+
else if (char === "]") {
|
|
28
|
+
depth -= 1;
|
|
29
|
+
if (depth <= 0) {
|
|
30
|
+
found = true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
return found;
|
|
37
|
+
}
|
|
38
|
+
export function unquoteTomlString(value, quote) {
|
|
39
|
+
if (quote === "'") {
|
|
40
|
+
return value.trim();
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(`"${value}"`);
|
|
44
|
+
return typeof parsed === "string" ? parsed.trim() : value.trim();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return value.replace(/\\"/g, '"').trim();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function tomlStringArrayValues(value) {
|
|
51
|
+
const values = [];
|
|
52
|
+
let openIndex = 0;
|
|
53
|
+
scanStringAware(value, TOML_SCAN_OPTIONS, {
|
|
54
|
+
onQuoteOpen(_quoteChar, i) {
|
|
55
|
+
openIndex = i + 1; // content starts after the opening quote
|
|
56
|
+
},
|
|
57
|
+
onQuoteClose(quoteChar, i) {
|
|
58
|
+
if (quoteChar === "`") {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const item = unquoteTomlString(value.slice(openIndex, i), quoteChar);
|
|
62
|
+
if (item.length > 0) {
|
|
63
|
+
values.push(item);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
return values;
|
|
68
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
export declare const TYPESCRIPT_PROJECT_REFERENCE_EDGE_CONFIDENCE = 0.87;
|
|
3
|
+
export declare function extractTypescriptProjectReferenceEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { graphEdge, normalizeGraphPath, resolveCandidate, isTypescriptProjectConfigPath } from "../graphPathUtils.js";
|
|
3
|
+
import { parseJsoncObject } from "./jsonc.js";
|
|
4
|
+
export const TYPESCRIPT_PROJECT_REFERENCE_EDGE_CONFIDENCE = 0.87;
|
|
5
|
+
function typescriptProjectReferenceSpecifiers(content) {
|
|
6
|
+
const parsed = parseJsoncObject(content);
|
|
7
|
+
if (!parsed || !Array.isArray(parsed.references)) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
return parsed.references
|
|
11
|
+
.map((item) => {
|
|
12
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const referencePath = item.path;
|
|
16
|
+
return typeof referencePath === "string" ? referencePath.trim() : undefined;
|
|
17
|
+
})
|
|
18
|
+
.filter((specifier) => Boolean(specifier));
|
|
19
|
+
}
|
|
20
|
+
function resolveTypescriptProjectReference(fromPath, specifier, pathLookup) {
|
|
21
|
+
const normalizedSpecifier = normalizeGraphPath(specifier);
|
|
22
|
+
if (normalizedSpecifier.length === 0 ||
|
|
23
|
+
normalizedSpecifier.startsWith("/") ||
|
|
24
|
+
/^[a-z][a-z0-9+.-]*:/i.test(normalizedSpecifier)) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const configDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
28
|
+
const target = configDir === "."
|
|
29
|
+
? normalizedSpecifier
|
|
30
|
+
: posix.join(configDir, normalizedSpecifier);
|
|
31
|
+
const direct = resolveCandidate(target, pathLookup);
|
|
32
|
+
if (direct && isTypescriptProjectConfigPath(direct)) {
|
|
33
|
+
return direct;
|
|
34
|
+
}
|
|
35
|
+
return pathLookup.get(posix.join(target, "tsconfig.json").toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
export function extractTypescriptProjectReferenceEdges(fromPath, content, pathLookup) {
|
|
38
|
+
if (!isTypescriptProjectConfigPath(fromPath)) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const edges = [];
|
|
42
|
+
for (const specifier of typescriptProjectReferenceSpecifiers(content)) {
|
|
43
|
+
const target = resolveTypescriptProjectReference(fromPath, specifier, pathLookup);
|
|
44
|
+
if (!target) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
edges.push(graphEdge({
|
|
48
|
+
from: fromPath,
|
|
49
|
+
to: target,
|
|
50
|
+
kind: "typescript-project-reference-link",
|
|
51
|
+
confidence: TYPESCRIPT_PROJECT_REFERENCE_EDGE_CONFIDENCE,
|
|
52
|
+
reason: `TypeScript project reference '${specifier}' resolves to '${target}'.`,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
return edges;
|
|
56
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface WorkspacePattern {
|
|
2
|
+
pattern: string;
|
|
3
|
+
negated: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function addWorkspacePattern(patterns: WorkspacePattern[], rawPattern: string): void;
|
|
6
|
+
export declare function collectWorkspacePatternValues(value: unknown, patterns: WorkspacePattern[]): void;
|
|
7
|
+
export declare function normalizeWorkspacePattern(workspacePath: string, pattern: string): string | undefined;
|
|
8
|
+
export declare function globPatternToRegExp(pattern: string): RegExp;
|
|
9
|
+
export declare function workspacePatternMatchesPackage(workspacePattern: string, packagePath: string): boolean;
|
|
10
|
+
export declare function workspacePatternMatchesManifest(workspacePattern: string, manifestPath: string, manifestName: string): boolean;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { normalizeGraphPath } from "../graphPathUtils.js";
|
|
3
|
+
export function addWorkspacePattern(patterns, rawPattern) {
|
|
4
|
+
const trimmedPattern = rawPattern.trim();
|
|
5
|
+
if (trimmedPattern.length === 0) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const negated = trimmedPattern.startsWith("!");
|
|
9
|
+
const pattern = negated ? trimmedPattern.slice(1).trim() : trimmedPattern;
|
|
10
|
+
if (pattern.length > 0) {
|
|
11
|
+
patterns.push({ pattern, negated });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function collectWorkspacePatternValues(value, patterns) {
|
|
15
|
+
if (!Array.isArray(value)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
for (const item of value) {
|
|
19
|
+
if (typeof item !== "string") {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
addWorkspacePattern(patterns, item);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function normalizeWorkspacePattern(workspacePath, pattern) {
|
|
26
|
+
const normalizedPattern = pattern
|
|
27
|
+
.replace(/\\/g, "/")
|
|
28
|
+
.replace(/^\.\//, "")
|
|
29
|
+
.replace(/\/+$/, "");
|
|
30
|
+
if (normalizedPattern.length === 0 ||
|
|
31
|
+
normalizedPattern.startsWith("/") ||
|
|
32
|
+
/^[a-z][a-z0-9+.-]*:/i.test(normalizedPattern)) {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const workspaceDir = posix.dirname(normalizeGraphPath(workspacePath));
|
|
36
|
+
return workspaceDir === "."
|
|
37
|
+
? normalizedPattern
|
|
38
|
+
: posix.join(workspaceDir, normalizedPattern);
|
|
39
|
+
}
|
|
40
|
+
export function globPatternToRegExp(pattern) {
|
|
41
|
+
let source = "^";
|
|
42
|
+
for (let index = 0; index < pattern.length; index++) {
|
|
43
|
+
const char = pattern[index];
|
|
44
|
+
const next = pattern[index + 1];
|
|
45
|
+
if (char === "*" && next === "*") {
|
|
46
|
+
source += ".*";
|
|
47
|
+
index++;
|
|
48
|
+
}
|
|
49
|
+
else if (char === "*") {
|
|
50
|
+
source += "[^/]*";
|
|
51
|
+
}
|
|
52
|
+
else if (char === "?") {
|
|
53
|
+
source += "[^/]";
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
source += char.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return new RegExp(`${source}$`, "i");
|
|
60
|
+
}
|
|
61
|
+
export function workspacePatternMatchesPackage(workspacePattern, packagePath) {
|
|
62
|
+
return workspacePatternMatchesManifest(workspacePattern, packagePath, "package.json");
|
|
63
|
+
}
|
|
64
|
+
export function workspacePatternMatchesManifest(workspacePattern, manifestPath, manifestName) {
|
|
65
|
+
const normalizedManifestPath = normalizeGraphPath(manifestPath);
|
|
66
|
+
const manifestDir = posix.dirname(normalizedManifestPath);
|
|
67
|
+
const lowerManifestPattern = `/${manifestName.toLowerCase()}`;
|
|
68
|
+
const patternTarget = workspacePattern.toLowerCase().endsWith(lowerManifestPattern)
|
|
69
|
+
? normalizedManifestPath
|
|
70
|
+
: manifestDir;
|
|
71
|
+
return globPatternToRegExp(workspacePattern).test(patternTarget);
|
|
72
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function stripYamlComment(line) {
|
|
2
|
+
let quote;
|
|
3
|
+
for (let index = 0; index < line.length; index++) {
|
|
4
|
+
const char = line[index];
|
|
5
|
+
if (quote) {
|
|
6
|
+
if (char === quote) {
|
|
7
|
+
quote = undefined;
|
|
8
|
+
}
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (char === '"' || char === "'") {
|
|
12
|
+
quote = char;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (char === "#") {
|
|
16
|
+
return line.slice(0, index);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return line;
|
|
20
|
+
}
|
|
21
|
+
export function unquoteYamlScalar(value) {
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
if (trimmed.length < 2) {
|
|
24
|
+
return trimmed;
|
|
25
|
+
}
|
|
26
|
+
const quote = trimmed[0];
|
|
27
|
+
if ((quote === '"' || quote === "'") && trimmed.at(-1) === quote) {
|
|
28
|
+
return trimmed.slice(1, -1).trim();
|
|
29
|
+
}
|
|
30
|
+
return trimmed;
|
|
31
|
+
}
|
|
32
|
+
export function splitYamlInlineList(value) {
|
|
33
|
+
const trimmed = value.trim();
|
|
34
|
+
if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const values = [];
|
|
38
|
+
let quote;
|
|
39
|
+
let start = 1;
|
|
40
|
+
for (let index = 1; index < trimmed.length - 1; index++) {
|
|
41
|
+
const char = trimmed[index];
|
|
42
|
+
if (quote) {
|
|
43
|
+
if (char === quote) {
|
|
44
|
+
quote = undefined;
|
|
45
|
+
}
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === '"' || char === "'") {
|
|
49
|
+
quote = char;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (char === ",") {
|
|
53
|
+
values.push(unquoteYamlScalar(trimmed.slice(start, index)));
|
|
54
|
+
start = index + 1;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
values.push(unquoteYamlScalar(trimmed.slice(start, -1)));
|
|
58
|
+
return values.filter((item) => item.length > 0);
|
|
59
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
|
+
export declare const YAML_PATH_REFERENCE_LINK_CONFIDENCE = 0.8;
|
|
3
|
+
export declare const YAML_CONFIG_EXTENSIONS: readonly [".yaml", ".yml", ".json", ".toml"];
|
|
4
|
+
export declare function extractYamlPathReferenceEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|