progmune-runtime 2.1.6 → 3.2.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 (356) hide show
  1. package/README.md +108 -468
  2. package/dist/ablation-study.js +144 -0
  3. package/dist/ablation-study.test.js +18 -0
  4. package/dist/action-runtime.js +3 -1
  5. package/dist/active-learning.js +211 -0
  6. package/dist/analytics.js +139 -0
  7. package/dist/asset-factory.js +309 -0
  8. package/dist/asset-growth.js +244 -0
  9. package/dist/asset-promotion.js +382 -0
  10. package/dist/asset-quality.js +550 -0
  11. package/dist/audit/business-translator.js +285 -0
  12. package/dist/audit/cli.js +66 -0
  13. package/dist/audit/formatters/html.js +379 -0
  14. package/dist/audit/formatters/json.js +11 -0
  15. package/dist/audit/formatters/markdown.js +192 -0
  16. package/dist/audit/formatters/terminal.js +189 -0
  17. package/dist/audit/index.js +25 -0
  18. package/dist/audit/report-builder.js +318 -0
  19. package/dist/audit/types.js +8 -0
  20. package/dist/audit.js +3 -3
  21. package/dist/auto-benchmark-generator.js +137 -0
  22. package/dist/auto-benchmark-generator.test.js +45 -0
  23. package/dist/auto-protocol-synthesizer.js +362 -0
  24. package/dist/auto-protocol-synthesizer.test.js +82 -0
  25. package/dist/autonomous-patch.js +175 -0
  26. package/dist/autonomous-patch.test.js +128 -0
  27. package/dist/badge/badge-server.js +98 -0
  28. package/dist/behavior-miner.js +442 -0
  29. package/dist/belief-layer.js +475 -0
  30. package/dist/benchmark-count.js +5 -0
  31. package/dist/benchmark-generator.js +211 -0
  32. package/dist/benchmark-harness.js +201 -0
  33. package/dist/benchmark-pass-rate.js +7 -0
  34. package/dist/benchmark-report.js +8 -3
  35. package/dist/benchmark-save.js +14 -1
  36. package/dist/bootstrap-validation.js +197 -0
  37. package/dist/bootstrap-validation.test.js +51 -0
  38. package/dist/branch-ledger.js +1 -1
  39. package/dist/capability-gap.js +130 -0
  40. package/dist/certify-html.js +351 -0
  41. package/dist/certify.js +326 -0
  42. package/dist/check.js +4 -4
  43. package/dist/compliance-miner.js +447 -0
  44. package/dist/continuous-benchmark.js +194 -0
  45. package/dist/continuous-benchmark.test.js +116 -0
  46. package/dist/corpus-stats.js +173 -0
  47. package/dist/counterfactual-engine.js +288 -0
  48. package/dist/coverage-dashboard.js +109 -0
  49. package/dist/coverage-system.test.js +205 -0
  50. package/dist/cross-repo-precision.js +352 -0
  51. package/dist/cve-benchmark.js +180 -0
  52. package/dist/cve-benchmark.test.js +28 -0
  53. package/dist/cve-collector.js +73 -0
  54. package/dist/data-quality.js +141 -0
  55. package/dist/decision-engine.js +388 -0
  56. package/dist/derive-metadata.js +250 -0
  57. package/dist/difficulty-active.test.js +198 -0
  58. package/dist/difficulty-map.js +244 -0
  59. package/dist/discovery-analytics.js +125 -0
  60. package/dist/discovery-model.js +149 -0
  61. package/dist/discovery-optimize.test.js +199 -0
  62. package/dist/discovery-trace.js +276 -0
  63. package/dist/discovery-trace.test.js +97 -0
  64. package/dist/emitter.js +83 -1
  65. package/dist/enterprise-dashboard.js +405 -0
  66. package/dist/eval-hardening.js +297 -0
  67. package/dist/eval-hardening.test.js +85 -0
  68. package/dist/evaluation-campaign.js +359 -0
  69. package/dist/evaluation-campaign.test.js +181 -0
  70. package/dist/evidence-growth.js +143 -0
  71. package/dist/evidence-repository.js +209 -0
  72. package/dist/evidence-system.js +441 -0
  73. package/dist/execute.js +15 -7
  74. package/dist/experimental/software-physics.js +291 -0
  75. package/dist/experimental/state-inference.js +516 -0
  76. package/dist/experimental/unsupervised-physics.js +230 -0
  77. package/dist/extract-ir-python.js +54 -7
  78. package/dist/extract-ir.js +376 -12
  79. package/dist/failure-collector.js +2 -2
  80. package/dist/failure-corpus.js +322 -9
  81. package/dist/feedback.js +16 -5
  82. package/dist/feedback.test.js +49 -0
  83. package/dist/file-lock.js +1 -1
  84. package/dist/flywheel-batch.js +292 -0
  85. package/dist/frameworks/express-cli.js +237 -0
  86. package/dist/frameworks/express-detector.js +445 -0
  87. package/dist/frameworks/express-detector.test.js +206 -0
  88. package/dist/frameworks/index.js +30 -0
  89. package/dist/frameworks/nestjs-detector.js +302 -0
  90. package/dist/frameworks/trpc-detector.js +161 -0
  91. package/dist/frameworks/version-awareness.js +179 -0
  92. package/dist/function-synonyms.js +164 -0
  93. package/dist/function-synonyms.test.js +68 -0
  94. package/dist/generalization.test.js +352 -0
  95. package/dist/goal-annotator.js +113 -0
  96. package/dist/goal-planner.js +563 -0
  97. package/dist/gold-cve.js +164 -0
  98. package/dist/gold-cve.test.js +104 -0
  99. package/dist/gold-quality.js +206 -0
  100. package/dist/gold-tiers.js +241 -0
  101. package/dist/governance-dashboard.js +327 -0
  102. package/dist/graph-viz.js +240 -0
  103. package/dist/guided-frontier.js +195 -0
  104. package/dist/hierarchical-planner.js +148 -0
  105. package/dist/identifier-parser.js +260 -0
  106. package/dist/immune-metrics.js +93 -0
  107. package/dist/immune-receiver.js +158 -0
  108. package/dist/immune-reporter.js +1 -1
  109. package/dist/improvement-orchestrator.js +206 -0
  110. package/dist/inject-p0-vocabulary.js +300 -0
  111. package/dist/intent-parser.js +218 -0
  112. package/dist/invariant-algebra.js +476 -0
  113. package/dist/invariant-calculus.js +533 -0
  114. package/dist/ir-utils.js +70 -0
  115. package/dist/ir-utils.test.js +50 -0
  116. package/dist/knowledge-api.js +312 -0
  117. package/dist/knowledge-evolution.js +452 -0
  118. package/dist/knowledge-explorer.js +506 -0
  119. package/dist/knowledge-flywheel.js +274 -0
  120. package/dist/knowledge-governance.js +338 -0
  121. package/dist/knowledge-governance.test.js +150 -0
  122. package/dist/knowledge-graph.js +181 -0
  123. package/dist/knowledge-guided-synth.js +246 -0
  124. package/dist/knowledge-loop.test.js +77 -0
  125. package/dist/knowledge-object.js +316 -0
  126. package/dist/knowledge-package.js +98 -0
  127. package/dist/kpi-dashboard.js +561 -0
  128. package/dist/l3-cross-function.js +280 -0
  129. package/dist/learning-ranker.js +148 -0
  130. package/dist/learning-ranker.test.js +291 -0
  131. package/dist/ledger/accountability.js +322 -0
  132. package/dist/ledger/chain-builder.js +185 -0
  133. package/dist/ledger/cli.js +222 -0
  134. package/dist/ledger/index.js +13 -0
  135. package/dist/ledger/signatures.js +193 -0
  136. package/dist/ledger/types.js +9 -0
  137. package/dist/llm.js +74 -3
  138. package/dist/load-benchmarks.js +8 -3
  139. package/dist/logger.js +66 -0
  140. package/dist/logger.test.js +37 -0
  141. package/dist/logistic-reward.js +339 -0
  142. package/dist/logistic-reward.test.js +180 -0
  143. package/dist/macro-graph.js +193 -0
  144. package/dist/macro-repair.js +183 -0
  145. package/dist/mcp-server.mjs +1202 -483
  146. package/dist/memory-layer.js +42 -5
  147. package/dist/multi-repo-precision.js +422 -0
  148. package/dist/name-free-protocol.js +425 -0
  149. package/dist/name-free-protocol.test.js +170 -0
  150. package/dist/name-scrambling.js +138 -0
  151. package/dist/name-scrambling.test.js +16 -0
  152. package/dist/p3-observability.test.js +281 -0
  153. package/dist/p5-orchestrator.test.js +225 -0
  154. package/dist/pairwise-preference.js +294 -0
  155. package/dist/pairwise-preference.test.js +140 -0
  156. package/dist/planner-constraints.js +104 -0
  157. package/dist/planner-prompts.js +155 -0
  158. package/dist/planner-telemetry.js +415 -0
  159. package/dist/planner-trace.js +214 -0
  160. package/dist/planner.js +162 -167
  161. package/dist/plsb/artifact.js +116 -0
  162. package/dist/plsb/cli.js +71 -0
  163. package/dist/plsb/index.js +19 -0
  164. package/dist/plsb/leaderboard.js +249 -0
  165. package/dist/plsb/report-md.js +156 -0
  166. package/dist/plsb/schema.js +179 -0
  167. package/dist/plsb-benchmark.js +284 -0
  168. package/dist/plsb-benchmark.test.js +119 -0
  169. package/dist/policy/cli.js +134 -0
  170. package/dist/policy/engine.js +333 -0
  171. package/dist/policy/index.js +12 -0
  172. package/dist/policy/types.js +59 -0
  173. package/dist/policy-miner.js +505 -0
  174. package/dist/precision-analyze.js +229 -0
  175. package/dist/precision-benchmark.js +147 -0
  176. package/dist/precision-label-c.js +134 -0
  177. package/dist/precision-label.js +193 -0
  178. package/dist/precision-report-c.js +149 -0
  179. package/dist/precision-report.js +246 -0
  180. package/dist/progmune-status.js +108 -0
  181. package/dist/proof-engine.js +479 -0
  182. package/dist/proof-provenance.js +315 -0
  183. package/dist/protocol-coverage.js +294 -0
  184. package/dist/protocol-detector.js +1189 -0
  185. package/dist/protocol-embedding-expanded.js +297 -0
  186. package/dist/protocol-embedding-expanded.test.js +97 -0
  187. package/dist/protocol-embedding.js +195 -0
  188. package/dist/protocol-embedding.test.js +82 -0
  189. package/dist/protocol-extractor-v2.js +354 -0
  190. package/dist/protocol-extractor-v2.test.js +140 -0
  191. package/dist/protocol-extractor.js +310 -0
  192. package/dist/protocol-extractor.test.js +113 -0
  193. package/dist/protocol-foundation.js +322 -0
  194. package/dist/protocol-foundation.test.js +163 -0
  195. package/dist/protocol-frontier.js +243 -0
  196. package/dist/protocol-frontier.test.js +92 -0
  197. package/dist/protocol-gap-analyzer.js +228 -0
  198. package/dist/protocol-gap-analyzer.test.js +49 -0
  199. package/dist/protocol-invariants.js +276 -0
  200. package/dist/protocol-invariants.test.js +111 -0
  201. package/dist/protocol-knowledge.js +464 -0
  202. package/dist/protocol-miner.js +343 -0
  203. package/dist/protocol-mining.js +207 -0
  204. package/dist/protocol-mining.test.js +37 -0
  205. package/dist/protocol-registry.js +1 -1
  206. package/dist/protocol-security-benchmark.js +222 -0
  207. package/dist/protocol-vulnerability.js +257 -0
  208. package/dist/protocol-vulnerability.test.js +60 -0
  209. package/dist/python-benchmark.js +120 -0
  210. package/dist/python-emitter.js +163 -45
  211. package/dist/python-protocol-extractor.js +187 -0
  212. package/dist/python-protocol-extractor.test.js +116 -0
  213. package/dist/realworld-benchmark.js +646 -0
  214. package/dist/realworld-benchmark.test.js +36 -0
  215. package/dist/repair-arch.test.js +411 -0
  216. package/dist/repair-evolution.test.js +454 -0
  217. package/dist/repair-executor.js +719 -0
  218. package/dist/repair-proposal.js +4 -4
  219. package/dist/repair-ranker.js +141 -0
  220. package/dist/repair-strategies.js +419 -0
  221. package/dist/repair-taxonomy.js +234 -0
  222. package/dist/repair-types.js +12 -0
  223. package/dist/repo-evaluator.js +250 -0
  224. package/dist/repo-evaluator.test.js +128 -0
  225. package/dist/resource-abstraction.js +242 -0
  226. package/dist/resource-detector.js +211 -0
  227. package/dist/result.test.js +43 -0
  228. package/dist/reward-system.js +411 -0
  229. package/dist/reward-system.test.js +175 -0
  230. package/dist/risk-model.js +215 -0
  231. package/dist/rule-miner.js +234 -7
  232. package/dist/rule-specificity.js +254 -0
  233. package/dist/runtime-types.js +27 -0
  234. package/dist/scaffold.js +208 -0
  235. package/dist/scale-collector.test.js +101 -0
  236. package/dist/scale-trajectory-collector.js +128 -0
  237. package/dist/sdk.js +250 -0
  238. package/dist/search-planner.js +4 -41
  239. package/dist/semantic-snapshot.js +1 -1
  240. package/dist/semantic-topology.js +121 -0
  241. package/dist/semantic-trace.js +310 -317
  242. package/dist/sequence-extractor.js +343 -0
  243. package/dist/skill-library.js +245 -0
  244. package/dist/skill-planner.test.js +189 -0
  245. package/dist/software-physics.js +291 -0
  246. package/dist/software-physics.test.js +81 -0
  247. package/dist/ssg-precision.js +478 -0
  248. package/dist/ssg-validator.js +71 -21
  249. package/dist/state-inference-doubleblind.test.js +160 -0
  250. package/dist/state-inference.js +516 -0
  251. package/dist/state-inference.test.js +115 -0
  252. package/dist/state-machine-fingerprint.js +345 -0
  253. package/dist/state-machine-fingerprint.test.js +120 -0
  254. package/dist/state-miner.js +386 -0
  255. package/dist/state-name-inference.js +213 -0
  256. package/dist/state-name-inference.test.js +69 -0
  257. package/dist/strategy-planner.js +262 -96
  258. package/dist/strategy-planner.test.js +135 -0
  259. package/dist/telemetry-analytics.test.js +402 -0
  260. package/dist/terminal-format.js +68 -0
  261. package/dist/terminal-format.test.js +83 -0
  262. package/dist/topology-factory.js +196 -0
  263. package/dist/topology-representation.js +242 -0
  264. package/dist/topology-representation.test.js +27 -0
  265. package/dist/trajectory-augmentation.js +254 -0
  266. package/dist/trajectory-augmentation.test.js +63 -0
  267. package/dist/trajectory-corpus.js +440 -0
  268. package/dist/trajectory-corpus.test.js +32 -0
  269. package/dist/trajectory-feedback.test.js +116 -0
  270. package/dist/transition-synthesizer.js +286 -0
  271. package/dist/transition-synthesizer.test.js +123 -0
  272. package/dist/trust/api-semantic-mapper.js +809 -0
  273. package/dist/trust/call-graph-propagator.js +225 -0
  274. package/dist/trust/cli.js +122 -0
  275. package/dist/trust/compliance-scorer.js +283 -0
  276. package/dist/trust/confidence-calculator.js +261 -0
  277. package/dist/trust/engine.js +1145 -0
  278. package/dist/trust/explainability.js +85 -0
  279. package/dist/trust/formatters/ci.js +42 -0
  280. package/dist/trust/formatters/json.js +11 -0
  281. package/dist/trust/formatters/terminal.js +152 -0
  282. package/dist/trust/index.js +39 -0
  283. package/dist/trust/phase1-verify.js +171 -0
  284. package/dist/trust/protocol-domain-validator.js +697 -0
  285. package/dist/trust/score-calculator.js +282 -0
  286. package/dist/trust/ssg-bridge.js +641 -0
  287. package/dist/trust/ssg-bridge.test.js +269 -0
  288. package/dist/trust/types.js +67 -0
  289. package/dist/trust/violation-trace.js +335 -0
  290. package/dist/trust-api.js +179 -0
  291. package/dist/trust-calibration.js +279 -0
  292. package/dist/unknown-protocol-discovery.js +339 -0
  293. package/dist/unknown-protocol-discovery.test.js +102 -0
  294. package/dist/unsupervised-physics.js +230 -0
  295. package/dist/unsupervised-physics.test.js +95 -0
  296. package/dist/utils.test.js +37 -0
  297. package/dist/validator.js +187 -10
  298. package/dist/verification-intelligence.js +475 -0
  299. package/dist/verify-api.js +432 -0
  300. package/dist/vi-impact-report.js +293 -0
  301. package/dist/wl-fingerprint.js +162 -0
  302. package/dist/wl-fingerprint.test.js +130 -0
  303. package/dist/zeroshot-strategy.js +139 -0
  304. package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
  305. package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
  306. package/package.json +74 -7
  307. package/protocols.json +1956 -50
  308. package/.dockerignore +0 -14
  309. package/.mcp.json +0 -11
  310. package/.progmune_allowlist +0 -50
  311. package/.test_report/test_report.md +0 -87
  312. package/Dockerfile +0 -9
  313. package/FAQ.md +0 -167
  314. package/WHITEPAPER.md +0 -540
  315. package/demo-project/auth.ts +0 -55
  316. package/demo-project/tsconfig.json +0 -8
  317. package/dist/acl-breakdown.js +0 -13
  318. package/dist/all-sessions.js +0 -11
  319. package/dist/antibody-stats.js +0 -11
  320. package/dist/branch-tree-count.js +0 -14
  321. package/dist/common-fixpath.js +0 -12
  322. package/dist/constraint-types.js +0 -12
  323. package/dist/exec-metrics.js +0 -11
  324. package/dist/failure-report.js +0 -11
  325. package/dist/fast-path-hits.js +0 -13
  326. package/dist/fingerprint-list.js +0 -15
  327. package/dist/gen-history-log.js +0 -13
  328. package/dist/heatmap-data.js +0 -11
  329. package/dist/recent-session.js +0 -12
  330. package/dist/svl-distribution.js +0 -11
  331. package/dist/terminal-status.js +0 -11
  332. package/dist/token-savings.js +0 -11
  333. package/dist/total-repairs.js +0 -12
  334. package/dist/unresolved-count.js +0 -12
  335. package/dist/valid-fingerprints.js +0 -13
  336. package/dist/verify-ledgers.js +0 -11
  337. package/docs/whitepaper-style.css +0 -77
  338. package/docs/whitepaper-v2.1.md +0 -609
  339. package/docs/whitepaper-v2.2.md +0 -1064
  340. package/docs/whitepaper-v2.2.pdf +0 -0
  341. package/fly.toml +0 -31
  342. package/public/dashboard.html +0 -119
  343. package/server/hub.js +0 -116
  344. package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
  345. package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
  346. package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
  347. package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
  348. package/test/replay-golden.ts +0 -84
  349. package/test_benchmark.js +0 -165
  350. package/test_comprehensive.mjs +0 -638
  351. package/test_concurrency.js +0 -129
  352. package/test_ir_robustness.js +0 -85
  353. package/test_semantic_contracts.js +0 -269
  354. package/test_ssg_stress.js +0 -156
  355. package/test_svl3.js +0 -58
  356. package/tsconfig.json +0 -17
