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.
Files changed (125) hide show
  1. package/README.md +29 -7
  2. package/audit-code-wrapper-lib.mjs +1605 -330
  3. package/dist/adapters/eslint.js +9 -5
  4. package/dist/cli.d.ts +42 -1
  5. package/dist/cli.js +192 -80
  6. package/dist/coverage.d.ts +2 -2
  7. package/dist/coverage.js +5 -5
  8. package/dist/extractors/bucketing.d.ts +4 -0
  9. package/dist/extractors/bucketing.js +6 -2
  10. package/dist/extractors/disposition.d.ts +4 -0
  11. package/dist/extractors/disposition.js +15 -2
  12. package/dist/extractors/fileInventory.js +24 -28
  13. package/dist/extractors/flows.d.ts +5 -0
  14. package/dist/extractors/flows.js +25 -39
  15. package/dist/extractors/pathPatterns.d.ts +13 -3
  16. package/dist/extractors/pathPatterns.js +116 -53
  17. package/dist/extractors/risk.js +7 -1
  18. package/dist/extractors/surfaces.d.ts +4 -0
  19. package/dist/extractors/surfaces.js +11 -11
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +2 -1
  22. package/dist/io/artifacts.d.ts +59 -44
  23. package/dist/io/artifacts.js +80 -120
  24. package/dist/io/json.d.ts +2 -0
  25. package/dist/io/json.js +65 -19
  26. package/dist/io/runArtifacts.d.ts +2 -1
  27. package/dist/io/runArtifacts.js +44 -7
  28. package/dist/mcp/server.d.ts +1 -0
  29. package/dist/mcp/server.js +579 -0
  30. package/dist/orchestrator/advance.js +84 -56
  31. package/dist/orchestrator/dependencyMap.js +9 -13
  32. package/dist/orchestrator/executors.js +7 -2
  33. package/dist/orchestrator/flowCoverage.js +11 -5
  34. package/dist/orchestrator/flowPlanning.d.ts +7 -2
  35. package/dist/orchestrator/flowPlanning.js +46 -21
  36. package/dist/orchestrator/flowRequeue.js +29 -9
  37. package/dist/orchestrator/internalExecutors.d.ts +2 -1
  38. package/dist/orchestrator/internalExecutors.js +130 -69
  39. package/dist/orchestrator/planning.js +25 -3
  40. package/dist/orchestrator/requeue.js +20 -5
  41. package/dist/orchestrator/resultIngestion.js +5 -6
  42. package/dist/orchestrator/runtimeValidation.d.ts +7 -2
  43. package/dist/orchestrator/runtimeValidation.js +61 -49
  44. package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
  45. package/dist/orchestrator/state.js +18 -13
  46. package/dist/orchestrator/taskBuilder.d.ts +4 -2
  47. package/dist/orchestrator/taskBuilder.js +153 -52
  48. package/dist/orchestrator/trivialAudit.js +8 -5
  49. package/dist/orchestrator/unitBuilder.d.ts +3 -1
  50. package/dist/orchestrator/unitBuilder.js +24 -16
  51. package/dist/prompts/renderWorkerPrompt.d.ts +1 -1
  52. package/dist/prompts/renderWorkerPrompt.js +19 -10
  53. package/dist/providers/claudeCodeProvider.d.ts +4 -1
  54. package/dist/providers/claudeCodeProvider.js +8 -5
  55. package/dist/providers/localSubprocessProvider.d.ts +4 -0
  56. package/dist/providers/localSubprocessProvider.js +7 -2
  57. package/dist/providers/spawnLoggedCommand.d.ts +9 -1
  58. package/dist/providers/spawnLoggedCommand.js +77 -29
  59. package/dist/reporting/mergeFindings.js +0 -11
  60. package/dist/reporting/synthesis.d.ts +26 -21
  61. package/dist/reporting/synthesis.js +97 -61
  62. package/dist/reporting/workBlocks.d.ts +12 -3
  63. package/dist/reporting/workBlocks.js +124 -70
  64. package/dist/supervisor/operatorHandoff.js +48 -18
  65. package/dist/supervisor/runLedger.d.ts +1 -1
  66. package/dist/supervisor/runLedger.js +112 -5
  67. package/dist/supervisor/sessionConfig.js +10 -10
  68. package/dist/types/externalAnalyzer.d.ts +3 -0
  69. package/dist/types/flowCoverage.d.ts +5 -1
  70. package/dist/types/flowCoverage.js +5 -1
  71. package/dist/types/flows.d.ts +6 -0
  72. package/dist/types/flows.js +1 -1
  73. package/dist/types/runLedger.d.ts +5 -1
  74. package/dist/types/runLedger.js +6 -1
  75. package/dist/types/runtimeValidation.d.ts +13 -3
  76. package/dist/types/runtimeValidation.js +16 -1
  77. package/dist/types/sessionConfig.d.ts +15 -2
  78. package/dist/types/sessionConfig.js +15 -1
  79. package/dist/types/surfaces.d.ts +4 -1
  80. package/dist/types/surfaces.js +1 -1
  81. package/dist/types/workerSession.d.ts +9 -0
  82. package/dist/types/workerSession.js +5 -1
  83. package/dist/types.d.ts +4 -7
  84. package/dist/validation/artifacts.d.ts +1 -1
  85. package/dist/validation/artifacts.js +33 -20
  86. package/dist/validation/auditResults.d.ts +2 -2
  87. package/dist/validation/auditResults.js +71 -114
  88. package/dist/validation/basic.d.ts +9 -1
  89. package/dist/validation/basic.js +40 -3
  90. package/dist/validation/sessionConfig.d.ts +4 -2
  91. package/dist/validation/sessionConfig.js +62 -15
  92. package/docs/agent-integrations.md +67 -38
  93. package/docs/artifacts.md +16 -56
  94. package/docs/bootstrap-install.md +60 -30
  95. package/docs/contract.md +22 -205
  96. package/docs/next-steps.md +76 -44
  97. package/docs/packaging.md +27 -3
  98. package/docs/product-direction.md +22 -0
  99. package/docs/production-launch-bar.md +4 -2
  100. package/docs/production-readiness.md +9 -5
  101. package/docs/releasing.md +98 -0
  102. package/docs/remediation-baseline.md +75 -0
  103. package/docs/run-flow.md +23 -11
  104. package/docs/session-config.md +50 -5
  105. package/docs/supervisor.md +7 -0
  106. package/docs/workflow-refactor-brief.md +177 -0
  107. package/package.json +4 -1
  108. package/schemas/audit_result.schema.json +8 -7
  109. package/schemas/audit_task.schema.json +3 -1
  110. package/schemas/coverage_matrix.schema.json +3 -3
  111. package/schemas/critical_flows.schema.json +6 -2
  112. package/schemas/file_disposition.schema.json +2 -2
  113. package/schemas/finding.schema.json +9 -4
  114. package/schemas/flow_coverage.schema.json +2 -2
  115. package/schemas/repo_manifest.schema.json +4 -4
  116. package/schemas/risk_register.schema.json +2 -2
  117. package/schemas/runtime_validation_report.schema.json +3 -3
  118. package/schemas/runtime_validation_tasks.schema.json +8 -2
  119. package/schemas/surface_manifest.schema.json +6 -3
  120. package/schemas/unit_manifest.schema.json +3 -2
  121. package/skills/audit-code/SKILL.md +16 -2
  122. package/skills/audit-code/audit-code.prompt.md +5 -8
  123. package/schemas/merged_findings.schema.json +0 -19
  124. package/schemas/root_cause_clusters.schema.json +0 -28
  125. 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.toLowerCase();
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 ext = path.split(".").pop()?.toLowerCase();
3
- switch (ext) {
4
- case "ts":
5
- case "tsx":
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;
@@ -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.toLowerCase();
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.toLowerCase();
19
+ const normalized = normalizeExtractorPath(entry);
22
20
  const linked = new Set([entry]);
23
21
  for (const path of availablePaths) {
24
- const lower = path.toLowerCase();
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.includes("billing") ||
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
- notes: [
98
- "Heuristic critical-flow inference from detected surfaces and related paths.",
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 lower = path.toLowerCase();
104
- if (isDataLayerPath(lower) || lower.includes("seed")) {
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
- notes: ["Heuristic data-evolution flow."],
92
+ confidence: "high",
93
+ notes: [EXTRACTOR_HEURISTIC_NOTE],
112
94
  });
113
95
  }
114
96
  }
