@hookwarden/engine 0.0.1 → 0.1.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.
Files changed (149) hide show
  1. package/dist/adapters/django.d.ts +4 -0
  2. package/dist/adapters/django.d.ts.map +1 -0
  3. package/dist/adapters/django.js +148 -0
  4. package/dist/adapters/django.js.map +1 -0
  5. package/dist/adapters/fastapi.d.ts +4 -0
  6. package/dist/adapters/fastapi.d.ts.map +1 -0
  7. package/dist/adapters/fastapi.js +118 -0
  8. package/dist/adapters/fastapi.js.map +1 -0
  9. package/dist/adapters/index.d.ts +9 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +10 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/nextjs.d.ts +4 -0
  14. package/dist/adapters/nextjs.d.ts.map +1 -0
  15. package/dist/adapters/nextjs.js +82 -0
  16. package/dist/adapters/nextjs.js.map +1 -0
  17. package/dist/evaluate.d.ts +6 -0
  18. package/dist/evaluate.d.ts.map +1 -0
  19. package/dist/evaluate.js +108 -0
  20. package/dist/evaluate.js.map +1 -0
  21. package/dist/evaluator/index.d.ts +4 -0
  22. package/dist/evaluator/index.d.ts.map +1 -0
  23. package/dist/evaluator/index.js +4 -0
  24. package/dist/evaluator/index.js.map +1 -0
  25. package/dist/evaluator/matchers.d.ts +13 -0
  26. package/dist/evaluator/matchers.d.ts.map +1 -0
  27. package/dist/evaluator/matchers.js +124 -0
  28. package/dist/evaluator/matchers.js.map +1 -0
  29. package/dist/evaluator/parse-error.d.ts +4 -0
  30. package/dist/evaluator/parse-error.d.ts.map +1 -0
  31. package/dist/evaluator/parse-error.js +46 -0
  32. package/dist/evaluator/parse-error.js.map +1 -0
  33. package/dist/evaluator/path-severity-overrides.d.ts +4 -0
  34. package/dist/evaluator/path-severity-overrides.d.ts.map +1 -0
  35. package/dist/evaluator/path-severity-overrides.js +29 -0
  36. package/dist/evaluator/path-severity-overrides.js.map +1 -0
  37. package/dist/evaluator/visit.d.ts +16 -0
  38. package/dist/evaluator/visit.d.ts.map +1 -0
  39. package/dist/evaluator/visit.js +96 -0
  40. package/dist/evaluator/visit.js.map +1 -0
  41. package/dist/findings/fingerprint.d.ts +22 -0
  42. package/dist/findings/fingerprint.d.ts.map +1 -0
  43. package/dist/findings/fingerprint.js +39 -0
  44. package/dist/findings/fingerprint.js.map +1 -0
  45. package/dist/findings/index.d.ts +3 -0
  46. package/dist/findings/index.d.ts.map +1 -0
  47. package/dist/findings/index.js +4 -0
  48. package/dist/findings/index.js.map +1 -0
  49. package/dist/findings/webcrypto.d.ts +2 -0
  50. package/dist/findings/webcrypto.d.ts.map +1 -0
  51. package/dist/findings/webcrypto.js +15 -0
  52. package/dist/findings/webcrypto.js.map +1 -0
  53. package/dist/index.d.ts +8 -8
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +9 -4
  56. package/dist/index.js.map +1 -1
  57. package/dist/model/build.d.ts +12 -0
  58. package/dist/model/build.d.ts.map +1 -0
  59. package/dist/model/build.js +154 -0
  60. package/dist/model/build.js.map +1 -0
  61. package/dist/model/catalog.d.ts +17 -0
  62. package/dist/model/catalog.d.ts.map +1 -0
  63. package/dist/model/catalog.js +303 -0
  64. package/dist/model/catalog.js.map +1 -0
  65. package/dist/model/evidence.d.ts +18 -0
  66. package/dist/model/evidence.d.ts.map +1 -0
  67. package/dist/model/evidence.js +114 -0
  68. package/dist/model/evidence.js.map +1 -0
  69. package/dist/model/index.d.ts +6 -0
  70. package/dist/model/index.d.ts.map +1 -0
  71. package/dist/model/index.js +7 -0
  72. package/dist/model/index.js.map +1 -0
  73. package/dist/model/middleware.d.ts +10 -0
  74. package/dist/model/middleware.d.ts.map +1 -0
  75. package/dist/model/middleware.js +140 -0
  76. package/dist/model/middleware.js.map +1 -0
  77. package/dist/model/reachability.d.ts +11 -0
  78. package/dist/model/reachability.d.ts.map +1 -0
  79. package/dist/model/reachability.js +260 -0
  80. package/dist/model/reachability.js.map +1 -0
  81. package/dist/parsers/babel.d.ts +11 -0
  82. package/dist/parsers/babel.d.ts.map +1 -0
  83. package/dist/parsers/babel.js +121 -0
  84. package/dist/parsers/babel.js.map +1 -0
  85. package/dist/parsers/index.d.ts +6 -0
  86. package/dist/parsers/index.d.ts.map +1 -0
  87. package/dist/parsers/index.js +7 -0
  88. package/dist/parsers/index.js.map +1 -0
  89. package/dist/parsers/literals.d.ts +4 -0
  90. package/dist/parsers/literals.d.ts.map +1 -0
  91. package/dist/parsers/literals.js +37 -0
  92. package/dist/parsers/literals.js.map +1 -0
  93. package/dist/parsers/python-literals.d.ts +5 -0
  94. package/dist/parsers/python-literals.d.ts.map +1 -0
  95. package/dist/parsers/python-literals.js +62 -0
  96. package/dist/parsers/python-literals.js.map +1 -0
  97. package/dist/parsers/python-loader.d.ts +9 -0
  98. package/dist/parsers/python-loader.d.ts.map +1 -0
  99. package/dist/parsers/python-loader.js +16 -0
  100. package/dist/parsers/python-loader.js.map +1 -0
  101. package/dist/parsers/python.d.ts +8 -0
  102. package/dist/parsers/python.d.ts.map +1 -0
  103. package/dist/parsers/python.js +125 -0
  104. package/dist/parsers/python.js.map +1 -0
  105. package/dist/parsers/walk.d.ts +15 -0
  106. package/dist/parsers/walk.d.ts.map +1 -0
  107. package/dist/parsers/walk.js +66 -0
  108. package/dist/parsers/walk.js.map +1 -0
  109. package/dist/redaction/index.d.ts +3 -0
  110. package/dist/redaction/index.d.ts.map +1 -0
  111. package/dist/redaction/index.js +2 -0
  112. package/dist/redaction/index.js.map +1 -0
  113. package/dist/redaction/structural.d.ts +14 -0
  114. package/dist/redaction/structural.d.ts.map +1 -0
  115. package/dist/redaction/structural.js +37 -0
  116. package/dist/redaction/structural.js.map +1 -0
  117. package/dist/types/config.d.ts +7 -0
  118. package/dist/types/config.d.ts.map +1 -0
  119. package/dist/types/config.js +6 -0
  120. package/dist/types/config.js.map +1 -0
  121. package/dist/types/finding.d.ts +32 -0
  122. package/dist/types/finding.d.ts.map +1 -0
  123. package/dist/types/finding.js +12 -0
  124. package/dist/types/finding.js.map +1 -0
  125. package/dist/types/handler.d.ts +39 -0
  126. package/dist/types/handler.d.ts.map +1 -0
  127. package/dist/types/handler.js +7 -0
  128. package/dist/types/handler.js.map +1 -0
  129. package/dist/types/index.d.ts +7 -0
  130. package/dist/types/index.d.ts.map +1 -0
  131. package/dist/types/index.js +4 -0
  132. package/dist/types/index.js.map +1 -0
  133. package/dist/types/project-model.d.ts +42 -0
  134. package/dist/types/project-model.d.ts.map +1 -0
  135. package/dist/types/project-model.js +5 -0
  136. package/dist/types/project-model.js.map +1 -0
  137. package/dist/types/rule-set.d.ts +42 -0
  138. package/dist/types/rule-set.d.ts.map +1 -0
  139. package/dist/types/rule-set.js +6 -0
  140. package/dist/types/rule-set.js.map +1 -0
  141. package/dist/types/scan-result.d.ts +19 -0
  142. package/dist/types/scan-result.d.ts.map +1 -0
  143. package/dist/types/scan-result.js +8 -0
  144. package/dist/types/scan-result.js.map +1 -0
  145. package/dist/version.d.ts +2 -0
  146. package/dist/version.d.ts.map +1 -0
  147. package/dist/version.js +5 -0
  148. package/dist/version.js.map +1 -0
  149. package/package.json +12 -1
