auditor-lambda 0.6.8 → 0.6.10

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.
Files changed (34) hide show
  1. package/dist/cli/auditStep.d.ts +63 -0
  2. package/dist/cli/auditStep.js +133 -0
  3. package/dist/cli/envelope.d.ts +47 -0
  4. package/dist/cli/envelope.js +64 -0
  5. package/dist/cli/lineIndex.d.ts +4 -0
  6. package/dist/cli/lineIndex.js +44 -0
  7. package/dist/cli/reviewRun.d.ts +29 -0
  8. package/dist/cli/reviewRun.js +143 -0
  9. package/dist/cli.js +7 -358
  10. package/dist/extractors/fileInventory.js +1 -1452
  11. package/dist/extractors/graph.js +5 -825
  12. package/dist/extractors/graphPathUtils.d.ts +12 -0
  13. package/dist/extractors/graphPathUtils.js +58 -0
  14. package/dist/extractors/graphRoutes.d.ts +12 -0
  15. package/dist/extractors/graphRoutes.js +435 -0
  16. package/dist/extractors/graphSuites.d.ts +4 -0
  17. package/dist/extractors/graphSuites.js +246 -0
  18. package/dist/extractors/graphTestSources.d.ts +2 -0
  19. package/dist/extractors/graphTestSources.js +102 -0
  20. package/dist/extractors/languageMap.generated.d.ts +1 -0
  21. package/dist/extractors/languageMap.generated.js +1455 -0
  22. package/dist/providers/claudeCodeProvider.d.ts +1 -1
  23. package/dist/providers/claudeCodeProvider.js +3 -2
  24. package/dist/providers/localSubprocessProvider.d.ts +1 -1
  25. package/dist/providers/localSubprocessProvider.js +3 -3
  26. package/dist/providers/opencodeProvider.js +6 -22
  27. package/dist/providers/subprocessTemplateProvider.js +22 -9
  28. package/dist/quota/index.d.ts +2 -2
  29. package/dist/quota/index.js +5 -2
  30. package/package.json +5 -4
  31. package/dist/providers/spawnLoggedCommand.d.ts +0 -12
  32. package/dist/providers/spawnLoggedCommand.js +0 -186
  33. package/dist/quota/scheduler.d.ts +0 -20
  34. package/dist/quota/scheduler.js +0 -151
