auditor-lambda 0.3.40 → 0.3.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/audit-code-wrapper-lib.mjs +20 -2
- package/dist/cli/args.d.ts +59 -0
- package/dist/cli/args.js +244 -0
- package/dist/cli/dispatch.d.ts +80 -0
- package/dist/cli/dispatch.js +528 -0
- package/dist/cli/prompts.d.ts +18 -0
- package/dist/cli/prompts.js +130 -0
- package/dist/cli/steps.d.ts +29 -0
- package/dist/cli/steps.js +30 -0
- package/dist/cli/waveManifest.d.ts +40 -0
- package/dist/cli/waveManifest.js +41 -0
- package/dist/cli/workerResult.d.ts +18 -0
- package/dist/cli/workerResult.js +42 -0
- package/dist/cli.d.ts +2 -22
- package/dist/cli.js +160 -973
- package/dist/extractors/browserExtension.d.ts +1 -3
- package/dist/extractors/browserExtension.js +2 -2
- package/dist/extractors/designAssessment.d.ts +1 -3
- package/dist/extractors/disposition.d.ts +2 -1
- package/dist/extractors/disposition.js +3 -0
- package/dist/extractors/flows.d.ts +1 -3
- package/dist/extractors/flows.js +2 -2
- package/dist/extractors/graph.d.ts +1 -2
- package/dist/extractors/graph.js +4 -326
- package/dist/extractors/graphManifestEdges.d.ts +1 -1
- package/dist/extractors/graphPathUtils.d.ts +1 -1
- package/dist/extractors/graphPythonImports.d.ts +3 -0
- package/dist/extractors/graphPythonImports.js +326 -0
- package/dist/extractors/risk.d.ts +1 -2
- package/dist/extractors/surfaces.d.ts +1 -3
- package/dist/extractors/surfaces.js +2 -2
- package/dist/io/artifacts.d.ts +1 -5
- package/dist/io/artifacts.js +1 -1
- package/dist/io/runArtifacts.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/orchestrator/advance.d.ts +1 -0
- package/dist/orchestrator/advance.js +8 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +27 -0
- package/dist/orchestrator/fileAnchors.d.ts +1 -1
- package/dist/orchestrator/fileIntegrity.d.ts +7 -0
- package/dist/orchestrator/fileIntegrity.js +41 -0
- package/dist/orchestrator/flowCoverage.d.ts +1 -1
- package/dist/orchestrator/flowPlanning.d.ts +1 -1
- package/dist/orchestrator/flowRequeue.d.ts +1 -1
- package/dist/orchestrator/internalExecutors.d.ts +3 -1
- package/dist/orchestrator/internalExecutors.js +23 -5
- package/dist/orchestrator/nextStep.d.ts +2 -1
- package/dist/orchestrator/nextStep.js +1 -1
- package/dist/orchestrator/planning.d.ts +1 -1
- package/dist/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.js +21 -113
- package/dist/orchestrator/runtimeValidation.d.ts +1 -1
- package/dist/orchestrator/taskBuilder.d.ts +1 -1
- package/dist/orchestrator/taskBuilder.js +1 -12
- package/dist/orchestrator/unionFind.d.ts +7 -0
- package/dist/orchestrator/unionFind.js +32 -0
- package/dist/orchestrator/unitBuilder.d.ts +2 -2
- package/dist/orchestrator/unitBuilder.js +4 -18
- package/dist/prompts/renderWorkerPrompt.js +18 -1
- package/dist/providers/claudeCodeProvider.d.ts +4 -4
- package/dist/providers/claudeCodeProvider.js +9 -3
- package/dist/providers/constants.d.ts +1 -1
- package/dist/providers/constants.js +1 -1
- package/dist/providers/index.d.ts +1 -2
- package/dist/providers/index.js +5 -4
- package/dist/providers/localSubprocessProvider.d.ts +2 -2
- package/dist/providers/localSubprocessProvider.js +1 -1
- package/dist/providers/opencodeProvider.d.ts +4 -4
- package/dist/providers/opencodeProvider.js +7 -2
- package/dist/providers/spawnLoggedCommand.d.ts +3 -1
- package/dist/providers/spawnLoggedCommand.js +21 -0
- package/dist/providers/subprocessTemplateProvider.d.ts +4 -4
- package/dist/providers/subprocessTemplateProvider.js +8 -3
- package/dist/providers/vscodeTaskProvider.d.ts +3 -4
- package/dist/providers/vscodeTaskProvider.js +2 -2
- package/dist/quota/discoveredLimits.js +1 -1
- package/dist/quota/hostLimits.d.ts +1 -2
- package/dist/quota/hostLimits.js +4 -46
- package/dist/quota/index.d.ts +18 -15
- package/dist/quota/index.js +4 -9
- package/dist/quota/scheduler.d.ts +1 -3
- package/dist/quota/scheduler.js +1 -2
- package/dist/reporting/synthesis.d.ts +1 -2
- package/dist/reporting/synthesis.js +2 -0
- package/dist/reporting/workBlocks.d.ts +1 -2
- package/dist/supervisor/operatorHandoff.js +1 -1
- package/dist/supervisor/runLedger.d.ts +1 -1
- package/dist/supervisor/runLedger.js +2 -2
- package/dist/supervisor/sessionConfig.d.ts +1 -1
- package/dist/supervisor/sessionConfig.js +1 -3
- package/dist/types/reviewPlanning.d.ts +1 -1
- package/dist/types/workerSession.d.ts +6 -0
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +1 -1
- package/dist/validation/auditResults.d.ts +1 -1
- package/dist/validation/auditResults.js +1 -1
- package/dist/validation/sessionConfig.d.ts +2 -3
- package/dist/validation/sessionConfig.js +2 -3
- package/package.json +4 -2
- package/scripts/postinstall.mjs +0 -1
- package/dist/io/json.d.ts +0 -10
- package/dist/io/json.js +0 -142
- package/dist/providers/types.d.ts +0 -33
- package/dist/providers/types.js +0 -1
- package/dist/quota/compositeQuotaSource.d.ts +0 -7
- package/dist/quota/compositeQuotaSource.js +0 -20
- package/dist/quota/errorParsers/claudeCodeErrorParser.d.ts +0 -6
- package/dist/quota/errorParsers/claudeCodeErrorParser.js +0 -39
- package/dist/quota/errorParsers/genericErrorParser.d.ts +0 -9
- package/dist/quota/errorParsers/genericErrorParser.js +0 -7
- package/dist/quota/errorParsers/index.d.ts +0 -5
- package/dist/quota/errorParsers/index.js +0 -12
- package/dist/quota/errorParsing.d.ts +0 -7
- package/dist/quota/errorParsing.js +0 -69
- package/dist/quota/fileLock.d.ts +0 -6
- package/dist/quota/fileLock.js +0 -64
- package/dist/quota/learnedQuotaSource.d.ts +0 -7
- package/dist/quota/learnedQuotaSource.js +0 -25
- package/dist/quota/limits.d.ts +0 -16
- package/dist/quota/limits.js +0 -77
- package/dist/quota/quotaSource.d.ts +0 -12
- package/dist/quota/quotaSource.js +0 -1
- package/dist/quota/slidingWindow.d.ts +0 -4
- package/dist/quota/slidingWindow.js +0 -28
- package/dist/quota/state.d.ts +0 -15
- package/dist/quota/state.js +0 -148
- package/dist/quota/types.d.ts +0 -67
- package/dist/quota/types.js +0 -1
- package/dist/reporting/rootCause.d.ts +0 -10
- package/dist/reporting/rootCause.js +0 -146
- package/dist/types/disposition.d.ts +0 -9
- package/dist/types/disposition.js +0 -1
- package/dist/types/flows.d.ts +0 -17
- package/dist/types/flows.js +0 -1
- package/dist/types/graph.d.ts +0 -22
- package/dist/types/graph.js +0 -1
- package/dist/types/risk.d.ts +0 -9
- package/dist/types/risk.js +0 -1
- package/dist/types/runLedger.d.ts +0 -17
- package/dist/types/runLedger.js +0 -6
- package/dist/types/sessionConfig.d.ts +0 -79
- package/dist/types/sessionConfig.js +0 -15
- package/dist/types/surfaces.d.ts +0 -15
- package/dist/types/surfaces.js +0 -1
- package/dist/validation/basic.d.ts +0 -13
- package/dist/validation/basic.js +0 -46
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { Lens, RepoManifest } from "../types.js";
|
|
2
|
-
import type { FileDisposition } from "
|
|
3
|
-
import type { GraphBundle, GraphEdge } from "../types/graph.js";
|
|
4
|
-
import type { SurfaceRecord } from "../types/surfaces.js";
|
|
2
|
+
import type { FileDisposition, GraphBundle, GraphEdge, SurfaceRecord } from "@audit-tools/shared";
|
|
5
3
|
export declare const BROWSER_EXTENSION_HEURISTIC_NOTE = "Chrome extension manifest and HTML asset references were resolved deterministically from local paths; verify unusual dynamic registration manually.";
|
|
6
4
|
export declare function isBrowserExtensionManifestPath(path: string): boolean;
|
|
7
5
|
export declare function extractChromeExtensionManifestEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
|
-
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
+
import { buildDispositionMap, isAuditExcludedStatus } from "./disposition.js";
|
|
3
3
|
import { graphEdge, normalizeGraphPath, resolveCandidate, } from "./graphPathUtils.js";
|
|
4
4
|
export const BROWSER_EXTENSION_HEURISTIC_NOTE = "Chrome extension manifest and HTML asset references were resolved deterministically from local paths; verify unusual dynamic registration manually.";
|
|
5
5
|
const CHROME_EXTENSION_BACKGROUND_EDGE = "chrome-extension-background-link";
|
|
@@ -334,7 +334,7 @@ export function buildBrowserExtensionSurfacesFromGraph(graphBundle, disposition)
|
|
|
334
334
|
const references = Array.isArray(graphBundle?.graphs.references)
|
|
335
335
|
? graphBundle.graphs.references
|
|
336
336
|
: [];
|
|
337
|
-
const dispositionMap =
|
|
337
|
+
const dispositionMap = buildDispositionMap(disposition);
|
|
338
338
|
const surfaces = [];
|
|
339
339
|
const seen = new Set();
|
|
340
340
|
for (const edge of references) {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { UnitManifest } from "../types.js";
|
|
2
|
+
import type { GraphBundle, CriticalFlowManifest, RiskRegister } from "@audit-tools/shared";
|
|
2
3
|
import type { DesignAssessment } from "../types/designAssessment.js";
|
|
3
|
-
import type { GraphBundle } from "../types/graph.js";
|
|
4
|
-
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
5
|
-
import type { RiskRegister } from "../types/risk.js";
|
|
6
4
|
export declare function buildDesignAssessment(params: {
|
|
7
5
|
unitManifest: UnitManifest;
|
|
8
6
|
graphBundle: GraphBundle;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
|
-
import type { FileDisposition, FileDispositionStatus } from "
|
|
2
|
+
import type { FileDisposition, FileDispositionStatus } from "@audit-tools/shared";
|
|
3
3
|
/**
|
|
4
4
|
* Applies shared path heuristics to mark files that should be excluded or
|
|
5
5
|
* down-scoped before audit planning begins.
|
|
6
6
|
*/
|
|
7
7
|
export declare function buildFileDisposition(repoManifest: RepoManifest): FileDisposition;
|
|
8
|
+
export declare function buildDispositionMap(disposition?: FileDisposition): Map<string, FileDispositionStatus>;
|
|
8
9
|
export declare function isAuditExcludedStatus(status: FileDispositionStatus): boolean;
|
|
@@ -75,6 +75,9 @@ export function buildFileDisposition(repoManifest) {
|
|
|
75
75
|
files: repoManifest.files.map((file) => inferDisposition(file.path)),
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
+
export function buildDispositionMap(disposition) {
|
|
79
|
+
return new Map(disposition?.files.map((item) => [item.path, item.status]) ?? []);
|
|
80
|
+
}
|
|
78
81
|
export function isAuditExcludedStatus(status) {
|
|
79
82
|
return (status === "excluded" ||
|
|
80
83
|
status === "generated" ||
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
|
-
import type { FileDisposition } from "
|
|
3
|
-
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
4
|
-
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
2
|
+
import type { FileDisposition, CriticalFlowManifest, SurfaceManifest } from "@audit-tools/shared";
|
|
5
3
|
/**
|
|
6
4
|
* Builds coarse critical-flow coverage from shared path heuristics. These
|
|
7
5
|
* bootstrap flows are intentionally conservative and should be reviewed when a
|
package/dist/extractors/flows.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isAuditExcludedStatus } from "./disposition.js";
|
|
1
|
+
import { buildDispositionMap, isAuditExcludedStatus } from "./disposition.js";
|
|
2
2
|
import { EXTRACTOR_HEURISTIC_NOTE, isAsyncTaskPath, isBillingPath, isIdentityPath, isSecuritySensitivePath, isTestPath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
3
3
|
function inferConcerns(paths) {
|
|
4
4
|
const concerns = new Set();
|
|
@@ -65,7 +65,7 @@ function dedupeFlows(flows) {
|
|
|
65
65
|
* repo uses unconventional naming or layout conventions.
|
|
66
66
|
*/
|
|
67
67
|
export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposition) {
|
|
68
|
-
const dispositionMap =
|
|
68
|
+
const dispositionMap = buildDispositionMap(disposition);
|
|
69
69
|
const availablePaths = repoManifest.files
|
|
70
70
|
.map((file) => file.path)
|
|
71
71
|
.filter((path) => {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
|
-
import type { FileDisposition } from "
|
|
2
|
+
import type { FileDisposition, GraphBundle } from "@audit-tools/shared";
|
|
3
3
|
import type { ExternalAnalyzerResults } from "../types/externalAnalyzer.js";
|
|
4
|
-
import type { GraphBundle } from "../types/graph.js";
|
|
5
4
|
export interface BuildGraphBundleOptions {
|
|
6
5
|
fileContents?: Record<string, string>;
|
|
7
6
|
externalAnalyzerResults?: ExternalAnalyzerResults;
|
package/dist/extractors/graph.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
3
|
import { posix } from "node:path";
|
|
4
|
-
import { isAuditExcludedStatus } from "./disposition.js";
|
|
4
|
+
import { buildDispositionMap, isAuditExcludedStatus } from "./disposition.js";
|
|
5
5
|
import { extractChromeExtensionManifestEdges, extractHtmlResourceEdges, } from "./browserExtension.js";
|
|
6
6
|
import { extractCargoWorkspaceMemberEdges, extractGoWorkspaceModuleEdges, extractMavenModuleEdges, extractPackageEntrypointEdges, extractPackageScriptEdges, extractPyprojectTestpathLinks, extractTypescriptProjectReferenceEdges, extractWorkspacePackageEdges, extractYamlPathReferenceEdges, isCargoManifestPath, isGoWorkspaceManifestPath, isMavenPomPath, isPyprojectPath, } from "./graphManifestEdges.js";
|
|
7
7
|
import { graphEdge, graphLookupKey, normalizeGraphPath, resolveCandidate, } from "./graphPathUtils.js";
|
|
8
|
+
import { extractPythonImportEdges, isPythonSourcePath, } from "./graphPythonImports.js";
|
|
8
9
|
import { isTestPath, normalizeExtractorPath } from "./pathPatterns.js";
|
|
9
10
|
const MAX_GRAPH_SOURCE_BYTES = 512 * 1024;
|
|
10
11
|
const SOURCE_LANGUAGES = new Set([
|
|
@@ -40,8 +41,6 @@ const SOURCE_EXTENSIONS = [
|
|
|
40
41
|
".java",
|
|
41
42
|
".cs",
|
|
42
43
|
];
|
|
43
|
-
const PYTHON_SOURCE_EXTENSIONS = [".py", ".pyi"];
|
|
44
|
-
const PYTHON_PACKAGE_INDEX_FILES = ["__init__.py", "__init__.pyi"];
|
|
45
44
|
const TYPESCRIPT_TYPE_CONTRACT_EXTENSIONS = [
|
|
46
45
|
".ts",
|
|
47
46
|
".tsx",
|
|
@@ -339,327 +338,6 @@ function extractImportBindings(fromPath, content, pathLookup) {
|
|
|
339
338
|
}
|
|
340
339
|
return bindings;
|
|
341
340
|
}
|
|
342
|
-
function isPythonSourcePath(path) {
|
|
343
|
-
const normalized = normalizeGraphPath(path).toLowerCase();
|
|
344
|
-
return PYTHON_SOURCE_EXTENSIONS.some((extension) => normalized.endsWith(extension));
|
|
345
|
-
}
|
|
346
|
-
function stripPythonLineComment(line) {
|
|
347
|
-
let quote;
|
|
348
|
-
let escaped = false;
|
|
349
|
-
for (let index = 0; index < line.length; index++) {
|
|
350
|
-
const char = line[index];
|
|
351
|
-
if (escaped) {
|
|
352
|
-
escaped = false;
|
|
353
|
-
continue;
|
|
354
|
-
}
|
|
355
|
-
if (quote) {
|
|
356
|
-
if (char === "\\") {
|
|
357
|
-
escaped = true;
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
if (char === quote) {
|
|
361
|
-
quote = undefined;
|
|
362
|
-
}
|
|
363
|
-
continue;
|
|
364
|
-
}
|
|
365
|
-
if (char === "'" || char === '"') {
|
|
366
|
-
quote = char;
|
|
367
|
-
continue;
|
|
368
|
-
}
|
|
369
|
-
if (char === "#") {
|
|
370
|
-
return line.slice(0, index);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
return line;
|
|
374
|
-
}
|
|
375
|
-
function pythonParenDelta(line) {
|
|
376
|
-
let quote;
|
|
377
|
-
let escaped = false;
|
|
378
|
-
let delta = 0;
|
|
379
|
-
for (const char of line) {
|
|
380
|
-
if (escaped) {
|
|
381
|
-
escaped = false;
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
if (quote) {
|
|
385
|
-
if (char === "\\") {
|
|
386
|
-
escaped = true;
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
if (char === quote) {
|
|
390
|
-
quote = undefined;
|
|
391
|
-
}
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
if (char === "'" || char === '"') {
|
|
395
|
-
quote = char;
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
if (char === "(") {
|
|
399
|
-
delta += 1;
|
|
400
|
-
}
|
|
401
|
-
else if (char === ")") {
|
|
402
|
-
delta -= 1;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return delta;
|
|
406
|
-
}
|
|
407
|
-
function pythonLogicalLines(content) {
|
|
408
|
-
const logicalLines = [];
|
|
409
|
-
let pending = "";
|
|
410
|
-
let parenDepth = 0;
|
|
411
|
-
for (const rawLine of content.split(/\r?\n/)) {
|
|
412
|
-
const stripped = stripPythonLineComment(rawLine).trim();
|
|
413
|
-
if (stripped.length === 0) {
|
|
414
|
-
continue;
|
|
415
|
-
}
|
|
416
|
-
if (pending.length === 0 && !/^(?:import|from)\s+/i.test(stripped)) {
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
const continued = stripped.endsWith("\\");
|
|
420
|
-
const line = continued ? stripped.slice(0, -1).trimEnd() : stripped;
|
|
421
|
-
pending = pending.length > 0 ? `${pending} ${line}` : line;
|
|
422
|
-
parenDepth += pythonParenDelta(line);
|
|
423
|
-
if (!continued && parenDepth <= 0) {
|
|
424
|
-
logicalLines.push(pending.replace(/\s+/g, " ").trim());
|
|
425
|
-
pending = "";
|
|
426
|
-
parenDepth = 0;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
if (pending.length > 0) {
|
|
430
|
-
logicalLines.push(pending.replace(/\s+/g, " ").trim());
|
|
431
|
-
}
|
|
432
|
-
return logicalLines;
|
|
433
|
-
}
|
|
434
|
-
function unwrapPythonImportList(value) {
|
|
435
|
-
let trimmed = value.trim();
|
|
436
|
-
if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
|
|
437
|
-
trimmed = trimmed.slice(1, -1).trim();
|
|
438
|
-
}
|
|
439
|
-
return trimmed;
|
|
440
|
-
}
|
|
441
|
-
function splitPythonImportList(value) {
|
|
442
|
-
const items = [];
|
|
443
|
-
let current = "";
|
|
444
|
-
let quote;
|
|
445
|
-
let escaped = false;
|
|
446
|
-
let parenDepth = 0;
|
|
447
|
-
for (const char of unwrapPythonImportList(value)) {
|
|
448
|
-
if (escaped) {
|
|
449
|
-
current += char;
|
|
450
|
-
escaped = false;
|
|
451
|
-
continue;
|
|
452
|
-
}
|
|
453
|
-
if (quote) {
|
|
454
|
-
current += char;
|
|
455
|
-
if (char === "\\") {
|
|
456
|
-
escaped = true;
|
|
457
|
-
}
|
|
458
|
-
else if (char === quote) {
|
|
459
|
-
quote = undefined;
|
|
460
|
-
}
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
if (char === "'" || char === '"') {
|
|
464
|
-
current += char;
|
|
465
|
-
quote = char;
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
if (char === "(") {
|
|
469
|
-
parenDepth += 1;
|
|
470
|
-
current += char;
|
|
471
|
-
continue;
|
|
472
|
-
}
|
|
473
|
-
if (char === ")") {
|
|
474
|
-
parenDepth -= 1;
|
|
475
|
-
current += char;
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
if (char === "," && parenDepth === 0) {
|
|
479
|
-
const item = current.trim();
|
|
480
|
-
if (item.length > 0) {
|
|
481
|
-
items.push(item);
|
|
482
|
-
}
|
|
483
|
-
current = "";
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
current += char;
|
|
487
|
-
}
|
|
488
|
-
const item = current.trim();
|
|
489
|
-
if (item.length > 0) {
|
|
490
|
-
items.push(item);
|
|
491
|
-
}
|
|
492
|
-
return items;
|
|
493
|
-
}
|
|
494
|
-
function stripPythonAlias(value) {
|
|
495
|
-
return value.replace(/\s+as\s+[A-Za-z_]\w*$/i, "").trim();
|
|
496
|
-
}
|
|
497
|
-
function isPythonIdentifier(value) {
|
|
498
|
-
return /^[A-Za-z_]\w*$/.test(value);
|
|
499
|
-
}
|
|
500
|
-
function isPythonAbsoluteModuleSpecifier(value) {
|
|
501
|
-
return /^[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*$/.test(value);
|
|
502
|
-
}
|
|
503
|
-
function isPythonRelativeModuleSpecifier(value) {
|
|
504
|
-
return /^\.+(?:[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)?$/.test(value);
|
|
505
|
-
}
|
|
506
|
-
function isPythonModuleSpecifier(value) {
|
|
507
|
-
return (isPythonAbsoluteModuleSpecifier(value) ||
|
|
508
|
-
isPythonRelativeModuleSpecifier(value));
|
|
509
|
-
}
|
|
510
|
-
function pythonModulePath(specifier) {
|
|
511
|
-
return specifier.split(".").filter(Boolean).join("/");
|
|
512
|
-
}
|
|
513
|
-
function resolvePythonPathCandidate(candidate, pathLookup) {
|
|
514
|
-
const normalized = normalizeGraphPath(candidate).replace(/\/+$/, "");
|
|
515
|
-
if (normalized.length === 0 || normalized === "." || normalized === "..") {
|
|
516
|
-
return undefined;
|
|
517
|
-
}
|
|
518
|
-
return resolveCandidate(normalized, pathLookup);
|
|
519
|
-
}
|
|
520
|
-
function pythonPathMatchesModule(path, modulePath) {
|
|
521
|
-
const normalizedPath = normalizeGraphPath(path).toLowerCase();
|
|
522
|
-
const normalizedModulePath = normalizeGraphPath(modulePath).toLowerCase();
|
|
523
|
-
return (PYTHON_SOURCE_EXTENSIONS.some((extension) => {
|
|
524
|
-
const moduleFile = `${normalizedModulePath}${extension}`;
|
|
525
|
-
return (normalizedPath === moduleFile ||
|
|
526
|
-
normalizedPath.endsWith(`/${moduleFile}`));
|
|
527
|
-
}) ||
|
|
528
|
-
PYTHON_PACKAGE_INDEX_FILES.some((indexFile) => {
|
|
529
|
-
const packageFile = posix.join(normalizedModulePath, indexFile);
|
|
530
|
-
return (normalizedPath === packageFile ||
|
|
531
|
-
normalizedPath.endsWith(`/${packageFile}`));
|
|
532
|
-
}));
|
|
533
|
-
}
|
|
534
|
-
function commonDirectoryPrefixLength(left, right) {
|
|
535
|
-
const leftParts = normalizeGraphPath(left).split("/").filter(Boolean);
|
|
536
|
-
const rightParts = normalizeGraphPath(right).split("/").filter(Boolean);
|
|
537
|
-
let count = 0;
|
|
538
|
-
while (count < leftParts.length &&
|
|
539
|
-
count < rightParts.length &&
|
|
540
|
-
leftParts[count].toLowerCase() === rightParts[count].toLowerCase()) {
|
|
541
|
-
count += 1;
|
|
542
|
-
}
|
|
543
|
-
return count;
|
|
544
|
-
}
|
|
545
|
-
function resolvePythonAbsoluteModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
546
|
-
const modulePath = pythonModulePath(specifier);
|
|
547
|
-
const direct = resolvePythonPathCandidate(modulePath, pathLookup);
|
|
548
|
-
if (direct) {
|
|
549
|
-
return direct;
|
|
550
|
-
}
|
|
551
|
-
const matches = [...new Set(pathLookup.values())].filter((path) => isPythonSourcePath(path) && pythonPathMatchesModule(path, modulePath));
|
|
552
|
-
if (matches.length === 1) {
|
|
553
|
-
return matches[0];
|
|
554
|
-
}
|
|
555
|
-
if (matches.length === 0) {
|
|
556
|
-
return undefined;
|
|
557
|
-
}
|
|
558
|
-
const fromDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
559
|
-
const scored = matches
|
|
560
|
-
.map((target) => ({
|
|
561
|
-
target,
|
|
562
|
-
score: commonDirectoryPrefixLength(fromDir, posix.dirname(normalizeGraphPath(target))),
|
|
563
|
-
}))
|
|
564
|
-
.sort((a, b) => b.score - a.score || a.target.localeCompare(b.target));
|
|
565
|
-
const bestScore = scored[0]?.score ?? 0;
|
|
566
|
-
const bestMatches = scored.filter((item) => item.score === bestScore);
|
|
567
|
-
if (bestScore > 0 && bestMatches.length === 1) {
|
|
568
|
-
return bestMatches[0].target;
|
|
569
|
-
}
|
|
570
|
-
const srcMatches = matches.filter((target) => normalizeGraphPath(target).toLowerCase().startsWith("src/"));
|
|
571
|
-
return srcMatches.length === 1 ? srcMatches[0] : undefined;
|
|
572
|
-
}
|
|
573
|
-
function resolvePythonRelativeModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
574
|
-
const match = /^(\.+)(.*)$/.exec(specifier);
|
|
575
|
-
if (!match) {
|
|
576
|
-
return undefined;
|
|
577
|
-
}
|
|
578
|
-
const level = match[1].length;
|
|
579
|
-
const remainder = match[2] ?? "";
|
|
580
|
-
let baseDir = posix.dirname(normalizeGraphPath(fromPath));
|
|
581
|
-
for (let index = 1; index < level; index++) {
|
|
582
|
-
const next = posix.dirname(baseDir);
|
|
583
|
-
if (next === baseDir) {
|
|
584
|
-
return undefined;
|
|
585
|
-
}
|
|
586
|
-
baseDir = next;
|
|
587
|
-
}
|
|
588
|
-
const modulePath = pythonModulePath(remainder);
|
|
589
|
-
const candidate = modulePath.length > 0 ? posix.join(baseDir, modulePath) : baseDir;
|
|
590
|
-
return resolvePythonPathCandidate(candidate, pathLookup);
|
|
591
|
-
}
|
|
592
|
-
function resolvePythonModuleSpecifier(fromPath, specifier, pathLookup) {
|
|
593
|
-
if (isPythonRelativeModuleSpecifier(specifier)) {
|
|
594
|
-
return resolvePythonRelativeModuleSpecifier(fromPath, specifier, pathLookup);
|
|
595
|
-
}
|
|
596
|
-
if (isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
597
|
-
return resolvePythonAbsoluteModuleSpecifier(fromPath, specifier, pathLookup);
|
|
598
|
-
}
|
|
599
|
-
return undefined;
|
|
600
|
-
}
|
|
601
|
-
function appendPythonImportedSpecifier(moduleSpecifier, importedName) {
|
|
602
|
-
return moduleSpecifier.endsWith(".")
|
|
603
|
-
? `${moduleSpecifier}${importedName}`
|
|
604
|
-
: `${moduleSpecifier}.${importedName}`;
|
|
605
|
-
}
|
|
606
|
-
function addPythonImportEdge(edges, fromPath, target, kind, specifier) {
|
|
607
|
-
if (!target || target === fromPath) {
|
|
608
|
-
return;
|
|
609
|
-
}
|
|
610
|
-
edges.push(graphEdge({
|
|
611
|
-
from: fromPath,
|
|
612
|
-
to: target,
|
|
613
|
-
kind,
|
|
614
|
-
confidence: IMPORT_EDGE_CONFIDENCE,
|
|
615
|
-
reason: `Resolved Python import specifier '${specifier}'.`,
|
|
616
|
-
}));
|
|
617
|
-
}
|
|
618
|
-
function extractPythonImportEdges(fromPath, content, pathLookup) {
|
|
619
|
-
if (!isPythonSourcePath(fromPath)) {
|
|
620
|
-
return [];
|
|
621
|
-
}
|
|
622
|
-
const edges = [];
|
|
623
|
-
for (const line of pythonLogicalLines(content)) {
|
|
624
|
-
const importMatch = /^import\s+(.+)$/i.exec(line);
|
|
625
|
-
if (importMatch) {
|
|
626
|
-
for (const rawSpecifier of splitPythonImportList(importMatch[1] ?? "")) {
|
|
627
|
-
const specifier = stripPythonAlias(rawSpecifier);
|
|
628
|
-
if (!isPythonAbsoluteModuleSpecifier(specifier)) {
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, specifier, pathLookup), "python-import", specifier);
|
|
632
|
-
}
|
|
633
|
-
continue;
|
|
634
|
-
}
|
|
635
|
-
const fromImportMatch = /^from\s+([.\w]+)\s+import\s+(.+)$/i.exec(line);
|
|
636
|
-
if (!fromImportMatch) {
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
const moduleSpecifier = fromImportMatch[1] ?? "";
|
|
640
|
-
if (!isPythonModuleSpecifier(moduleSpecifier)) {
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
const importedNames = splitPythonImportList(fromImportMatch[2] ?? "")
|
|
644
|
-
.map(stripPythonAlias)
|
|
645
|
-
.filter((name) => name !== "*" && isPythonIdentifier(name));
|
|
646
|
-
const submoduleTargets = importedNames
|
|
647
|
-
.map((name) => appendPythonImportedSpecifier(moduleSpecifier, name))
|
|
648
|
-
.map((specifier) => ({
|
|
649
|
-
specifier,
|
|
650
|
-
target: resolvePythonModuleSpecifier(fromPath, specifier, pathLookup),
|
|
651
|
-
}))
|
|
652
|
-
.filter((item) => item.target);
|
|
653
|
-
if (submoduleTargets.length > 0) {
|
|
654
|
-
for (const { specifier, target } of submoduleTargets) {
|
|
655
|
-
addPythonImportEdge(edges, fromPath, target, "python-from-import", specifier);
|
|
656
|
-
}
|
|
657
|
-
continue;
|
|
658
|
-
}
|
|
659
|
-
addPythonImportEdge(edges, fromPath, resolvePythonModuleSpecifier(fromPath, moduleSpecifier, pathLookup), "python-from-import", moduleSpecifier);
|
|
660
|
-
}
|
|
661
|
-
return edges;
|
|
662
|
-
}
|
|
663
341
|
function extractImportEdges(fromPath, content, pathLookup) {
|
|
664
342
|
const edges = [];
|
|
665
343
|
for (const { pattern, kind } of IMPORT_PATTERNS) {
|
|
@@ -1239,7 +917,7 @@ function extractPytestConftestLinks(pathLookup) {
|
|
|
1239
917
|
}
|
|
1240
918
|
export async function buildGraphBundleFromFs(repoManifest, root, disposition, options = {}) {
|
|
1241
919
|
const rootPath = resolve(root);
|
|
1242
|
-
const dispositionMap =
|
|
920
|
+
const dispositionMap = buildDispositionMap(disposition);
|
|
1243
921
|
const fileContents = {};
|
|
1244
922
|
await Promise.all(repoManifest.files.map(async (file) => {
|
|
1245
923
|
const status = dispositionMap.get(file.path);
|
|
@@ -1267,7 +945,7 @@ export function buildGraphBundle(repoManifest, disposition, options = {}) {
|
|
|
1267
945
|
const calls = [];
|
|
1268
946
|
const references = [];
|
|
1269
947
|
const routes = [];
|
|
1270
|
-
const dispositionMap =
|
|
948
|
+
const dispositionMap = buildDispositionMap(disposition);
|
|
1271
949
|
const pathLookup = buildPathLookup(repoManifest, dispositionMap);
|
|
1272
950
|
for (const file of repoManifest.files) {
|
|
1273
951
|
const status = dispositionMap.get(file.path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphEdge } from "
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
2
|
export declare function extractPackageEntrypointEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
3
3
|
export declare function extractPackageScriptEdges(fromPath: string, content: string, pathLookup: Map<string, string>): GraphEdge[];
|
|
4
4
|
export declare function isGoWorkspaceManifestPath(path: string): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GraphEdge } from "
|
|
1
|
+
import type { GraphEdge } from "@audit-tools/shared";
|
|
2
2
|
export declare function normalizeGraphPath(path: string): string;
|
|
3
3
|
export declare function graphLookupKey(path: string): string;
|
|
4
4
|
export declare function resolveCandidate(candidate: string, pathLookup: Map<string, string>): string | undefined;
|