@@ -0,0 +1,154 @@
1
+ // buildProjectModel: orchestrates parsers' output into a ProjectModel that the evaluator (Plan 08)
2
+ // consumes. Async (D-02 — handler ids are WebCrypto sha256). Pure (D-01 — no fs/http).
3
+ //
4
+ // Wires together:
5
+ // - Plan 06a's detectCatalogHandlers + computeEvidence (6 of 7 D-32 signals)
6
+ // - Plan 07's bespoke adapters (Next.js / Django / FastAPI) via the bespokeAdapters hook
7
+ // - This plan's computeReachableSymbols (D-34 cross-file traversal) + extractMiddlewareChain (D-36)
8
+ // - The sdk_verify_call evidence overlay — completes D-32's 7th signal.
9
+ import { computeHandlerId } from "../findings/fingerprint.js";
10
+ import { extractBabelLiterals } from "../parsers/literals.js";
11
+ import { extractPythonLiterals } from "../parsers/python-literals.js";
12
+ import { redactSnippet } from "../redaction/structural.js";
13
+ import { detectCatalogHandlers } from "./catalog.js";
14
+ import { computeEvidence } from "./evidence.js";
15
+ import { extractMiddlewareChain } from "./middleware.js";
16
+ import { computeReachableSymbols } from "./reachability.js";
17
+ export async function buildProjectModel(input) {
18
+ // 1. Aggregate every file's imports → import_graph (engine-internal cross-file index).
19
+ const importGraph = [];
20
+ for (const file of input.parsedFiles) {
21
+ for (const edge of file.imports)
22
+ importGraph.push(edge);
23
+ }
24
+ // 2. Detect candidate handlers per file (catalog + bespoke). Skip parse-error files (D-27).
25
+ const candidates = [];
26
+ const adapters = input.bespokeAdapters ?? [];
27
+ for (const file of input.parsedFiles) {
28
+ if (file.parse_error !== null)
29
+ continue;
30
+ for (const cand of detectCatalogHandlers(file))
31
+ candidates.push({ cand, file });
32
+ for (const adapter of adapters) {
33
+ for (const cand of adapter(file, input.parsedFiles))
34
+ candidates.push({ cand, file });
35
+ }
36
+ }
37
+ // 3. For each candidate, compute id + evidence (with sdk_verify_call overlay) + reachability +
38
+ // middleware_chain + redacted snippet.
39
+ const handlers = [];
40
+ for (const { cand, file } of candidates) {
41
+ handlers.push(await assembleHandler(cand, file, input));
42
+ }
43
+ // 4. Aggregate middleware registrations at the project level (engine-internal index — Phase 8
44
+ // rule authors who need cross-handler middleware ordering can query this).
45
+ const middlewareRegistrations = [];
46
+ return {
47
+ parsed_files: input.parsedFiles,
48
+ handlers,
49
+ middleware_registrations: middlewareRegistrations,
50
+ import_graph: importGraph,
51
+ };
52
+ }
53
+ async function assembleHandler(cand, file, input) {
54
+ const id = await computeHandlerId({
55
+ file_path: cand.file_path,
56
+ route_pattern: cand.route_pattern,
57
+ http_methods: cand.http_methods,
58
+ handler_function_name: cand.handler_function_name,
59
+ });
60
+ const baseEvidence = computeEvidence({
61
+ handler: cand,
62
+ parsedFile: file,
63
+ providerCatalog: input.ruleSet.providers,
64
+ imports: file.imports,
65
+ });
66
+ const reachableSymbols = computeReachableSymbols({
67
+ handler_body_node: cand.handler_body_node,
68
+ handler_file: file,
69
+ all_files: input.parsedFiles,
70
+ imports: file.imports,
71
+ maxDepth: input.config.reachability_max_depth,
72
+ });
73
+ const middlewareChain = extractMiddlewareChain({
74
+ handler: cand,
75
+ parsedFile: file,
76
+ imports: file.imports,
77
+ });
78
+ // sdk_verify_call evidence overlay (issue #7 fix) — completes D-32's 7th signal.
79
+ const sdkVerifyEvidence = collectSdkVerifyCallEvidence(cand, reachableSymbols, input.ruleSet);
80
+ const evidence = [...baseEvidence.evidence, ...sdkVerifyEvidence];
81
+ // Recompute provider attribution since sdk_verify_call evidence may shift the count.
82
+ const provider = recomputeProvider(evidence, baseEvidence.provider);
83
+ const redactedSnippet = renderHandlerSnippet(file, cand);
84
+ return {
85
+ id,
86
+ framework: cand.framework,
87
+ framework_version: cand.framework_version,
88
+ route_pattern: cand.route_pattern,
89
+ http_methods: cand.http_methods,
90
+ file_path: cand.file_path,
91
+ location: cand.location,
92
+ handler_function_name: cand.handler_function_name,
93
+ provider,
94
+ verification_state: "manual-review", // PITFALLS #3 default; Plan 08 evaluator promotes
95
+ evidence,
96
+ middleware_chain: middlewareChain,
97
+ reachable_symbols: reachableSymbols,
98
+ findings_ref: [], // back-populated by Plan 08 evaluator
99
+ redacted_snippet: redactedSnippet,
100
+ };
101
+ }
102
+ function collectSdkVerifyCallEvidence(cand, reachableSymbols, ruleSet) {
103
+ const out = [];
104
+ for (const [providerName, entry] of Object.entries(ruleSet.providers)) {
105
+ for (const verifyCall of entry.sdk_verify_calls) {
106
+ const matched = reachableSymbols.some((s) => s.qualified_name === verifyCall || s.qualified_name.endsWith(`.${verifyCall}`));
107
+ if (matched) {
108
+ out.push({
109
+ kind: "sdk_verify_call",
110
+ provider: providerName,
111
+ location: cand.location,
112
+ detail: verifyCall,
113
+ });
114
+ }
115
+ }
116
+ }
117
+ return out;
118
+ }
119
+ function recomputeProvider(evidence, fallback) {
120
+ const counts = new Map();
121
+ for (const e of evidence) {
122
+ if (e.provider === "unknown")
123
+ continue;
124
+ counts.set(e.provider, (counts.get(e.provider) ?? 0) + 1);
125
+ }
126
+ let topProvider = "unknown";
127
+ let topCount = 0;
128
+ let tied = false;
129
+ for (const [p, c] of counts) {
130
+ if (c > topCount) {
131
+ topProvider = p;
132
+ topCount = c;
133
+ tied = false;
134
+ }
135
+ else if (c === topCount && c > 0) {
136
+ tied = true;
137
+ }
138
+ }
139
+ if (topProvider === "unknown")
140
+ return fallback;
141
+ return tied ? "multiple" : topProvider;
142
+ }
143
+ function renderHandlerSnippet(file, cand) {
144
+ const slice = file.source_text.slice(cand.handler_source_start, cand.handler_source_end);
145
+ const offset = cand.handler_source_start;
146
+ const allLiterals = file.dialect === "babel"
147
+ ? extractBabelLiterals(file.raw_ast)
148
+ : extractPythonLiterals(file.raw_ast);
149
+ const sliceLiterals = allLiterals
150
+ .filter((l) => l.start >= cand.handler_source_start && l.end <= cand.handler_source_end)
151
+ .map((l) => ({ ...l, start: l.start - offset, end: l.end - offset }));
152
+ return redactSnippet({ source_text: slice, literals: sliceLiterals });
153
+ }
154
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/model/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SourceLocation } from "../types/finding.js";
2
+ import type { Framework } from "../types/handler.js";
3
+ import type { ParsedFile } from "../types/project-model.js";
4
+ export interface CandidateHandler {
5
+ readonly framework: Framework;
6
+ readonly framework_version: string | null;
7
+ readonly route_pattern: string;
8
+ readonly http_methods: ReadonlyArray<string>;
9
+ readonly file_path: string;
10
+ readonly location: SourceLocation;
11
+ readonly handler_function_name: string | null;
12
+ readonly handler_body_node: unknown;
13
+ readonly handler_source_start: number;
14
+ readonly handler_source_end: number;
15
+ }
16
+ export declare function detectCatalogHandlers(parsedFile: ParsedFile): ReadonlyArray<CandidateHandler>;
17
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/model/catalog.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9C,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAEpC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AA6BD,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAK7F"}
@@ -0,0 +1,303 @@
1
+ // Catalog-driven framework detection (D-31). Covers the four frameworks the catalog data
2
+ // can express uniformly. Next.js / Django / FastAPI need bespoke adapters in Plan 07.
3
+ //
4
+ // This module produces "candidate handlers" — partial WebhookHandler shapes — that Plan 06b's
5
+ // build.ts enriches with cross-file data (reachable_symbols, middleware_chain) and evidence.
6
+ import { walkBabelAst } from "../parsers/walk.js";
7
+ const BODY_METHODS = new Set(["post", "put", "patch", "delete", "all"]);
8
+ const ALL_METHODS = new Set([
9
+ "get",
10
+ "post",
11
+ "put",
12
+ "patch",
13
+ "delete",
14
+ "head",
15
+ "options",
16
+ "all",
17
+ ]);
18
+ export function detectCatalogHandlers(parsedFile) {
19
+ if (parsedFile.parse_error !== null || parsedFile.raw_ast === null)
20
+ return [];
21
+ if (parsedFile.dialect === "babel")
22
+ return detectJsTsCatalog(parsedFile);
23
+ if (parsedFile.dialect === "tree-sitter-python")
24
+ return detectPythonCatalog(parsedFile);
25
+ return [];
26
+ }
27
+ // ---- JS/TS: Express, Hono, Fastify ----
28
+ function detectJsTsCatalog(parsedFile) {
29
+ const ast = parsedFile.raw_ast;
30
+ const out = [];
31
+ const imports = parsedFile.imports;
32
+ const hasHono = imports.some((i) => i.to_module === "hono" || i.to_module.startsWith("hono/"));
33
+ const hasFastify = imports.some((i) => i.to_module === "fastify");
34
+ walkBabelAst(ast, (node) => {
35
+ const handler = matchAppMethodCall(node, parsedFile.file_path, hasHono, hasFastify);
36
+ if (handler !== null)
37
+ out.push(handler);
38
+ if (hasFastify) {
39
+ const fastifyRoute = matchFastifyRouteCall(node, parsedFile.file_path);
40
+ if (fastifyRoute !== null)
41
+ out.push(fastifyRoute);
42
+ }
43
+ });
44
+ return out;
45
+ }
46
+ // Matches `app.METHOD(path, ...handlers)` for body-bearing methods (POST/PUT/PATCH/DELETE/ALL).
47
+ // Returns null when the node shape does not match — keeps the walker visitor side-effect-free.
48
+ function matchAppMethodCall(node, filePath, hasHono, hasFastify) {
49
+ if (node.type !== "ExpressionStatement")
50
+ return null;
51
+ const expr = node.expression;
52
+ if (expr.type !== "CallExpression")
53
+ return null;
54
+ const callee = expr.callee;
55
+ if (callee.type !== "MemberExpression")
56
+ return null;
57
+ const property = callee.property;
58
+ if (property.type !== "Identifier")
59
+ return null;
60
+ const methodName = property.name.toLowerCase();
61
+ if (!ALL_METHODS.has(methodName) || !BODY_METHODS.has(methodName))
62
+ return null;
63
+ const args = expr.arguments;
64
+ const pathArg = args[0];
65
+ if (!pathArg)
66
+ return null;
67
+ const path = extractStringPath(pathArg);
68
+ if (path === null || !isWebhookishPath(path))
69
+ return null;
70
+ const fnNode = args[args.length - 1];
71
+ if (!fnNode || fnNode.type === "SpreadElement" || fnNode.type === "ArgumentPlaceholder") {
72
+ return null;
73
+ }
74
+ const framework = hasHono ? "hono" : hasFastify ? "fastify" : "express";
75
+ const fnSpan = spanOf(fnNode);
76
+ return {
77
+ framework,
78
+ framework_version: null, // D-01 — never inferred in Phase 2 (issue #5).
79
+ route_pattern: path,
80
+ http_methods: [methodName.toUpperCase()],
81
+ file_path: filePath,
82
+ location: locationOf(node),
83
+ handler_function_name: extractFunctionName(fnNode),
84
+ handler_body_node: fnNode,
85
+ handler_source_start: fnSpan.start,
86
+ handler_source_end: fnSpan.end,
87
+ };
88
+ }
89
+ // Matches `fastify.route({ method, url, handler })` shape.
90
+ function matchFastifyRouteCall(node, filePath) {
91
+ if (node.type !== "ExpressionStatement")
92
+ return null;
93
+ const expr = node.expression;
94
+ if (expr.type !== "CallExpression")
95
+ return null;
96
+ const callee = expr.callee;
97
+ if (callee.type !== "MemberExpression")
98
+ return null;
99
+ const property = callee.property;
100
+ if (property.type !== "Identifier" || property.name !== "route")
101
+ return null;
102
+ const opts = expr.arguments[0];
103
+ if (!opts || opts.type !== "ObjectExpression")
104
+ return null;
105
+ const route = readRouteOptions(opts);
106
+ const method = readMethodField(route.method);
107
+ const url = route.url;
108
+ if (!method || !url || !isWebhookishPath(url))
109
+ return null;
110
+ if (!route.handler)
111
+ return null;
112
+ const fnSpan = spanOf(route.handler);
113
+ return {
114
+ framework: "fastify",
115
+ framework_version: null, // issue #5
116
+ route_pattern: url,
117
+ http_methods: method,
118
+ file_path: filePath,
119
+ location: locationOf(node),
120
+ handler_function_name: extractFunctionName(route.handler),
121
+ handler_body_node: route.handler,
122
+ handler_source_start: fnSpan.start,
123
+ handler_source_end: fnSpan.end,
124
+ };
125
+ }
126
+ function readRouteOptions(node) {
127
+ let method = null;
128
+ let url = null;
129
+ let handler = null;
130
+ for (const prop of node.properties) {
131
+ if (prop.type !== "ObjectProperty")
132
+ continue;
133
+ const keyName = propertyKeyName(prop.key);
134
+ if (keyName === null)
135
+ continue;
136
+ const value = prop.value;
137
+ if (keyName === "method") {
138
+ if (value.type === "StringLiteral") {
139
+ method = value.value;
140
+ }
141
+ else if (value.type === "ArrayExpression") {
142
+ method = value.elements
143
+ .filter((e) => e !== null && e.type === "StringLiteral")
144
+ .map((e) => e.value);
145
+ }
146
+ }
147
+ else if (keyName === "url") {
148
+ if (value.type === "StringLiteral")
149
+ url = value.value;
150
+ }
151
+ else if (keyName === "handler") {
152
+ // Skip Pattern (destructuring assignment LHS) — only Expression-shaped values can be a handler.
153
+ if (value.type !== "RestElement" &&
154
+ value.type !== "AssignmentPattern" &&
155
+ value.type !== "ArrayPattern" &&
156
+ value.type !== "ObjectPattern") {
157
+ handler = value;
158
+ }
159
+ }
160
+ }
161
+ return { method, url, handler };
162
+ }
163
+ function propertyKeyName(key) {
164
+ if (key.type === "Identifier")
165
+ return key.name;
166
+ if (key.type === "StringLiteral")
167
+ return key.value;
168
+ return null;
169
+ }
170
+ function extractStringPath(node) {
171
+ if (node.type === "StringLiteral")
172
+ return node.value;
173
+ if (node.type === "TemplateLiteral" &&
174
+ node.expressions.length === 0 &&
175
+ node.quasis.length === 1) {
176
+ return node.quasis[0]?.value.cooked ?? null;
177
+ }
178
+ return null;
179
+ }
180
+ function isWebhookishPath(path) {
181
+ // Pre-filter: catch obvious webhook paths and conventional provider paths.
182
+ // The catalog's `conventional_paths` is also used for evidence; the prefilter is just to keep
183
+ // noise low so we don't enumerate every route in the project.
184
+ const lower = path.toLowerCase();
185
+ return lower.includes("webhook") || lower.includes("/hook") || lower.includes("/hooks");
186
+ }
187
+ function extractFunctionName(node) {
188
+ if (node.type === "FunctionExpression" || node.type === "FunctionDeclaration") {
189
+ return node.id?.name ?? null;
190
+ }
191
+ if (node.type === "Identifier")
192
+ return node.name;
193
+ return null; // arrow function or anonymous
194
+ }
195
+ function locationOf(node) {
196
+ const loc = node.loc;
197
+ return {
198
+ line: loc?.start.line ?? 1,
199
+ col: (loc?.start.column ?? 0) + 1,
200
+ end_line: loc?.end.line ?? 1,
201
+ end_col: (loc?.end.column ?? 0) + 1,
202
+ };
203
+ }
204
+ function spanOf(node) {
205
+ return { start: node.start ?? 0, end: node.end ?? 0 };
206
+ }
207
+ function readMethodField(value) {
208
+ if (value === null)
209
+ return null;
210
+ if (typeof value === "string") {
211
+ return BODY_METHODS.has(value.toLowerCase()) ? [value.toUpperCase()] : null;
212
+ }
213
+ const upper = value.map((v) => v.toUpperCase());
214
+ return upper.some((m) => BODY_METHODS.has(m.toLowerCase())) ? upper : null;
215
+ }
216
+ // ---- Python: Flask ----
217
+ function detectPythonCatalog(parsedFile) {
218
+ const tree = parsedFile.raw_ast;
219
+ const out = [];
220
+ // Detect `@app.route('/x', methods=['POST'])\ndef fn(...)` — Flask convention.
221
+ const decorated = tree.rootNode.descendantsOfType(["decorated_definition"]);
222
+ for (const node of decorated) {
223
+ const handler = matchFlaskDecorator(node, parsedFile.file_path);
224
+ if (handler !== null)
225
+ out.push(handler);
226
+ }
227
+ return out;
228
+ }
229
+ function matchFlaskDecorator(node, filePath) {
230
+ const fnDef = node.namedChildren.find((c) => c.type === "function_definition");
231
+ if (!fnDef)
232
+ return null;
233
+ for (const dec of node.descendantsOfType(["decorator"])) {
234
+ const route = matchRouteDecorator(dec);
235
+ if (!route)
236
+ continue;
237
+ if (!isWebhookishPath(route.path))
238
+ continue;
239
+ if (!route.methods.some((m) => BODY_METHODS.has(m.toLowerCase())))
240
+ continue;
241
+ return {
242
+ framework: "flask",
243
+ framework_version: null, // issue #5
244
+ route_pattern: route.path,
245
+ http_methods: route.methods,
246
+ file_path: filePath,
247
+ location: {
248
+ line: node.startPosition.row + 1,
249
+ col: node.startPosition.column + 1,
250
+ end_line: node.endPosition.row + 1,
251
+ end_col: node.endPosition.column + 1,
252
+ },
253
+ handler_function_name: fnDef.childForFieldName("name")?.text ?? null,
254
+ handler_body_node: fnDef,
255
+ handler_source_start: fnDef.startIndex,
256
+ handler_source_end: fnDef.endIndex,
257
+ };
258
+ }
259
+ return null;
260
+ }
261
+ function matchRouteDecorator(dec) {
262
+ const call = dec.descendantsOfType(["call"])[0];
263
+ if (!call)
264
+ return null;
265
+ if (!(call.childForFieldName("function")?.text ?? "").endsWith(".route"))
266
+ return null;
267
+ const args = call.childForFieldName("arguments");
268
+ if (!args)
269
+ return null;
270
+ const pathArg = args.namedChildren.find((c) => c.type === "string");
271
+ if (!pathArg)
272
+ return null;
273
+ const path = stripPyString(pathArg.text);
274
+ const methods = [];
275
+ for (const kw of args.namedChildren) {
276
+ if (kw.type !== "keyword_argument")
277
+ continue;
278
+ if (kw.childForFieldName("name")?.text !== "methods")
279
+ continue;
280
+ const list = kw.childForFieldName("value");
281
+ if (!list)
282
+ continue;
283
+ for (const elem of list.namedChildren) {
284
+ if (elem.type === "string")
285
+ methods.push(stripPyString(elem.text).toUpperCase());
286
+ }
287
+ }
288
+ return { path, methods: methods.length > 0 ? methods : ["GET"] };
289
+ }
290
+ function stripPyString(raw) {
291
+ let i = 0;
292
+ while (i < raw.length && /[bBrRuUfF]/.test(raw[i] ?? ""))
293
+ i++;
294
+ const quoted = raw.slice(i);
295
+ if (quoted.startsWith('"""') || quoted.startsWith("'''")) {
296
+ return quoted.slice(3, quoted.length - 3);
297
+ }
298
+ if (quoted.startsWith('"') || quoted.startsWith("'")) {
299
+ return quoted.slice(1, quoted.length - 1);
300
+ }
301
+ return quoted;
302
+ }
303
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/model/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { SourceLocation } from "../types/finding.js";
2
+ import type { WebhookEvidence } from "../types/handler.js";
3
+ import type { ImportEdge, ParsedFile } from "../types/project-model.js";
4
+ import type { ProviderCatalog } from "../types/rule-set.js";
5
+ import type { CandidateHandler } from "./catalog.js";
6
+ export interface ComputeEvidenceInput {
7
+ readonly handler: CandidateHandler;
8
+ readonly parsedFile: ParsedFile;
9
+ readonly providerCatalog: ProviderCatalog;
10
+ readonly imports: ReadonlyArray<ImportEdge>;
11
+ }
12
+ export interface ComputeEvidenceOutput {
13
+ readonly evidence: ReadonlyArray<WebhookEvidence>;
14
+ readonly provider: string;
15
+ }
16
+ export declare function computeEvidence(input: ComputeEvidenceInput): ComputeEvidenceOutput;
17
+ export declare function locationFromCandidate(handler: CandidateHandler): SourceLocation;
18
+ //# sourceMappingURL=evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../../src/model/evidence.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CAoHlF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,CAE/E"}
@@ -0,0 +1,114 @@
1
+ // D-32: every candidate handler is enriched with WebhookEvidence[] derived from the provider
2
+ // catalog. Engine computes evidence; rules query thresholds. Engine never decides "is webhook?" —
3
+ // that's rule-side. Engine assigns provider attribution heuristically (worst case "unknown").
4
+ //
5
+ // Phase 2 split: this function emits 6 of the 7 D-32 signals. The seventh —
6
+ // `sdk_verify_call` — is appended in Plan 06b's build.ts after reachable_symbols is computed.
7
+ export function computeEvidence(input) {
8
+ const out = [];
9
+ const handlerLoc = input.handler.location;
10
+ const handlerText = input.parsedFile.source_text.slice(input.handler.handler_source_start, input.handler.handler_source_end);
11
+ // Signal A — path_pattern_match (catalog conventional_paths).
12
+ for (const [providerName, entry] of Object.entries(input.providerCatalog)) {
13
+ for (const conv of entry.conventional_paths) {
14
+ if (input.handler.route_pattern.toLowerCase().includes(conv.toLowerCase())) {
15
+ out.push({
16
+ kind: "path_pattern_match",
17
+ provider: providerName,
18
+ location: handlerLoc,
19
+ detail: conv,
20
+ });
21
+ }
22
+ }
23
+ }
24
+ // Signal B — sdk_import (catalog sdk_packages).
25
+ for (const [providerName, entry] of Object.entries(input.providerCatalog)) {
26
+ for (const pkg of entry.sdk_packages) {
27
+ if (input.imports.some((i) => i.to_module === pkg)) {
28
+ out.push({
29
+ kind: "sdk_import",
30
+ provider: providerName,
31
+ location: handlerLoc,
32
+ detail: pkg,
33
+ });
34
+ }
35
+ }
36
+ }
37
+ // Signal C — secret_env_var_reference (catalog secret_env_prefix). Substring match within the
38
+ // handler's source range so we count only references in/near this handler.
39
+ for (const [providerName, entry] of Object.entries(input.providerCatalog)) {
40
+ for (const env of entry.secret_env_prefix) {
41
+ if (handlerText.includes(env)) {
42
+ out.push({
43
+ kind: "secret_env_var_reference",
44
+ provider: providerName,
45
+ location: handlerLoc,
46
+ detail: env,
47
+ });
48
+ }
49
+ }
50
+ }
51
+ // Signal D — secret_literal_match (catalog secret_literal_prefix). Restricted to handler text.
52
+ for (const [providerName, entry] of Object.entries(input.providerCatalog)) {
53
+ for (const prefix of entry.secret_literal_prefix) {
54
+ if (handlerText.includes(prefix)) {
55
+ out.push({
56
+ kind: "secret_literal_match",
57
+ provider: providerName,
58
+ location: handlerLoc,
59
+ detail: prefix,
60
+ });
61
+ }
62
+ }
63
+ }
64
+ // Signal E — signature_header_read (catalog signature_header). Substring match on handler text.
65
+ for (const [providerName, entry] of Object.entries(input.providerCatalog)) {
66
+ for (const header of entry.signature_header) {
67
+ if (handlerText.toLowerCase().includes(header.toLowerCase())) {
68
+ out.push({
69
+ kind: "signature_header_read",
70
+ provider: providerName,
71
+ location: handlerLoc,
72
+ detail: header,
73
+ });
74
+ }
75
+ }
76
+ }
77
+ // Signal F — body_as_bytes_or_buffer. Heuristic token search inside the handler.
78
+ if (/(Buffer|Uint8Array|\braw\b|\bbytes\b|c\.req\.raw|request\.get_data\(\)|request\.body)/i.test(handlerText)) {
79
+ out.push({
80
+ kind: "body_as_bytes_or_buffer",
81
+ provider: "unknown",
82
+ location: handlerLoc,
83
+ detail: "heuristic",
84
+ });
85
+ }
86
+ // Signal G — sdk_verify_call: NOT EMITTED HERE. Plan 06b's build.ts appends it after computing
87
+ // reachable_symbols, by cross-checking against catalog.providers[*].sdk_verify_calls.
88
+ // Provider attribution — most-cited provider wins; ties → "multiple"; zero → "unknown".
89
+ const counts = new Map();
90
+ for (const e of out) {
91
+ if (e.provider === "unknown")
92
+ continue;
93
+ counts.set(e.provider, (counts.get(e.provider) ?? 0) + 1);
94
+ }
95
+ let topProvider = "unknown";
96
+ let topCount = 0;
97
+ let tied = false;
98
+ for (const [p, c] of counts) {
99
+ if (c > topCount) {
100
+ topProvider = p;
101
+ topCount = c;
102
+ tied = false;
103
+ }
104
+ else if (c === topCount && c > 0) {
105
+ tied = true;
106
+ }
107
+ }
108
+ const provider = tied ? "multiple" : topProvider;
109
+ return { evidence: out, provider };
110
+ }
111
+ export function locationFromCandidate(handler) {
112
+ return handler.location;
113
+ }
114
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/model/evidence.ts"],"names":[],"mappings":"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"}