@antasphere/chassis-server 1.0.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 (798) hide show
  1. package/LICENSE +82 -0
  2. package/dist/accounts/deletion.d.ts +163 -0
  3. package/dist/accounts/deletion.d.ts.map +1 -0
  4. package/dist/accounts/deletion.js +360 -0
  5. package/dist/accounts/deletion.js.map +1 -0
  6. package/dist/accounts/erasure-log.d.ts +66 -0
  7. package/dist/accounts/erasure-log.d.ts.map +1 -0
  8. package/dist/accounts/erasure-log.js +117 -0
  9. package/dist/accounts/erasure-log.js.map +1 -0
  10. package/dist/accounts/index.d.ts +6 -0
  11. package/dist/accounts/index.d.ts.map +1 -0
  12. package/dist/accounts/index.js +6 -0
  13. package/dist/accounts/index.js.map +1 -0
  14. package/dist/accounts/mint-refusal.d.ts +47 -0
  15. package/dist/accounts/mint-refusal.d.ts.map +1 -0
  16. package/dist/accounts/mint-refusal.js +59 -0
  17. package/dist/accounts/mint-refusal.js.map +1 -0
  18. package/dist/accounts/signup-duplicate.d.ts +14 -0
  19. package/dist/accounts/signup-duplicate.d.ts.map +1 -0
  20. package/dist/accounts/signup-duplicate.js +25 -0
  21. package/dist/accounts/signup-duplicate.js.map +1 -0
  22. package/dist/accounts/superadmin.d.ts +27 -0
  23. package/dist/accounts/superadmin.d.ts.map +1 -0
  24. package/dist/accounts/superadmin.js +46 -0
  25. package/dist/accounts/superadmin.js.map +1 -0
  26. package/dist/api/apikeys.d.ts +14 -0
  27. package/dist/api/apikeys.d.ts.map +1 -0
  28. package/dist/api/apikeys.js +124 -0
  29. package/dist/api/apikeys.js.map +1 -0
  30. package/dist/api/audit.d.ts +4 -0
  31. package/dist/api/audit.d.ts.map +1 -0
  32. package/dist/api/audit.js +75 -0
  33. package/dist/api/audit.js.map +1 -0
  34. package/dist/api/break-glass.d.ts +48 -0
  35. package/dist/api/break-glass.d.ts.map +1 -0
  36. package/dist/api/break-glass.js +217 -0
  37. package/dist/api/break-glass.js.map +1 -0
  38. package/dist/api/cli-auth.d.ts +84 -0
  39. package/dist/api/cli-auth.d.ts.map +1 -0
  40. package/dist/api/cli-auth.js +177 -0
  41. package/dist/api/cli-auth.js.map +1 -0
  42. package/dist/api/create-api.d.ts +123 -0
  43. package/dist/api/create-api.d.ts.map +1 -0
  44. package/dist/api/create-api.js +1165 -0
  45. package/dist/api/create-api.js.map +1 -0
  46. package/dist/api/demo-passes.d.ts +45 -0
  47. package/dist/api/demo-passes.d.ts.map +1 -0
  48. package/dist/api/demo-passes.js +143 -0
  49. package/dist/api/demo-passes.js.map +1 -0
  50. package/dist/api/errors.d.ts +5 -0
  51. package/dist/api/errors.d.ts.map +1 -0
  52. package/dist/api/errors.js +5 -0
  53. package/dist/api/errors.js.map +1 -0
  54. package/dist/api/export.d.ts +63 -0
  55. package/dist/api/export.d.ts.map +1 -0
  56. package/dist/api/export.js +393 -0
  57. package/dist/api/export.js.map +1 -0
  58. package/dist/api/files.d.ts +40 -0
  59. package/dist/api/files.d.ts.map +1 -0
  60. package/dist/api/files.js +150 -0
  61. package/dist/api/files.js.map +1 -0
  62. package/dist/api/index.d.ts +17 -0
  63. package/dist/api/index.d.ts.map +1 -0
  64. package/dist/api/index.js +17 -0
  65. package/dist/api/index.js.map +1 -0
  66. package/dist/api/invitations.d.ts +50 -0
  67. package/dist/api/invitations.d.ts.map +1 -0
  68. package/dist/api/invitations.js +313 -0
  69. package/dist/api/invitations.js.map +1 -0
  70. package/dist/api/members.d.ts +25 -0
  71. package/dist/api/members.d.ts.map +1 -0
  72. package/dist/api/members.js +522 -0
  73. package/dist/api/members.js.map +1 -0
  74. package/dist/api/onboarding.d.ts +26 -0
  75. package/dist/api/onboarding.d.ts.map +1 -0
  76. package/dist/api/onboarding.js +23 -0
  77. package/dist/api/onboarding.js.map +1 -0
  78. package/dist/api/openapi-doc.d.ts +21 -0
  79. package/dist/api/openapi-doc.d.ts.map +1 -0
  80. package/dist/api/openapi-doc.js +25 -0
  81. package/dist/api/openapi-doc.js.map +1 -0
  82. package/dist/api/projects.d.ts +24 -0
  83. package/dist/api/projects.d.ts.map +1 -0
  84. package/dist/api/projects.js +624 -0
  85. package/dist/api/projects.js.map +1 -0
  86. package/dist/api/scope-routes.d.ts +12 -0
  87. package/dist/api/scope-routes.d.ts.map +1 -0
  88. package/dist/api/scope-routes.js +2 -0
  89. package/dist/api/scope-routes.js.map +1 -0
  90. package/dist/api/sso-connect.d.ts +70 -0
  91. package/dist/api/sso-connect.d.ts.map +1 -0
  92. package/dist/api/sso-connect.js +164 -0
  93. package/dist/api/sso-connect.js.map +1 -0
  94. package/dist/api/sso-logout.d.ts +41 -0
  95. package/dist/api/sso-logout.d.ts.map +1 -0
  96. package/dist/api/sso-logout.js +34 -0
  97. package/dist/api/sso-logout.js.map +1 -0
  98. package/dist/api/teams.d.ts +43 -0
  99. package/dist/api/teams.d.ts.map +1 -0
  100. package/dist/api/teams.js +447 -0
  101. package/dist/api/teams.js.map +1 -0
  102. package/dist/api/workspaces.d.ts +114 -0
  103. package/dist/api/workspaces.d.ts.map +1 -0
  104. package/dist/api/workspaces.js +462 -0
  105. package/dist/api/workspaces.js.map +1 -0
  106. package/dist/apikeys/index.d.ts +3 -0
  107. package/dist/apikeys/index.d.ts.map +1 -0
  108. package/dist/apikeys/index.js +3 -0
  109. package/dist/apikeys/index.js.map +1 -0
  110. package/dist/apikeys/peppers.d.ts +53 -0
  111. package/dist/apikeys/peppers.d.ts.map +1 -0
  112. package/dist/apikeys/peppers.js +97 -0
  113. package/dist/apikeys/peppers.js.map +1 -0
  114. package/dist/apikeys/service.d.ts +56 -0
  115. package/dist/apikeys/service.d.ts.map +1 -0
  116. package/dist/apikeys/service.js +196 -0
  117. package/dist/apikeys/service.js.map +1 -0
  118. package/dist/app.d.ts +65 -0
  119. package/dist/app.d.ts.map +1 -0
  120. package/dist/app.js +142 -0
  121. package/dist/app.js.map +1 -0
  122. package/dist/audit/filters.d.ts +38 -0
  123. package/dist/audit/filters.d.ts.map +1 -0
  124. package/dist/audit/filters.js +97 -0
  125. package/dist/audit/filters.js.map +1 -0
  126. package/dist/audit/index.d.ts +3 -0
  127. package/dist/audit/index.d.ts.map +1 -0
  128. package/dist/audit/index.js +3 -0
  129. package/dist/audit/index.js.map +1 -0
  130. package/dist/audit/service.d.ts +65 -0
  131. package/dist/audit/service.d.ts.map +1 -0
  132. package/dist/audit/service.js +103 -0
  133. package/dist/audit/service.js.map +1 -0
  134. package/dist/boot.d.ts +8 -0
  135. package/dist/boot.d.ts.map +1 -0
  136. package/dist/boot.js +822 -0
  137. package/dist/boot.js.map +1 -0
  138. package/dist/constant-time.d.ts +3 -0
  139. package/dist/constant-time.d.ts.map +1 -0
  140. package/dist/constant-time.js +10 -0
  141. package/dist/constant-time.js.map +1 -0
  142. package/dist/email/driver.d.ts +16 -0
  143. package/dist/email/driver.d.ts.map +1 -0
  144. package/dist/email/driver.js +136 -0
  145. package/dist/email/driver.js.map +1 -0
  146. package/dist/email/index.d.ts +4 -0
  147. package/dist/email/index.d.ts.map +1 -0
  148. package/dist/email/index.js +4 -0
  149. package/dist/email/index.js.map +1 -0
  150. package/dist/email/shell.d.ts +72 -0
  151. package/dist/email/shell.d.ts.map +1 -0
  152. package/dist/email/shell.js +146 -0
  153. package/dist/email/shell.js.map +1 -0
  154. package/dist/email/templates.d.ts +83 -0
  155. package/dist/email/templates.d.ts.map +1 -0
  156. package/dist/email/templates.js +96 -0
  157. package/dist/email/templates.js.map +1 -0
  158. package/dist/entitlements/check.d.ts +140 -0
  159. package/dist/entitlements/check.d.ts.map +1 -0
  160. package/dist/entitlements/check.js +276 -0
  161. package/dist/entitlements/check.js.map +1 -0
  162. package/dist/entitlements/clock-skew.d.ts +27 -0
  163. package/dist/entitlements/clock-skew.d.ts.map +1 -0
  164. package/dist/entitlements/clock-skew.js +58 -0
  165. package/dist/entitlements/clock-skew.js.map +1 -0
  166. package/dist/entitlements/gate.d.ts +113 -0
  167. package/dist/entitlements/gate.d.ts.map +1 -0
  168. package/dist/entitlements/gate.js +430 -0
  169. package/dist/entitlements/gate.js.map +1 -0
  170. package/dist/entitlements/hub-machine-token.d.ts +83 -0
  171. package/dist/entitlements/hub-machine-token.d.ts.map +1 -0
  172. package/dist/entitlements/hub-machine-token.js +175 -0
  173. package/dist/entitlements/hub-machine-token.js.map +1 -0
  174. package/dist/entitlements/hub-subject.d.ts +32 -0
  175. package/dist/entitlements/hub-subject.d.ts.map +1 -0
  176. package/dist/entitlements/hub-subject.js +68 -0
  177. package/dist/entitlements/hub-subject.js.map +1 -0
  178. package/dist/entitlements/index.d.ts +9 -0
  179. package/dist/entitlements/index.d.ts.map +1 -0
  180. package/dist/entitlements/index.js +9 -0
  181. package/dist/entitlements/index.js.map +1 -0
  182. package/dist/entitlements/poster.d.ts +81 -0
  183. package/dist/entitlements/poster.d.ts.map +1 -0
  184. package/dist/entitlements/poster.js +169 -0
  185. package/dist/entitlements/poster.js.map +1 -0
  186. package/dist/entitlements/profiles.d.ts +121 -0
  187. package/dist/entitlements/profiles.d.ts.map +1 -0
  188. package/dist/entitlements/profiles.js +212 -0
  189. package/dist/entitlements/profiles.js.map +1 -0
  190. package/dist/entitlements/slot.d.ts +33 -0
  191. package/dist/entitlements/slot.d.ts.map +1 -0
  192. package/dist/entitlements/slot.js +75 -0
  193. package/dist/entitlements/slot.js.map +1 -0
  194. package/dist/env.d.ts +293 -0
  195. package/dist/env.d.ts.map +1 -0
  196. package/dist/env.js +383 -0
  197. package/dist/env.js.map +1 -0
  198. package/dist/files/http.d.ts +23 -0
  199. package/dist/files/http.d.ts.map +1 -0
  200. package/dist/files/http.js +66 -0
  201. package/dist/files/http.js.map +1 -0
  202. package/dist/files/index.d.ts +5 -0
  203. package/dist/files/index.d.ts.map +1 -0
  204. package/dist/files/index.js +5 -0
  205. package/dist/files/index.js.map +1 -0
  206. package/dist/files/serve.d.ts +43 -0
  207. package/dist/files/serve.d.ts.map +1 -0
  208. package/dist/files/serve.js +71 -0
  209. package/dist/files/serve.js.map +1 -0
  210. package/dist/files/service.d.ts +69 -0
  211. package/dist/files/service.d.ts.map +1 -0
  212. package/dist/files/service.js +188 -0
  213. package/dist/files/service.js.map +1 -0
  214. package/dist/files/spool.d.ts +21 -0
  215. package/dist/files/spool.d.ts.map +1 -0
  216. package/dist/files/spool.js +47 -0
  217. package/dist/files/spool.js.map +1 -0
  218. package/dist/identity/better-auth.d.ts +3927 -0
  219. package/dist/identity/better-auth.d.ts.map +1 -0
  220. package/dist/identity/better-auth.js +896 -0
  221. package/dist/identity/better-auth.js.map +1 -0
  222. package/dist/identity/demo-pass-plugin.d.ts +29 -0
  223. package/dist/identity/demo-pass-plugin.d.ts.map +1 -0
  224. package/dist/identity/demo-pass-plugin.js +88 -0
  225. package/dist/identity/demo-pass-plugin.js.map +1 -0
  226. package/dist/identity/demo-pass-rules.d.ts +84 -0
  227. package/dist/identity/demo-pass-rules.d.ts.map +1 -0
  228. package/dist/identity/demo-pass-rules.js +223 -0
  229. package/dist/identity/demo-pass-rules.js.map +1 -0
  230. package/dist/identity/demo-pass.d.ts +159 -0
  231. package/dist/identity/demo-pass.d.ts.map +1 -0
  232. package/dist/identity/demo-pass.js +319 -0
  233. package/dist/identity/demo-pass.js.map +1 -0
  234. package/dist/identity/hub-grant.d.ts +182 -0
  235. package/dist/identity/hub-grant.d.ts.map +1 -0
  236. package/dist/identity/hub-grant.js +594 -0
  237. package/dist/identity/hub-grant.js.map +1 -0
  238. package/dist/identity/hub-jwt.d.ts +22 -0
  239. package/dist/identity/hub-jwt.d.ts.map +1 -0
  240. package/dist/identity/hub-jwt.js +77 -0
  241. package/dist/identity/hub-jwt.js.map +1 -0
  242. package/dist/identity/hub-live-gate.d.ts +17 -0
  243. package/dist/identity/hub-live-gate.d.ts.map +1 -0
  244. package/dist/identity/hub-live-gate.js +146 -0
  245. package/dist/identity/hub-live-gate.js.map +1 -0
  246. package/dist/identity/hub-logout.d.ts +88 -0
  247. package/dist/identity/hub-logout.d.ts.map +1 -0
  248. package/dist/identity/hub-logout.js +158 -0
  249. package/dist/identity/hub-logout.js.map +1 -0
  250. package/dist/identity/hub-projection.d.ts +103 -0
  251. package/dist/identity/hub-projection.d.ts.map +1 -0
  252. package/dist/identity/hub-projection.js +130 -0
  253. package/dist/identity/hub-projection.js.map +1 -0
  254. package/dist/identity/hub-reconcile.d.ts +151 -0
  255. package/dist/identity/hub-reconcile.d.ts.map +1 -0
  256. package/dist/identity/hub-reconcile.js +400 -0
  257. package/dist/identity/hub-reconcile.js.map +1 -0
  258. package/dist/identity/hub-sso.d.ts +363 -0
  259. package/dist/identity/hub-sso.d.ts.map +1 -0
  260. package/dist/identity/hub-sso.js +536 -0
  261. package/dist/identity/hub-sso.js.map +1 -0
  262. package/dist/identity/hub-user-client.d.ts +222 -0
  263. package/dist/identity/hub-user-client.d.ts.map +1 -0
  264. package/dist/identity/hub-user-client.js +406 -0
  265. package/dist/identity/hub-user-client.js.map +1 -0
  266. package/dist/identity/index.d.ts +13 -0
  267. package/dist/identity/index.d.ts.map +1 -0
  268. package/dist/identity/index.js +13 -0
  269. package/dist/identity/index.js.map +1 -0
  270. package/dist/identity/oauth-jwt.d.ts +32 -0
  271. package/dist/identity/oauth-jwt.d.ts.map +1 -0
  272. package/dist/identity/oauth-jwt.js +122 -0
  273. package/dist/identity/oauth-jwt.js.map +1 -0
  274. package/dist/identity/resolve-membership.d.ts +28 -0
  275. package/dist/identity/resolve-membership.d.ts.map +1 -0
  276. package/dist/identity/resolve-membership.js +69 -0
  277. package/dist/identity/resolve-membership.js.map +1 -0
  278. package/dist/identity/signing-key.d.ts +49 -0
  279. package/dist/identity/signing-key.d.ts.map +1 -0
  280. package/dist/identity/signing-key.js +144 -0
  281. package/dist/identity/signing-key.js.map +1 -0
  282. package/dist/index.d.ts +21 -0
  283. package/dist/index.d.ts.map +1 -0
  284. package/dist/index.js +11 -0
  285. package/dist/index.js.map +1 -0
  286. package/dist/invitations/index.d.ts +2 -0
  287. package/dist/invitations/index.d.ts.map +1 -0
  288. package/dist/invitations/index.js +2 -0
  289. package/dist/invitations/index.js.map +1 -0
  290. package/dist/invitations/service.d.ts +36 -0
  291. package/dist/invitations/service.d.ts.map +1 -0
  292. package/dist/invitations/service.js +122 -0
  293. package/dist/invitations/service.js.map +1 -0
  294. package/dist/jobs/index.d.ts +3 -0
  295. package/dist/jobs/index.d.ts.map +1 -0
  296. package/dist/jobs/index.js +3 -0
  297. package/dist/jobs/index.js.map +1 -0
  298. package/dist/jobs/pgboss.d.ts +119 -0
  299. package/dist/jobs/pgboss.d.ts.map +1 -0
  300. package/dist/jobs/pgboss.js +521 -0
  301. package/dist/jobs/pgboss.js.map +1 -0
  302. package/dist/jobs/timers.d.ts +127 -0
  303. package/dist/jobs/timers.d.ts.map +1 -0
  304. package/dist/jobs/timers.js +228 -0
  305. package/dist/jobs/timers.js.map +1 -0
  306. package/dist/logger.d.ts +17 -0
  307. package/dist/logger.d.ts.map +1 -0
  308. package/dist/logger.js +64 -0
  309. package/dist/logger.js.map +1 -0
  310. package/dist/mcp/errors.d.ts +37 -0
  311. package/dist/mcp/errors.d.ts.map +1 -0
  312. package/dist/mcp/errors.js +77 -0
  313. package/dist/mcp/errors.js.map +1 -0
  314. package/dist/mcp/http.d.ts +35 -0
  315. package/dist/mcp/http.d.ts.map +1 -0
  316. package/dist/mcp/http.js +80 -0
  317. package/dist/mcp/http.js.map +1 -0
  318. package/dist/mcp/index.d.ts +8 -0
  319. package/dist/mcp/index.d.ts.map +1 -0
  320. package/dist/mcp/index.js +8 -0
  321. package/dist/mcp/index.js.map +1 -0
  322. package/dist/mcp/inputs.d.ts +19 -0
  323. package/dist/mcp/inputs.d.ts.map +1 -0
  324. package/dist/mcp/inputs.js +28 -0
  325. package/dist/mcp/inputs.js.map +1 -0
  326. package/dist/mcp/projects.d.ts +31 -0
  327. package/dist/mcp/projects.d.ts.map +1 -0
  328. package/dist/mcp/projects.js +315 -0
  329. package/dist/mcp/projects.js.map +1 -0
  330. package/dist/mcp/server.d.ts +52 -0
  331. package/dist/mcp/server.d.ts.map +1 -0
  332. package/dist/mcp/server.js +93 -0
  333. package/dist/mcp/server.js.map +1 -0
  334. package/dist/mcp/teams.d.ts +7 -0
  335. package/dist/mcp/teams.d.ts.map +1 -0
  336. package/dist/mcp/teams.js +62 -0
  337. package/dist/mcp/teams.js.map +1 -0
  338. package/dist/mcp/tool-kit.d.ts +67 -0
  339. package/dist/mcp/tool-kit.d.ts.map +1 -0
  340. package/dist/mcp/tool-kit.js +74 -0
  341. package/dist/mcp/tool-kit.js.map +1 -0
  342. package/dist/members/removal.d.ts +95 -0
  343. package/dist/members/removal.d.ts.map +1 -0
  344. package/dist/members/removal.js +143 -0
  345. package/dist/members/removal.js.map +1 -0
  346. package/dist/middleware/auth-body.d.ts +25 -0
  347. package/dist/middleware/auth-body.d.ts.map +1 -0
  348. package/dist/middleware/auth-body.js +55 -0
  349. package/dist/middleware/auth-body.js.map +1 -0
  350. package/dist/middleware/auth-context.d.ts +170 -0
  351. package/dist/middleware/auth-context.d.ts.map +1 -0
  352. package/dist/middleware/auth-context.js +251 -0
  353. package/dist/middleware/auth-context.js.map +1 -0
  354. package/dist/middleware/body-cap.d.ts +17 -0
  355. package/dist/middleware/body-cap.d.ts.map +1 -0
  356. package/dist/middleware/body-cap.js +31 -0
  357. package/dist/middleware/body-cap.js.map +1 -0
  358. package/dist/middleware/body-refusal.d.ts +20 -0
  359. package/dist/middleware/body-refusal.d.ts.map +1 -0
  360. package/dist/middleware/body-refusal.js +5 -0
  361. package/dist/middleware/body-refusal.js.map +1 -0
  362. package/dist/middleware/cross-site.d.ts +61 -0
  363. package/dist/middleware/cross-site.d.ts.map +1 -0
  364. package/dist/middleware/cross-site.js +59 -0
  365. package/dist/middleware/cross-site.js.map +1 -0
  366. package/dist/middleware/hub-managed.d.ts +45 -0
  367. package/dist/middleware/hub-managed.d.ts.map +1 -0
  368. package/dist/middleware/hub-managed.js +56 -0
  369. package/dist/middleware/hub-managed.js.map +1 -0
  370. package/dist/middleware/idempotency.d.ts +14 -0
  371. package/dist/middleware/idempotency.d.ts.map +1 -0
  372. package/dist/middleware/idempotency.js +222 -0
  373. package/dist/middleware/idempotency.js.map +1 -0
  374. package/dist/middleware/index.d.ts +12 -0
  375. package/dist/middleware/index.d.ts.map +1 -0
  376. package/dist/middleware/index.js +12 -0
  377. package/dist/middleware/index.js.map +1 -0
  378. package/dist/middleware/json-depth.d.ts +32 -0
  379. package/dist/middleware/json-depth.d.ts.map +1 -0
  380. package/dist/middleware/json-depth.js +80 -0
  381. package/dist/middleware/json-depth.js.map +1 -0
  382. package/dist/middleware/no-store.d.ts +21 -0
  383. package/dist/middleware/no-store.d.ts.map +1 -0
  384. package/dist/middleware/no-store.js +32 -0
  385. package/dist/middleware/no-store.js.map +1 -0
  386. package/dist/middleware/oauth-public.d.ts +16 -0
  387. package/dist/middleware/oauth-public.d.ts.map +1 -0
  388. package/dist/middleware/oauth-public.js +50 -0
  389. package/dist/middleware/oauth-public.js.map +1 -0
  390. package/dist/middleware/rate-limit.d.ts +182 -0
  391. package/dist/middleware/rate-limit.d.ts.map +1 -0
  392. package/dist/middleware/rate-limit.js +277 -0
  393. package/dist/middleware/rate-limit.js.map +1 -0
  394. package/dist/middleware/request-id.d.ts +10 -0
  395. package/dist/middleware/request-id.d.ts.map +1 -0
  396. package/dist/middleware/request-id.js +42 -0
  397. package/dist/middleware/request-id.js.map +1 -0
  398. package/dist/middleware/scopes.d.ts +33 -0
  399. package/dist/middleware/scopes.d.ts.map +1 -0
  400. package/dist/middleware/scopes.js +139 -0
  401. package/dist/middleware/scopes.js.map +1 -0
  402. package/dist/middleware/security-headers.d.ts +53 -0
  403. package/dist/middleware/security-headers.d.ts.map +1 -0
  404. package/dist/middleware/security-headers.js +96 -0
  405. package/dist/middleware/security-headers.js.map +1 -0
  406. package/dist/observability/index.d.ts +3 -0
  407. package/dist/observability/index.d.ts.map +1 -0
  408. package/dist/observability/index.js +3 -0
  409. package/dist/observability/index.js.map +1 -0
  410. package/dist/observability/metrics.d.ts +17 -0
  411. package/dist/observability/metrics.d.ts.map +1 -0
  412. package/dist/observability/metrics.js +82 -0
  413. package/dist/observability/metrics.js.map +1 -0
  414. package/dist/observability/otel.d.ts +20 -0
  415. package/dist/observability/otel.d.ts.map +1 -0
  416. package/dist/observability/otel.js +54 -0
  417. package/dist/observability/otel.js.map +1 -0
  418. package/dist/pagination.d.ts +57 -0
  419. package/dist/pagination.d.ts.map +1 -0
  420. package/dist/pagination.js +90 -0
  421. package/dist/pagination.js.map +1 -0
  422. package/dist/platform/edition.d.ts +57 -0
  423. package/dist/platform/edition.d.ts.map +1 -0
  424. package/dist/platform/edition.js +90 -0
  425. package/dist/platform/edition.js.map +1 -0
  426. package/dist/platform/entitlements.d.ts +26 -0
  427. package/dist/platform/entitlements.d.ts.map +1 -0
  428. package/dist/platform/entitlements.js +28 -0
  429. package/dist/platform/entitlements.js.map +1 -0
  430. package/dist/platform/events.d.ts +87 -0
  431. package/dist/platform/events.d.ts.map +1 -0
  432. package/dist/platform/events.js +32 -0
  433. package/dist/platform/events.js.map +1 -0
  434. package/dist/platform/index.d.ts +8 -0
  435. package/dist/platform/index.d.ts.map +1 -0
  436. package/dist/platform/index.js +8 -0
  437. package/dist/platform/index.js.map +1 -0
  438. package/dist/platform/local-identity.d.ts +39 -0
  439. package/dist/platform/local-identity.d.ts.map +1 -0
  440. package/dist/platform/local-identity.js +87 -0
  441. package/dist/platform/local-identity.js.map +1 -0
  442. package/dist/platform/registry.d.ts +23 -0
  443. package/dist/platform/registry.d.ts.map +1 -0
  444. package/dist/platform/registry.js +5 -0
  445. package/dist/platform/registry.js.map +1 -0
  446. package/dist/platform/usage.d.ts +11 -0
  447. package/dist/platform/usage.d.ts.map +1 -0
  448. package/dist/platform/usage.js +12 -0
  449. package/dist/platform/usage.js.map +1 -0
  450. package/dist/platform/workspaces.d.ts +25 -0
  451. package/dist/platform/workspaces.d.ts.map +1 -0
  452. package/dist/platform/workspaces.js +44 -0
  453. package/dist/platform/workspaces.js.map +1 -0
  454. package/dist/projects/access.d.ts +40 -0
  455. package/dist/projects/access.d.ts.map +1 -0
  456. package/dist/projects/access.js +133 -0
  457. package/dist/projects/access.js.map +1 -0
  458. package/dist/projects/index.d.ts +2 -0
  459. package/dist/projects/index.d.ts.map +1 -0
  460. package/dist/projects/index.js +2 -0
  461. package/dist/projects/index.js.map +1 -0
  462. package/dist/route-label.d.ts +23 -0
  463. package/dist/route-label.d.ts.map +1 -0
  464. package/dist/route-label.js +29 -0
  465. package/dist/route-label.js.map +1 -0
  466. package/dist/routes/health.d.ts +30 -0
  467. package/dist/routes/health.d.ts.map +1 -0
  468. package/dist/routes/health.js +54 -0
  469. package/dist/routes/health.js.map +1 -0
  470. package/dist/routes/index.d.ts +3 -0
  471. package/dist/routes/index.d.ts.map +1 -0
  472. package/dist/routes/index.js +3 -0
  473. package/dist/routes/index.js.map +1 -0
  474. package/dist/routes/wellknown.d.ts +11 -0
  475. package/dist/routes/wellknown.d.ts.map +1 -0
  476. package/dist/routes/wellknown.js +45 -0
  477. package/dist/routes/wellknown.js.map +1 -0
  478. package/dist/secret.d.ts +30 -0
  479. package/dist/secret.d.ts.map +1 -0
  480. package/dist/secret.js +97 -0
  481. package/dist/secret.js.map +1 -0
  482. package/dist/setup-transport.d.ts +23 -0
  483. package/dist/setup-transport.d.ts.map +1 -0
  484. package/dist/setup-transport.js +52 -0
  485. package/dist/setup-transport.js.map +1 -0
  486. package/dist/state.d.ts +21 -0
  487. package/dist/state.d.ts.map +1 -0
  488. package/dist/state.js +4 -0
  489. package/dist/state.js.map +1 -0
  490. package/dist/storage/driver.d.ts +38 -0
  491. package/dist/storage/driver.d.ts.map +1 -0
  492. package/dist/storage/driver.js +14 -0
  493. package/dist/storage/driver.js.map +1 -0
  494. package/dist/storage/factory.d.ts +4 -0
  495. package/dist/storage/factory.d.ts.map +1 -0
  496. package/dist/storage/factory.js +20 -0
  497. package/dist/storage/factory.js.map +1 -0
  498. package/dist/storage/index.d.ts +4 -0
  499. package/dist/storage/index.d.ts.map +1 -0
  500. package/dist/storage/index.js +4 -0
  501. package/dist/storage/index.js.map +1 -0
  502. package/dist/storage/local.d.ts +21 -0
  503. package/dist/storage/local.d.ts.map +1 -0
  504. package/dist/storage/local.js +88 -0
  505. package/dist/storage/local.js.map +1 -0
  506. package/dist/storage/s3.d.ts +29 -0
  507. package/dist/storage/s3.d.ts.map +1 -0
  508. package/dist/storage/s3.js +82 -0
  509. package/dist/storage/s3.js.map +1 -0
  510. package/dist/testing/fake-hub.d.ts +425 -0
  511. package/dist/testing/fake-hub.d.ts.map +1 -0
  512. package/dist/testing/fake-hub.js +1074 -0
  513. package/dist/testing/fake-hub.js.map +1 -0
  514. package/dist/testing/helpers.d.ts +124 -0
  515. package/dist/testing/helpers.d.ts.map +1 -0
  516. package/dist/testing/helpers.js +174 -0
  517. package/dist/testing/helpers.js.map +1 -0
  518. package/dist/testing/index.d.ts +12 -0
  519. package/dist/testing/index.d.ts.map +1 -0
  520. package/dist/testing/index.js +12 -0
  521. package/dist/testing/index.js.map +1 -0
  522. package/dist/testing/setup-origins.d.ts +21 -0
  523. package/dist/testing/setup-origins.d.ts.map +1 -0
  524. package/dist/testing/setup-origins.js +57 -0
  525. package/dist/testing/setup-origins.js.map +1 -0
  526. package/dist/testing/sso-helpers.d.ts +43 -0
  527. package/dist/testing/sso-helpers.d.ts.map +1 -0
  528. package/dist/testing/sso-helpers.js +159 -0
  529. package/dist/testing/sso-helpers.js.map +1 -0
  530. package/dist/tool-definition.d.ts +382 -0
  531. package/dist/tool-definition.d.ts.map +1 -0
  532. package/dist/tool-definition.js +46 -0
  533. package/dist/tool-definition.js.map +1 -0
  534. package/dist/util/index.d.ts +8 -0
  535. package/dist/util/index.d.ts.map +1 -0
  536. package/dist/util/index.js +8 -0
  537. package/dist/util/index.js.map +1 -0
  538. package/package.json +161 -0
  539. package/src/accounts/deletion.ts +389 -0
  540. package/src/accounts/erasure-log.ts +140 -0
  541. package/src/accounts/index.ts +5 -0
  542. package/src/accounts/mint-refusal.ts +67 -0
  543. package/src/accounts/signup-duplicate.ts +21 -0
  544. package/src/accounts/superadmin.ts +46 -0
  545. package/src/api/apikeys.ts +147 -0
  546. package/src/api/audit.ts +83 -0
  547. package/src/api/break-glass.ts +294 -0
  548. package/src/api/cli-auth.ts +308 -0
  549. package/src/api/create-api.ts +1403 -0
  550. package/src/api/demo-passes.ts +207 -0
  551. package/src/api/errors.ts +13 -0
  552. package/src/api/export.ts +482 -0
  553. package/src/api/files.ts +200 -0
  554. package/src/api/index.ts +29 -0
  555. package/src/api/invitations.ts +396 -0
  556. package/src/api/members.ts +617 -0
  557. package/src/api/onboarding.ts +50 -0
  558. package/src/api/openapi-doc.ts +34 -0
  559. package/src/api/projects.ts +788 -0
  560. package/src/api/scope-routes.ts +12 -0
  561. package/src/api/sso-connect.ts +246 -0
  562. package/src/api/sso-logout.ts +76 -0
  563. package/src/api/teams.ts +575 -0
  564. package/src/api/workspaces.ts +649 -0
  565. package/src/apikeys/index.ts +2 -0
  566. package/src/apikeys/peppers.ts +118 -0
  567. package/src/apikeys/service.ts +223 -0
  568. package/src/app.ts +228 -0
  569. package/src/audit/filters.ts +101 -0
  570. package/src/audit/index.ts +9 -0
  571. package/src/audit/service.ts +154 -0
  572. package/src/boot.ts +953 -0
  573. package/src/constant-time.ts +9 -0
  574. package/src/email/driver.ts +139 -0
  575. package/src/email/index.ts +26 -0
  576. package/src/email/shell.ts +201 -0
  577. package/src/email/templates.ts +184 -0
  578. package/src/entitlements/check.ts +435 -0
  579. package/src/entitlements/clock-skew.ts +58 -0
  580. package/src/entitlements/gate.ts +636 -0
  581. package/src/entitlements/hub-machine-token.ts +205 -0
  582. package/src/entitlements/hub-subject.ts +77 -0
  583. package/src/entitlements/index.ts +37 -0
  584. package/src/entitlements/poster.ts +265 -0
  585. package/src/entitlements/profiles.ts +303 -0
  586. package/src/entitlements/slot.ts +105 -0
  587. package/src/env.ts +456 -0
  588. package/src/files/http.ts +77 -0
  589. package/src/files/index.ts +4 -0
  590. package/src/files/serve.ts +115 -0
  591. package/src/files/service.ts +209 -0
  592. package/src/files/spool.ts +58 -0
  593. package/src/identity/better-auth.ts +1103 -0
  594. package/src/identity/demo-pass-plugin.ts +121 -0
  595. package/src/identity/demo-pass-rules.ts +229 -0
  596. package/src/identity/demo-pass.ts +390 -0
  597. package/src/identity/hub-grant.ts +704 -0
  598. package/src/identity/hub-jwt.ts +78 -0
  599. package/src/identity/hub-live-gate.ts +167 -0
  600. package/src/identity/hub-logout.ts +174 -0
  601. package/src/identity/hub-projection.ts +251 -0
  602. package/src/identity/hub-reconcile.ts +572 -0
  603. package/src/identity/hub-sso.ts +696 -0
  604. package/src/identity/hub-user-client.ts +554 -0
  605. package/src/identity/index.ts +56 -0
  606. package/src/identity/oauth-jwt.ts +128 -0
  607. package/src/identity/resolve-membership.ts +104 -0
  608. package/src/identity/signing-key.ts +164 -0
  609. package/src/index.ts +65 -0
  610. package/src/invitations/index.ts +1 -0
  611. package/src/invitations/service.ts +171 -0
  612. package/src/jobs/index.ts +25 -0
  613. package/src/jobs/pgboss.ts +594 -0
  614. package/src/jobs/timers.ts +287 -0
  615. package/src/logger.ts +67 -0
  616. package/src/mcp/errors.ts +111 -0
  617. package/src/mcp/http.ts +129 -0
  618. package/src/mcp/index.ts +28 -0
  619. package/src/mcp/inputs.ts +33 -0
  620. package/src/mcp/projects.ts +480 -0
  621. package/src/mcp/server.ts +174 -0
  622. package/src/mcp/teams.ts +97 -0
  623. package/src/mcp/tool-kit.ts +148 -0
  624. package/src/members/removal.ts +216 -0
  625. package/src/middleware/auth-body.ts +58 -0
  626. package/src/middleware/auth-context.ts +384 -0
  627. package/src/middleware/body-cap.ts +33 -0
  628. package/src/middleware/body-refusal.ts +23 -0
  629. package/src/middleware/cross-site.ts +122 -0
  630. package/src/middleware/hub-managed.ts +61 -0
  631. package/src/middleware/idempotency.ts +264 -0
  632. package/src/middleware/index.ts +33 -0
  633. package/src/middleware/json-depth.ts +74 -0
  634. package/src/middleware/no-store.ts +30 -0
  635. package/src/middleware/oauth-public.ts +54 -0
  636. package/src/middleware/rate-limit.ts +432 -0
  637. package/src/middleware/request-id.ts +54 -0
  638. package/src/middleware/scopes.ts +150 -0
  639. package/src/middleware/security-headers.ts +129 -0
  640. package/src/observability/index.ts +2 -0
  641. package/src/observability/metrics.ts +102 -0
  642. package/src/observability/otel.ts +79 -0
  643. package/src/pagination.ts +118 -0
  644. package/src/platform/edition.ts +140 -0
  645. package/src/platform/entitlements.ts +47 -0
  646. package/src/platform/events.ts +71 -0
  647. package/src/platform/index.ts +7 -0
  648. package/src/platform/local-identity.ts +90 -0
  649. package/src/platform/registry.ts +28 -0
  650. package/src/platform/usage.ts +13 -0
  651. package/src/platform/workspaces.ts +41 -0
  652. package/src/projects/access.ts +160 -0
  653. package/src/projects/index.ts +7 -0
  654. package/src/route-label.ts +29 -0
  655. package/src/routes/health.ts +79 -0
  656. package/src/routes/index.ts +2 -0
  657. package/src/routes/wellknown.ts +67 -0
  658. package/src/secret.ts +115 -0
  659. package/src/setup-transport.ts +46 -0
  660. package/src/state.ts +23 -0
  661. package/src/storage/driver.ts +48 -0
  662. package/src/storage/factory.ts +34 -0
  663. package/src/storage/index.ts +3 -0
  664. package/src/storage/local.ts +93 -0
  665. package/src/storage/s3.ts +109 -0
  666. package/src/testing/fake-hub.ts +1316 -0
  667. package/src/testing/helpers.ts +254 -0
  668. package/src/testing/index.ts +11 -0
  669. package/src/testing/setup-origins.ts +58 -0
  670. package/src/testing/sso-helpers.ts +178 -0
  671. package/src/tool-definition.ts +463 -0
  672. package/src/util/index.ts +17 -0
  673. package/test/fixtures/onboarding-backfill.sql +13 -0
  674. package/test/fixtures/operator-user-id-backfill.sql +18 -0
  675. package/test/host/dr-lib.sh +253 -0
  676. package/test/host/drizzle/0000_chassis_baseline.sql +438 -0
  677. package/test/host/drizzle/0001_last_owner_guard.sql +42 -0
  678. package/test/host/drizzle/meta/0000_snapshot.json +3566 -0
  679. package/test/host/drizzle/meta/_journal.json +20 -0
  680. package/test/host/drizzle.config.ts +17 -0
  681. package/test/host/identity.ts +41 -0
  682. package/test/host/minimal-host.ts +35 -0
  683. package/test/host/minimal-tool.ts +123 -0
  684. package/test/integration/account-oracle-uniformity.test.ts +284 -0
  685. package/test/integration/account-recovery.test.ts +236 -0
  686. package/test/integration/account.test.ts +120 -0
  687. package/test/integration/api-quota.test.ts +208 -0
  688. package/test/integration/apikey-expiry.test.ts +178 -0
  689. package/test/integration/apikey-pepper-rotation.test.ts +190 -0
  690. package/test/integration/boot-posture.test.ts +169 -0
  691. package/test/integration/break-glass.test.ts +484 -0
  692. package/test/integration/cloud-lifecycle.test.ts +233 -0
  693. package/test/integration/credential-boundaries.test.ts +195 -0
  694. package/test/integration/default-workspace.test.ts +414 -0
  695. package/test/integration/demo-pass-rules.test.ts +332 -0
  696. package/test/integration/demo-pass.test.ts +1222 -0
  697. package/test/integration/dr-verify-real-dump.test.ts +154 -0
  698. package/test/integration/edition.test.ts +868 -0
  699. package/test/integration/email-change.test.ts +394 -0
  700. package/test/integration/empty-tool.test.ts +267 -0
  701. package/test/integration/entitlements-null-hook.test.ts +187 -0
  702. package/test/integration/entitlements.test.ts +693 -0
  703. package/test/integration/export-entries.test.ts +321 -0
  704. package/test/integration/files.test.ts +320 -0
  705. package/test/integration/first-boot-claim.test.ts +131 -0
  706. package/test/integration/gdpr.test.ts +532 -0
  707. package/test/integration/helpers.ts +29 -0
  708. package/test/integration/hub-grant.test.ts +505 -0
  709. package/test/integration/hub-live-gate.test.ts +612 -0
  710. package/test/integration/hub-managed-membership.test.ts +559 -0
  711. package/test/integration/hub-org-selector.test.ts +281 -0
  712. package/test/integration/hub-reconcile.test.ts +646 -0
  713. package/test/integration/hub-sso.test.ts +704 -0
  714. package/test/integration/hub-teams.test.ts +771 -0
  715. package/test/integration/idempotency.test.ts +261 -0
  716. package/test/integration/invite-verification.test.ts +210 -0
  717. package/test/integration/last-owner-race.test.ts +263 -0
  718. package/test/integration/m9-fixes.test.ts +290 -0
  719. package/test/integration/mcp-projects.test.ts +463 -0
  720. package/test/integration/member-removal-race.test.ts +466 -0
  721. package/test/integration/member-removal.test.ts +794 -0
  722. package/test/integration/oauth-mcp.test.ts +477 -0
  723. package/test/integration/oauth-workspace.test.ts +371 -0
  724. package/test/integration/observability.test.ts +183 -0
  725. package/test/integration/onboarding.test.ts +268 -0
  726. package/test/integration/orphan-purge.test.ts +451 -0
  727. package/test/integration/pagination.test.ts +344 -0
  728. package/test/integration/platform-core.test.ts +305 -0
  729. package/test/integration/platform.test.ts +246 -0
  730. package/test/integration/pool-survives-restart.test.ts +80 -0
  731. package/test/integration/projects-cloud.test.ts +193 -0
  732. package/test/integration/projects.test.ts +1310 -0
  733. package/test/integration/security-fixes.test.ts +190 -0
  734. package/test/integration/setup-transport.test.ts +118 -0
  735. package/test/integration/signin-wall.test.ts +103 -0
  736. package/test/integration/signing-key-rotation.test.ts +349 -0
  737. package/test/integration/sso-helpers.ts +15 -0
  738. package/test/integration/sso-logout.test.ts +283 -0
  739. package/test/integration/teams-cloud.test.ts +194 -0
  740. package/test/integration/teams.test.ts +551 -0
  741. package/test/integration/timers.test.ts +377 -0
  742. package/test/integration/two-factor.test.ts +301 -0
  743. package/test/integration/usage-window.test.ts +161 -0
  744. package/test/integration/workspace-create-cloud.test.ts +523 -0
  745. package/test/integration/workspace-create.test.ts +510 -0
  746. package/test/integration/workspace-scoping.test.ts +530 -0
  747. package/test/integration/zz-adv-replay-owner.test.ts +205 -0
  748. package/test/unit/apikey-peppers.test.ts +110 -0
  749. package/test/unit/apikey-prefix.test.ts +34 -0
  750. package/test/unit/audit-filters.test.ts +135 -0
  751. package/test/unit/auth-origins.test.ts +92 -0
  752. package/test/unit/body-cap.test.ts +84 -0
  753. package/test/unit/clock-skew.test.ts +68 -0
  754. package/test/unit/cross-site.test.ts +166 -0
  755. package/test/unit/declared-credits.test.ts +13 -0
  756. package/test/unit/demo-pass-rules.test.ts +192 -0
  757. package/test/unit/email-driver.test.ts +127 -0
  758. package/test/unit/end-pool.test.ts +181 -0
  759. package/test/unit/entitlement-check.test.ts +492 -0
  760. package/test/unit/entitlement-gate.test.ts +1333 -0
  761. package/test/unit/entitlement-profiles.test.ts +289 -0
  762. package/test/unit/erasure-log.test.ts +72 -0
  763. package/test/unit/error-mapping.test.ts +89 -0
  764. package/test/unit/export-entries.test.ts +85 -0
  765. package/test/unit/export-sanitize.test.ts +27 -0
  766. package/test/unit/files-head-route.test.ts +155 -0
  767. package/test/unit/files-http.test.ts +97 -0
  768. package/test/unit/head-rewrite.test.ts +72 -0
  769. package/test/unit/hub-create-org.test.ts +181 -0
  770. package/test/unit/hub-jwt.test.ts +93 -0
  771. package/test/unit/hub-sso-params.test.ts +39 -0
  772. package/test/unit/hub-subject.test.ts +83 -0
  773. package/test/unit/idempotency-crypto.test.ts +45 -0
  774. package/test/unit/json-depth.test.ts +88 -0
  775. package/test/unit/logger-redaction.test.ts +66 -0
  776. package/test/unit/mcp-errors.test.ts +110 -0
  777. package/test/unit/mcp-inputs.test.ts +106 -0
  778. package/test/unit/mcp-project-hints.test.ts +26 -0
  779. package/test/unit/no-store.test.ts +49 -0
  780. package/test/unit/no-tool-migration-filename.test.ts +70 -0
  781. package/test/unit/observability.test.ts +64 -0
  782. package/test/unit/openapi-doc.test.ts +93 -0
  783. package/test/unit/rate-limit-consume-on.test.ts +76 -0
  784. package/test/unit/rate-limit.test.ts +39 -0
  785. package/test/unit/readyz-storage.test.ts +157 -0
  786. package/test/unit/request-quota.test.ts +146 -0
  787. package/test/unit/scopes.test.ts +66 -0
  788. package/test/unit/security-headers.test.ts +131 -0
  789. package/test/unit/serve-content-type.test.ts +74 -0
  790. package/test/unit/setup-transport.test.ts +29 -0
  791. package/test/unit/storage-local.test.ts +53 -0
  792. package/test/unit/superadmin.test.ts +32 -0
  793. package/test/unit/timers.test.ts +287 -0
  794. package/test/unit/tool-definition-guards.test.ts +166 -0
  795. package/test/unit/tool-entitlements-guard.test.ts +168 -0
  796. package/test/unit/usage-poster.test.ts +542 -0
  797. package/test/unit/usage-window.test.ts +48 -0
  798. package/test/unit/workspace-create-audit.test.ts +48 -0
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Writable } from 'node:stream';
3
+ import { pino } from 'pino';
4
+ import { REDACT_PATHS } from '@antasphere/chassis-server/logger';
5
+ import { buildCsp, inlineScriptHashes } from '@antasphere/chassis-server/middleware';
6
+
7
+ describe('pino redaction (secrets never reach the stream)', () => {
8
+ it('censors passwords, tokens, auth headers, and connection strings', () => {
9
+ const lines: string[] = [];
10
+ const sink = new Writable({
11
+ write(chunk, _enc, cb) {
12
+ lines.push(String(chunk));
13
+ cb();
14
+ }
15
+ });
16
+ // Uses the REAL redaction list exported from logger.ts, so this test
17
+ // cannot drift from what production logs.
18
+ const log = pino({ redact: { paths: REDACT_PATHS, censor: '[redacted]' } }, sink);
19
+
20
+ log.info(
21
+ {
22
+ req: { headers: { authorization: 'Bearer super-secret', cookie: 'session=abc' } },
23
+ body: { password: 'hunter2', token: 'tok_123', secret: 's3cr3t' },
24
+ DATABASE_URL: 'postgres://u:p@h/db',
25
+ RESEND_API_KEY: 're_live_deadbeef',
26
+ BREVO_API_KEY: 'xkeysib-deadbeef',
27
+ S3_SECRET_ACCESS_KEY: 's3-super-secret',
28
+ SETUP_TOKEN: 'setup-deadbeef'
29
+ },
30
+ 'test'
31
+ );
32
+
33
+ const out = lines.join('');
34
+ expect(out).not.toContain('super-secret');
35
+ expect(out).not.toContain('session=abc');
36
+ expect(out).not.toContain('hunter2');
37
+ expect(out).not.toContain('tok_123');
38
+ expect(out).not.toContain('postgres://u:p@h/db');
39
+ expect(out).not.toContain('re_live_deadbeef');
40
+ expect(out).not.toContain('xkeysib-deadbeef');
41
+ expect(out).not.toContain('s3-super-secret');
42
+ expect(out).not.toContain('setup-deadbeef');
43
+ expect(out).toContain('[redacted]');
44
+ });
45
+ });
46
+
47
+ describe('CSP with inline-script hashes', () => {
48
+ it('hashes each non-empty inline script and skips src scripts', () => {
49
+ const html = `<html><head>
50
+ <script src="/app.js"></script>
51
+ <script>console.log("boot")</script>
52
+ <script type="module">start()</script>
53
+ <script></script>
54
+ </head></html>`;
55
+ const hashes = inlineScriptHashes(html);
56
+ expect(hashes).toHaveLength(2);
57
+ for (const h of hashes) expect(h).toMatch(/^'sha256-[A-Za-z0-9+/=]+'$/);
58
+
59
+ const csp = buildCsp(hashes);
60
+ expect(csp).toContain(`script-src 'self' ${hashes[0]} ${hashes[1]}`);
61
+ expect(csp).toContain("frame-ancestors 'none'");
62
+ expect(csp).toContain("object-src 'none'");
63
+ });
64
+ });
@@ -0,0 +1,93 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi';
3
+ import { readdirSync, readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { registerOpenApiDoc } from '@antasphere/chassis-server/api';
6
+
7
+ /**
8
+ * PLT-3: `api.doc()` runs the whole synchronous OpenAPI generator inside the
9
+ * request handler, on an endpoint that is unauthenticated by design and
10
+ * therefore never reaches the per-principal quota — an anonymous event-loop
11
+ * DoS that starves /healthz and trips the container healthcheck.
12
+ */
13
+ function apiWithRoutes(): OpenAPIHono {
14
+ const api = new OpenAPIHono();
15
+ api.openapi(
16
+ createRoute({
17
+ method: 'get',
18
+ path: '/things',
19
+ responses: {
20
+ 200: { description: 'ok', content: { 'application/json': { schema: z.object({ a: z.string() }) } } }
21
+ }
22
+ }),
23
+ (c) => c.json({ a: 'b' }, 200)
24
+ );
25
+ return api;
26
+ }
27
+
28
+ const CONFIG = { openapi: '3.1.0', info: { title: 'Test API', version: '1' } };
29
+
30
+ describe('registerOpenApiDoc', () => {
31
+ it('generates the document exactly ONCE, at registration', async () => {
32
+ const api = apiWithRoutes();
33
+ const spy = vi.spyOn(api, 'getOpenAPIDocument');
34
+ registerOpenApiDoc(api, CONFIG);
35
+ expect(spy).toHaveBeenCalledTimes(1);
36
+
37
+ for (let i = 0; i < 25; i++) {
38
+ const res = await api.request('/openapi.json');
39
+ expect(res.status).toBe(200);
40
+ }
41
+ // Not once more, however hard it is hammered.
42
+ expect(spy).toHaveBeenCalledTimes(1);
43
+ });
44
+
45
+ it('serves a byte-identical, correctly typed, cacheable document', async () => {
46
+ const api = apiWithRoutes();
47
+ registerOpenApiDoc(api, CONFIG);
48
+ const first = await api.request('/openapi.json');
49
+ const second = await api.request('/openapi.json');
50
+ expect(first.headers.get('content-type')).toContain('application/json');
51
+ expect(first.headers.get('cache-control')).toBe('public, max-age=300');
52
+ const a = await first.text();
53
+ const b = await second.text();
54
+ expect(a).toBe(b);
55
+ expect(JSON.parse(a)).toMatchObject({ info: { title: 'Test API' }, paths: { '/things': {} } });
56
+ });
57
+ });
58
+
59
+ /**
60
+ * The other half of PLT-3, and the half `registerOpenApiDoc` alone cannot
61
+ * prove: the API app has to actually USE it. Reverting `api/index.ts` to
62
+ * `api.doc('/openapi.json', …)` restores the per-request generator while every
63
+ * test above stays green, because none of them touch `api/index.ts`. Assert on
64
+ * the source, the same way head-rewrite.test.ts guards the dead HEAD idiom.
65
+ */
66
+ describe('the API app does not register a per-request document generator', () => {
67
+ it('never calls api.doc() — registerOpenApiDoc is the only registration', () => {
68
+ // The routers live in two places since the chassis extraction: the generic
69
+ // ones here, the tool's in the app that composes it. This audits the
70
+ // generic ones; the tool audits its own in its own unit suite
71
+ // (apps/server/test/unit/api-registrations.test.ts in the tool template).
72
+ const apiDirs = [join(import.meta.dirname, '../../src/api')];
73
+ const offenders: string[] = [];
74
+ let registrations = 0;
75
+ const files = apiDirs.flatMap((dir) => readdirSync(dir).map((file) => join(dir, file)));
76
+ for (const file of files) {
77
+ // Skip the helper's own definition — we are auditing its CALLERS.
78
+ if (!file.endsWith('.ts') || file.endsWith('/openapi-doc.ts')) continue;
79
+ const code = readFileSync(file, 'utf8')
80
+ .split('\n')
81
+ .filter((line) => {
82
+ const t = line.trim();
83
+ return !t.startsWith('//') && !t.startsWith('*') && !t.startsWith('/*');
84
+ })
85
+ .join('\n');
86
+ if (/\bapi\.doc\d?\s*\(/.test(code)) offenders.push(file);
87
+ registrations += (code.match(/registerOpenApiDoc\s*\(/g) ?? []).length;
88
+ }
89
+ expect(offenders).toEqual([]);
90
+ // index.ts imports it and calls it exactly once.
91
+ expect(registrations).toBe(1);
92
+ });
93
+ });
@@ -0,0 +1,76 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Hono } from 'hono';
3
+ import { RateLimiterMemory } from 'rate-limiter-flexible';
4
+ import { emailKeyOf, rateLimit } from '@antasphere/chassis-server/middleware';
5
+
6
+ /**
7
+ * AF-4: the login wall consumed its buckets on ARRIVAL, before any credential
8
+ * was verified — and one of its keys is `email:<addr>` read straight out of
9
+ * the request body. Ten POSTs naming a victim therefore emptied that account's
10
+ * bucket and locked the owner out for the window, and the owner's own correct
11
+ * sign-ins spent the same budget.
12
+ *
13
+ * `consumeOn: 'failure'` keeps the brute-force wall exactly as tight (a wrong
14
+ * password IS a failure and still costs a point, an exhausted bucket still
15
+ * 429s before the handler runs) while a successful sign-in costs nothing.
16
+ */
17
+ const ip = () => '203.0.113.9';
18
+
19
+ function loginApp(limiter: RateLimiterMemory, consumeOn: 'arrival' | 'failure') {
20
+ const app = new Hono();
21
+ app.use('/sign-in', rateLimit(limiter, ip, emailKeyOf, { consumeOn }));
22
+ app.post('/sign-in', async (c) => {
23
+ const body = (await c.req.json()) as { email: string; password: string };
24
+ if (body.password !== 'correct-horse') return c.json({ error: 'bad credentials' }, 401);
25
+ return c.json({ ok: true });
26
+ });
27
+ return app;
28
+ }
29
+
30
+ const attempt = (app: Hono, password: string) =>
31
+ app.request('/sign-in', {
32
+ method: 'POST',
33
+ headers: { 'content-type': 'application/json' },
34
+ body: JSON.stringify({ email: 'victim@example.com', password })
35
+ });
36
+
37
+ describe('rateLimit consumeOn', () => {
38
+ it('a SUCCESSFUL sign-in costs the account nothing', async () => {
39
+ const limiter = new RateLimiterMemory({ points: 3, duration: 900 });
40
+ const app = loginApp(limiter, 'failure');
41
+ for (let i = 0; i < 10; i++) {
42
+ const res = await attempt(app, 'correct-horse');
43
+ expect(res.status).toBe(200);
44
+ }
45
+ expect(await limiter.get('email:victim@example.com')).toBeNull();
46
+ });
47
+
48
+ it('a FAILED sign-in still costs a point — the brute-force wall is intact', async () => {
49
+ const limiter = new RateLimiterMemory({ points: 3, duration: 900 });
50
+ const app = loginApp(limiter, 'failure');
51
+ expect((await attempt(app, 'wrong')).status).toBe(401);
52
+ expect((await attempt(app, 'wrong')).status).toBe(401);
53
+ expect((await attempt(app, 'wrong')).status).toBe(401);
54
+ // Fourth arrival finds an empty bucket and is refused BEFORE the handler.
55
+ const fourth = await attempt(app, 'wrong');
56
+ expect(fourth.status).toBe(429);
57
+ expect(await fourth.json()).toMatchObject({ error: { code: 'rate_limited' } });
58
+ });
59
+
60
+ it('consumeOn arrival — the old behaviour — burns the victim budget on success', async () => {
61
+ // Pinning the contrast, so a revert to the default is loud.
62
+ const limiter = new RateLimiterMemory({ points: 3, duration: 900 });
63
+ const app = loginApp(limiter, 'arrival');
64
+ for (let i = 0; i < 3; i++) expect((await attempt(app, 'correct-horse')).status).toBe(200);
65
+ expect((await attempt(app, 'correct-horse')).status).toBe(429);
66
+ });
67
+
68
+ it('defaults to arrival so every other surface is unchanged', async () => {
69
+ const limiter = new RateLimiterMemory({ points: 1, duration: 900 });
70
+ const app = new Hono();
71
+ app.use('/send', rateLimit(limiter, ip));
72
+ app.post('/send', (c) => c.json({ sent: true }));
73
+ expect((await app.request('/send', { method: 'POST' })).status).toBe(200);
74
+ expect((await app.request('/send', { method: 'POST' })).status).toBe(429);
75
+ });
76
+ });
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { Context } from 'hono';
3
+ import { makeClientIp } from '@antasphere/chassis-server/middleware';
4
+
5
+ /**
6
+ * makeClientIp reads the RIGHTMOST x-forwarded-for hop (the one the trusted
7
+ * proxy appended/set) — the leftmost is client-claimed and spoofable. The
8
+ * stub has no socket, so getConnInfo throws and the fallback is 'unknown'.
9
+ */
10
+ function stubContext(xff?: string): Context {
11
+ return {
12
+ req: {
13
+ header: (name: string) => (name.toLowerCase() === 'x-forwarded-for' ? xff : undefined)
14
+ }
15
+ } as unknown as Context;
16
+ }
17
+
18
+ describe('makeClientIp (rightmost XFF hop)', () => {
19
+ it('picks the rightmost hop when TRUST_PROXY is on', () => {
20
+ const clientIp = makeClientIp(true);
21
+ expect(clientIp(stubContext('6.6.6.6, 203.0.113.9'))).toBe('203.0.113.9');
22
+ });
23
+
24
+ it('returns the single hop when there is only one', () => {
25
+ const clientIp = makeClientIp(true);
26
+ expect(clientIp(stubContext('203.0.113.9'))).toBe('203.0.113.9');
27
+ });
28
+
29
+ it('trims whitespace around the selected hop', () => {
30
+ const clientIp = makeClientIp(true);
31
+ expect(clientIp(stubContext('a, 203.0.113.9 '))).toBe('203.0.113.9');
32
+ });
33
+
34
+ it('ignores x-forwarded-for entirely when TRUST_PROXY is off', () => {
35
+ const clientIp = makeClientIp(false);
36
+ // Header ignored → no socket in the stub → 'unknown' fallback.
37
+ expect(clientIp(stubContext('6.6.6.6, 203.0.113.9'))).toBe('unknown');
38
+ });
39
+ });
@@ -0,0 +1,157 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { healthRoutes } from '@antasphere/chassis-server/routes';
3
+ import { createRuntimeState } from '@antasphere/chassis-server/util';
4
+
5
+ /**
6
+ * OPS-4: /readyz must be a LIVE claim about the backing store, not a memory
7
+ * of the boot-time probe.
8
+ *
9
+ * The failure this guards is not theoretical: a restore that dies after
10
+ * wiping /data leaves the app running against storage it cannot write, and
11
+ * the old readiness route — a boot-time boolean — kept answering 200. A load
12
+ * balancer therefore kept sending it traffic, and the operator's own drill
13
+ * reported the instance healthy.
14
+ */
15
+ function readyState() {
16
+ const state = createRuntimeState();
17
+ state.ready = true;
18
+ state.reason = '';
19
+ return state;
20
+ }
21
+
22
+ describe('/readyz asserts storage reachability', () => {
23
+ it('503s with reason "storage" when the store is unwritable, even though boot said ready', async () => {
24
+ const state = readyState();
25
+ const app = healthRoutes(state, {
26
+ probeStorage: () => Promise.reject(new Error('EROFS: /data/tmp is read-only'))
27
+ });
28
+
29
+ const res = await app.request('/readyz');
30
+ expect(res.status).toBe(503);
31
+ expect(await res.json()).toEqual({ status: 'unavailable', reason: 'storage' });
32
+ });
33
+
34
+ it('200s when the store is writable', async () => {
35
+ const app = healthRoutes(readyState(), { probeStorage: () => Promise.resolve() });
36
+ const res = await app.request('/readyz');
37
+ expect(res.status).toBe(200);
38
+ expect(await res.json()).toEqual({ status: 'ready' });
39
+ });
40
+
41
+ it('never leaks the driver error text to the unauthenticated endpoint', async () => {
42
+ const app = healthRoutes(readyState(), {
43
+ probeStorage: () => Promise.reject(new Error('s3: bucket acme-prod-secrets AccessDenied'))
44
+ });
45
+ const body = await (await app.request('/readyz')).text();
46
+ expect(body).not.toContain('acme-prod-secrets');
47
+ expect(body).not.toContain('AccessDenied');
48
+ });
49
+
50
+ it('flips back to 503 when a healthy instance loses its storage later', async () => {
51
+ let fail = false;
52
+ let clock = 0;
53
+ const app = healthRoutes(readyState(), {
54
+ probeStorage: () => (fail ? Promise.reject(new Error('gone')) : Promise.resolve()),
55
+ storageProbeTtlMs: 10,
56
+ now: () => clock
57
+ });
58
+
59
+ expect((await app.request('/readyz')).status).toBe(200);
60
+ fail = true;
61
+ clock += 1000; // past the success TTL
62
+ expect((await app.request('/readyz')).status).toBe(503);
63
+ });
64
+
65
+ it('caches a SUCCESS for the TTL but never caches a FAILURE', async () => {
66
+ let probes = 0;
67
+ let fail = false;
68
+ let clock = 0;
69
+ const app = healthRoutes(readyState(), {
70
+ probeStorage: () => {
71
+ probes++;
72
+ return fail ? Promise.reject(new Error('gone')) : Promise.resolve();
73
+ },
74
+ storageProbeTtlMs: 10_000,
75
+ now: () => clock
76
+ });
77
+
78
+ await app.request('/readyz');
79
+ await app.request('/readyz');
80
+ await app.request('/readyz');
81
+ expect(probes, 'successes are cached for the TTL').toBe(1);
82
+
83
+ clock += 10_001;
84
+ fail = true;
85
+ await app.request('/readyz');
86
+ await app.request('/readyz');
87
+ // A failure must re-probe every time so recovery is seen immediately.
88
+ expect(probes).toBe(3);
89
+
90
+ fail = false;
91
+ expect((await app.request('/readyz')).status).toBe(200);
92
+ });
93
+
94
+ it('coalesces concurrent probes into one call', async () => {
95
+ let probes = 0;
96
+ let release!: () => void;
97
+ const gate = new Promise<void>((r) => (release = r));
98
+ const app = healthRoutes(readyState(), {
99
+ probeStorage: () => {
100
+ probes++;
101
+ return gate;
102
+ }
103
+ });
104
+
105
+ const all = Promise.all([app.request('/readyz'), app.request('/readyz'), app.request('/readyz')]);
106
+ release();
107
+ for (const res of await all) expect(res.status).toBe(200);
108
+ expect(probes).toBe(1);
109
+ });
110
+
111
+ it('reports the failure to the logger hook', async () => {
112
+ const seen: unknown[] = [];
113
+ const app = healthRoutes(readyState(), {
114
+ probeStorage: () => Promise.reject(new Error('EROFS')),
115
+ onStorageFailure: (err) => seen.push(err)
116
+ });
117
+ await app.request('/readyz');
118
+ expect(seen).toHaveLength(1);
119
+ expect((seen[0] as Error).message).toBe('EROFS');
120
+ });
121
+
122
+ it('keeps draining and not-yet-ready ahead of the storage probe', async () => {
123
+ let probes = 0;
124
+ const state = createRuntimeState(); // ready=false, reason='booting'
125
+ const app = healthRoutes(state, {
126
+ probeStorage: () => {
127
+ probes++;
128
+ return Promise.resolve();
129
+ }
130
+ });
131
+
132
+ let res = await app.request('/readyz');
133
+ expect(res.status).toBe(503);
134
+ expect(await res.json()).toEqual({ status: 'unavailable', reason: 'booting' });
135
+
136
+ state.ready = true;
137
+ state.reason = '';
138
+ state.draining = true;
139
+ res = await app.request('/readyz');
140
+ expect(res.status).toBe(503);
141
+ expect(await res.json()).toEqual({ status: 'unavailable', reason: 'draining' });
142
+ expect(probes, 'no pointless writes against the store while shutting down').toBe(0);
143
+ });
144
+
145
+ it('/healthz stays dependency-free — it must not touch storage', async () => {
146
+ let probes = 0;
147
+ const app = healthRoutes(readyState(), {
148
+ probeStorage: () => {
149
+ probes++;
150
+ return Promise.reject(new Error('gone'));
151
+ }
152
+ });
153
+ const res = await app.request('/healthz');
154
+ expect(res.status).toBe(200);
155
+ expect(probes).toBe(0);
156
+ });
157
+ });
@@ -0,0 +1,146 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { RateLimiterMemory } from 'rate-limiter-flexible';
3
+ import type { EntitlementService, Principal, RequestQuota } from '@antasphere/chassis-contract';
4
+ import { createRequestQuota, principalBucketKey } from '@antasphere/chassis-server/middleware';
5
+ import type { Logger } from '@antasphere/chassis-server/logger';
6
+
7
+ /**
8
+ * The general per-principal quota service: bucket keys derive from the
9
+ * AUTHENTICATED principal identity only, limits come from the
10
+ * EntitlementService seam, and backend/entitlement failures fail OPEN (the
11
+ * quota is a cost control, not an authz boundary).
12
+ */
13
+
14
+ const noopLogger = { error: () => {}, info: () => {}, warn: () => {} } as unknown as Logger;
15
+
16
+ function principal(overrides: Partial<Principal> = {}): Principal {
17
+ return {
18
+ userId: 'user-1',
19
+ email: 'u@example.test',
20
+ name: 'U',
21
+ workspaceId: 'ws-1',
22
+ role: 'member',
23
+ origin: 'local',
24
+ via: 'session',
25
+ scopes: null,
26
+ ...overrides
27
+ };
28
+ }
29
+
30
+ function stubEntitlements(quota: RequestQuota | (() => RequestQuota)): EntitlementService {
31
+ return {
32
+ check: async () => ({ allowed: true }),
33
+ getRequestQuota: async () => (typeof quota === 'function' ? quota() : quota)
34
+ };
35
+ }
36
+
37
+ const memoryMake = (prefix: string, points: number, duration: number) =>
38
+ new RateLimiterMemory({ keyPrefix: `rl:${prefix}`, points, duration });
39
+
40
+ describe('principalBucketKey', () => {
41
+ it('keys API-key principals by the key id, not the user', () => {
42
+ const p = principal({ via: 'api_key', apiKeyId: 'key-abc', scopes: new Set(['things:read']) });
43
+ expect(principalBucketKey(p)).toBe('key:key-abc');
44
+ });
45
+
46
+ it('keys OAuth principals by the token subject (userId)', () => {
47
+ const p = principal({ via: 'oauth', scopes: new Set(['things:read']) });
48
+ expect(principalBucketKey(p)).toBe('oauth:user-1');
49
+ });
50
+
51
+ it('keys session principals by the user id', () => {
52
+ expect(principalBucketKey(principal())).toBe('session:user-1');
53
+ });
54
+
55
+ it('gives two API keys of the same user distinct buckets', () => {
56
+ const a = principal({ via: 'api_key', apiKeyId: 'key-a', scopes: new Set() });
57
+ const b = principal({ via: 'api_key', apiKeyId: 'key-b', scopes: new Set() });
58
+ expect(principalBucketKey(a)).not.toBe(principalBucketKey(b));
59
+ });
60
+ });
61
+
62
+ describe('createRequestQuota', () => {
63
+ it('trips at the sustained threshold with a retry hint and recovers headers state', async () => {
64
+ const quota = createRequestQuota({
65
+ entitlements: stubEntitlements({ perMinute: 3, burstPerSecond: 0 }),
66
+ make: memoryMake,
67
+ logger: noopLogger
68
+ });
69
+ const p = principal();
70
+
71
+ for (let i = 0; i < 3; i++) {
72
+ const d = await quota.consume(p);
73
+ expect(d?.ok).toBe(true);
74
+ expect(d?.limit).toBe(3);
75
+ expect(d?.remaining).toBe(2 - i);
76
+ }
77
+
78
+ const rejected = await quota.consume(p);
79
+ expect(rejected?.ok).toBe(false);
80
+ expect(rejected?.remaining).toBe(0);
81
+ expect(rejected?.retryAfterSeconds).toBeGreaterThanOrEqual(1);
82
+ expect(rejected?.retryAfterSeconds).toBeLessThanOrEqual(60);
83
+ });
84
+
85
+ it('isolates principals: A exhausted, B unaffected', async () => {
86
+ const quota = createRequestQuota({
87
+ entitlements: stubEntitlements({ perMinute: 2, burstPerSecond: 0 }),
88
+ make: memoryMake,
89
+ logger: noopLogger
90
+ });
91
+ const keyA = principal({ via: 'api_key', apiKeyId: 'key-a', scopes: new Set() });
92
+ const keyB = principal({ via: 'api_key', apiKeyId: 'key-b', scopes: new Set() });
93
+
94
+ await quota.consume(keyA);
95
+ await quota.consume(keyA);
96
+ expect((await quota.consume(keyA))?.ok).toBe(false);
97
+ expect((await quota.consume(keyB))?.ok).toBe(true);
98
+ });
99
+
100
+ it('returns null (disabled) when perMinute is 0', async () => {
101
+ const quota = createRequestQuota({
102
+ entitlements: stubEntitlements({ perMinute: 0, burstPerSecond: 100 }),
103
+ make: memoryMake,
104
+ logger: noopLogger
105
+ });
106
+ expect(await quota.consume(principal())).toBeNull();
107
+ });
108
+
109
+ it('caps 1-second spikes without burning sustained points, and a fresh window recovers', async () => {
110
+ const quota = createRequestQuota({
111
+ entitlements: stubEntitlements({ perMinute: 100, burstPerSecond: 2 }),
112
+ make: memoryMake,
113
+ logger: noopLogger
114
+ });
115
+ const p = principal();
116
+
117
+ expect((await quota.consume(p))?.ok).toBe(true);
118
+ expect((await quota.consume(p))?.ok).toBe(true);
119
+
120
+ const spiked = await quota.consume(p);
121
+ expect(spiked?.ok).toBe(false);
122
+ expect(spiked?.retryAfterSeconds).toBe(1);
123
+ // The rejected spike reported the sustained bucket untouched: 2 consumed.
124
+ expect(spiked?.remaining).toBe(98);
125
+
126
+ await new Promise((r) => setTimeout(r, 1100));
127
+ const recovered = await quota.consume(p);
128
+ expect(recovered?.ok).toBe(true);
129
+ // 3 sustained points consumed in total — the 429 burned none.
130
+ expect(recovered?.remaining).toBe(97);
131
+ });
132
+
133
+ it('fails open (null) when the entitlement lookup throws', async () => {
134
+ const quota = createRequestQuota({
135
+ entitlements: {
136
+ check: async () => ({ allowed: true }),
137
+ getRequestQuota: async () => {
138
+ throw new Error('plan service down');
139
+ }
140
+ },
141
+ make: memoryMake,
142
+ logger: noopLogger
143
+ });
144
+ expect(await quota.consume(principal())).toBeNull();
145
+ });
146
+ });
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createScopeAllowlist } from '../../src/middleware/scopes.js';
3
+
4
+ /**
5
+ * The chassis team routes in the fail-closed machine allowlist (PRDCT-2813):
6
+ * EXACT shapes and methods only. A method the route does not serve on a listed
7
+ * shape answers null (the gate's 403 `endpoint_not_allowed`), so a future
8
+ * handler on that shape stays unreachable to keys and tokens until opened
9
+ * consciously (verifier round 1, mutation #12: POST on the member path).
10
+ */
11
+ const requiredScopeFor = createScopeAllowlist({ read: 'r', write: 'w', dataExport: 'x', rules: [] });
12
+ const TEAM = '/api/v1/teams/11111111-2222-3333-4444-555555555555';
13
+
14
+ describe('requiredScopeFor — teams (PRDCT-2813)', () => {
15
+ it('the list: GET under the read scope, POST under the write scope', () => {
16
+ expect(requiredScopeFor('/api/v1/teams', 'GET')).toBe('r');
17
+ expect(requiredScopeFor('/api/v1/teams', 'POST')).toBe('w');
18
+ });
19
+
20
+ it('the seat of one person: DELETE under the write scope, every other method closed', () => {
21
+ const seat = `${TEAM}/members/user-abc`;
22
+ expect(requiredScopeFor(seat, 'DELETE')).toBe('w');
23
+ expect(requiredScopeFor(seat, 'POST')).toBeNull();
24
+ expect(requiredScopeFor(seat, 'PUT')).toBeNull();
25
+ expect(requiredScopeFor(seat, 'PATCH')).toBeNull();
26
+ });
27
+
28
+ it('the roster: GET under the read scope, PUT closed', () => {
29
+ expect(requiredScopeFor(`${TEAM}/members`, 'GET')).toBe('r');
30
+ expect(requiredScopeFor(`${TEAM}/members`, 'PUT')).toBeNull();
31
+ });
32
+
33
+ it('a team id that is not a uuid is not a listed shape', () => {
34
+ expect(requiredScopeFor('/api/v1/teams/not-a-uuid', 'GET')).toBeNull();
35
+ });
36
+ });
37
+
38
+ describe('requiredScopeFor — members stay closed to machines (ADR 014, PRDCT-2816)', () => {
39
+ const MEMBER = '/api/v1/members/11111111-2222-3333-4444-555555555555';
40
+
41
+ it('the account deletion and the removal are UNLISTED for every method: sessions only', () => {
42
+ for (const method of ['POST', 'GET', 'PUT', 'PATCH', 'DELETE']) {
43
+ expect(requiredScopeFor(MEMBER, method)).toBeNull();
44
+ expect(requiredScopeFor(`${MEMBER}/remove`, method)).toBeNull();
45
+ }
46
+ });
47
+ });
48
+
49
+ describe('requiredScopeFor — the default workspace (PRDCT-2815)', () => {
50
+ const PATH = '/api/v1/me/default-workspace';
51
+
52
+ it('PUT is listed under the write scope', () => {
53
+ expect(requiredScopeFor(PATH, 'PUT')).toBe('w');
54
+ });
55
+
56
+ it('every other method on the path stays unlisted', () => {
57
+ for (const method of ['GET', 'POST', 'PATCH', 'DELETE']) {
58
+ expect(requiredScopeFor(PATH, method)).toBeNull();
59
+ }
60
+ });
61
+
62
+ it('a longer path and any other path under /me stay unlisted for PUT', () => {
63
+ expect(requiredScopeFor(`${PATH}/x`, 'PUT')).toBeNull();
64
+ expect(requiredScopeFor('/api/v1/me/anything', 'PUT')).toBeNull();
65
+ });
66
+ });