vaspera 2.13.0 → 2.15.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 (300) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +15 -2
  3. package/dist/__tests__/antagonist-integration.test.d.ts +6 -0
  4. package/dist/__tests__/antagonist-integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/antagonist-integration.test.js +239 -0
  6. package/dist/__tests__/antagonist-integration.test.js.map +1 -0
  7. package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts +2 -0
  8. package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts.map +1 -0
  9. package/dist/__tests__/certification/agent-certificate-e2e.test.js +90 -0
  10. package/dist/__tests__/certification/agent-certificate-e2e.test.js.map +1 -0
  11. package/dist/__tests__/certification/agent-certificate-map.test.d.ts +2 -0
  12. package/dist/__tests__/certification/agent-certificate-map.test.d.ts.map +1 -0
  13. package/dist/__tests__/certification/agent-certificate-map.test.js +107 -0
  14. package/dist/__tests__/certification/agent-certificate-map.test.js.map +1 -0
  15. package/dist/__tests__/certification/agent-certificate.test.d.ts +2 -0
  16. package/dist/__tests__/certification/agent-certificate.test.d.ts.map +1 -0
  17. package/dist/__tests__/certification/agent-certificate.test.js +78 -0
  18. package/dist/__tests__/certification/agent-certificate.test.js.map +1 -0
  19. package/dist/__tests__/certification/verify-endpoint.test.d.ts +2 -0
  20. package/dist/__tests__/certification/verify-endpoint.test.d.ts.map +1 -0
  21. package/dist/__tests__/certification/verify-endpoint.test.js +81 -0
  22. package/dist/__tests__/certification/verify-endpoint.test.js.map +1 -0
  23. package/dist/__tests__/compliance/ai-frameworks.test.d.ts +2 -0
  24. package/dist/__tests__/compliance/ai-frameworks.test.d.ts.map +1 -0
  25. package/dist/__tests__/compliance/ai-frameworks.test.js +87 -0
  26. package/dist/__tests__/compliance/ai-frameworks.test.js.map +1 -0
  27. package/dist/__tests__/eval/llm-analyzer.test.d.ts +2 -0
  28. package/dist/__tests__/eval/llm-analyzer.test.d.ts.map +1 -0
  29. package/dist/__tests__/eval/llm-analyzer.test.js +93 -0
  30. package/dist/__tests__/eval/llm-analyzer.test.js.map +1 -0
  31. package/dist/__tests__/eval/redteam-harness.test.d.ts +2 -0
  32. package/dist/__tests__/eval/redteam-harness.test.d.ts.map +1 -0
  33. package/dist/__tests__/eval/redteam-harness.test.js +136 -0
  34. package/dist/__tests__/eval/redteam-harness.test.js.map +1 -0
  35. package/dist/__tests__/evidence/evidence.test.d.ts +2 -0
  36. package/dist/__tests__/evidence/evidence.test.d.ts.map +1 -0
  37. package/dist/__tests__/evidence/evidence.test.js +240 -0
  38. package/dist/__tests__/evidence/evidence.test.js.map +1 -0
  39. package/dist/__tests__/history/decisions.test.d.ts +2 -0
  40. package/dist/__tests__/history/decisions.test.d.ts.map +1 -0
  41. package/dist/__tests__/history/decisions.test.js +54 -0
  42. package/dist/__tests__/history/decisions.test.js.map +1 -0
  43. package/dist/__tests__/http-auth.test.d.ts +2 -0
  44. package/dist/__tests__/http-auth.test.d.ts.map +1 -0
  45. package/dist/__tests__/http-auth.test.js +55 -0
  46. package/dist/__tests__/http-auth.test.js.map +1 -0
  47. package/dist/__tests__/http-policy.test.d.ts +2 -0
  48. package/dist/__tests__/http-policy.test.d.ts.map +1 -0
  49. package/dist/__tests__/http-policy.test.js +69 -0
  50. package/dist/__tests__/http-policy.test.js.map +1 -0
  51. package/dist/__tests__/http-server-transport.test.d.ts +2 -0
  52. package/dist/__tests__/http-server-transport.test.d.ts.map +1 -0
  53. package/dist/__tests__/http-server-transport.test.js +132 -0
  54. package/dist/__tests__/http-server-transport.test.js.map +1 -0
  55. package/dist/__tests__/integration/destructive-guards.test.d.ts +2 -0
  56. package/dist/__tests__/integration/destructive-guards.test.d.ts.map +1 -0
  57. package/dist/__tests__/integration/destructive-guards.test.js +49 -0
  58. package/dist/__tests__/integration/destructive-guards.test.js.map +1 -0
  59. package/dist/__tests__/logger-redaction.test.d.ts +2 -0
  60. package/dist/__tests__/logger-redaction.test.d.ts.map +1 -0
  61. package/dist/__tests__/logger-redaction.test.js +74 -0
  62. package/dist/__tests__/logger-redaction.test.js.map +1 -0
  63. package/dist/__tests__/manifest-schema.test.d.ts +2 -0
  64. package/dist/__tests__/manifest-schema.test.d.ts.map +1 -0
  65. package/dist/__tests__/manifest-schema.test.js +43 -0
  66. package/dist/__tests__/manifest-schema.test.js.map +1 -0
  67. package/dist/__tests__/scanners/builtin-rules.test.d.ts +2 -0
  68. package/dist/__tests__/scanners/builtin-rules.test.d.ts.map +1 -0
  69. package/dist/__tests__/scanners/builtin-rules.test.js +51 -0
  70. package/dist/__tests__/scanners/builtin-rules.test.js.map +1 -0
  71. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +13 -1
  72. package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -1
  73. package/dist/__tests__/tool-guard.test.d.ts +2 -0
  74. package/dist/__tests__/tool-guard.test.d.ts.map +1 -0
  75. package/dist/__tests__/tool-guard.test.js +97 -0
  76. package/dist/__tests__/tool-guard.test.js.map +1 -0
  77. package/dist/__tests__/util/contained-file.test.d.ts +2 -0
  78. package/dist/__tests__/util/contained-file.test.d.ts.map +1 -0
  79. package/dist/__tests__/util/contained-file.test.js +78 -0
  80. package/dist/__tests__/util/contained-file.test.js.map +1 -0
  81. package/dist/__tests__/util/subprocess.test.d.ts +2 -0
  82. package/dist/__tests__/util/subprocess.test.d.ts.map +1 -0
  83. package/dist/__tests__/util/subprocess.test.js +48 -0
  84. package/dist/__tests__/util/subprocess.test.js.map +1 -0
  85. package/dist/action/diff-mode.d.ts.map +1 -1
  86. package/dist/action/diff-mode.js +31 -12
  87. package/dist/action/diff-mode.js.map +1 -1
  88. package/dist/agents/antagonist/challenger.d.ts +46 -0
  89. package/dist/agents/antagonist/challenger.d.ts.map +1 -0
  90. package/dist/agents/antagonist/challenger.js +257 -0
  91. package/dist/agents/antagonist/challenger.js.map +1 -0
  92. package/dist/agents/antagonist/index.d.ts +31 -0
  93. package/dist/agents/antagonist/index.d.ts.map +1 -0
  94. package/dist/agents/antagonist/index.js +175 -0
  95. package/dist/agents/antagonist/index.js.map +1 -0
  96. package/dist/agents/antagonist/prioritizer.d.ts +27 -0
  97. package/dist/agents/antagonist/prioritizer.d.ts.map +1 -0
  98. package/dist/agents/antagonist/prioritizer.js +181 -0
  99. package/dist/agents/antagonist/prioritizer.js.map +1 -0
  100. package/dist/agents/antagonist/prompts.d.ts +12 -0
  101. package/dist/agents/antagonist/prompts.d.ts.map +1 -0
  102. package/dist/agents/antagonist/prompts.js +155 -0
  103. package/dist/agents/antagonist/prompts.js.map +1 -0
  104. package/dist/agents/antagonist/synthesizer.d.ts +34 -0
  105. package/dist/agents/antagonist/synthesizer.d.ts.map +1 -0
  106. package/dist/agents/antagonist/synthesizer.js +451 -0
  107. package/dist/agents/antagonist/synthesizer.js.map +1 -0
  108. package/dist/agents/antagonist/types.d.ts +145 -0
  109. package/dist/agents/antagonist/types.d.ts.map +1 -0
  110. package/dist/agents/antagonist/types.js +63 -0
  111. package/dist/agents/antagonist/types.js.map +1 -0
  112. package/dist/agents/index.d.ts +1 -0
  113. package/dist/agents/index.d.ts.map +1 -1
  114. package/dist/agents/index.js +2 -0
  115. package/dist/agents/index.js.map +1 -1
  116. package/dist/certification/agent-certificate-map.d.ts +51 -0
  117. package/dist/certification/agent-certificate-map.d.ts.map +1 -0
  118. package/dist/certification/agent-certificate-map.js +265 -0
  119. package/dist/certification/agent-certificate-map.js.map +1 -0
  120. package/dist/certification/agent-certificate-sample.d.ts +25 -0
  121. package/dist/certification/agent-certificate-sample.d.ts.map +1 -0
  122. package/dist/certification/agent-certificate-sample.js +207 -0
  123. package/dist/certification/agent-certificate-sample.js.map +1 -0
  124. package/dist/certification/agent-certificate.d.ts +1981 -0
  125. package/dist/certification/agent-certificate.d.ts.map +1 -0
  126. package/dist/certification/agent-certificate.js +309 -0
  127. package/dist/certification/agent-certificate.js.map +1 -0
  128. package/dist/certification/autofix.d.ts.map +1 -1
  129. package/dist/certification/autofix.js +5 -3
  130. package/dist/certification/autofix.js.map +1 -1
  131. package/dist/certification/consensus.test.js +2 -0
  132. package/dist/certification/consensus.test.js.map +1 -1
  133. package/dist/certification/store.d.ts.map +1 -1
  134. package/dist/certification/store.js +11 -3
  135. package/dist/certification/store.js.map +1 -1
  136. package/dist/certification/types.d.ts +1 -1
  137. package/dist/certification/types.d.ts.map +1 -1
  138. package/dist/certification/types.js +2 -0
  139. package/dist/certification/types.js.map +1 -1
  140. package/dist/certification/verify-endpoint.d.ts +48 -0
  141. package/dist/certification/verify-endpoint.d.ts.map +1 -0
  142. package/dist/certification/verify-endpoint.js +79 -0
  143. package/dist/certification/verify-endpoint.js.map +1 -0
  144. package/dist/compliance/index.d.ts +2 -0
  145. package/dist/compliance/index.d.ts.map +1 -1
  146. package/dist/compliance/index.js +4 -0
  147. package/dist/compliance/index.js.map +1 -1
  148. package/dist/compliance/iso42001.d.ts +21 -0
  149. package/dist/compliance/iso42001.d.ts.map +1 -0
  150. package/dist/compliance/iso42001.js +160 -0
  151. package/dist/compliance/iso42001.js.map +1 -0
  152. package/dist/compliance/mapper.d.ts.map +1 -1
  153. package/dist/compliance/mapper.js +12 -0
  154. package/dist/compliance/mapper.js.map +1 -1
  155. package/dist/compliance/nist-ai-rmf.d.ts +20 -0
  156. package/dist/compliance/nist-ai-rmf.d.ts.map +1 -0
  157. package/dist/compliance/nist-ai-rmf.js +140 -0
  158. package/dist/compliance/nist-ai-rmf.js.map +1 -0
  159. package/dist/config/flags.d.ts +4 -4
  160. package/dist/eval/fixtures.d.ts.map +1 -1
  161. package/dist/eval/fixtures.js +161 -119
  162. package/dist/eval/fixtures.js.map +1 -1
  163. package/dist/eval/fixtures.test.js +4 -2
  164. package/dist/eval/fixtures.test.js.map +1 -1
  165. package/dist/eval/llm-analyzer.d.ts +40 -0
  166. package/dist/eval/llm-analyzer.d.ts.map +1 -0
  167. package/dist/eval/llm-analyzer.js +154 -0
  168. package/dist/eval/llm-analyzer.js.map +1 -0
  169. package/dist/eval/redteam-harness.d.ts +95 -0
  170. package/dist/eval/redteam-harness.d.ts.map +1 -0
  171. package/dist/eval/redteam-harness.js +137 -0
  172. package/dist/eval/redteam-harness.js.map +1 -0
  173. package/dist/evidence/collector.d.ts.map +1 -1
  174. package/dist/evidence/collector.js +21 -1
  175. package/dist/evidence/collector.js.map +1 -1
  176. package/dist/evidence/store.d.ts.map +1 -1
  177. package/dist/evidence/store.js +29 -5
  178. package/dist/evidence/store.js.map +1 -1
  179. package/dist/evidence/types.d.ts +16 -9
  180. package/dist/evidence/types.d.ts.map +1 -1
  181. package/dist/history/decisions.d.ts +63 -0
  182. package/dist/history/decisions.d.ts.map +1 -0
  183. package/dist/history/decisions.js +60 -0
  184. package/dist/history/decisions.js.map +1 -0
  185. package/dist/history/index.d.ts +2 -0
  186. package/dist/history/index.d.ts.map +1 -1
  187. package/dist/history/index.js +2 -0
  188. package/dist/history/index.js.map +1 -1
  189. package/dist/history/types.d.ts +34 -5
  190. package/dist/history/types.d.ts.map +1 -1
  191. package/dist/history/types.js +2 -0
  192. package/dist/history/types.js.map +1 -1
  193. package/dist/http-auth.d.ts +22 -0
  194. package/dist/http-auth.d.ts.map +1 -0
  195. package/dist/http-auth.js +58 -0
  196. package/dist/http-auth.js.map +1 -0
  197. package/dist/http-policy.d.ts +30 -0
  198. package/dist/http-policy.d.ts.map +1 -0
  199. package/dist/http-policy.js +54 -0
  200. package/dist/http-policy.js.map +1 -0
  201. package/dist/http-server.js +195 -12
  202. package/dist/http-server.js.map +1 -1
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +411 -15
  205. package/dist/index.js.map +1 -1
  206. package/dist/logger.d.ts.map +1 -1
  207. package/dist/logger.js +56 -2
  208. package/dist/logger.js.map +1 -1
  209. package/dist/plugins/types.d.ts +2 -2
  210. package/dist/sbom/provenance.test.js +2 -2
  211. package/dist/sbom/provenance.test.js.map +1 -1
  212. package/dist/sbom/signing.d.ts.map +1 -1
  213. package/dist/sbom/signing.js +5 -3
  214. package/dist/sbom/signing.js.map +1 -1
  215. package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
  216. package/dist/scanners/agent/prompt-injection-fuzzer.js +26 -0
  217. package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
  218. package/dist/scanners/agent/types.d.ts +10 -10
  219. package/dist/scanners/bandit.d.ts.map +1 -1
  220. package/dist/scanners/bandit.js +35 -29
  221. package/dist/scanners/bandit.js.map +1 -1
  222. package/dist/scanners/binary-analysis.d.ts.map +1 -1
  223. package/dist/scanners/binary-analysis.js +24 -49
  224. package/dist/scanners/binary-analysis.js.map +1 -1
  225. package/dist/scanners/brakeman.d.ts.map +1 -1
  226. package/dist/scanners/brakeman.js +19 -33
  227. package/dist/scanners/brakeman.js.map +1 -1
  228. package/dist/scanners/builtin-rules.d.ts +24 -0
  229. package/dist/scanners/builtin-rules.d.ts.map +1 -0
  230. package/dist/scanners/builtin-rules.js +175 -0
  231. package/dist/scanners/builtin-rules.js.map +1 -0
  232. package/dist/scanners/dast.d.ts.map +1 -1
  233. package/dist/scanners/dast.js +24 -34
  234. package/dist/scanners/dast.js.map +1 -1
  235. package/dist/scanners/deploy/types.d.ts +6 -6
  236. package/dist/scanners/eslint.d.ts.map +1 -1
  237. package/dist/scanners/eslint.js +15 -24
  238. package/dist/scanners/eslint.js.map +1 -1
  239. package/dist/scanners/gosec.d.ts.map +1 -1
  240. package/dist/scanners/gosec.js +14 -62
  241. package/dist/scanners/gosec.js.map +1 -1
  242. package/dist/scanners/index.d.ts.map +1 -1
  243. package/dist/scanners/index.js +38 -7
  244. package/dist/scanners/index.js.map +1 -1
  245. package/dist/scanners/memory-safety.d.ts.map +1 -1
  246. package/dist/scanners/memory-safety.js +27 -28
  247. package/dist/scanners/memory-safety.js.map +1 -1
  248. package/dist/scanners/openapi.d.ts.map +1 -1
  249. package/dist/scanners/openapi.js +14 -22
  250. package/dist/scanners/openapi.js.map +1 -1
  251. package/dist/scanners/race-condition.d.ts.map +1 -1
  252. package/dist/scanners/race-condition.js +17 -16
  253. package/dist/scanners/race-condition.js.map +1 -1
  254. package/dist/scanners/runtime/types.d.ts +4 -4
  255. package/dist/scanners/rust.d.ts.map +1 -1
  256. package/dist/scanners/rust.js +38 -37
  257. package/dist/scanners/rust.js.map +1 -1
  258. package/dist/scanners/scale/types.d.ts +16 -16
  259. package/dist/scanners/secrets.d.ts.map +1 -1
  260. package/dist/scanners/secrets.js +66 -78
  261. package/dist/scanners/secrets.js.map +1 -1
  262. package/dist/scanners/semgrep.d.ts +2 -0
  263. package/dist/scanners/semgrep.d.ts.map +1 -1
  264. package/dist/scanners/semgrep.js +12 -0
  265. package/dist/scanners/semgrep.js.map +1 -1
  266. package/dist/scanners/terraform.d.ts.map +1 -1
  267. package/dist/scanners/terraform.js +47 -40
  268. package/dist/scanners/terraform.js.map +1 -1
  269. package/dist/scanners/trivy.d.ts.map +1 -1
  270. package/dist/scanners/trivy.js +38 -30
  271. package/dist/scanners/trivy.js.map +1 -1
  272. package/dist/tool-guard.d.ts +40 -0
  273. package/dist/tool-guard.d.ts.map +1 -0
  274. package/dist/tool-guard.js +55 -0
  275. package/dist/tool-guard.js.map +1 -0
  276. package/dist/util/index.d.ts +2 -1
  277. package/dist/util/index.d.ts.map +1 -1
  278. package/dist/util/index.js +2 -1
  279. package/dist/util/index.js.map +1 -1
  280. package/dist/util/paths.d.ts +20 -3
  281. package/dist/util/paths.d.ts.map +1 -1
  282. package/dist/util/paths.js +84 -4
  283. package/dist/util/paths.js.map +1 -1
  284. package/dist/util/subprocess.d.ts +51 -0
  285. package/dist/util/subprocess.d.ts.map +1 -0
  286. package/dist/util/subprocess.js +77 -0
  287. package/dist/util/subprocess.js.map +1 -0
  288. package/package.json +12 -2
  289. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +0 -28
  290. package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +0 -1
  291. package/dist/eval/fixtures/healthcare/audit-gaps.js +0 -90
  292. package/dist/eval/fixtures/healthcare/audit-gaps.js.map +0 -1
  293. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +0 -31
  294. package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +0 -1
  295. package/dist/eval/fixtures/healthcare/consent-bypass.js +0 -61
  296. package/dist/eval/fixtures/healthcare/consent-bypass.js.map +0 -1
  297. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +0 -24
  298. package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +0 -1
  299. package/dist/eval/fixtures/healthcare/phi-in-logs.js +0 -41
  300. package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +0 -1