115
- return { flows: dedupeFlows(flows) };
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
- * Centralised path-pattern predicates shared across disposition, bucketing,
3
- * surfaces, and flows extractors. Every function operates on the
4
- * already-lower-cased form of the path.
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
- * Centralised path-pattern predicates shared across disposition, bucketing,
3
- * surfaces, and flows extractors. Every function operates on the
4
- * already-lower-cased form of the path.
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
- const segments = normalized.split(/[/\\]/);
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.startsWith("dist/") || normalized.startsWith("build/");
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.endsWith(".png") ||
18
- normalized.endsWith(".jpg") ||
19
- normalized.endsWith(".jpeg") ||
20
- normalized.endsWith(".gif") ||
21
- normalized.endsWith(".pdf") ||
22
- normalized.endsWith(".zip"));
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.startsWith("docs/");
101
+ return normalized.endsWith(".md") || hasSegment(normalized, "docs");
26
102
  }
27
103
  export function isTestPath(normalized) {
28
- return (normalized.includes("test") ||
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.includes("route") ||
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.includes("model") ||
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.includes("auth") ||
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.includes("queue") ||
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.includes("script") ||
62
- normalized.startsWith("scripts/") ||
63
- normalized.startsWith("bin/"));
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.includes("docker") ||
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.includes("api/") ||
79
- normalized.includes("route") ||
80
- normalized.includes("controller") ||
81
- normalized.includes("worker") ||
82
- normalized.includes("job") ||
83
- normalized.includes("command") ||
84
- normalized.includes("cli"));
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
  }
@@ -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) + flowHits + externalHits,
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.toLowerCase();
5
- if (normalized.includes("api") || normalized.includes("route")) {
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.toLowerCase();
22
+ const normalized = normalizeExtractorPath(file.path);
19
23
  if (isSurfacePath(normalized)) {
20
24
  surfaces.push({
21
25
  id: `surface:${file.path}`,
22
- kind: normalized.includes("worker") || normalized.includes("job")
23
- ? "background"
24
- : "interface",
26
+ kind: isBackgroundSurfacePath(normalized) ? "background" : "interface",
25
27
  entrypoint: file.path,
26
- exposure: normalized.includes("api") || normalized.includes("route")
27
- ? "network"
28
- : "local",
28
+ exposure: isNetworkSurfacePath(normalized) ? "network" : "local",
29
29
  methods: methodsForPath(file.path),
30
- notes: ["Heuristic surface detection."],
30
+ notes: [EXTRACTOR_HEURISTIC_NOTE],
31
31
  });
32
32
  }
33
33
  }
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- import "./cli.js";
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);