auditor-lambda 0.3.40 → 0.5.0
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 +532 -0
- package/dist/cli/prompts.d.ts +37 -0
- package/dist/cli/prompts.js +225 -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 +442 -975
- package/dist/extractors/analyzers/css.d.ts +2 -0
- package/dist/extractors/analyzers/css.js +101 -0
- package/dist/extractors/analyzers/html.d.ts +2 -0
- package/dist/extractors/analyzers/html.js +92 -0
- package/dist/extractors/analyzers/merge.d.ts +14 -0
- package/dist/extractors/analyzers/merge.js +85 -0
- package/dist/extractors/analyzers/python.d.ts +2 -0
- package/dist/extractors/analyzers/python.js +104 -0
- package/dist/extractors/analyzers/registry.d.ts +33 -0
- package/dist/extractors/analyzers/registry.js +100 -0
- package/dist/extractors/analyzers/resourceUrl.d.ts +7 -0
- package/dist/extractors/analyzers/resourceUrl.js +25 -0
- package/dist/extractors/analyzers/sql.d.ts +2 -0
- package/dist/extractors/analyzers/sql.js +19 -0
- package/dist/extractors/analyzers/treeSitter.d.ts +34 -0
- package/dist/extractors/analyzers/treeSitter.js +111 -0
- package/dist/extractors/analyzers/types.d.ts +53 -0
- package/dist/extractors/analyzers/typescript.d.ts +2 -0
- package/dist/extractors/analyzers/typescript.js +257 -0
- 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 +11 -1
- package/dist/extractors/flows.d.ts +1 -3
- package/dist/extractors/flows.js +2 -2
- package/dist/extractors/graph.d.ts +2 -2
- package/dist/extractors/graph.js +171 -327
- package/dist/extractors/graphManifestEdges.d.ts +1 -1
- package/dist/extractors/graphPathUtils.d.ts +1 -1
- package/dist/extractors/graphPythonImports.d.ts +18 -0
- package/dist/extractors/graphPythonImports.js +362 -0
- package/dist/extractors/pathPatterns.d.ts +6 -0
- package/dist/extractors/pathPatterns.js +8 -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 +12 -5
- package/dist/io/artifacts.js +13 -1
- package/dist/io/runArtifacts.js +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/orchestrator/advance.d.ts +21 -0
- package/dist/orchestrator/advance.js +69 -7
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +27 -0
- package/dist/orchestrator/dependencyMap.js +27 -0
- package/dist/orchestrator/edgeReasoning.d.ts +39 -0
- package/dist/orchestrator/edgeReasoning.js +125 -0
- package/dist/orchestrator/executors.js +11 -1
- 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/graphEnrichmentExecutor.d.ts +29 -0
- package/dist/orchestrator/graphEnrichmentExecutor.js +196 -0
- package/dist/orchestrator/internalExecutors.d.ts +13 -2
- package/dist/orchestrator/internalExecutors.js +112 -16
- package/dist/orchestrator/localCommands.js +6 -25
- package/dist/orchestrator/nextStep.d.ts +2 -1
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/planning.d.ts +1 -1
- package/dist/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/orchestrator/reviewPackets.d.ts +37 -4
- package/dist/orchestrator/reviewPackets.js +113 -158
- package/dist/orchestrator/runtimeValidation.d.ts +1 -1
- package/dist/orchestrator/runtimeValidation.js +4 -31
- package/dist/orchestrator/scope.d.ts +62 -0
- package/dist/orchestrator/scope.js +227 -0
- package/dist/orchestrator/state.js +2 -0
- 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 +37 -3
- package/dist/reporting/synthesis.js +97 -16
- package/dist/reporting/synthesisNarrativePrompt.d.ts +7 -0
- package/dist/reporting/synthesisNarrativePrompt.js +60 -0
- package/dist/reporting/workBlocks.d.ts +2 -11
- 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 +8 -1
- package/dist/supervisor/sessionConfig.js +22 -3
- package/dist/types/analyzerCapability.d.ts +16 -0
- package/dist/types/auditScope.d.ts +43 -0
- package/dist/types/auditScope.js +14 -0
- package/dist/types/reviewPlanning.d.ts +1 -1
- package/dist/types/synthesisNarrative.d.ts +7 -0
- package/dist/types/synthesisNarrative.js +5 -0
- package/dist/types/workerSession.d.ts +6 -0
- package/dist/types.d.ts +2 -19
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +10 -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 +25 -3
- package/package.json +7 -3
- package/schemas/analyzer_capability.schema.json +47 -0
- package/schemas/audit_findings.schema.json +141 -0
- package/schemas/finding.schema.json +2 -1
- package/schemas/graph_bundle.schema.json +5 -0
- package/schemas/scope.schema.json +46 -0
- 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/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/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
- /package/dist/{providers → extractors/analyzers}/types.js +0 -0
- /package/dist/{quota/quotaSource.js → types/analyzerCapability.js} +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
5
|
+
let modulePromise;
|
|
6
|
+
let initPromise;
|
|
7
|
+
const languageCache = new Map();
|
|
8
|
+
async function importParserModule(dependencyPath) {
|
|
9
|
+
const specifiers = [];
|
|
10
|
+
if (dependencyPath) {
|
|
11
|
+
try {
|
|
12
|
+
const manifest = requireFromHere(join(dependencyPath, "package.json"));
|
|
13
|
+
const entry = manifest.module ?? manifest.main ?? "index.js";
|
|
14
|
+
specifiers.push(pathToFileURL(join(dependencyPath, entry)).href);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// Fall through to the bare specifier.
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
specifiers.push("web-tree-sitter");
|
|
21
|
+
for (const specifier of specifiers) {
|
|
22
|
+
try {
|
|
23
|
+
const mod = (await import(specifier));
|
|
24
|
+
const resolved = (mod.Parser ? mod : mod.default);
|
|
25
|
+
if (resolved?.Parser && resolved.Language) {
|
|
26
|
+
return resolved;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Try the next specifier.
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
async function getModule(dependencyPath) {
|
|
36
|
+
if (!modulePromise) {
|
|
37
|
+
modulePromise = importParserModule(dependencyPath);
|
|
38
|
+
}
|
|
39
|
+
return modulePromise;
|
|
40
|
+
}
|
|
41
|
+
async function ensureInit(parserModule) {
|
|
42
|
+
if (!initPromise) {
|
|
43
|
+
initPromise = parserModule.Parser.init()
|
|
44
|
+
.then(() => true)
|
|
45
|
+
.catch(() => false);
|
|
46
|
+
}
|
|
47
|
+
return initPromise;
|
|
48
|
+
}
|
|
49
|
+
function resolveGrammarPath(grammar) {
|
|
50
|
+
// tree-sitter-wasms ships prebuilt grammars under out/tree-sitter-<lang>.wasm.
|
|
51
|
+
try {
|
|
52
|
+
return requireFromHere.resolve(`tree-sitter-wasms/out/tree-sitter-${grammar}.wasm`);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Fall back to locating the package root, then the file under out/.
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const pkg = requireFromHere.resolve("tree-sitter-wasms/package.json");
|
|
59
|
+
return join(dirname(pkg), "out", `tree-sitter-${grammar}.wasm`);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function loadLanguage(parserModule, grammar) {
|
|
66
|
+
if (languageCache.has(grammar)) {
|
|
67
|
+
return languageCache.get(grammar) ?? undefined;
|
|
68
|
+
}
|
|
69
|
+
const grammarPath = resolveGrammarPath(grammar);
|
|
70
|
+
if (!grammarPath) {
|
|
71
|
+
languageCache.set(grammar, null);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const language = await parserModule.Language.load(grammarPath);
|
|
76
|
+
languageCache.set(grammar, language);
|
|
77
|
+
return language;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
languageCache.set(grammar, null);
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Obtain a parser bound to `grammar` (e.g. "python", "html", "css"), or
|
|
86
|
+
* `undefined` if web-tree-sitter or the grammar wasm cannot be loaded.
|
|
87
|
+
*/
|
|
88
|
+
export async function getTreeSitterParser(grammar, dependencyPath) {
|
|
89
|
+
const parserModule = await getModule(dependencyPath);
|
|
90
|
+
if (!parserModule)
|
|
91
|
+
return undefined;
|
|
92
|
+
if (!(await ensureInit(parserModule)))
|
|
93
|
+
return undefined;
|
|
94
|
+
const language = await loadLanguage(parserModule, grammar);
|
|
95
|
+
if (!language)
|
|
96
|
+
return undefined;
|
|
97
|
+
try {
|
|
98
|
+
const parser = new parserModule.Parser();
|
|
99
|
+
parser.setLanguage(language);
|
|
100
|
+
return parser;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Test seam: reset the memoised runtime/grammar caches. */
|
|
107
|
+
export function __resetTreeSitterForTests() {
|
|
108
|
+
modulePromise = undefined;
|
|
109
|
+
initPromise = undefined;
|
|
110
|
+
languageCache.clear();
|
|
111
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { GraphEdge, RouteEdge, AnalyzerSetting } from "@audit-tools/shared";
|
|
2
|
+
import type { FileDisposition } from "@audit-tools/shared";
|
|
3
|
+
import type { RepoManifest } from "../../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* The compiler/parser graph seam (Phase 5.0). A `LanguageAnalyzer` enriches the
|
|
6
|
+
* deterministic regex floor with edges derived from a real parser/compiler. Each
|
|
7
|
+
* analyzer is optional: its dependency resolves from the audited repo's
|
|
8
|
+
* node_modules, a shared version-keyed cache, or not at all — and when it cannot
|
|
9
|
+
* resolve, the orchestrator simply keeps the regex floor.
|
|
10
|
+
*/
|
|
11
|
+
export interface AnalyzerOutput {
|
|
12
|
+
edges: GraphEdge[];
|
|
13
|
+
routes?: RouteEdge[];
|
|
14
|
+
}
|
|
15
|
+
export interface AnalyzerContext {
|
|
16
|
+
/** Absolute repository root. */
|
|
17
|
+
root: string;
|
|
18
|
+
repoManifest: RepoManifest;
|
|
19
|
+
disposition?: FileDisposition;
|
|
20
|
+
/** Repo-relative, audit-included file paths (the analyzer's working set). */
|
|
21
|
+
includedFiles: string[];
|
|
22
|
+
/** graphLookupKey(path) → repo-relative path, for resolving targets. */
|
|
23
|
+
pathLookup: Map<string, string>;
|
|
24
|
+
/** Resolved npm package directory for this analyzer's dependency, if any. */
|
|
25
|
+
dependencyPath?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface LanguageAnalyzer {
|
|
28
|
+
/** Stable id; also the `analyzers.<id>` session-config key. */
|
|
29
|
+
id: string;
|
|
30
|
+
/** Optional npm dependency spec ("name" or "name@range") this analyzer needs. */
|
|
31
|
+
dependency?: string;
|
|
32
|
+
/** Whether this analyzer can contribute edges for the given repo-relative file. */
|
|
33
|
+
supports(file: string): boolean;
|
|
34
|
+
/** Analyze the supported subset of `files` and return enrichment edges/routes. */
|
|
35
|
+
analyze(files: string[], context: AnalyzerContext): Promise<AnalyzerOutput> | AnalyzerOutput;
|
|
36
|
+
}
|
|
37
|
+
/** How an analyzer's dependency resolved (or why it will not run). */
|
|
38
|
+
export type AnalyzerResolution = "repo" | "cache" | "installed" | "absent" | "skip" | "not_applicable";
|
|
39
|
+
/**
|
|
40
|
+
* Deterministic pre-install resolution for one analyzer. Computed without
|
|
41
|
+
* mutating anything (no install), so the conversation-first CLI can decide
|
|
42
|
+
* whether to propose an install before the executor runs.
|
|
43
|
+
*/
|
|
44
|
+
export interface AnalyzerPlanEntry {
|
|
45
|
+
id: string;
|
|
46
|
+
dependency?: string;
|
|
47
|
+
setting: AnalyzerSetting;
|
|
48
|
+
resolution: AnalyzerResolution;
|
|
49
|
+
/** Resolved package directory when resolution is repo/cache. */
|
|
50
|
+
path?: string;
|
|
51
|
+
/** Count of in-scope files the analyzer supports. */
|
|
52
|
+
supportedCount: number;
|
|
53
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { graphEdge, normalizeGraphPath, resolveCandidate } from "../graphPathUtils.js";
|
|
5
|
+
import { TS_CALL_EDGE_CONFIDENCE, TS_EXTENDS_EDGE_CONFIDENCE, TS_IMPLEMENTS_EDGE_CONFIDENCE, TS_IMPORT_EDGE_CONFIDENCE, TS_REEXPORT_EDGE_CONFIDENCE, } from "./merge.js";
|
|
6
|
+
const SUPPORTED_EXTENSIONS = [
|
|
7
|
+
".ts",
|
|
8
|
+
".tsx",
|
|
9
|
+
".mts",
|
|
10
|
+
".cts",
|
|
11
|
+
".js",
|
|
12
|
+
".jsx",
|
|
13
|
+
".mjs",
|
|
14
|
+
".cjs",
|
|
15
|
+
];
|
|
16
|
+
function supports(file) {
|
|
17
|
+
const lower = normalizeGraphPath(file).toLowerCase();
|
|
18
|
+
if (lower.endsWith(".d.ts"))
|
|
19
|
+
return false;
|
|
20
|
+
return SUPPORTED_EXTENSIONS.some((extension) => lower.endsWith(extension));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Load the TypeScript compiler module. Prefers the dependency resolved from the
|
|
24
|
+
* audited repo / shared cache (so its tsconfig + version semantics match);
|
|
25
|
+
* falls back to the bundled `typescript` so the analyzer still works when the
|
|
26
|
+
* caller did not pin a path.
|
|
27
|
+
*/
|
|
28
|
+
async function loadTypescript(dependencyPath) {
|
|
29
|
+
if (dependencyPath) {
|
|
30
|
+
try {
|
|
31
|
+
const manifest = JSON.parse(readFileSync(join(dependencyPath, "package.json"), "utf8"));
|
|
32
|
+
const mainPath = resolve(dependencyPath, manifest.main ?? "index.js");
|
|
33
|
+
const mod = (await import(pathToFileURL(mainPath).href));
|
|
34
|
+
return (mod.default ?? mod);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Fall through to the bundled compiler.
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const mod = (await import("typescript"));
|
|
41
|
+
return (mod.default ?? mod);
|
|
42
|
+
}
|
|
43
|
+
function loadCompilerOptions(ts, root) {
|
|
44
|
+
let options = {};
|
|
45
|
+
try {
|
|
46
|
+
const configPath = ts.findConfigFile(root, (path) => ts.sys.fileExists(path), "tsconfig.json");
|
|
47
|
+
if (configPath) {
|
|
48
|
+
const read = ts.readConfigFile(configPath, (path) => ts.sys.readFile(path));
|
|
49
|
+
const parsed = ts.parseJsonConfigFileContent(read.config ?? {}, ts.sys, dirname(configPath));
|
|
50
|
+
options = parsed.options;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
options = {};
|
|
55
|
+
}
|
|
56
|
+
// Force a lenient, emit-free, JS-aware program: we only want resolution + the
|
|
57
|
+
// checker, never diagnostics or output.
|
|
58
|
+
return {
|
|
59
|
+
...options,
|
|
60
|
+
allowJs: true,
|
|
61
|
+
checkJs: false,
|
|
62
|
+
noEmit: true,
|
|
63
|
+
skipLibCheck: true,
|
|
64
|
+
skipDefaultLibCheck: true,
|
|
65
|
+
declaration: false,
|
|
66
|
+
composite: false,
|
|
67
|
+
incremental: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Map an absolute file path back to its canonical audit-included repo path. */
|
|
71
|
+
function mapToIncluded(state, absolutePath) {
|
|
72
|
+
const normalizedAbsolute = isAbsolute(absolutePath)
|
|
73
|
+
? absolutePath
|
|
74
|
+
: resolve(state.root, absolutePath);
|
|
75
|
+
const relativePath = normalizeGraphPath(relative(state.root, normalizedAbsolute));
|
|
76
|
+
if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return resolveCandidate(relativePath, state.context.pathLookup);
|
|
80
|
+
}
|
|
81
|
+
function resolveSpecifierTarget(state, specifier, containingFile) {
|
|
82
|
+
const resolved = state.ts.resolveModuleName(specifier, containingFile, state.options, state.ts.sys);
|
|
83
|
+
const target = resolved.resolvedModule;
|
|
84
|
+
if (!target ||
|
|
85
|
+
target.isExternalLibraryImport ||
|
|
86
|
+
target.resolvedFileName.endsWith(".d.ts")) {
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
return mapToIncluded(state, target.resolvedFileName);
|
|
90
|
+
}
|
|
91
|
+
/** Follow import aliases to the symbol's real declaration source file. */
|
|
92
|
+
function resolveSymbolToIncluded(state, symbol) {
|
|
93
|
+
if (!symbol)
|
|
94
|
+
return undefined;
|
|
95
|
+
let resolved = symbol;
|
|
96
|
+
if (resolved.flags & state.ts.SymbolFlags.Alias) {
|
|
97
|
+
try {
|
|
98
|
+
resolved = state.checker.getAliasedSymbol(resolved);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Keep the un-aliased symbol on failure.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const declaration of resolved.declarations ?? []) {
|
|
105
|
+
const fileName = declaration.getSourceFile().fileName;
|
|
106
|
+
if (fileName.endsWith(".d.ts"))
|
|
107
|
+
continue;
|
|
108
|
+
const included = mapToIncluded(state, fileName);
|
|
109
|
+
if (included)
|
|
110
|
+
return included;
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
function collectFileEdges(state, sourceFile, fromPath, imports, references, calls) {
|
|
115
|
+
const ts = state.ts;
|
|
116
|
+
const callTargets = new Set();
|
|
117
|
+
const recordCall = (target) => {
|
|
118
|
+
if (!target || target === fromPath || callTargets.has(target))
|
|
119
|
+
return;
|
|
120
|
+
callTargets.add(target);
|
|
121
|
+
calls.push(graphEdge({
|
|
122
|
+
from: fromPath,
|
|
123
|
+
to: target,
|
|
124
|
+
kind: "ts-call",
|
|
125
|
+
confidence: TS_CALL_EDGE_CONFIDENCE,
|
|
126
|
+
reason: `TypeScript checker resolved a cross-file call into '${target}'.`,
|
|
127
|
+
}));
|
|
128
|
+
};
|
|
129
|
+
const visitHeritage = (node) => {
|
|
130
|
+
for (const clause of node.heritageClauses ?? []) {
|
|
131
|
+
const isExtends = clause.token === ts.SyntaxKind.ExtendsKeyword;
|
|
132
|
+
for (const typeNode of clause.types) {
|
|
133
|
+
const target = resolveSymbolToIncluded(state, state.checker.getSymbolAtLocation(typeNode.expression));
|
|
134
|
+
if (!target || target === fromPath)
|
|
135
|
+
continue;
|
|
136
|
+
references.push(graphEdge({
|
|
137
|
+
from: fromPath,
|
|
138
|
+
to: target,
|
|
139
|
+
kind: isExtends ? "ts-extends" : "ts-implements",
|
|
140
|
+
confidence: isExtends
|
|
141
|
+
? TS_EXTENDS_EDGE_CONFIDENCE
|
|
142
|
+
: TS_IMPLEMENTS_EDGE_CONFIDENCE,
|
|
143
|
+
reason: `TypeScript ${isExtends ? "extends" : "implements"} heritage resolves to '${target}'.`,
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const visit = (node) => {
|
|
149
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
150
|
+
const target = resolveSpecifierTarget(state, node.moduleSpecifier.text, sourceFile.fileName);
|
|
151
|
+
if (target && target !== fromPath) {
|
|
152
|
+
imports.push(graphEdge({
|
|
153
|
+
from: fromPath,
|
|
154
|
+
to: target,
|
|
155
|
+
kind: "ts-import",
|
|
156
|
+
confidence: TS_IMPORT_EDGE_CONFIDENCE,
|
|
157
|
+
reason: `TypeScript resolved import '${node.moduleSpecifier.text}' to '${target}'.`,
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else if (ts.isExportDeclaration(node) &&
|
|
162
|
+
node.moduleSpecifier &&
|
|
163
|
+
ts.isStringLiteral(node.moduleSpecifier)) {
|
|
164
|
+
const target = resolveSpecifierTarget(state, node.moduleSpecifier.text, sourceFile.fileName);
|
|
165
|
+
if (target && target !== fromPath) {
|
|
166
|
+
imports.push(graphEdge({
|
|
167
|
+
from: fromPath,
|
|
168
|
+
to: target,
|
|
169
|
+
kind: "ts-reexport",
|
|
170
|
+
confidence: TS_REEXPORT_EDGE_CONFIDENCE,
|
|
171
|
+
reason: `TypeScript resolved re-export '${node.moduleSpecifier.text}' to '${target}'.`,
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else if (ts.isImportEqualsDeclaration(node) &&
|
|
176
|
+
ts.isExternalModuleReference(node.moduleReference) &&
|
|
177
|
+
ts.isStringLiteral(node.moduleReference.expression)) {
|
|
178
|
+
const target = resolveSpecifierTarget(state, node.moduleReference.expression.text, sourceFile.fileName);
|
|
179
|
+
if (target && target !== fromPath) {
|
|
180
|
+
imports.push(graphEdge({
|
|
181
|
+
from: fromPath,
|
|
182
|
+
to: target,
|
|
183
|
+
kind: "ts-import",
|
|
184
|
+
confidence: TS_IMPORT_EDGE_CONFIDENCE,
|
|
185
|
+
reason: `TypeScript resolved import-equals to '${target}'.`,
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else if (ts.isCallExpression(node)) {
|
|
190
|
+
if (node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
191
|
+
node.arguments[0] &&
|
|
192
|
+
ts.isStringLiteral(node.arguments[0])) {
|
|
193
|
+
const target = resolveSpecifierTarget(state, node.arguments[0].text, sourceFile.fileName);
|
|
194
|
+
if (target && target !== fromPath) {
|
|
195
|
+
imports.push(graphEdge({
|
|
196
|
+
from: fromPath,
|
|
197
|
+
to: target,
|
|
198
|
+
kind: "ts-import",
|
|
199
|
+
confidence: TS_IMPORT_EDGE_CONFIDENCE,
|
|
200
|
+
reason: `TypeScript resolved dynamic import to '${target}'.`,
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
recordCall(resolveSymbolToIncluded(state, state.checker.getSymbolAtLocation(node.expression)));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (ts.isClassDeclaration(node) ||
|
|
209
|
+
ts.isClassExpression(node) ||
|
|
210
|
+
ts.isInterfaceDeclaration(node)) {
|
|
211
|
+
visitHeritage(node);
|
|
212
|
+
}
|
|
213
|
+
ts.forEachChild(node, visit);
|
|
214
|
+
};
|
|
215
|
+
ts.forEachChild(sourceFile, visit);
|
|
216
|
+
}
|
|
217
|
+
async function analyze(files, context) {
|
|
218
|
+
if (files.length === 0)
|
|
219
|
+
return { edges: [] };
|
|
220
|
+
let ts;
|
|
221
|
+
try {
|
|
222
|
+
ts = await loadTypescript(context.dependencyPath);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return { edges: [] };
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const root = resolve(context.root);
|
|
229
|
+
const options = loadCompilerOptions(ts, root);
|
|
230
|
+
const rootNames = files.map((file) => resolve(root, file));
|
|
231
|
+
const program = ts.createProgram({ rootNames, options });
|
|
232
|
+
const checker = program.getTypeChecker();
|
|
233
|
+
const state = { ts, options, checker, context, root };
|
|
234
|
+
const imports = [];
|
|
235
|
+
const references = [];
|
|
236
|
+
const calls = [];
|
|
237
|
+
for (const sourceFile of program.getSourceFiles()) {
|
|
238
|
+
if (sourceFile.isDeclarationFile)
|
|
239
|
+
continue;
|
|
240
|
+
const fromPath = mapToIncluded(state, sourceFile.fileName);
|
|
241
|
+
if (!fromPath)
|
|
242
|
+
continue;
|
|
243
|
+
collectFileEdges(state, sourceFile, fromPath, imports, references, calls);
|
|
244
|
+
}
|
|
245
|
+
return { edges: [...imports, ...references, ...calls] };
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// Any compiler failure degrades cleanly to the regex floor.
|
|
249
|
+
return { edges: [] };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
export const typescriptAnalyzer = {
|
|
253
|
+
id: "typescript",
|
|
254
|
+
dependency: "typescript@5",
|
|
255
|
+
supports,
|
|
256
|
+
analyze,
|
|
257
|
+
};
|
|
@@ -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;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isGeneratedPath, isAuditArtifactPath, isGeneratedTestArtifactPath, isGeneratedInstallArtifactPath, isExamplesOrFixturesPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isTmpPath, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, isGeneratedPath, isAuditArtifactPath, isGeneratedTestArtifactPath, isGeneratedInstallArtifactPath, isExamplesOrFixturesPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
3
|
const normalized = normalizeExtractorPath(path);
|
|
4
4
|
if (isNodeModulesOrGit(normalized)) {
|
|
5
5
|
return { path, status: "excluded", reason: "node_modules or .git excluded by convention." };
|
|
6
6
|
}
|
|
7
|
+
if (isTmpPath(normalized)) {
|
|
8
|
+
return {
|
|
9
|
+
path,
|
|
10
|
+
status: "excluded",
|
|
11
|
+
reason: "Temporary/bundled artifact directory (.tmp) excluded by convention.",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
7
14
|
if (isBuildOutput(normalized)) {
|
|
8
15
|
return { path, status: "generated", reason: "Build output path." };
|
|
9
16
|
}
|
|
@@ -75,6 +82,9 @@ export function buildFileDisposition(repoManifest) {
|
|
|
75
82
|
files: repoManifest.files.map((file) => inferDisposition(file.path)),
|
|
76
83
|
};
|
|
77
84
|
}
|
|
85
|
+
export function buildDispositionMap(disposition) {
|
|
86
|
+
return new Map(disposition?.files.map((item) => [item.path, item.status]) ?? []);
|
|
87
|
+
}
|
|
78
88
|
export function isAuditExcludedStatus(status) {
|
|
79
89
|
return (status === "excluded" ||
|
|
80
90
|
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,10 +1,10 @@
|
|
|
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;
|
|
8
7
|
}
|
|
8
|
+
export declare function buildPathLookup(repoManifest: RepoManifest, dispositionMap: Map<string, FileDisposition["files"][number]["status"]>): Map<string, string>;
|
|
9
9
|
export declare function buildGraphBundleFromFs(repoManifest: RepoManifest, root: string, disposition?: FileDisposition, options?: Pick<BuildGraphBundleOptions, "externalAnalyzerResults">): Promise<GraphBundle>;
|
|
10
10
|
export declare function buildGraphBundle(repoManifest: RepoManifest, disposition?: FileDisposition, options?: BuildGraphBundleOptions): GraphBundle;
|