auditor-lambda 0.2.6 → 0.2.9
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/README.md +29 -7
- package/audit-code-wrapper-lib.mjs +1605 -330
- package/dist/adapters/eslint.js +9 -5
- package/dist/cli.d.ts +42 -1
- package/dist/cli.js +192 -80
- package/dist/coverage.d.ts +2 -2
- package/dist/coverage.js +5 -5
- package/dist/extractors/bucketing.d.ts +4 -0
- package/dist/extractors/bucketing.js +6 -2
- package/dist/extractors/disposition.d.ts +4 -0
- package/dist/extractors/disposition.js +15 -2
- package/dist/extractors/fileInventory.js +24 -28
- package/dist/extractors/flows.d.ts +5 -0
- package/dist/extractors/flows.js +25 -39
- package/dist/extractors/pathPatterns.d.ts +13 -3
- package/dist/extractors/pathPatterns.js +116 -53
- package/dist/extractors/risk.js +7 -1
- package/dist/extractors/surfaces.d.ts +4 -0
- package/dist/extractors/surfaces.js +11 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -1
- package/dist/io/artifacts.d.ts +59 -44
- package/dist/io/artifacts.js +80 -120
- package/dist/io/json.d.ts +2 -0
- package/dist/io/json.js +65 -19
- package/dist/io/runArtifacts.d.ts +2 -1
- package/dist/io/runArtifacts.js +44 -7
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +579 -0
- package/dist/orchestrator/advance.js +84 -56
- package/dist/orchestrator/dependencyMap.js +9 -13
- package/dist/orchestrator/executors.js +7 -2
- package/dist/orchestrator/flowCoverage.js +11 -5
- package/dist/orchestrator/flowPlanning.d.ts +7 -2
- package/dist/orchestrator/flowPlanning.js +46 -21
- package/dist/orchestrator/flowRequeue.js +29 -9
- package/dist/orchestrator/internalExecutors.d.ts +2 -1
- package/dist/orchestrator/internalExecutors.js +130 -69
- package/dist/orchestrator/planning.js +25 -3
- package/dist/orchestrator/requeue.js +20 -5
- package/dist/orchestrator/resultIngestion.js +5 -6
- package/dist/orchestrator/runtimeValidation.d.ts +7 -2
- package/dist/orchestrator/runtimeValidation.js +61 -49
- package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
- package/dist/orchestrator/state.js +18 -13
- package/dist/orchestrator/taskBuilder.d.ts +4 -2
- package/dist/orchestrator/taskBuilder.js +153 -52
- package/dist/orchestrator/trivialAudit.js +8 -5
- package/dist/orchestrator/unitBuilder.d.ts +3 -1
- package/dist/orchestrator/unitBuilder.js +24 -16
- package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
- package/dist/prompts/renderWorkerPrompt.js +19 -10
- package/dist/providers/claudeCodeProvider.d.ts +4 -1
- package/dist/providers/claudeCodeProvider.js +8 -5
- package/dist/providers/localSubprocessProvider.d.ts +4 -0
- package/dist/providers/localSubprocessProvider.js +7 -2
- package/dist/providers/spawnLoggedCommand.d.ts +9 -1
- package/dist/providers/spawnLoggedCommand.js +77 -29
- package/dist/reporting/mergeFindings.js +0 -11
- package/dist/reporting/synthesis.d.ts +26 -21
- package/dist/reporting/synthesis.js +97 -61
- package/dist/reporting/workBlocks.d.ts +12 -3
- package/dist/reporting/workBlocks.js +124 -70
- package/dist/supervisor/operatorHandoff.js +48 -18
- package/dist/supervisor/runLedger.d.ts +1 -1
- package/dist/supervisor/runLedger.js +112 -5
- package/dist/supervisor/sessionConfig.js +10 -10
- package/dist/types/externalAnalyzer.d.ts +3 -0
- package/dist/types/flowCoverage.d.ts +5 -1
- package/dist/types/flowCoverage.js +5 -1
- package/dist/types/flows.d.ts +6 -0
- package/dist/types/flows.js +1 -1
- package/dist/types/runLedger.d.ts +5 -1
- package/dist/types/runLedger.js +6 -1
- package/dist/types/runtimeValidation.d.ts +13 -3
- package/dist/types/runtimeValidation.js +16 -1
- package/dist/types/sessionConfig.d.ts +15 -2
- package/dist/types/sessionConfig.js +15 -1
- package/dist/types/surfaces.d.ts +4 -1
- package/dist/types/surfaces.js +1 -1
- package/dist/types/workerSession.d.ts +9 -0
- package/dist/types/workerSession.js +5 -1
- package/dist/types.d.ts +4 -7
- package/dist/validation/artifacts.d.ts +1 -1
- package/dist/validation/artifacts.js +33 -20
- package/dist/validation/auditResults.d.ts +2 -2
- package/dist/validation/auditResults.js +71 -114
- package/dist/validation/basic.d.ts +9 -1
- package/dist/validation/basic.js +40 -3
- package/dist/validation/sessionConfig.d.ts +4 -2
- package/dist/validation/sessionConfig.js +62 -15
- package/docs/agent-integrations.md +67 -38
- package/docs/artifacts.md +16 -56
- package/docs/bootstrap-install.md +60 -30
- package/docs/contract.md +22 -205
- package/docs/next-steps.md +76 -44
- package/docs/packaging.md +27 -3
- package/docs/product-direction.md +22 -0
- package/docs/production-launch-bar.md +4 -2
- package/docs/production-readiness.md +9 -5
- package/docs/releasing.md +98 -0
- package/docs/remediation-baseline.md +75 -0
- package/docs/run-flow.md +23 -11
- package/docs/session-config.md +50 -5
- package/docs/supervisor.md +7 -0
- package/docs/workflow-refactor-brief.md +177 -0
- package/package.json +4 -1
- package/schemas/audit_result.schema.json +8 -7
- package/schemas/audit_task.schema.json +3 -1
- package/schemas/coverage_matrix.schema.json +3 -3
- package/schemas/critical_flows.schema.json +6 -2
- package/schemas/file_disposition.schema.json +2 -2
- package/schemas/finding.schema.json +9 -4
- package/schemas/flow_coverage.schema.json +2 -2
- package/schemas/repo_manifest.schema.json +4 -4
- package/schemas/risk_register.schema.json +2 -2
- package/schemas/runtime_validation_report.schema.json +3 -3
- package/schemas/runtime_validation_tasks.schema.json +8 -2
- package/schemas/surface_manifest.schema.json +6 -3
- package/schemas/unit_manifest.schema.json +3 -2
- package/skills/audit-code/SKILL.md +16 -2
- package/skills/audit-code/audit-code.prompt.md +5 -8
- package/schemas/merged_findings.schema.json +0 -19
- package/schemas/root_cause_clusters.schema.json +0 -28
- package/schemas/synthesis_report.schema.json +0 -61
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isDocPath, } from "./pathPatterns.js";
|
|
1
|
+
import { isNodeModulesOrGit, isBuildOutput, isVendorPath, isBinaryArtifact, isLicensePath, isLockfilePath, isLogPath, isDocPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
2
2
|
function inferDisposition(path) {
|
|
3
|
-
const normalized = path
|
|
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
|
}
|
|
@@ -17,6 +17,15 @@ function inferDisposition(path) {
|
|
|
17
17
|
reason: "Non-source binary-like artifact.",
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
if (isLogPath(normalized)) {
|
|
21
|
+
return { path, status: "generated", reason: "Runtime log artifact." };
|
|
22
|
+
}
|
|
23
|
+
if (isLicensePath(normalized)) {
|
|
24
|
+
return { path, status: "doc_only", reason: "License file is not auditable code." };
|
|
25
|
+
}
|
|
26
|
+
if (isLockfilePath(normalized)) {
|
|
27
|
+
return { path, status: "generated", reason: "Lockfile excluded from code audit scope." };
|
|
28
|
+
}
|
|
20
29
|
if (isDocPath(normalized)) {
|
|
21
30
|
return { path, status: "doc_only", reason: "Documentation artifact." };
|
|
22
31
|
}
|
|
@@ -26,6 +35,10 @@ function inferDisposition(path) {
|
|
|
26
35
|
reason: "Default included source or config artifact.",
|
|
27
36
|
};
|
|
28
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Applies shared path heuristics to mark files that should be excluded or
|
|
40
|
+
* down-scoped before audit planning begins.
|
|
41
|
+
*/
|
|
29
42
|
export function buildFileDisposition(repoManifest) {
|
|
30
43
|
return {
|
|
31
44
|
files: repoManifest.files.map((file) => inferDisposition(file.path)),
|
|
@@ -1,32 +1,28 @@
|
|
|
1
|
+
import { normalizeExtractorPath } from "./pathPatterns.js";
|
|
2
|
+
const LANGUAGE_BY_EXTENSION = {
|
|
3
|
+
ts: "typescript",
|
|
4
|
+
tsx: "typescript",
|
|
5
|
+
mts: "typescript",
|
|
6
|
+
cts: "typescript",
|
|
7
|
+
js: "javascript",
|
|
8
|
+
jsx: "javascript",
|
|
9
|
+
mjs: "javascript",
|
|
10
|
+
cjs: "javascript",
|
|
11
|
+
py: "python",
|
|
12
|
+
go: "go",
|
|
13
|
+
rs: "rust",
|
|
14
|
+
java: "java",
|
|
15
|
+
cs: "csharp",
|
|
16
|
+
json: "json",
|
|
17
|
+
yml: "yaml",
|
|
18
|
+
yaml: "yaml",
|
|
19
|
+
md: "markdown",
|
|
20
|
+
};
|
|
1
21
|
function inferLanguage(path) {
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return "typescript";
|
|
7
|
-
case "js":
|
|
8
|
-
case "jsx":
|
|
9
|
-
return "javascript";
|
|
10
|
-
case "py":
|
|
11
|
-
return "python";
|
|
12
|
-
case "go":
|
|
13
|
-
return "go";
|
|
14
|
-
case "rs":
|
|
15
|
-
return "rust";
|
|
16
|
-
case "java":
|
|
17
|
-
return "java";
|
|
18
|
-
case "cs":
|
|
19
|
-
return "csharp";
|
|
20
|
-
case "json":
|
|
21
|
-
return "json";
|
|
22
|
-
case "yml":
|
|
23
|
-
case "yaml":
|
|
24
|
-
return "yaml";
|
|
25
|
-
case "md":
|
|
26
|
-
return "markdown";
|
|
27
|
-
default:
|
|
28
|
-
return "unknown";
|
|
29
|
-
}
|
|
22
|
+
const normalized = normalizeExtractorPath(path);
|
|
23
|
+
const base = normalized.split("/").pop() ?? normalized;
|
|
24
|
+
const extension = base.includes(".") ? base.split(".").pop() ?? "" : "";
|
|
25
|
+
return LANGUAGE_BY_EXTENSION[extension] ?? "unknown";
|
|
30
26
|
}
|
|
31
27
|
export function buildRepoManifest(repositoryName, files) {
|
|
32
28
|
return {
|
|
@@ -2,4 +2,9 @@ import type { RepoManifest } from "../types.js";
|
|
|
2
2
|
import type { FileDisposition } from "../types/disposition.js";
|
|
3
3
|
import type { CriticalFlowManifest } from "../types/flows.js";
|
|
4
4
|
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
5
|
+
/**
|
|
6
|
+
* Builds coarse critical-flow coverage from shared path heuristics. These
|
|
7
|
+
* bootstrap flows are intentionally conservative and should be reviewed when a
|
|
8
|
+
* repo uses unconventional naming or layout conventions.
|
|
9
|
+
*/
|
|
5
10
|
export declare function buildCriticalFlowManifest(repoManifest: RepoManifest, surfaceManifest: SurfaceManifest, disposition?: FileDisposition): CriticalFlowManifest;
|
package/dist/extractors/flows.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
-
import { isSecuritySensitivePath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, } from "./pathPatterns.js";
|
|
2
|
+
import { EXTRACTOR_HEURISTIC_NOTE, isAsyncTaskPath, isBillingPath, isIdentityPath, isSecuritySensitivePath, isDataLayerPath, isConcurrencyPath, isInterfacePath, isDeploymentConfigPath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
3
3
|
function inferConcerns(paths) {
|
|
4
4
|
const concerns = new Set();
|
|
5
5
|
for (const path of paths) {
|
|
6
|
-
const normalized = path
|
|
6
|
+
const normalized = normalizeExtractorPath(path);
|
|
7
7
|
if (isSecuritySensitivePath(normalized))
|
|
8
8
|
concerns.add("security");
|
|
9
|
-
if (isDataLayerPath(normalized) ||
|
|
10
|
-
normalized.includes("invoice") ||
|
|
11
|
-
normalized.includes("payment"))
|
|
9
|
+
if (isDataLayerPath(normalized) || isBillingPath(normalized))
|
|
12
10
|
concerns.add("data_integrity");
|
|
13
11
|
if (isConcurrencyPath(normalized))
|
|
14
12
|
concerns.add("reliability");
|
|
@@ -18,47 +16,26 @@ function inferConcerns(paths) {
|
|
|
18
16
|
return concerns.size > 0 ? [...concerns] : ["correctness"];
|
|
19
17
|
}
|
|
20
18
|
function relatedPaths(entry, availablePaths) {
|
|
21
|
-
const normalized = entry
|
|
19
|
+
const normalized = normalizeExtractorPath(entry);
|
|
22
20
|
const linked = new Set([entry]);
|
|
23
21
|
for (const path of availablePaths) {
|
|
24
|
-
const lower = path
|
|
22
|
+
const lower = normalizeExtractorPath(path);
|
|
25
23
|
if (path === entry)
|
|
26
24
|
continue;
|
|
27
25
|
// Auth / session flows: link sibling auth, session, token, user paths
|
|
28
|
-
if (isSecuritySensitivePath(normalized) &&
|
|
29
|
-
(lower.includes("auth") ||
|
|
30
|
-
lower.includes("session") ||
|
|
31
|
-
lower.includes("token") ||
|
|
32
|
-
lower.includes("user"))) {
|
|
26
|
+
if (isSecuritySensitivePath(normalized) && isIdentityPath(lower)) {
|
|
33
27
|
linked.add(path);
|
|
34
28
|
}
|
|
35
29
|
// Billing / payment flows: link ledger and subscription paths
|
|
36
|
-
if ((normalized
|
|
37
|
-
normalized.includes("invoice") ||
|
|
38
|
-
normalized.includes("payment")) &&
|
|
39
|
-
(lower.includes("billing") ||
|
|
40
|
-
lower.includes("invoice") ||
|
|
41
|
-
lower.includes("payment") ||
|
|
42
|
-
lower.includes("ledger") ||
|
|
43
|
-
lower.includes("subscription"))) {
|
|
30
|
+
if (isBillingPath(normalized) && isBillingPath(lower)) {
|
|
44
31
|
linked.add(path);
|
|
45
32
|
}
|
|
46
33
|
// Async / queue flows: link worker, job, retry, and task paths
|
|
47
|
-
if (isConcurrencyPath(normalized) &&
|
|
48
|
-
(lower.includes("queue") ||
|
|
49
|
-
lower.includes("retry") ||
|
|
50
|
-
lower.includes("worker") ||
|
|
51
|
-
lower.includes("job") ||
|
|
52
|
-
lower.includes("task"))) {
|
|
34
|
+
if (isConcurrencyPath(normalized) && isAsyncTaskPath(lower)) {
|
|
53
35
|
linked.add(path);
|
|
54
36
|
}
|
|
55
37
|
// Deployment / infra flows: link docker, k8s, terraform, workflow paths
|
|
56
|
-
if (isDeploymentConfigPath(normalized) &&
|
|
57
|
-
(lower.includes("deploy") ||
|
|
58
|
-
lower.includes("docker") ||
|
|
59
|
-
lower.includes("workflow") ||
|
|
60
|
-
lower.includes("k8s") ||
|
|
61
|
-
lower.includes("terraform"))) {
|
|
38
|
+
if (isDeploymentConfigPath(normalized) && isDeploymentConfigPath(lower)) {
|
|
62
39
|
linked.add(path);
|
|
63
40
|
}
|
|
64
41
|
}
|
|
@@ -76,6 +53,11 @@ function dedupeFlows(flows) {
|
|
|
76
53
|
}
|
|
77
54
|
return deduped;
|
|
78
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Builds coarse critical-flow coverage from shared path heuristics. These
|
|
58
|
+
* bootstrap flows are intentionally conservative and should be reviewed when a
|
|
59
|
+
* repo uses unconventional naming or layout conventions.
|
|
60
|
+
*/
|
|
79
61
|
export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposition) {
|
|
80
62
|
const dispositionMap = new Map(disposition?.files.map((item) => [item.path, item.status]) ?? []);
|
|
81
63
|
const availablePaths = repoManifest.files
|
|
@@ -94,23 +76,27 @@ export function buildCriticalFlowManifest(repoManifest, surfaceManifest, disposi
|
|
|
94
76
|
entrypoints: [entry],
|
|
95
77
|
paths,
|
|
96
78
|
concerns: inferConcerns(paths),
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
],
|
|
79
|
+
confidence: paths.length > 1 ? "high" : "low",
|
|
80
|
+
notes: [EXTRACTOR_HEURISTIC_NOTE],
|
|
100
81
|
});
|
|
101
82
|
}
|
|
102
83
|
for (const path of availablePaths) {
|
|
103
|
-
const
|
|
104
|
-
if (isDataLayerPath(
|
|
84
|
+
const normalized = normalizeExtractorPath(path);
|
|
85
|
+
if (isDataLayerPath(normalized)) {
|
|
105
86
|
flows.push({
|
|
106
87
|
id: `flow:data:${path.replace(/[^a-zA-Z0-9:_-]/g, "-")}`,
|
|
107
88
|
name: `data evolution flow for ${path}`,
|
|
108
89
|
entrypoints: [path],
|
|
109
90
|
paths: relatedPaths(path, availablePaths),
|
|
110
91
|
concerns: ["data_integrity", "reliability"],
|
|
111
|
-
|
|
92
|
+
confidence: "high",
|
|
93
|
+
notes: [EXTRACTOR_HEURISTIC_NOTE],
|
|
112
94
|
});
|
|
113
95
|
}
|
|
114
96
|
}
|
|
115
|
-
|
|
97
|
+
const deduped = dedupeFlows(flows);
|
|
98
|
+
return {
|
|
99
|
+
flows: deduped,
|
|
100
|
+
fallback_required: deduped.length === 0 || deduped.some((flow) => flow.confidence === "low"),
|
|
101
|
+
};
|
|
116
102
|
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Shared bootstrap heuristics for the extractor layer. These rules run before
|
|
3
|
+
* richer graph/unit analysis exists, so they intentionally favor recall over
|
|
4
|
+
* precision and always normalize case plus path separators first.
|
|
5
5
|
*/
|
|
6
|
+
export declare const EXTRACTOR_HEURISTIC_NOTE = "Heuristic path classification normalizes case and path separators, then matches conservative keyword groups; confirm unusual repo layouts manually.";
|
|
7
|
+
export declare function normalizeExtractorPath(path: string): string;
|
|
6
8
|
export declare function isNodeModulesOrGit(normalized: string): boolean;
|
|
7
9
|
export declare function isBuildOutput(normalized: string): boolean;
|
|
8
10
|
export declare function isVendorPath(normalized: string): boolean;
|
|
9
11
|
export declare function isBinaryArtifact(normalized: string): boolean;
|
|
12
|
+
export declare function isLogPath(normalized: string): boolean;
|
|
13
|
+
export declare function isLicensePath(normalized: string): boolean;
|
|
14
|
+
export declare function isLockfilePath(normalized: string): boolean;
|
|
10
15
|
export declare function isDocPath(normalized: string): boolean;
|
|
11
16
|
export declare function isTestPath(normalized: string): boolean;
|
|
12
17
|
export declare function isInterfacePath(normalized: string): boolean;
|
|
@@ -17,3 +22,8 @@ export declare function isScriptPath(normalized: string): boolean;
|
|
|
17
22
|
export declare function isDeploymentConfigPath(normalized: string): boolean;
|
|
18
23
|
export declare function isGeneratedPath(normalized: string): boolean;
|
|
19
24
|
export declare function isSurfacePath(normalized: string): boolean;
|
|
25
|
+
export declare function isBackgroundSurfacePath(normalized: string): boolean;
|
|
26
|
+
export declare function isNetworkSurfacePath(normalized: string): boolean;
|
|
27
|
+
export declare function isBillingPath(normalized: string): boolean;
|
|
28
|
+
export declare function isIdentityPath(normalized: string): boolean;
|
|
29
|
+
export declare function isAsyncTaskPath(normalized: string): boolean;
|
|
@@ -1,85 +1,148 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Shared bootstrap heuristics for the extractor layer. These rules run before
|
|
3
|
+
* richer graph/unit analysis exists, so they intentionally favor recall over
|
|
4
|
+
* precision and always normalize case plus path separators first.
|
|
5
5
|
*/
|
|
6
|
+
export const EXTRACTOR_HEURISTIC_NOTE = "Heuristic path classification normalizes case and path separators, then matches conservative keyword groups; confirm unusual repo layouts manually.";
|
|
7
|
+
const BINARY_EXTENSIONS = [
|
|
8
|
+
".png",
|
|
9
|
+
".jpg",
|
|
10
|
+
".jpeg",
|
|
11
|
+
".gif",
|
|
12
|
+
".pdf",
|
|
13
|
+
".zip",
|
|
14
|
+
];
|
|
15
|
+
const LOCKFILE_NAMES = [
|
|
16
|
+
"package-lock.json",
|
|
17
|
+
"pnpm-lock.yaml",
|
|
18
|
+
"yarn.lock",
|
|
19
|
+
"cargo.lock",
|
|
20
|
+
"composer.lock",
|
|
21
|
+
"go.sum",
|
|
22
|
+
];
|
|
23
|
+
const TEST_KEYWORDS = ["test", "spec", "__tests__"];
|
|
24
|
+
const INTERFACE_KEYWORDS = ["route", "controller", "handler"];
|
|
25
|
+
const DATA_LAYER_KEYWORDS = ["model", "schema", "migration", "seed"];
|
|
26
|
+
const SECURITY_KEYWORDS = [
|
|
27
|
+
"auth",
|
|
28
|
+
"secret",
|
|
29
|
+
"token",
|
|
30
|
+
"permission",
|
|
31
|
+
"session",
|
|
32
|
+
];
|
|
33
|
+
const CONCURRENCY_KEYWORDS = [
|
|
34
|
+
"queue",
|
|
35
|
+
"worker",
|
|
36
|
+
"job",
|
|
37
|
+
"cache",
|
|
38
|
+
"retry",
|
|
39
|
+
"lock",
|
|
40
|
+
];
|
|
41
|
+
const SCRIPT_KEYWORDS = ["script"];
|
|
42
|
+
const DEPLOYMENT_KEYWORDS = [
|
|
43
|
+
"docker",
|
|
44
|
+
"terraform",
|
|
45
|
+
"deploy",
|
|
46
|
+
"workflow",
|
|
47
|
+
"k8s",
|
|
48
|
+
];
|
|
49
|
+
const SURFACE_KEYWORDS = ["route", "controller", "worker", "job", "command"];
|
|
50
|
+
const BILLING_KEYWORDS = [
|
|
51
|
+
"billing",
|
|
52
|
+
"invoice",
|
|
53
|
+
"payment",
|
|
54
|
+
"ledger",
|
|
55
|
+
"subscription",
|
|
56
|
+
];
|
|
57
|
+
const IDENTITY_KEYWORDS = ["user"];
|
|
58
|
+
const ASYNC_TASK_KEYWORDS = ["task"];
|
|
59
|
+
export function normalizeExtractorPath(path) {
|
|
60
|
+
return path.replace(/\\/g, "/").toLowerCase();
|
|
61
|
+
}
|
|
62
|
+
function splitSegments(normalized) {
|
|
63
|
+
return normalized.split("/").filter(Boolean);
|
|
64
|
+
}
|
|
65
|
+
function hasSegment(normalized, segment) {
|
|
66
|
+
return splitSegments(normalized).includes(segment);
|
|
67
|
+
}
|
|
68
|
+
function includesAny(normalized, values) {
|
|
69
|
+
return values.some((value) => normalized.includes(value));
|
|
70
|
+
}
|
|
71
|
+
function endsWithAny(normalized, suffixes) {
|
|
72
|
+
return suffixes.some((suffix) => normalized.endsWith(suffix));
|
|
73
|
+
}
|
|
74
|
+
function baseName(normalized) {
|
|
75
|
+
const segments = splitSegments(normalized);
|
|
76
|
+
return segments.at(-1) ?? normalized;
|
|
77
|
+
}
|
|
6
78
|
export function isNodeModulesOrGit(normalized) {
|
|
7
|
-
|
|
8
|
-
return segments.includes("node_modules") || segments.includes(".git");
|
|
79
|
+
return hasSegment(normalized, "node_modules") || hasSegment(normalized, ".git");
|
|
9
80
|
}
|
|
10
81
|
export function isBuildOutput(normalized) {
|
|
11
|
-
return normalized
|
|
82
|
+
return hasSegment(normalized, "dist") || hasSegment(normalized, "build");
|
|
12
83
|
}
|
|
13
84
|
export function isVendorPath(normalized) {
|
|
14
85
|
return normalized.includes("vendor") || normalized.includes("third_party");
|
|
15
86
|
}
|
|
16
87
|
export function isBinaryArtifact(normalized) {
|
|
17
|
-
return (normalized
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
88
|
+
return endsWithAny(normalized, BINARY_EXTENSIONS);
|
|
89
|
+
}
|
|
90
|
+
export function isLogPath(normalized) {
|
|
91
|
+
return normalized.endsWith(".log") || includesAny(normalized, ["stdout.log", "stderr.log"]);
|
|
92
|
+
}
|
|
93
|
+
export function isLicensePath(normalized) {
|
|
94
|
+
const base = baseName(normalized);
|
|
95
|
+
return base === "license" || base.startsWith("license.");
|
|
96
|
+
}
|
|
97
|
+
export function isLockfilePath(normalized) {
|
|
98
|
+
return endsWithAny(normalized, LOCKFILE_NAMES);
|
|
23
99
|
}
|
|
24
100
|
export function isDocPath(normalized) {
|
|
25
|
-
return normalized.endsWith(".md") || normalized
|
|
101
|
+
return normalized.endsWith(".md") || hasSegment(normalized, "docs");
|
|
26
102
|
}
|
|
27
103
|
export function isTestPath(normalized) {
|
|
28
|
-
return (normalized
|
|
29
|
-
normalized.includes("spec") ||
|
|
30
|
-
normalized.includes("__tests__"));
|
|
104
|
+
return includesAny(normalized, TEST_KEYWORDS);
|
|
31
105
|
}
|
|
32
106
|
export function isInterfacePath(normalized) {
|
|
33
|
-
return (normalized
|
|
34
|
-
normalized.includes("controller") ||
|
|
35
|
-
normalized.includes("handler") ||
|
|
36
|
-
normalized.includes("api/"));
|
|
107
|
+
return includesAny(normalized, INTERFACE_KEYWORDS) || hasSegment(normalized, "api");
|
|
37
108
|
}
|
|
38
109
|
export function isDataLayerPath(normalized) {
|
|
39
|
-
return (normalized
|
|
40
|
-
normalized.includes("schema") ||
|
|
41
|
-
normalized.includes("migration") ||
|
|
42
|
-
normalized.includes("seed") ||
|
|
43
|
-
normalized.includes("db/"));
|
|
110
|
+
return includesAny(normalized, DATA_LAYER_KEYWORDS) || hasSegment(normalized, "db");
|
|
44
111
|
}
|
|
45
112
|
export function isSecuritySensitivePath(normalized) {
|
|
46
|
-
return (normalized
|
|
47
|
-
normalized.includes("secret") ||
|
|
48
|
-
normalized.includes("token") ||
|
|
49
|
-
normalized.includes("permission") ||
|
|
50
|
-
normalized.includes("session"));
|
|
113
|
+
return includesAny(normalized, SECURITY_KEYWORDS);
|
|
51
114
|
}
|
|
52
115
|
export function isConcurrencyPath(normalized) {
|
|
53
|
-
return (normalized
|
|
54
|
-
normalized.includes("worker") ||
|
|
55
|
-
normalized.includes("job") ||
|
|
56
|
-
normalized.includes("cache") ||
|
|
57
|
-
normalized.includes("retry") ||
|
|
58
|
-
normalized.includes("lock"));
|
|
116
|
+
return includesAny(normalized, CONCURRENCY_KEYWORDS);
|
|
59
117
|
}
|
|
60
118
|
export function isScriptPath(normalized) {
|
|
61
|
-
return (normalized
|
|
62
|
-
normalized
|
|
63
|
-
normalized
|
|
119
|
+
return (includesAny(normalized, SCRIPT_KEYWORDS) ||
|
|
120
|
+
hasSegment(normalized, "scripts") ||
|
|
121
|
+
hasSegment(normalized, "bin"));
|
|
64
122
|
}
|
|
65
123
|
export function isDeploymentConfigPath(normalized) {
|
|
66
|
-
return (normalized
|
|
67
|
-
normalized.includes("terraform") ||
|
|
68
|
-
normalized.includes("deploy") ||
|
|
69
|
-
normalized.includes("workflow") ||
|
|
70
|
-
normalized.includes("k8s") ||
|
|
71
|
-
normalized.endsWith(".yml") ||
|
|
72
|
-
normalized.endsWith(".yaml"));
|
|
124
|
+
return includesAny(normalized, DEPLOYMENT_KEYWORDS) || endsWithAny(normalized, [".yml", ".yaml"]);
|
|
73
125
|
}
|
|
74
126
|
export function isGeneratedPath(normalized) {
|
|
75
127
|
return normalized.includes("vendor") || normalized.includes("generated");
|
|
76
128
|
}
|
|
77
129
|
export function isSurfacePath(normalized) {
|
|
78
|
-
return (normalized
|
|
79
|
-
normalized
|
|
80
|
-
normalized
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
130
|
+
return (hasSegment(normalized, "api") ||
|
|
131
|
+
includesAny(normalized, SURFACE_KEYWORDS) ||
|
|
132
|
+
hasSegment(normalized, "cli"));
|
|
133
|
+
}
|
|
134
|
+
export function isBackgroundSurfacePath(normalized) {
|
|
135
|
+
return includesAny(normalized, ["worker", "job"]);
|
|
136
|
+
}
|
|
137
|
+
export function isNetworkSurfacePath(normalized) {
|
|
138
|
+
return hasSegment(normalized, "api") || includesAny(normalized, ["route", "controller"]);
|
|
139
|
+
}
|
|
140
|
+
export function isBillingPath(normalized) {
|
|
141
|
+
return includesAny(normalized, BILLING_KEYWORDS);
|
|
142
|
+
}
|
|
143
|
+
export function isIdentityPath(normalized) {
|
|
144
|
+
return isSecuritySensitivePath(normalized) || includesAny(normalized, IDENTITY_KEYWORDS);
|
|
145
|
+
}
|
|
146
|
+
export function isAsyncTaskPath(normalized) {
|
|
147
|
+
return isConcurrencyPath(normalized) || includesAny(normalized, ASYNC_TASK_KEYWORDS);
|
|
85
148
|
}
|
package/dist/extractors/risk.js
CHANGED
|
@@ -19,6 +19,9 @@ export function buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerR
|
|
|
19
19
|
signals.push("writes_or_persistence");
|
|
20
20
|
if (unit.required_lenses.includes("config_deployment"))
|
|
21
21
|
signals.push("operational_surface");
|
|
22
|
+
if (unit.files.some((path) => /(write|save|persist|lock|cache|retry|open|sync|refresh)/i.test(path))) {
|
|
23
|
+
signals.push("path_level_stateful_behavior");
|
|
24
|
+
}
|
|
22
25
|
const flowHits = unit.files.reduce((sum, path) => sum + (flowMap.get(path) ?? 0), 0);
|
|
23
26
|
if (flowHits > 0) {
|
|
24
27
|
signals.push("critical_flow_member");
|
|
@@ -29,7 +32,10 @@ export function buildRiskRegister(unitManifest, criticalFlows, externalAnalyzerR
|
|
|
29
32
|
}
|
|
30
33
|
return {
|
|
31
34
|
unit_id: unit.unit_id,
|
|
32
|
-
risk_score: (unit.risk_score ?? 0) +
|
|
35
|
+
risk_score: (unit.risk_score ?? 0) +
|
|
36
|
+
flowHits +
|
|
37
|
+
externalHits +
|
|
38
|
+
(signals.includes("path_level_stateful_behavior") ? 1 : 0),
|
|
33
39
|
signals,
|
|
34
40
|
notes: [
|
|
35
41
|
"Initial heuristic risk scoring.",
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { RepoManifest } from "../types.js";
|
|
2
2
|
import type { FileDisposition } from "../types/disposition.js";
|
|
3
3
|
import type { SurfaceManifest } from "../types/surfaces.js";
|
|
4
|
+
/**
|
|
5
|
+
* Detects likely execution surfaces from file paths using the shared extractor
|
|
6
|
+
* heuristics, primarily to seed later audit planning.
|
|
7
|
+
*/
|
|
4
8
|
export declare function buildSurfaceManifest(repoManifest: RepoManifest, disposition?: FileDisposition): SurfaceManifest;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { isAuditExcludedStatus } from "./disposition.js";
|
|
2
|
-
import { isSurfacePath } from "./pathPatterns.js";
|
|
2
|
+
import { EXTRACTOR_HEURISTIC_NOTE, isBackgroundSurfacePath, isNetworkSurfacePath, isSurfacePath, normalizeExtractorPath, } from "./pathPatterns.js";
|
|
3
3
|
function methodsForPath(path) {
|
|
4
|
-
const normalized = path
|
|
5
|
-
if (
|
|
4
|
+
const normalized = normalizeExtractorPath(path);
|
|
5
|
+
if (isNetworkSurfacePath(normalized)) {
|
|
6
6
|
return ["GET", "POST"];
|
|
7
7
|
}
|
|
8
8
|
return undefined;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Detects likely execution surfaces from file paths using the shared extractor
|
|
12
|
+
* heuristics, primarily to seed later audit planning.
|
|
13
|
+
*/
|
|
10
14
|
export function buildSurfaceManifest(repoManifest, disposition) {
|
|
11
15
|
const surfaces = [];
|
|
12
16
|
const dispositionMap = new Map(disposition?.files.map((item) => [item.path, item.status]) ?? []);
|
|
@@ -15,19 +19,15 @@ export function buildSurfaceManifest(repoManifest, disposition) {
|
|
|
15
19
|
if (status && isAuditExcludedStatus(status)) {
|
|
16
20
|
continue;
|
|
17
21
|
}
|
|
18
|
-
const normalized = file.path
|
|
22
|
+
const normalized = normalizeExtractorPath(file.path);
|
|
19
23
|
if (isSurfacePath(normalized)) {
|
|
20
24
|
surfaces.push({
|
|
21
25
|
id: `surface:${file.path}`,
|
|
22
|
-
kind: normalized
|
|
23
|
-
? "background"
|
|
24
|
-
: "interface",
|
|
26
|
+
kind: isBackgroundSurfacePath(normalized) ? "background" : "interface",
|
|
25
27
|
entrypoint: file.path,
|
|
26
|
-
exposure: normalized
|
|
27
|
-
? "network"
|
|
28
|
-
: "local",
|
|
28
|
+
exposure: isNetworkSurfacePath(normalized) ? "network" : "local",
|
|
29
29
|
methods: methodsForPath(file.path),
|
|
30
|
-
notes: [
|
|
30
|
+
notes: [EXTRACTOR_HEURISTIC_NOTE],
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import "./cli.js";
|
|
1
|
+
import { runCli } from "./cli.js";
|
|
2
|
+
await runCli(process.argv);
|