@@ -21,6 +21,13 @@ export class PathValidationError extends Error {
21
21
  this.name = "PathValidationError";
22
22
  }
23
23
  }
24
+ /**
25
+ * Options for path validation
26
+ */
27
+ /** Segment-aware containment: "/base" must not match "/base-evil". */
28
+ function isWithin(target, base) {
29
+ return target === base || target.startsWith(base + path.sep);
30
+ }
24
31
  /**
25
32
  * Validate a project path for security
26
33
  *
@@ -59,7 +66,7 @@ export async function validateProjectPath(projectPath, options = {}) {
59
66
  // If basePath is specified, ensure symlink target is within it
60
67
  if (basePath) {
61
68
  const resolvedBase = path.resolve(basePath);
62
- if (!realPath.startsWith(resolvedBase)) {
69
+ if (!isWithin(realPath, resolvedBase)) {
63
70
  throw new PathValidationError(`Symlink escapes base directory: ${projectPath} -> ${realPath}`, projectPath, "symlink_escape");
64
71
  }
65
72
  }
@@ -75,10 +82,13 @@ export async function validateProjectPath(projectPath, options = {}) {
75
82
  if (requireDirectory && !lstats.isDirectory()) {
76
83
  throw new PathValidationError(`Path is not a directory: ${projectPath}`, projectPath, "not_directory");
77
84
  }
78
- // If basePath is specified, ensure the path is within it
85
+ // If basePath is specified, ensure the path is within it. Compare
86
+ // *real* paths so a symlinked ancestor (e.g. /base/link/sub where
87
+ // /base/link -> /etc) cannot escape via a lexical-only check.
79
88
  if (basePath) {
80
- const resolvedBase = path.resolve(basePath);
81
- if (!resolvedPath.startsWith(resolvedBase)) {
89
+ const realBase = await realpath(path.resolve(basePath));
90
+ const realTarget = await realpath(resolvedPath);
91
+ if (!isWithin(realTarget, realBase)) {
82
92
  throw new PathValidationError(`Path is outside base directory: ${projectPath}`, projectPath, "path_traversal");
83
93
  }
84
94
  }
@@ -114,6 +124,76 @@ export async function isPathSafe(projectPath, options = {}) {
114
124
  return false;
115
125
  }
116
126
  }
127
+ /**
128
+ * Resolve a relative file path inside a project tree, rejecting escapes.
129
+ * For paths that originate from untrusted sources (scanner output, agent
130
+ * findings): `../` sequences, absolute paths, and in-tree symlinks
131
+ * pointing outside the project are all refused.
132
+ *
133
+ * @returns The real (symlink-resolved) absolute path of the file
134
+ * @throws PathValidationError if the path escapes the project tree
135
+ */
136
+ export async function resolveContainedFile(projectPath, relFile) {
137
+ const root = await realpath(projectPath);
138
+ const contained = (p) => p === root || p.startsWith(root + path.sep);
139
+ const target = path.resolve(root, relFile);
140
+ if (!contained(target)) {
141
+ throw new PathValidationError(`File path escapes project tree: ${relFile}`, relFile, "path_traversal");
142
+ }
143
+ const real = await realpath(target);
144
+ if (!contained(real)) {
145
+ throw new PathValidationError(`Symlinked file escapes project tree: ${relFile}`, relFile, "symlink_escape");
146
+ }
147
+ return real;
148
+ }
149
+ /**
150
+ * Resolve a relative *write* target inside a project tree, rejecting
151
+ * escapes — like resolveContainedFile but for a file that may not exist
152
+ * yet (the parent directory must exist and is symlink-resolved).
153
+ * For untrusted output paths (e.g. an `output_file` tool argument).
154
+ *
155
+ * @returns The absolute path to write to, contained within the tree
156
+ * @throws PathValidationError if the path escapes the project tree
157
+ */
158
+ export async function resolveContainedWritePath(projectPath, relFile) {
159
+ const root = await realpath(projectPath);
160
+ const contained = (p) => p === root || p.startsWith(root + path.sep);
161
+ const target = path.resolve(root, relFile);
162
+ if (!contained(target)) {
163
+ throw new PathValidationError(`File path escapes project tree: ${relFile}`, relFile, "path_traversal");
164
+ }
165
+ // The leaf (and possibly intermediate dirs) may not exist yet. Resolve
166
+ // the nearest existing ancestor through symlinks so a symlinked
167
+ // directory inside the tree cannot redirect the write outside it, then
168
+ // re-attach the not-yet-existing remainder.
169
+ let ancestor = path.dirname(target);
170
+ while (true) {
171
+ try {
172
+ const realAncestor = await realpath(ancestor);
173
+ if (!contained(realAncestor)) {
174
+ throw new PathValidationError(`Symlinked directory escapes project tree: ${relFile}`, relFile, "symlink_escape");
175
+ }
176
+ const remainder = path.relative(ancestor, target);
177
+ const finalPath = path.join(realAncestor, remainder);
178
+ if (!contained(finalPath)) {
179
+ throw new PathValidationError(`File path escapes project tree: ${relFile}`, relFile, "path_traversal");
180
+ }
181
+ return finalPath;
182
+ }
183
+ catch (error) {
184
+ if (error instanceof PathValidationError)
185
+ throw error;
186
+ if (error.code !== "ENOENT")
187
+ throw error;
188
+ const parent = path.dirname(ancestor);
189
+ if (parent === ancestor) {
190
+ // Reached the filesystem root without an existing ancestor.
191
+ throw new PathValidationError(`Cannot resolve write path: ${relFile}`, relFile, "invalid_path");
192
+ }
193
+ ancestor = parent;
194
+ }
195
+ }
196
+ }
117
197
  /**
118
198
  * Sanitize a path for use in error messages (remove sensitive info)
119
199
  */
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/util/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Safe subprocess execution for scanner adapters.
3
+ *
4
+ * Wraps execFile (never a shell) so argument values — project paths,
5
+ * target URLs, config file paths — can never be interpreted as shell
6
+ * syntax. This is the only sanctioned way to invoke external scanner
7
+ * binaries (CONSTITUTION: "No string-concat shell commands").
8
+ *
9
+ * @module util/subprocess
10
+ */
11
+ export declare class CommandError extends Error {
12
+ readonly binary: string;
13
+ readonly args: string[];
14
+ readonly exitCode: number | null;
15
+ readonly stdout: string;
16
+ readonly stderr: string;
17
+ readonly cause?: Error | undefined;
18
+ constructor(message: string, binary: string, args: string[], exitCode: number | null, stdout: string, stderr: string, cause?: Error | undefined);
19
+ }
20
+ export interface RunCommandOptions {
21
+ /** Milliseconds before the process is killed. Default 120000. */
22
+ timeout?: number;
23
+ /** Max bytes captured per stream. Default 10MB. */
24
+ maxBuffer?: number;
25
+ cwd?: string;
26
+ env?: NodeJS.ProcessEnv;
27
+ /**
28
+ * Scanners conventionally exit non-zero when findings exist (e.g.
29
+ * bandit/semgrep exit 1). When true (default), a non-zero exit that
30
+ * still produced stdout resolves normally instead of throwing —
31
+ * matching the historical execAsync `.catch(e => e.stdout)` pattern.
32
+ */
33
+ tolerateExitWithOutput?: boolean;
34
+ }
35
+ export interface RunCommandResult {
36
+ stdout: string;
37
+ stderr: string;
38
+ exitCode: number;
39
+ }
40
+ /**
41
+ * Run a binary with discrete argv entries. No shell is ever invoked,
42
+ * so callers MUST NOT pre-quote values or pass shell syntax
43
+ * (pipes, redirects, `&&`) — restructure such logic in JS instead.
44
+ */
45
+ export declare function runCommand(binary: string, args: string[], options?: RunCommandOptions): Promise<RunCommandResult>;
46
+ /**
47
+ * Probe for a scanner binary by running it with a version-style flag.
48
+ * Returns the first line of stdout (trimmed) or null when unavailable.
49
+ */
50
+ export declare function probeBinary(binary: string, args?: string[], timeout?: number): Promise<string | null>;
51
+ //# sourceMappingURL=subprocess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/util/subprocess.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,qBAAa,YAAa,SAAQ,KAAK;aAGnB,MAAM,EAAE,MAAM;aACd,IAAI,EAAE,MAAM,EAAE;aACd,QAAQ,EAAE,MAAM,GAAG,IAAI;aACvB,MAAM,EAAE,MAAM;aACd,MAAM,EAAE,MAAM;aACd,KAAK,CAAC,EAAE,KAAK;gBAN7B,OAAO,EAAE,MAAM,EACC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAqD3B;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,MAAM,EAAkB,EAC9B,OAAO,SAAO,GACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAUxB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Safe subprocess execution for scanner adapters.
3
+ *
4
+ * Wraps execFile (never a shell) so argument values — project paths,
5
+ * target URLs, config file paths — can never be interpreted as shell
6
+ * syntax. This is the only sanctioned way to invoke external scanner
7
+ * binaries (CONSTITUTION: "No string-concat shell commands").
8
+ *
9
+ * @module util/subprocess
10
+ */
11
+ import { execFile } from "child_process";
12
+ export class CommandError extends Error {
13
+ binary;
14
+ args;
15
+ exitCode;
16
+ stdout;
17
+ stderr;
18
+ cause;
19
+ constructor(message, binary, args, exitCode, stdout, stderr, cause) {
20
+ super(message);
21
+ this.binary = binary;
22
+ this.args = args;
23
+ this.exitCode = exitCode;
24
+ this.stdout = stdout;
25
+ this.stderr = stderr;
26
+ this.cause = cause;
27
+ this.name = "CommandError";
28
+ }
29
+ }
30
+ /**
31
+ * Run a binary with discrete argv entries. No shell is ever invoked,
32
+ * so callers MUST NOT pre-quote values or pass shell syntax
33
+ * (pipes, redirects, `&&`) — restructure such logic in JS instead.
34
+ */
35
+ export async function runCommand(binary, args, options = {}) {
36
+ const { timeout = 120000, maxBuffer = 10 * 1024 * 1024, cwd, env, tolerateExitWithOutput = true, } = options;
37
+ return new Promise((resolve, reject) => {
38
+ execFile(binary, args, { timeout, maxBuffer, cwd, env, encoding: "utf8" }, (error, stdout, stderr) => {
39
+ if (!error) {
40
+ resolve({ stdout, stderr, exitCode: 0 });
41
+ return;
42
+ }
43
+ const exitCode = typeof error.code === "number" ? error.code : null;
44
+ if (tolerateExitWithOutput &&
45
+ exitCode !== null &&
46
+ !error.killed &&
47
+ stdout &&
48
+ stdout.length > 0) {
49
+ resolve({ stdout, stderr: stderr || "", exitCode });
50
+ return;
51
+ }
52
+ const reason = error.killed
53
+ ? `timed out after ${timeout}ms`
54
+ : exitCode !== null
55
+ ? `exited with code ${exitCode}`
56
+ : `failed to start (${error.code ?? error.message})`;
57
+ reject(new CommandError(`${binary} ${reason}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`, binary, args, exitCode, stdout ?? "", stderr ?? "", error));
58
+ });
59
+ });
60
+ }
61
+ /**
62
+ * Probe for a scanner binary by running it with a version-style flag.
63
+ * Returns the first line of stdout (trimmed) or null when unavailable.
64
+ */
65
+ export async function probeBinary(binary, args = ["--version"], timeout = 5000) {
66
+ try {
67
+ const { stdout } = await runCommand(binary, args, {
68
+ timeout,
69
+ tolerateExitWithOutput: false,
70
+ });
71
+ return stdout.trim().split("\n")[0] ?? null;
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ }
77
+ //# sourceMappingURL=subprocess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subprocess.js","sourceRoot":"","sources":["../../src/util/subprocess.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaspera",
3
- "version": "2.13.0",
3
+ "version": "2.15.0",
4
4
  "packageManager": "npm@10.2.4",
5
5
  "files": [
6
6
  "dist",
@@ -38,7 +38,7 @@
38
38
  "claude"
39
39
  ],
40
40
  "scripts": {
41
- "build": "npm run generate:manifest && tsc",
41
+ "build": "tsc && npm run generate:manifest",
42
42
  "build:mcp": "tsc",
43
43
  "start": "node dist/index.js",
44
44
  "start:http": "node dist/http-server.js",
@@ -53,6 +53,12 @@
53
53
  "profile": "npx tsx scripts/profile.ts",
54
54
  "generate:manifest": "npx tsx scripts/generate-manifest.ts",
55
55
  "self-certify": "npm run generate:manifest && npx tsx scripts/self-certify.ts",
56
+ "constitution": "npx tsx scripts/constitution-check.ts",
57
+ "emit:cert": "npx tsx scripts/emit-sample-certificate.ts",
58
+ "verify:cert": "npx tsx scripts/verify-certificate.ts",
59
+ "benchmark": "npx tsx scripts/run-benchmark.ts",
60
+ "benchmark:llm": "npx tsx scripts/run-llm-benchmark.ts",
61
+ "benchmark:redteam": "npx tsx scripts/run-redteam-benchmark.ts",
56
62
  "test:self": "npm run self-certify",
57
63
  "release-notes": "npx tsx scripts/release-notes.ts",
58
64
  "changeset": "changeset",
@@ -76,6 +82,9 @@
76
82
  "yaml": "~2.9.0",
77
83
  "zod": "^3.24.0"
78
84
  },
85
+ "overrides": {
86
+ "shell-quote": "~1.8.4"
87
+ },
79
88
  "devDependencies": {
80
89
  "@changesets/changelog-github": "^0.5.0",
81
90
  "@changesets/cli": "^2.27.0",
@@ -86,6 +95,7 @@
86
95
  "@vitest/coverage-v8": "~4.1.4",
87
96
  "concurrently": "^9.1.2",
88
97
  "fast-check": "~4.8.0",
98
+ "openai": "~6.42.0",
89
99
  "turbo": "~2.9.6",
90
100
  "vitest": "~4.1.4"
91
101
  }
@@ -1,28 +0,0 @@
1
- /**
2
- * Test Fixture: Audit Gaps
3
- *
4
- * This file contains intentional audit trail gaps that should be
5
- * detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - PHI access without audit log (high)
9
- * - Missing user ID in audit entries (medium)
10
- * - Audit log without timestamp (medium)
11
- *
12
- * @module eval/fixtures/healthcare/audit-gaps
13
- */
14
- export declare function readPatientRecord(patientId: string, userId: string): Promise<{}>;
15
- export declare function updateMedicalRecord(patientId: string, updates: object): Promise<{
16
- success: boolean;
17
- }>;
18
- export declare function viewPatientData(patientId: string): Promise<{
19
- id: string;
20
- name: string;
21
- }>;
22
- export declare function deletePatientData(patientId: string, userId: string): Promise<boolean>;
23
- export declare function clearAuditLogs(adminId: string): Promise<void>;
24
- export declare function properAuditedAccess(patientId: string, userId: string): Promise<{
25
- id: string;
26
- name: string;
27
- }>;
28
- //# sourceMappingURL=audit-gaps.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"audit-gaps.d.ts","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/audit-gaps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAIxE;AAGD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;GAI3E;AAGD,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM;;;GAQtD;AAGD,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAQxE;AAGD,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,iBAGnD;AAqBD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;GA0B1E"}
@@ -1,90 +0,0 @@
1
- /**
2
- * Test Fixture: Audit Gaps
3
- *
4
- * This file contains intentional audit trail gaps that should be
5
- * detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - PHI access without audit log (high)
9
- * - Missing user ID in audit entries (medium)
10
- * - Audit log without timestamp (medium)
11
- *
12
- * @module eval/fixtures/healthcare/audit-gaps
13
- */
14
- // PHI access without audit logging - SHOULD BE DETECTED
15
- export async function readPatientRecord(patientId, userId) {
16
- // No audit log call before or after PHI access
17
- const patient = await database.query(`SELECT * FROM patients WHERE id = ?`, [patientId]);
18
- return patient;
19
- }
20
- // Another missing audit log - SHOULD BE DETECTED
21
- export async function updateMedicalRecord(patientId, updates) {
22
- await database.query(`UPDATE patients SET ? WHERE id = ?`, [updates, patientId]);
23
- // No audit trail for this modification
24
- return { success: true };
25
- }
26
- // Missing user ID in audit - SHOULD BE DETECTED
27
- export async function viewPatientData(patientId) {
28
- await auditLog.write({
29
- action: "view_patient",
30
- resourceId: patientId,
31
- // Missing: userId
32
- timestamp: new Date().toISOString(),
33
- });
34
- return await fetchPatient(patientId);
35
- }
36
- // Audit log without timestamp - SHOULD BE DETECTED
37
- export async function deletePatientData(patientId, userId) {
38
- await auditLog.write({
39
- action: "delete_patient",
40
- userId: userId,
41
- resourceId: patientId,
42
- // Missing: timestamp
43
- });
44
- return await database.delete("patients", patientId);
45
- }
46
- // Deletable audit log - SHOULD BE DETECTED
47
- export async function clearAuditLogs(adminId) {
48
- // Audit logs should be immutable
49
- await database.query("DELETE FROM audit_logs WHERE created_at < ?", [thirtyDaysAgo()]);
50
- }
51
- // Simulated database and audit
52
- const database = {
53
- query: async (sql, params) => ({}),
54
- delete: async (table, id) => true,
55
- };
56
- const auditLog = {
57
- write: async (entry) => true,
58
- };
59
- function thirtyDaysAgo() {
60
- return new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString();
61
- }
62
- async function fetchPatient(id) {
63
- return { id, name: "Test Patient" };
64
- }
65
- // This is OK - proper audit trail
66
- export async function properAuditedAccess(patientId, userId) {
67
- // Log before access
68
- await auditLog.write({
69
- action: "phi_access",
70
- userId: userId,
71
- resourceType: "patient",
72
- resourceId: patientId,
73
- timestamp: new Date().toISOString(),
74
- ipAddress: "127.0.0.1",
75
- outcome: "pending",
76
- });
77
- const patient = await fetchPatient(patientId);
78
- // Log after access with outcome
79
- await auditLog.write({
80
- action: "phi_access",
81
- userId: userId,
82
- resourceType: "patient",
83
- resourceId: patientId,
84
- timestamp: new Date().toISOString(),
85
- outcome: "success",
86
- dataAccessed: ["name", "dob", "mrn"],
87
- });
88
- return patient;
89
- }
90
- //# sourceMappingURL=audit-gaps.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"audit-gaps.js","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/audit-gaps.ts"],"names":[],"mappings":"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"}
@@ -1,31 +0,0 @@
1
- /**
2
- * Test Fixture: Consent Bypass
3
- *
4
- * This file contains intentional consent validation bypass patterns that
5
- * should be detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - Always-true consent check (high)
9
- * - Missing consent validation in PHI access (high)
10
- * - Consent check commented out (high)
11
- *
12
- * @module eval/fixtures/healthcare/consent-bypass
13
- */
14
- export declare function hasConsent(): boolean;
15
- export declare function checkConsentStatus(): boolean;
16
- export declare function accessPatientRecord(patientId: string): Promise<{
17
- id: string;
18
- medicalHistory: never[];
19
- ssn: string;
20
- }>;
21
- export declare function getPatientMedicalHistory(patientId: string): Promise<never[]>;
22
- export declare function getSUDTreatmentPlan(patientId: string): Promise<{
23
- patientId: string;
24
- treatmentPlan: string;
25
- }>;
26
- export declare function properConsentCheck(patientId: string, userId: string): Promise<{
27
- id: string;
28
- medicalHistory: never[];
29
- ssn: string;
30
- }>;
31
- //# sourceMappingURL=consent-bypass.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"consent-bypass.d.ts","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/consent-bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAGD,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAGD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM;;;;GAK1D;AAGD,wBAAsB,wBAAwB,CAAC,SAAS,EAAE,MAAM,oBAI/D;AAGD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM;;;GAI1D;AAYD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;GAMzE"}
@@ -1,61 +0,0 @@
1
- /**
2
- * Test Fixture: Consent Bypass
3
- *
4
- * This file contains intentional consent validation bypass patterns that
5
- * should be detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - Always-true consent check (high)
9
- * - Missing consent validation in PHI access (high)
10
- * - Consent check commented out (high)
11
- *
12
- * @module eval/fixtures/healthcare/consent-bypass
13
- */
14
- // Always-true consent check - SHOULD BE DETECTED
15
- export function hasConsent() {
16
- return true; // BUG: Always returns true without validation
17
- }
18
- // Another always-true pattern - SHOULD BE DETECTED
19
- export function checkConsentStatus() {
20
- const consentGiven = true;
21
- return consentGiven; // BUG: Hard-coded consent
22
- }
23
- // Consent check commented out - SHOULD BE DETECTED
24
- export async function accessPatientRecord(patientId) {
25
- // if (!await checkConsentStatus()) {
26
- // throw new Error("Consent not given");
27
- // }
28
- return fetchPatientData(patientId);
29
- }
30
- // Missing consent validation before PHI access - SHOULD BE DETECTED
31
- export async function getPatientMedicalHistory(patientId) {
32
- // No consent check before accessing sensitive data
33
- const patient = await fetchPatientData(patientId);
34
- return patient.medicalHistory;
35
- }
36
- // Missing consent check with SUD data - SHOULD BE DETECTED
37
- export async function getSUDTreatmentPlan(patientId) {
38
- // SUD data requires explicit consent under 42 CFR Part 2
39
- // but no consent validation here
40
- return await fetchSUDRecords(patientId);
41
- }
42
- // Helper functions (simulated)
43
- async function fetchPatientData(patientId) {
44
- return { id: patientId, medicalHistory: [], ssn: "123-45-6789" };
45
- }
46
- async function fetchSUDRecords(patientId) {
47
- return { patientId, treatmentPlan: "Methadone maintenance" };
48
- }
49
- // This is OK - proper consent check
50
- export async function properConsentCheck(patientId, userId) {
51
- const consent = await validateConsent(patientId, userId);
52
- if (!consent.valid) {
53
- throw new Error("Patient consent not obtained");
54
- }
55
- return await fetchPatientData(patientId);
56
- }
57
- async function validateConsent(patientId, userId) {
58
- // Real implementation would check database
59
- return { valid: false, scope: [], expiresAt: null };
60
- }
61
- //# sourceMappingURL=consent-bypass.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"consent-bypass.js","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/consent-bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,iDAAiD;AACjD,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,CAAC,8CAA8C;AAC7D,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,kBAAkB;IAChC,MAAM,YAAY,GAAG,IAAI,CAAC;IAC1B,OAAO,YAAY,CAAC,CAAC,0BAA0B;AACjD,CAAC;AAED,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IACzD,qCAAqC;IACrC,0CAA0C;IAC1C,IAAI;IACJ,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,SAAiB;IAC9D,mDAAmD;IACnD,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,cAAc,CAAC;AAChC,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,SAAiB;IACzD,yDAAyD;IACzD,iCAAiC;IACjC,OAAO,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;AAC1C,CAAC;AAED,+BAA+B;AAC/B,KAAK,UAAU,gBAAgB,CAAC,SAAiB;IAC/C,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC;AACnE,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,SAAiB;IAC9C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,uBAAuB,EAAE,CAAC;AAC/D,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,MAAc;IACxE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACzD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,SAAiB,EAAE,MAAc;IAC9D,2CAA2C;IAC3C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACtD,CAAC"}
@@ -1,24 +0,0 @@
1
- /**
2
- * Test Fixture: PHI in Logs
3
- *
4
- * This file contains intentional PHI exposure patterns that should be
5
- * detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - SSN in log output (critical)
9
- * - MRN in console.log (critical)
10
- * - Patient data in error logs (high)
11
- *
12
- * @module eval/fixtures/healthcare/phi-in-logs
13
- */
14
- export declare function logPatientInfo(patientId: string, ssn: string): void;
15
- export declare function logMedicalRecordAccess(mrn: string, action: string): void;
16
- export declare function handlePatientError(error: Error, patientSSN: string): void;
17
- export declare function debugPatientRecord(patient: {
18
- name: string;
19
- ssn: string;
20
- mrn: string;
21
- }): void;
22
- export declare function logMedicationDispense(patientId: string, medication: string): void;
23
- export declare function logGenericMessage(message: string): void;
24
- //# sourceMappingURL=phi-in-logs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"phi-in-logs.d.ts","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/phi-in-logs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAE5D;AAGD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAGjE;AAGD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,QAElE;AAGD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,QAErF;AAGD,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAI1E;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,QAEhD"}
@@ -1,41 +0,0 @@
1
- /**
2
- * Test Fixture: PHI in Logs
3
- *
4
- * This file contains intentional PHI exposure patterns that should be
5
- * detected by the healthcare scanner. Used for testing only.
6
- *
7
- * EXPECTED FINDINGS:
8
- * - SSN in log output (critical)
9
- * - MRN in console.log (critical)
10
- * - Patient data in error logs (high)
11
- *
12
- * @module eval/fixtures/healthcare/phi-in-logs
13
- */
14
- // SSN in logger output - SHOULD BE DETECTED
15
- export function logPatientInfo(patientId, ssn) {
16
- console.log(`Processing patient ${patientId} with SSN: ${ssn}`);
17
- }
18
- // MRN exposure in logs - SHOULD BE DETECTED
19
- export function logMedicalRecordAccess(mrn, action) {
20
- console.log(`MRN ${mrn}: ${action}`);
21
- console.info(`Medical record MRN: ${mrn} accessed`);
22
- }
23
- // PHI in error message - SHOULD BE DETECTED
24
- export function handlePatientError(error, patientSSN) {
25
- console.error(`Failed to process patient. SSN: ${patientSSN}, Error: ${error.message}`);
26
- }
27
- // Patient data in debug logs - SHOULD BE DETECTED
28
- export function debugPatientRecord(patient) {
29
- console.debug(`Patient record: ${JSON.stringify(patient)}`);
30
- }
31
- // SUD medication in logs - SHOULD BE DETECTED
32
- export function logMedicationDispense(patientId, medication) {
33
- if (medication.toLowerCase().includes("methadone") || medication.toLowerCase().includes("suboxone")) {
34
- console.log(`Dispensed ${medication} to patient ${patientId}`);
35
- }
36
- }
37
- // This is OK - no PHI in logs
38
- export function logGenericMessage(message) {
39
- console.log(message);
40
- }
41
- //# sourceMappingURL=phi-in-logs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"phi-in-logs.js","sourceRoot":"","sources":["../../../../src/eval/fixtures/healthcare/phi-in-logs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,4CAA4C;AAC5C,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,GAAW;IAC3D,OAAO,CAAC,GAAG,CAAC,sBAAsB,SAAS,cAAc,GAAG,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,MAAc;IAChE,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,MAAM,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,uBAAuB,GAAG,WAAW,CAAC,CAAC;AACtD,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,kBAAkB,CAAC,KAAY,EAAE,UAAkB;IACjE,OAAO,CAAC,KAAK,CAAC,mCAAmC,UAAU,YAAY,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,kBAAkB,CAAC,OAAmD;IACpF,OAAO,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAC9D,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,UAAkB;IACzE,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QACpG,OAAO,CAAC,GAAG,CAAC,aAAa,UAAU,eAAe,SAAS,EAAE,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC"}