@@ -0,0 +1,445 @@
1
+ "use strict";
2
+ /**
3
+ * Express Framework Adapter — Protocol Detection for Express.js
4
+ *
5
+ * Detects Express-specific patterns that the generic \w* regex detector
6
+ * cannot see: middleware chains, route handlers, auth guards, and the
7
+ * relationship between them.
8
+ *
9
+ * This is the FIRST framework adapter. Before this, Progmune had 0/13
10
+ * framework adapters despite TS being its primary language.
11
+ *
12
+ * Key Express patterns detected:
13
+ * - App initialization: express(), const app = express()
14
+ * - Middleware registration: app.use(fn), router.use(fn)
15
+ * - Route handlers: app.get(), app.post(), router.get(), etc.
16
+ * - Auth middleware: passport.authenticate(), express-jwt, custom auth
17
+ * - Missing auth: route without middleware when auth middleware exists
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.detectExpressApp = detectExpressApp;
54
+ exports.extractRoutes = extractRoutes;
55
+ exports.classifyMiddleware = classifyMiddleware;
56
+ exports.extractGlobalMiddleware = extractGlobalMiddleware;
57
+ exports.analyzeExpressApp = analyzeExpressApp;
58
+ exports.analyzeExpressFile = analyzeExpressFile;
59
+ exports.analyzeExpressProject = analyzeExpressProject;
60
+ exports.formatExpressReport = formatExpressReport;
61
+ const fs = __importStar(require("fs"));
62
+ // ── Known auth/security middleware patterns ──
63
+ const AUTH_MIDDLEWARE_PATTERNS = [
64
+ /\bpassport\.initialize\b/,
65
+ /\bpassport\.authenticate\b/,
66
+ /\bexpress-jwt\b/,
67
+ /\bjwt\s*\(\s*\{/,
68
+ /\bauthMiddleware\b/,
69
+ /\brequireAuth\b/,
70
+ /\bwithAuth\b/,
71
+ /\bauthenticateToken\b/,
72
+ /\bverifyToken\b/,
73
+ /\bvalidateToken\b/,
74
+ /\bisAuthenticated\b/,
75
+ /\bensureAuthenticated\b/,
76
+ /\bauthGuard\b/,
77
+ /\bAuthGuard\b/,
78
+ /\brequire\w*[Aa]uth\b/,
79
+ /\bcheckAuth\b/,
80
+ /\bprotect\b/,
81
+ /\bauthenticateRequest\b/,
82
+ // Variable references — common Express convention (e.g., const auth = passport.authenticate(...))
83
+ // These are standalone identifiers in middleware position
84
+ /^auth$/i,
85
+ /^authMw$/i,
86
+ /^jwtAuth$/i,
87
+ /^tokenAuth$/i,
88
+ ];
89
+ const RATE_LIMIT_MIDDLEWARE_PATTERNS = [
90
+ /\bexpress-rate-limit\b/,
91
+ /\brateLimit\b/,
92
+ /\brate_limiter\b/,
93
+ /\bRateLimiter\b/,
94
+ /\bthrottle\b/,
95
+ // Common variable references
96
+ /^loginLimiter$/i,
97
+ /^apiLimiter$/i,
98
+ /^rateLimiter$/i,
99
+ /^limiter$/i,
100
+ ];
101
+ const VALIDATION_MIDDLEWARE_PATTERNS = [
102
+ /\bexpress-validator\b/,
103
+ /\bcheck\s*\(/,
104
+ /\bbody\s*\(/,
105
+ /\bparam\s*\(/,
106
+ /\bquery\s*\(/,
107
+ /\bvalidate\b/,
108
+ /\bcelebrate\b/,
109
+ /\bJoi\./,
110
+ /\bzod\b/,
111
+ /\byup\b/,
112
+ ];
113
+ const SECURITY_HEADER_PATTERNS = [
114
+ /\bhelmet\b/,
115
+ /\bcors\s*\(/,
116
+ /\bcors\b/,
117
+ /\bcsp\b/,
118
+ /\bcontentSecurityPolicy\b/,
119
+ /\bhsts\b/,
120
+ ];
121
+ const SESSION_PATTERNS = [
122
+ /\bexpress-session\b/,
123
+ /\bcookie-session\b/,
124
+ /\bcookieParser\b/,
125
+ /\bsession\s*\(/,
126
+ ];
127
+ // ── Detection Functions ──
128
+ /**
129
+ * Detect Express app initialization from source code.
130
+ * Returns the app variable name if found.
131
+ */
132
+ function detectExpressApp(code) {
133
+ // Pattern: const app = express()
134
+ const m = code.match(/(?:const|let|var)\s+(\w+)\s*=\s*express\s*\(\s*\)/);
135
+ if (m)
136
+ return m[1];
137
+ // Pattern: import express from 'express' ... const app = express()
138
+ if (/\brequire\s*\(\s*['"]express['"]\s*\)/.test(code) || /from\s+['"]express['"]/.test(code)) {
139
+ const varMatch = code.match(/(?:const|let|var)\s+(\w+)\s*=\s*express\s*\(\s*\)/);
140
+ if (varMatch)
141
+ return varMatch[1];
142
+ // Couldn't find app variable, but express is imported
143
+ return "app"; // default convention
144
+ }
145
+ return null;
146
+ }
147
+ /**
148
+ * Extract all routes registered on an Express app or router.
149
+ */
150
+ function extractRoutes(code, appName) {
151
+ const routes = [];
152
+ const methods = ["get", "post", "put", "delete", "patch", "all", "use"];
153
+ for (const method of methods) {
154
+ // Pattern: app.get('/path', middleware1, middleware2, handler)
155
+ // or: router.post('/path', handler)
156
+ const routeRegex = new RegExp(`${appName}\\.${method}\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*,([^;]+)\\)`, "gi");
157
+ let match;
158
+ while ((match = routeRegex.exec(code)) !== null) {
159
+ const rawArgs = match[2].trim();
160
+ const args = rawArgs.split(",").map(a => a.trim()).filter(a => a.length > 0);
161
+ // Last arg is the handler, everything before is middleware
162
+ const handler = args[args.length - 1] || "anonymous";
163
+ const middlewares = args.slice(0, -1);
164
+ routes.push({
165
+ method,
166
+ path: match[1],
167
+ handler,
168
+ middlewares,
169
+ line: code.slice(0, match.index).split("\n").length,
170
+ });
171
+ }
172
+ }
173
+ return routes;
174
+ }
175
+ /**
176
+ * Identify the type of a middleware function from its name or pattern.
177
+ */
178
+ function classifyMiddleware(code, name) {
179
+ const trimmed = name.trim();
180
+ for (const p of AUTH_MIDDLEWARE_PATTERNS) {
181
+ if (p.test(trimmed))
182
+ return "auth";
183
+ }
184
+ for (const p of RATE_LIMIT_MIDDLEWARE_PATTERNS) {
185
+ if (p.test(trimmed))
186
+ return "rate_limit";
187
+ }
188
+ for (const p of VALIDATION_MIDDLEWARE_PATTERNS) {
189
+ if (p.test(trimmed))
190
+ return "validation";
191
+ }
192
+ for (const p of SECURITY_HEADER_PATTERNS) {
193
+ if (p.test(trimmed))
194
+ return "security_header";
195
+ }
196
+ for (const p of SESSION_PATTERNS) {
197
+ if (p.test(trimmed))
198
+ return "session";
199
+ }
200
+ if (/\bcors\b/i.test(trimmed))
201
+ return "cors";
202
+ if (/\berrorHandler\b|\bhandleError\b|\berror_handler\b/i.test(trimmed))
203
+ return "error_handler";
204
+ if (/\blogger\b|\bmorgan\b|\blogging\b/i.test(trimmed))
205
+ return "logging";
206
+ return "unknown";
207
+ }
208
+ /**
209
+ * Extract global middleware registrations (app.use(fn)).
210
+ */
211
+ function extractGlobalMiddleware(code, appName) {
212
+ const middleware = [];
213
+ const useRegex = new RegExp(`${appName}\\.use\\s*\\(([^)]+)\\)`, "gi");
214
+ let match;
215
+ while ((match = useRegex.exec(code)) !== null) {
216
+ const args = match[1].split(",").map(a => a.trim());
217
+ for (const arg of args) {
218
+ if (arg.startsWith("'") || arg.startsWith('"'))
219
+ continue; // skip path strings
220
+ if (/^(express|router|Router)\./.test(arg))
221
+ continue; // skip sub-routers (handled separately)
222
+ middleware.push({
223
+ name: arg,
224
+ type: classifyMiddleware(code, arg),
225
+ registeredAt: code.slice(0, match.index).split("\n").length,
226
+ });
227
+ }
228
+ }
229
+ return middleware;
230
+ }
231
+ /**
232
+ * Analyze an Express app for security issues.
233
+ * This is the main entry point — call this function on an Express source file.
234
+ */
235
+ function analyzeExpressApp(code) {
236
+ const appName = detectExpressApp(code);
237
+ if (!appName) {
238
+ return { hasExpress: false, appName: "", routes: [], globalMiddleware: [], issues: [] };
239
+ }
240
+ const routes = extractRoutes(code, appName);
241
+ const globalMiddleware = extractGlobalMiddleware(code, appName);
242
+ const issues = [];
243
+ // Check 1: Does the app have any auth middleware at all?
244
+ const hasGlobalAuth = globalMiddleware.some(m => m.type === "auth");
245
+ const hasAnyAuth = hasGlobalAuth || routes.some(r => r.middlewares.some(m => AUTH_MIDDLEWARE_PATTERNS.some(p => p.test(m))));
246
+ // Check 2: Does the app have rate limiting on auth routes?
247
+ const hasRateLimit = globalMiddleware.some(m => m.type === "rate_limit");
248
+ const authRoutes = routes.filter(r => /\b(login|signin|signup|register|auth|token|password)\b/i.test(r.path));
249
+ // Check 3: Does the app have security headers (helmet)?
250
+ const hasHelmet = globalMiddleware.some(m => m.type === "security_header") ||
251
+ /\bhelmet\s*\(/.test(code);
252
+ // Check 4: Does the app have input validation on POST/PUT routes?
253
+ const hasValidation = globalMiddleware.some(m => m.type === "validation");
254
+ // Check 5: Does the app have CORS configured?
255
+ const hasCors = globalMiddleware.some(m => m.type === "cors") || /\bcors\s*\(/.test(code);
256
+ // Check 6: Does the app have session management?
257
+ const hasSession = globalMiddleware.some(m => m.type === "session") || /\bsession\s*\(/.test(code);
258
+ // ── Generate Issues ──
259
+ if (!hasAnyAuth) {
260
+ issues.push({
261
+ severity: "critical",
262
+ rule: "EXPRESS_NO_AUTH_MIDDLEWARE",
263
+ message: "Express app has no authentication middleware registered. All routes are publicly accessible.",
264
+ line: 1,
265
+ fix: "Add an auth middleware (e.g., passport.authenticate('jwt'), express-jwt, or a custom auth middleware) to protect routes.",
266
+ });
267
+ }
268
+ // Check for routes without auth middleware (when auth middleware exists globally)
269
+ if (hasAnyAuth) {
270
+ for (const route of routes) {
271
+ if (["use", "all"].includes(route.method))
272
+ continue; // skip middleware registrations
273
+ const routeHasAuth = route.middlewares.some(m => AUTH_MIDDLEWARE_PATTERNS.some(p => p.test(m)));
274
+ if (!routeHasAuth && !hasGlobalAuth) {
275
+ // Route has no auth middleware AND no global auth → each route needs its own
276
+ // (already reported as EXPRESS_NO_AUTH_MIDDLEWARE above)
277
+ continue;
278
+ }
279
+ if (!routeHasAuth && hasGlobalAuth && !isPublicRoute(route.path)) {
280
+ issues.push({
281
+ severity: "high",
282
+ rule: "EXPRESS_ROUTE_MISSING_AUTH",
283
+ message: `Route ${route.method.toUpperCase()} ${route.path} has no auth middleware. It may be inadvertently public.`,
284
+ route: `${route.method.toUpperCase()} ${route.path}`,
285
+ line: route.line,
286
+ fix: `Add auth middleware to the route: app.${route.method}('${route.path}', authMiddleware, ${route.handler})`,
287
+ });
288
+ }
289
+ }
290
+ }
291
+ // Auth routes without rate limiting
292
+ if (authRoutes.length > 0 && !hasRateLimit) {
293
+ for (const route of authRoutes) {
294
+ issues.push({
295
+ severity: "high",
296
+ rule: "EXPRESS_AUTH_NO_RATE_LIMIT",
297
+ message: `Auth route ${route.method.toUpperCase()} ${route.path} has no rate limiting. Vulnerable to brute-force attacks.`,
298
+ route: `${route.method.toUpperCase()} ${route.path}`,
299
+ line: route.line,
300
+ fix: "Add express-rate-limit middleware to auth routes: max 5 attempts per minute per IP.",
301
+ });
302
+ }
303
+ }
304
+ // Missing security headers
305
+ if (!hasHelmet) {
306
+ issues.push({
307
+ severity: "medium",
308
+ rule: "EXPRESS_NO_HELMET",
309
+ message: "Express app does not use helmet middleware. Missing security headers (CSP, HSTS, X-Frame-Options, etc.).",
310
+ line: 1,
311
+ fix: "Add helmet middleware: app.use(helmet())",
312
+ });
313
+ }
314
+ // POST/PUT routes without validation
315
+ const mutationRoutes = routes.filter(r => ["post", "put", "patch"].includes(r.method));
316
+ if (mutationRoutes.length > 0 && !hasValidation) {
317
+ issues.push({
318
+ severity: "medium",
319
+ rule: "EXPRESS_NO_INPUT_VALIDATION",
320
+ message: `${mutationRoutes.length} POST/PUT/PATCH routes have no input validation middleware.`,
321
+ line: mutationRoutes[0]?.line ?? 1,
322
+ fix: "Add express-validator or zod validation to mutation routes.",
323
+ });
324
+ }
325
+ // Missing CORS configuration
326
+ if (!hasCors) {
327
+ issues.push({
328
+ severity: "low",
329
+ rule: "EXPRESS_NO_CORS_CONFIG",
330
+ message: "Express app has no explicit CORS configuration. Defaults to same-origin only — may break legitimate cross-origin requests or be overly permissive.",
331
+ line: 1,
332
+ fix: "Add explicit CORS configuration: app.use(cors({ origin: 'https://your-domain.com' }))",
333
+ });
334
+ }
335
+ // Session without secure settings (if present)
336
+ if (hasSession) {
337
+ const sessionSecure = /secure\s*:\s*true/.test(code) && /httpOnly\s*:\s*true/.test(code) && /sameSite\s*:\s*['"](?:strict|lax)['"]/.test(code);
338
+ if (!sessionSecure) {
339
+ issues.push({
340
+ severity: "medium",
341
+ rule: "EXPRESS_SESSION_INSECURE",
342
+ message: "Express session configured without secure, httpOnly, or sameSite cookie flags.",
343
+ line: 1,
344
+ fix: "Set cookie: { secure: true, httpOnly: true, sameSite: 'strict' } in session config.",
345
+ });
346
+ }
347
+ }
348
+ return { hasExpress: true, appName, routes, globalMiddleware, issues };
349
+ }
350
+ /**
351
+ * Check if a route is intentionally public (login, health, static, etc.).
352
+ */
353
+ function isPublicRoute(path) {
354
+ const publicPatterns = [
355
+ /^\/login$/i,
356
+ /^\/signin$/i,
357
+ /^\/signup$/i,
358
+ /^\/register$/i,
359
+ /^\/auth\//i,
360
+ /^\/health$/i,
361
+ /^\/healthcheck$/i,
362
+ /^\/ping$/i,
363
+ /^\/status$/i,
364
+ /^\/public\//i,
365
+ /^\/static\//i,
366
+ /^\/assets\//i,
367
+ /^\/favicon/i,
368
+ /^\/robots\.txt/i,
369
+ /^\/$/,
370
+ ];
371
+ return publicPatterns.some(p => p.test(path));
372
+ }
373
+ /**
374
+ * Analyze a file on disk. Returns null if not an Express app.
375
+ */
376
+ function analyzeExpressFile(filePath) {
377
+ if (!fs.existsSync(filePath))
378
+ return null;
379
+ const code = fs.readFileSync(filePath, "utf-8");
380
+ // Quick check: does this file import express?
381
+ if (!/\bexpress\b/.test(code) && !/from\s+['"]express['"]/.test(code))
382
+ return null;
383
+ return analyzeExpressApp(code);
384
+ }
385
+ /**
386
+ * Batch analyze multiple files and return summary.
387
+ */
388
+ function analyzeExpressProject(filePaths) {
389
+ let expressApps = 0;
390
+ let totalRoutes = 0;
391
+ const allIssues = [];
392
+ for (const fp of filePaths) {
393
+ const analysis = analyzeExpressFile(fp);
394
+ if (analysis && analysis.hasExpress) {
395
+ expressApps++;
396
+ totalRoutes += analysis.routes.length;
397
+ allIssues.push(...analysis.issues);
398
+ }
399
+ }
400
+ return {
401
+ files: filePaths.length,
402
+ expressApps,
403
+ totalRoutes,
404
+ issues: allIssues,
405
+ };
406
+ }
407
+ /**
408
+ * Format a summary report for CLI output.
409
+ */
410
+ function formatExpressReport(analysis) {
411
+ if (!analysis.hasExpress) {
412
+ return "Not an Express app (no express import found).";
413
+ }
414
+ const lines = [
415
+ `Express App: ${analysis.appName}`,
416
+ `Routes: ${analysis.routes.length}`,
417
+ `Global Middleware: ${analysis.globalMiddleware.length}`,
418
+ `Security Issues: ${analysis.issues.length}`,
419
+ "",
420
+ ];
421
+ if (analysis.issues.length === 0) {
422
+ lines.push("✅ No Express security issues detected.");
423
+ return lines.join("\n");
424
+ }
425
+ const bySeverity = {
426
+ critical: analysis.issues.filter(i => i.severity === "critical"),
427
+ high: analysis.issues.filter(i => i.severity === "high"),
428
+ medium: analysis.issues.filter(i => i.severity === "medium"),
429
+ low: analysis.issues.filter(i => i.severity === "low"),
430
+ };
431
+ for (const [sev, issues] of Object.entries(bySeverity)) {
432
+ if (issues.length === 0)
433
+ continue;
434
+ const emoji = sev === "critical" ? "🔴" : sev === "high" ? "🟠" : sev === "medium" ? "🟡" : "🔵";
435
+ lines.push(`${emoji} ${sev.toUpperCase()} (${issues.length})`);
436
+ for (const issue of issues) {
437
+ lines.push(` [${issue.rule}] ${issue.message}`);
438
+ if (issue.route)
439
+ lines.push(` Route: ${issue.route} (line ${issue.line})`);
440
+ lines.push(` Fix: ${issue.fix}`);
441
+ }
442
+ lines.push("");
443
+ }
444
+ return lines.join("\n");
445
+ }
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for Express Framework Adapter
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const vitest_1 = require("vitest");
7
+ const express_detector_1 = require("./express-detector");
8
+ // ── Test fixtures ──
9
+ const BASIC_EXPRESS_APP = `
10
+ const express = require('express');
11
+ const app = express();
12
+
13
+ app.get('/', (req, res) => { res.send('Hello'); });
14
+ app.listen(3000);
15
+ `;
16
+ const AUTH_APP = `
17
+ const express = require('express');
18
+ const passport = require('passport');
19
+ const app = express();
20
+
21
+ app.use(express.json());
22
+ app.use(passport.initialize());
23
+
24
+ app.post('/login', passport.authenticate('local'), (req, res) => {
25
+ res.json({ token: 'xxx' });
26
+ });
27
+
28
+ app.get('/profile', passport.authenticate('jwt'), (req, res) => {
29
+ res.json(req.user);
30
+ });
31
+
32
+ app.listen(3000);
33
+ `;
34
+ const INSECURE_APP = `
35
+ const express = require('express');
36
+ const app = express();
37
+
38
+ app.get('/api/users', getUsers);
39
+ app.post('/api/users', createUser);
40
+ app.delete('/api/users/:id', deleteUser);
41
+ app.listen(3000);
42
+ `;
43
+ const SECURE_APP = `
44
+ const express = require('express');
45
+ const helmet = require('helmet');
46
+ const cors = require('cors');
47
+ const rateLimit = require('express-rate-limit');
48
+ const session = require('express-session');
49
+ const passport = require('passport');
50
+ const app = express();
51
+
52
+ app.use(helmet());
53
+ app.use(cors({ origin: 'https://example.com' }));
54
+ app.use(express.json());
55
+ app.use(session({
56
+ secret: 'mysecret',
57
+ resave: false,
58
+ saveUninitialized: false,
59
+ cookie: { secure: true, httpOnly: true, sameSite: 'strict' }
60
+ }));
61
+ app.use(passport.initialize());
62
+
63
+ const auth = passport.authenticate('jwt', { session: false });
64
+ const loginLimiter = rateLimit({ windowMs: 60_000, max: 5 });
65
+
66
+ app.post('/login', loginLimiter, passport.authenticate('local'), (req, res) => {
67
+ res.json({ token: 'xxx' });
68
+ });
69
+
70
+ app.get('/profile', auth, (req, res) => {
71
+ res.json(req.user);
72
+ });
73
+
74
+ app.get('/public', (req, res) => {
75
+ res.json({ message: 'public' });
76
+ });
77
+
78
+ app.listen(3000);
79
+ `;
80
+ // ── Tests ──
81
+ (0, vitest_1.describe)("detectExpressApp", () => {
82
+ (0, vitest_1.it)("should detect express() call", () => {
83
+ (0, vitest_1.expect)((0, express_detector_1.detectExpressApp)(BASIC_EXPRESS_APP)).toBe("app");
84
+ });
85
+ (0, vitest_1.it)("should detect express with require", () => {
86
+ // require('express')() creates an app directly — detectExpressApp
87
+ // returns 'app' as default when express is imported but we can't find the variable
88
+ (0, vitest_1.expect)((0, express_detector_1.detectExpressApp)("const server = require('express')();")).toBe("app");
89
+ });
90
+ (0, vitest_1.it)("should return null for non-express code", () => {
91
+ (0, vitest_1.expect)((0, express_detector_1.detectExpressApp)("const http = require('http');")).toBeNull();
92
+ });
93
+ });
94
+ (0, vitest_1.describe)("extractRoutes", () => {
95
+ (0, vitest_1.it)("should extract GET/POST routes", () => {
96
+ const routes = (0, express_detector_1.extractRoutes)(SECURE_APP, "app");
97
+ // SECURE_APP has post('/login'), get('/profile'), get('/public')
98
+ // (the const auth variable is passed by reference, not inline, so not extracted)
99
+ (0, vitest_1.expect)(routes.length).toBeGreaterThanOrEqual(3);
100
+ (0, vitest_1.expect)(routes.some(r => r.path === "/login")).toBe(true);
101
+ (0, vitest_1.expect)(routes.some(r => r.path === "/profile")).toBe(true);
102
+ });
103
+ (0, vitest_1.it)("should identify middleware on routes", () => {
104
+ const routes = (0, express_detector_1.extractRoutes)(SECURE_APP, "app");
105
+ const profileRoute = routes.find(r => r.path === "/profile");
106
+ (0, vitest_1.expect)(profileRoute).toBeDefined();
107
+ (0, vitest_1.expect)(profileRoute.middlewares.length).toBeGreaterThan(0);
108
+ });
109
+ (0, vitest_1.it)("should find routes with no middleware", () => {
110
+ const routes = (0, express_detector_1.extractRoutes)(INSECURE_APP, "app");
111
+ (0, vitest_1.expect)(routes.length).toBeGreaterThan(0);
112
+ // Some routes may have inline handlers that look like middleware
113
+ // The key assertion: at least some routes have no middleware
114
+ const withoutMiddleware = routes.filter(r => r.middlewares.length === 0);
115
+ (0, vitest_1.expect)(withoutMiddleware.length).toBeGreaterThan(0);
116
+ });
117
+ });
118
+ (0, vitest_1.describe)("classifyMiddleware", () => {
119
+ (0, vitest_1.it)("should classify passport.authenticate as auth", () => {
120
+ (0, vitest_1.expect)((0, express_detector_1.classifyMiddleware)("", "passport.authenticate('jwt')")).toBe("auth");
121
+ });
122
+ (0, vitest_1.it)("should classify rateLimit as rate_limit", () => {
123
+ (0, vitest_1.expect)((0, express_detector_1.classifyMiddleware)("", "rateLimit({ windowMs: 60000 })")).toBe("rate_limit");
124
+ });
125
+ (0, vitest_1.it)("should classify helmet as security_header", () => {
126
+ (0, vitest_1.expect)((0, express_detector_1.classifyMiddleware)("", "helmet()")).toBe("security_header");
127
+ });
128
+ });
129
+ (0, vitest_1.describe)("extractGlobalMiddleware", () => {
130
+ (0, vitest_1.it)("should extract app.use middleware", () => {
131
+ const mw = (0, express_detector_1.extractGlobalMiddleware)(SECURE_APP, "app");
132
+ (0, vitest_1.expect)(mw.length).toBeGreaterThanOrEqual(4);
133
+ });
134
+ (0, vitest_1.it)("should classify passport as auth", () => {
135
+ const mw = (0, express_detector_1.extractGlobalMiddleware)(AUTH_APP, "app");
136
+ // passport.initialize() and passport.authenticate() are now both classified as auth
137
+ (0, vitest_1.expect)(mw.some(m => m.type === "auth")).toBe(true);
138
+ });
139
+ });
140
+ (0, vitest_1.describe)("analyzeExpressApp", () => {
141
+ (0, vitest_1.it)("should return hasExpress=false for non-express code", () => {
142
+ const result = (0, express_detector_1.analyzeExpressApp)("const x = 1;");
143
+ (0, vitest_1.expect)(result.hasExpress).toBe(false);
144
+ });
145
+ (0, vitest_1.it)("should detect missing auth as critical issue", () => {
146
+ const result = (0, express_detector_1.analyzeExpressApp)(INSECURE_APP);
147
+ const critical = result.issues.filter(i => i.severity === "critical");
148
+ (0, vitest_1.expect)(critical.length).toBeGreaterThan(0);
149
+ (0, vitest_1.expect)(critical[0].rule).toBe("EXPRESS_NO_AUTH_MIDDLEWARE");
150
+ });
151
+ (0, vitest_1.it)("should detect auth routes without rate limiting", () => {
152
+ const result = (0, express_detector_1.analyzeExpressApp)(AUTH_APP);
153
+ const rateIssues = result.issues.filter(i => i.rule === "EXPRESS_AUTH_NO_RATE_LIMIT");
154
+ (0, vitest_1.expect)(rateIssues.length).toBeGreaterThan(0);
155
+ });
156
+ (0, vitest_1.it)("should detect missing helmet", () => {
157
+ const result = (0, express_detector_1.analyzeExpressApp)(INSECURE_APP);
158
+ (0, vitest_1.expect)(result.issues.some(i => i.rule === "EXPRESS_NO_HELMET")).toBe(true);
159
+ });
160
+ (0, vitest_1.it)("should detect missing CORS", () => {
161
+ const result = (0, express_detector_1.analyzeExpressApp)(INSECURE_APP);
162
+ (0, vitest_1.expect)(result.issues.some(i => i.rule === "EXPRESS_NO_CORS_CONFIG")).toBe(true);
163
+ });
164
+ (0, vitest_1.it)("should flag no input validation on POST routes", () => {
165
+ const result = (0, express_detector_1.analyzeExpressApp)(INSECURE_APP);
166
+ (0, vitest_1.expect)(result.issues.some(i => i.rule === "EXPRESS_NO_INPUT_VALIDATION")).toBe(true);
167
+ });
168
+ (0, vitest_1.it)("should flag insecure session", () => {
169
+ const insecureSession = `
170
+ const app = require('express')();
171
+ app.use(require('express-session')({ secret: 'x', cookie: {} }));
172
+ app.listen(3000);
173
+ `;
174
+ const result = (0, express_detector_1.analyzeExpressApp)(insecureSession);
175
+ (0, vitest_1.expect)(result.issues.some(i => i.rule === "EXPRESS_SESSION_INSECURE")).toBe(true);
176
+ });
177
+ (0, vitest_1.it)("should PASS a fully secured Express app", () => {
178
+ const result = (0, express_detector_1.analyzeExpressApp)(SECURE_APP);
179
+ const critical = result.issues.filter(i => i.severity === "critical");
180
+ // /public route without explicit auth will trigger EXPRESS_ROUTE_MISSING_AUTH (high)
181
+ // — that's correct behavior; public routes should be explicitly marked.
182
+ // The KEY assertion: no CRITICAL issues (critical = BLOCKED decision)
183
+ (0, vitest_1.expect)(critical.length).toBe(0);
184
+ });
185
+ (0, vitest_1.it)("should not flag public routes for auth", () => {
186
+ const publicApp = `
187
+ const app = require('express')();
188
+ app.use(require('passport').initialize());
189
+ app.get('/health', (req, res) => { res.send('ok'); });
190
+ app.get('/login', (req, res) => { res.send('login'); });
191
+ app.listen(3000);
192
+ `;
193
+ const result = (0, express_detector_1.analyzeExpressApp)(publicApp);
194
+ const missingAuth = result.issues.filter(i => i.rule === "EXPRESS_ROUTE_MISSING_AUTH");
195
+ // /health and /login are public, should not be flagged
196
+ (0, vitest_1.expect)(missingAuth.length).toBe(0);
197
+ });
198
+ });
199
+ (0, vitest_1.describe)("formatExpressReport", () => {
200
+ (0, vitest_1.it)("should return a human-readable report", () => {
201
+ const analysis = (0, express_detector_1.analyzeExpressApp)(INSECURE_APP);
202
+ const report = (0, express_detector_1.formatExpressReport)(analysis);
203
+ (0, vitest_1.expect)(report).toContain("Express App:");
204
+ (0, vitest_1.expect)(report).toContain("Security Issues:");
205
+ });
206
+ });
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * Progmune Framework Adapters
4
+ *
5
+ * Framework-specific protocol detection that complements the generic
6
+ * \w* regex patterns in protocol-detector.ts.
7
+ *
8
+ * Each adapter knows the API surface of a specific framework:
9
+ * middleware chains, route handlers, dependency injection, guards, etc.
10
+ *
11
+ * Current: Express.js (first adapter — broke the 0/13 gap)
12
+ * Planned: Next.js, NestJS, Fastify, FastAPI, Django
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.generateVersionAwarenessReport = exports.checkFileRename = exports.checkFrameworkConventions = exports.detectFrameworks = exports.formatExpressReport = exports.classifyMiddleware = exports.extractGlobalMiddleware = exports.extractRoutes = exports.detectExpressApp = exports.analyzeExpressProject = exports.analyzeExpressFile = exports.analyzeExpressApp = void 0;
16
+ var express_detector_1 = require("./express-detector");
17
+ Object.defineProperty(exports, "analyzeExpressApp", { enumerable: true, get: function () { return express_detector_1.analyzeExpressApp; } });
18
+ Object.defineProperty(exports, "analyzeExpressFile", { enumerable: true, get: function () { return express_detector_1.analyzeExpressFile; } });
19
+ Object.defineProperty(exports, "analyzeExpressProject", { enumerable: true, get: function () { return express_detector_1.analyzeExpressProject; } });
20
+ Object.defineProperty(exports, "detectExpressApp", { enumerable: true, get: function () { return express_detector_1.detectExpressApp; } });
21
+ Object.defineProperty(exports, "extractRoutes", { enumerable: true, get: function () { return express_detector_1.extractRoutes; } });
22
+ Object.defineProperty(exports, "extractGlobalMiddleware", { enumerable: true, get: function () { return express_detector_1.extractGlobalMiddleware; } });
23
+ Object.defineProperty(exports, "classifyMiddleware", { enumerable: true, get: function () { return express_detector_1.classifyMiddleware; } });
24
+ Object.defineProperty(exports, "formatExpressReport", { enumerable: true, get: function () { return express_detector_1.formatExpressReport; } });
25
+ // ── Framework Version-Aware Governance ──
26
+ var version_awareness_1 = require("./version-awareness");
27
+ Object.defineProperty(exports, "detectFrameworks", { enumerable: true, get: function () { return version_awareness_1.detectFrameworks; } });
28
+ Object.defineProperty(exports, "checkFrameworkConventions", { enumerable: true, get: function () { return version_awareness_1.checkFrameworkConventions; } });
29
+ Object.defineProperty(exports, "checkFileRename", { enumerable: true, get: function () { return version_awareness_1.checkFileRename; } });
30
+ Object.defineProperty(exports, "generateVersionAwarenessReport", { enumerable: true, get: function () { return version_awareness_1.generateVersionAwarenessReport; } });