@@ -0,0 +1,246 @@
1
+ import { posix } from "node:path";
2
+ import { graphEdge, isJsonSchemaPath, isPytestConftestPath, normalizeGraphPath, resolveCandidate, STRING_LITERAL_PATTERN, } from "./graphPathUtils.js";
3
+ import { isTestPath, normalizeExtractorPath } from "./pathPatterns.js";
4
+ const JSON_SCHEMA_REF_EDGE_CONFIDENCE = 0.93;
5
+ const SCHEMA_CONTRACT_TEST_EDGE_CONFIDENCE = 0.86;
6
+ const SCHEMA_SUITE_EDGE_CONFIDENCE = 0.78;
7
+ const GITHUB_WORKFLOW_SUITE_EDGE_CONFIDENCE = 0.78;
8
+ const PACKAGE_SCRIPT_SUITE_EDGE_CONFIDENCE = 0.78;
9
+ const TYPESCRIPT_TYPE_SUITE_EDGE_CONFIDENCE = 0.78;
10
+ const PYTHON_TEST_UTIL_SUITE_EDGE_CONFIDENCE = 0.72;
11
+ const PYTHON_TEST_UTIL_SEGMENT_NAMES = new Set(["utils", "helpers", "support"]);
12
+ const MAX_BOUNDED_SUITE_EDGE_FILES = 12;
13
+ const MAX_BOUNDED_TYPE_SUITE_EDGE_FILES = 16;
14
+ const MAX_TYPE_CONTRACT_SOURCE_BYTES = 64 * 1024;
15
+ const TYPESCRIPT_TYPE_CONTRACT_EXTENSIONS = [
16
+ ".ts",
17
+ ".tsx",
18
+ ".mts",
19
+ ".cts",
20
+ ];
21
+ const PACKAGE_SCRIPT_SUITE_EXTENSIONS = [
22
+ ".js",
23
+ ".jsx",
24
+ ".mjs",
25
+ ".cjs",
26
+ ".ts",
27
+ ".tsx",
28
+ ".mts",
29
+ ".cts",
30
+ ];
31
+ function collectJsonSchemaRefs(value, refs) {
32
+ if (Array.isArray(value)) {
33
+ for (const item of value) {
34
+ collectJsonSchemaRefs(item, refs);
35
+ }
36
+ return;
37
+ }
38
+ if (value === null || typeof value !== "object") {
39
+ return;
40
+ }
41
+ for (const [key, item] of Object.entries(value)) {
42
+ if (key === "$ref" && typeof item === "string" && item.trim().length > 0) {
43
+ refs.add(item.trim());
44
+ continue;
45
+ }
46
+ collectJsonSchemaRefs(item, refs);
47
+ }
48
+ }
49
+ function resolveJsonSchemaRef(fromPath, ref, pathLookup) {
50
+ const targetSpecifier = (ref.split("#", 1)[0] ?? "").trim();
51
+ if (targetSpecifier.length === 0) {
52
+ return undefined;
53
+ }
54
+ const normalizedSpecifier = normalizeGraphPath(targetSpecifier);
55
+ if (normalizedSpecifier.startsWith("/") ||
56
+ /^[a-z][a-z0-9+.-]*:/i.test(normalizedSpecifier)) {
57
+ return undefined;
58
+ }
59
+ const baseDir = posix.dirname(normalizeGraphPath(fromPath));
60
+ const candidate = targetSpecifier.startsWith(".") || !normalizedSpecifier.includes("/")
61
+ ? posix.join(baseDir, normalizedSpecifier)
62
+ : normalizedSpecifier;
63
+ return resolveCandidate(candidate, pathLookup);
64
+ }
65
+ export function extractJsonSchemaReferenceEdges(fromPath, content, pathLookup) {
66
+ if (!isJsonSchemaPath(fromPath)) {
67
+ return [];
68
+ }
69
+ let parsed;
70
+ try {
71
+ parsed = JSON.parse(content);
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ const refs = new Set();
77
+ collectJsonSchemaRefs(parsed, refs);
78
+ const edges = [];
79
+ for (const ref of refs) {
80
+ const target = resolveJsonSchemaRef(fromPath, ref, pathLookup);
81
+ if (!target || target === fromPath) {
82
+ continue;
83
+ }
84
+ edges.push(graphEdge({
85
+ from: fromPath,
86
+ to: target,
87
+ kind: "json-schema-ref",
88
+ confidence: JSON_SCHEMA_REF_EDGE_CONFIDENCE,
89
+ reason: `JSON Schema $ref '${ref}' resolves to '${target}'.`,
90
+ }));
91
+ }
92
+ return edges;
93
+ }
94
+ export function extractSchemaContractTestEdges(fromPath, content, pathLookup) {
95
+ if (!isTestPath(normalizeExtractorPath(fromPath)) ||
96
+ !/schema/i.test(fromPath) ||
97
+ !/\.schema\.json/i.test(content)) {
98
+ return [];
99
+ }
100
+ const literalBasenames = new Set();
101
+ STRING_LITERAL_PATTERN.lastIndex = 0;
102
+ for (const match of content.matchAll(STRING_LITERAL_PATTERN)) {
103
+ const literal = match[1];
104
+ if (!literal || !literal.toLowerCase().endsWith(".schema.json")) {
105
+ continue;
106
+ }
107
+ literalBasenames.add(posix.basename(normalizeGraphPath(literal)).toLowerCase());
108
+ }
109
+ if (literalBasenames.size === 0 ||
110
+ literalBasenames.size > MAX_BOUNDED_SUITE_EDGE_FILES) {
111
+ return [];
112
+ }
113
+ const targets = [...new Set(pathLookup.values())]
114
+ .filter((path) => {
115
+ const normalized = normalizeGraphPath(path);
116
+ return (isJsonSchemaPath(normalized) &&
117
+ literalBasenames.has(posix.basename(normalized).toLowerCase()));
118
+ })
119
+ .sort((a, b) => a.localeCompare(b));
120
+ if (targets.length > MAX_BOUNDED_SUITE_EDGE_FILES) {
121
+ return [];
122
+ }
123
+ return targets.map((target) => graphEdge({
124
+ from: fromPath,
125
+ to: target,
126
+ kind: "schema-contract-test-link",
127
+ confidence: SCHEMA_CONTRACT_TEST_EDGE_CONFIDENCE,
128
+ reason: `Schema contract test references '${posix.basename(target)}'.`,
129
+ }));
130
+ }
131
+ function isGithubWorkflowPath(path) {
132
+ const normalized = normalizeGraphPath(path).toLowerCase();
133
+ return (normalized.startsWith(".github/workflows/") &&
134
+ (normalized.endsWith(".yml") || normalized.endsWith(".yaml")));
135
+ }
136
+ function isTypescriptTypeContractPath(path, fileContents) {
137
+ const normalized = normalizeGraphPath(path);
138
+ const segments = normalized.split("/").filter(Boolean);
139
+ if (!segments.includes("types") ||
140
+ isTestPath(normalizeExtractorPath(normalized)) ||
141
+ !TYPESCRIPT_TYPE_CONTRACT_EXTENSIONS.some((extension) => normalized.endsWith(extension))) {
142
+ return false;
143
+ }
144
+ const content = fileContents[path];
145
+ if (!content || content.length > MAX_TYPE_CONTRACT_SOURCE_BYTES) {
146
+ return false;
147
+ }
148
+ return /\bexport\s+(?:declare\s+)?(?:interface|type|enum|const)\b/.test(content);
149
+ }
150
+ function packageScriptSuiteDirectories(graphEdges) {
151
+ const directories = new Set();
152
+ for (const edge of graphEdges) {
153
+ if (edge.kind !== "package-script-link") {
154
+ continue;
155
+ }
156
+ const directory = posix.dirname(normalizeGraphPath(edge.to));
157
+ const basename = posix.basename(directory);
158
+ if (basename === "scripts" || basename === "bin") {
159
+ directories.add(directory);
160
+ }
161
+ }
162
+ return directories;
163
+ }
164
+ function isPackageScriptSuitePath(path, suiteDirectories) {
165
+ const normalized = normalizeGraphPath(path);
166
+ return (suiteDirectories.has(posix.dirname(normalized)) &&
167
+ PACKAGE_SCRIPT_SUITE_EXTENSIONS.some((extension) => normalized.endsWith(extension)));
168
+ }
169
+ function isPythonTestUtilSuitePath(path) {
170
+ const normalized = normalizeGraphPath(path);
171
+ if (!normalized.endsWith(".py"))
172
+ return false;
173
+ if (isPytestConftestPath(normalized))
174
+ return false;
175
+ const dir = posix.dirname(normalized);
176
+ if (!PYTHON_TEST_UTIL_SEGMENT_NAMES.has(posix.basename(dir).toLowerCase()))
177
+ return false;
178
+ return isTestPath(normalizeExtractorPath(dir));
179
+ }
180
+ export function extractBoundedSuiteEdges(pathLookup, fileContents, graphEdges) {
181
+ const files = [...new Set(pathLookup.values())].sort((a, b) => a.localeCompare(b));
182
+ const edges = [];
183
+ const scriptSuiteDirectories = packageScriptSuiteDirectories(graphEdges);
184
+ const addSuiteEdges = (params) => {
185
+ const groups = new Map();
186
+ for (const file of files) {
187
+ if (!params.predicate(file)) {
188
+ continue;
189
+ }
190
+ const directory = posix.dirname(normalizeGraphPath(file));
191
+ const group = groups.get(directory) ?? [];
192
+ group.push(file);
193
+ groups.set(directory, group);
194
+ }
195
+ for (const [directory, group] of groups) {
196
+ const maxFiles = params.maxFiles ?? MAX_BOUNDED_SUITE_EDGE_FILES;
197
+ if (group.length < 2 ||
198
+ group.length > maxFiles) {
199
+ continue;
200
+ }
201
+ const suiteName = directory === "." ? "repository root" : directory;
202
+ for (let index = 1; index < group.length; index++) {
203
+ edges.push(graphEdge({
204
+ from: group[index - 1],
205
+ to: group[index],
206
+ kind: params.kind,
207
+ direction: "undirected",
208
+ confidence: params.confidence,
209
+ reason: `${params.label} suite '${suiteName}' groups ${group.length} related file(s).`,
210
+ }));
211
+ }
212
+ }
213
+ };
214
+ addSuiteEdges({
215
+ predicate: isJsonSchemaPath,
216
+ kind: "schema-suite-link",
217
+ confidence: SCHEMA_SUITE_EDGE_CONFIDENCE,
218
+ label: "JSON Schema",
219
+ });
220
+ addSuiteEdges({
221
+ predicate: isGithubWorkflowPath,
222
+ kind: "github-workflow-suite-link",
223
+ confidence: GITHUB_WORKFLOW_SUITE_EDGE_CONFIDENCE,
224
+ label: "GitHub Actions workflow",
225
+ });
226
+ addSuiteEdges({
227
+ predicate: (path) => isPackageScriptSuitePath(path, scriptSuiteDirectories),
228
+ kind: "package-script-suite-link",
229
+ confidence: PACKAGE_SCRIPT_SUITE_EDGE_CONFIDENCE,
230
+ label: "Package script",
231
+ });
232
+ addSuiteEdges({
233
+ predicate: (path) => isTypescriptTypeContractPath(path, fileContents),
234
+ kind: "typescript-type-suite-link",
235
+ confidence: TYPESCRIPT_TYPE_SUITE_EDGE_CONFIDENCE,
236
+ label: "TypeScript type contract",
237
+ maxFiles: MAX_BOUNDED_TYPE_SUITE_EDGE_FILES,
238
+ });
239
+ addSuiteEdges({
240
+ predicate: isPythonTestUtilSuitePath,
241
+ kind: "python-test-util-suite-link",
242
+ confidence: PYTHON_TEST_UTIL_SUITE_EDGE_CONFIDENCE,
243
+ label: "Python test utility",
244
+ });
245
+ return edges;
246
+ }
@@ -0,0 +1,2 @@
1
+ import type { GraphEdge } from "@audit-tools/shared";
2
+ export declare function extractTestSourceEdges(fromPath: string, pathLookup: Map<string, string>): GraphEdge[];
@@ -0,0 +1,102 @@
1
+ import { posix } from "node:path";
2
+ import { graphEdge, normalizeGraphPath, resolveCandidate, SOURCE_EXTENSIONS, } from "./graphPathUtils.js";
3
+ import { isTestPath, normalizeExtractorPath } from "./pathPatterns.js";
4
+ import { isPythonSourcePath } from "./graphPythonImports.js";
5
+ const TEST_SOURCE_EDGE_CONFIDENCE = 0.88;
6
+ const TOP_LEVEL_TEST_SEGMENTS = new Set(["test", "tests", "spec", "specs"]);
7
+ const COLOCATED_TEST_SEGMENTS = new Set([
8
+ "__test__",
9
+ "__tests__",
10
+ "__spec__",
11
+ "__specs__",
12
+ "test",
13
+ "tests",
14
+ "spec",
15
+ "specs",
16
+ ]);
17
+ function stripKnownSourceExtension(path) {
18
+ const lowerPath = path.toLowerCase();
19
+ const extension = SOURCE_EXTENSIONS.find((item) => lowerPath.endsWith(item));
20
+ if (!extension) {
21
+ return undefined;
22
+ }
23
+ return path.slice(0, -extension.length);
24
+ }
25
+ function stripTestSuffix(pathWithoutExtension) {
26
+ const stripped = pathWithoutExtension.replace(/[._-](?:test|spec)$/i, "");
27
+ return stripped === pathWithoutExtension ? undefined : stripped;
28
+ }
29
+ function stripPythonTestPrefix(pathWithoutExtension) {
30
+ const basename = posix.basename(pathWithoutExtension);
31
+ const match = /^test[._-](.+)$/i.exec(basename);
32
+ if (!match?.[1]) {
33
+ return undefined;
34
+ }
35
+ const directory = posix.dirname(pathWithoutExtension);
36
+ return directory === "." ? match[1] : posix.join(directory, match[1]);
37
+ }
38
+ function addTestSourceCandidatesForBase(basePath, candidates) {
39
+ candidates.add(basePath);
40
+ const parts = basePath.split("/").filter(Boolean);
41
+ const topLevelSegment = parts[0]?.toLowerCase();
42
+ if (topLevelSegment && TOP_LEVEL_TEST_SEGMENTS.has(topLevelSegment)) {
43
+ const mirroredParts = parts.slice(1);
44
+ if (mirroredParts.length > 0) {
45
+ candidates.add(posix.join("src", ...mirroredParts));
46
+ }
47
+ }
48
+ for (let index = 1; index < parts.length; index++) {
49
+ if (COLOCATED_TEST_SEGMENTS.has(parts[index].toLowerCase())) {
50
+ const colocatedParts = [
51
+ ...parts.slice(0, index),
52
+ ...parts.slice(index + 1),
53
+ ];
54
+ if (colocatedParts.length > 0) {
55
+ candidates.add(posix.join(...colocatedParts));
56
+ }
57
+ }
58
+ }
59
+ }
60
+ function testSourceCandidates(testPath) {
61
+ const normalizedPath = normalizeGraphPath(testPath);
62
+ const withoutExtension = stripKnownSourceExtension(normalizedPath);
63
+ if (!withoutExtension) {
64
+ return [];
65
+ }
66
+ const baseCandidates = new Set();
67
+ const withoutTestSuffix = stripTestSuffix(withoutExtension);
68
+ if (withoutTestSuffix) {
69
+ baseCandidates.add(withoutTestSuffix);
70
+ }
71
+ if (isPythonSourcePath(normalizedPath)) {
72
+ const withoutPythonPrefix = stripPythonTestPrefix(withoutExtension);
73
+ if (withoutPythonPrefix) {
74
+ baseCandidates.add(withoutPythonPrefix);
75
+ }
76
+ }
77
+ const candidates = new Set();
78
+ for (const basePath of baseCandidates) {
79
+ addTestSourceCandidatesForBase(basePath, candidates);
80
+ }
81
+ return [...candidates];
82
+ }
83
+ export function extractTestSourceEdges(fromPath, pathLookup) {
84
+ if (!isTestPath(normalizeExtractorPath(fromPath))) {
85
+ return [];
86
+ }
87
+ const edges = [];
88
+ for (const candidate of testSourceCandidates(fromPath)) {
89
+ const target = resolveCandidate(candidate, pathLookup);
90
+ if (!target || isTestPath(normalizeExtractorPath(target))) {
91
+ continue;
92
+ }
93
+ edges.push(graphEdge({
94
+ from: fromPath,
95
+ to: target,
96
+ kind: "test-source-link",
97
+ confidence: TEST_SOURCE_EDGE_CONFIDENCE,
98
+ reason: `Test path naming maps to source path '${target}'.`,
99
+ }));
100
+ }
101
+ return edges;
102
+ }
@@ -0,0 +1 @@
1
+ export declare const LANGUAGE_BY_EXTENSION: Record<string, string>;