@fuzdev/fuz_app 0.147.0 → 0.149.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 (303) hide show
  1. package/dist/actions/CLAUDE.md +8 -6
  2. package/dist/actions/action_codegen.d.ts +15 -1
  3. package/dist/actions/action_codegen.d.ts.map +1 -1
  4. package/dist/actions/action_codegen.js +23 -2
  5. package/dist/actions/action_event.d.ts.map +1 -1
  6. package/dist/actions/action_event.js +14 -1
  7. package/dist/actions/perform_action.d.ts +17 -1
  8. package/dist/actions/perform_action.d.ts.map +1 -1
  9. package/dist/actions/perform_action.js +23 -3
  10. package/dist/auth/CLAUDE.md +3 -2
  11. package/dist/auth/account_action_specs.d.ts +12 -0
  12. package/dist/auth/account_action_specs.d.ts.map +1 -1
  13. package/dist/auth/account_action_specs.js +16 -2
  14. package/dist/auth/account_actions.d.ts.map +1 -1
  15. package/dist/auth/account_actions.js +7 -4
  16. package/dist/auth/admin_action_specs.d.ts.map +1 -1
  17. package/dist/auth/admin_action_specs.js +29 -8
  18. package/dist/auth/audit_emitter.d.ts +14 -0
  19. package/dist/auth/audit_emitter.d.ts.map +1 -1
  20. package/dist/auth/audit_emitter.js +5 -1
  21. package/dist/auth/cell_action_specs.d.ts +3 -1
  22. package/dist/auth/cell_action_specs.d.ts.map +1 -1
  23. package/dist/auth/cell_action_specs.js +5 -5
  24. package/dist/auth/cell_actions.d.ts.map +1 -1
  25. package/dist/auth/cell_actions.js +2 -3
  26. package/dist/auth/cell_data_schema.d.ts +1 -1
  27. package/dist/auth/cell_data_schema.js +1 -1
  28. package/dist/auth/cell_field_action_specs.d.ts +4 -3
  29. package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
  30. package/dist/auth/cell_field_action_specs.js +5 -6
  31. package/dist/auth/cell_field_actions.d.ts.map +1 -1
  32. package/dist/auth/cell_field_actions.js +8 -1
  33. package/dist/auth/cell_item_action_specs.d.ts +4 -2
  34. package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
  35. package/dist/auth/cell_item_action_specs.js +5 -5
  36. package/dist/auth/cell_item_actions.d.ts.map +1 -1
  37. package/dist/auth/cell_item_actions.js +8 -1
  38. package/dist/auth/role_grant_offer_action_specs.d.ts +2 -0
  39. package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
  40. package/dist/auth/role_grant_offer_action_specs.js +8 -4
  41. package/dist/http/CLAUDE.md +14 -2
  42. package/dist/http/error_schemas.d.ts +8 -0
  43. package/dist/http/error_schemas.d.ts.map +1 -1
  44. package/dist/http/error_schemas.js +12 -0
  45. package/dist/http/jsonrpc_errors.d.ts +40 -15
  46. package/dist/http/jsonrpc_errors.d.ts.map +1 -1
  47. package/dist/http/jsonrpc_errors.js +90 -35
  48. package/dist/primitive_schemas.d.ts +1 -1
  49. package/dist/primitive_schemas.d.ts.map +1 -1
  50. package/dist/primitive_schemas.js +2 -1
  51. package/dist/schema_meta.d.ts +80 -0
  52. package/dist/schema_meta.d.ts.map +1 -1
  53. package/dist/schema_meta.js +71 -1
  54. package/dist/testing/CLAUDE.md +853 -146
  55. package/dist/testing/admin_integration.d.ts.map +1 -1
  56. package/dist/testing/admin_integration.js +73 -5
  57. package/dist/testing/adversarial_input.d.ts +0 -47
  58. package/dist/testing/adversarial_input.d.ts.map +1 -1
  59. package/dist/testing/adversarial_input.js +4 -340
  60. package/dist/testing/adversarial_input_cases.d.ts +124 -0
  61. package/dist/testing/adversarial_input_cases.d.ts.map +1 -0
  62. package/dist/testing/adversarial_input_cases.js +393 -0
  63. package/dist/testing/audit_completeness.d.ts.map +1 -1
  64. package/dist/testing/audit_completeness.js +24 -20
  65. package/dist/testing/audit_drift_guard.d.ts +30 -3
  66. package/dist/testing/audit_drift_guard.d.ts.map +1 -1
  67. package/dist/testing/audit_drift_guard.js +55 -3
  68. package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
  69. package/dist/testing/cross_backend/account_lifecycle.js +29 -12
  70. package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
  71. package/dist/testing/cross_backend/actor_lookup.js +7 -25
  72. package/dist/testing/cross_backend/app_settings.d.ts.map +1 -1
  73. package/dist/testing/cross_backend/app_settings.js +4 -6
  74. package/dist/testing/cross_backend/audit_cross_helpers.d.ts +57 -0
  75. package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -0
  76. package/dist/testing/cross_backend/audit_cross_helpers.js +89 -0
  77. package/dist/testing/cross_backend/backend_config.d.ts +2 -1
  78. package/dist/testing/cross_backend/backend_config.d.ts.map +1 -1
  79. package/dist/testing/cross_backend/body_size.d.ts +6 -0
  80. package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
  81. package/dist/testing/cross_backend/body_size.js +26 -44
  82. package/dist/testing/cross_backend/body_size_smuggling.d.ts +5 -0
  83. package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
  84. package/dist/testing/cross_backend/body_size_smuggling.js +7 -14
  85. package/dist/testing/cross_backend/build_test_backend_paths.d.ts +3 -1
  86. package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -1
  87. package/dist/testing/cross_backend/capabilities.d.ts +78 -59
  88. package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
  89. package/dist/testing/cross_backend/capabilities.js +25 -24
  90. package/dist/testing/cross_backend/cargo_binary.d.ts +70 -0
  91. package/dist/testing/cross_backend/cargo_binary.d.ts.map +1 -0
  92. package/dist/testing/cross_backend/cargo_binary.js +148 -0
  93. package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
  94. package/dist/testing/cross_backend/cell_crud.js +174 -3
  95. package/dist/testing/cross_backend/cell_gated_create.d.ts +0 -60
  96. package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
  97. package/dist/testing/cross_backend/cell_gated_create.js +9 -487
  98. package/dist/testing/cross_backend/cell_grant_role.d.ts +14 -2
  99. package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
  100. package/dist/testing/cross_backend/cell_grant_role.js +22 -12
  101. package/dist/testing/cross_backend/cell_moderate.d.ts +66 -0
  102. package/dist/testing/cross_backend/cell_moderate.d.ts.map +1 -0
  103. package/dist/testing/cross_backend/cell_moderate.js +511 -0
  104. package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -1
  105. package/dist/testing/cross_backend/cell_ref_admission.js +1 -1
  106. package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
  107. package/dist/testing/cross_backend/cell_relations.js +40 -19
  108. package/dist/testing/cross_backend/conformance_case.d.ts +43 -4
  109. package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
  110. package/dist/testing/cross_backend/conformance_case.js +29 -1
  111. package/dist/testing/cross_backend/conformance_rpc_auth.d.ts +93 -0
  112. package/dist/testing/cross_backend/conformance_rpc_auth.d.ts.map +1 -0
  113. package/dist/testing/cross_backend/conformance_rpc_auth.js +125 -0
  114. package/dist/testing/cross_backend/conformance_table.d.ts +144 -4
  115. package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
  116. package/dist/testing/cross_backend/conformance_table.js +297 -65
  117. package/dist/testing/cross_backend/cookie_attributes.d.ts.map +1 -1
  118. package/dist/testing/cross_backend/cookie_attributes.js +3 -2
  119. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +38 -5
  120. package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -1
  121. package/dist/testing/cross_backend/create_cross_backend_global_setup.js +24 -3
  122. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +5 -5
  123. package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts.map +1 -1
  124. package/dist/testing/cross_backend/credential_deadline.d.ts +10 -6
  125. package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -1
  126. package/dist/testing/cross_backend/credential_deadline.js +32 -31
  127. package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -1
  128. package/dist/testing/cross_backend/credential_header_robustness.js +4 -6
  129. package/dist/testing/cross_backend/{cell_cross_helpers.d.ts → cross_rpc.d.ts} +14 -2
  130. package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -0
  131. package/dist/testing/cross_backend/{cell_cross_helpers.js → cross_rpc.js} +31 -7
  132. package/dist/testing/cross_backend/default_backend_configs.d.ts +58 -61
  133. package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
  134. package/dist/testing/cross_backend/default_backend_configs.js +97 -91
  135. package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
  136. package/dist/testing/cross_backend/default_spine_surface.js +2 -2
  137. package/dist/testing/cross_backend/differential.d.ts +126 -0
  138. package/dist/testing/cross_backend/differential.d.ts.map +1 -0
  139. package/dist/testing/cross_backend/differential.js +201 -0
  140. package/dist/testing/cross_backend/differential_normalize.d.ts +150 -0
  141. package/dist/testing/cross_backend/differential_normalize.d.ts.map +1 -0
  142. package/dist/testing/cross_backend/differential_normalize.js +153 -0
  143. package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
  144. package/dist/testing/cross_backend/fact_serving.js +27 -17
  145. package/dist/testing/cross_backend/full_spine_mount.d.ts +15 -0
  146. package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
  147. package/dist/testing/cross_backend/full_spine_mount.js +55 -1
  148. package/dist/testing/cross_backend/identity_parity.d.ts.map +1 -1
  149. package/dist/testing/cross_backend/identity_parity.js +6 -5
  150. package/dist/testing/cross_backend/in_process_setup.d.ts +12 -2
  151. package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
  152. package/dist/testing/cross_backend/in_process_setup.js +10 -7
  153. package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
  154. package/dist/testing/cross_backend/login_security.js +13 -18
  155. package/dist/testing/cross_backend/origin.js +1 -1
  156. package/dist/testing/cross_backend/origin_conformance.js +1 -1
  157. package/dist/testing/cross_backend/origin_scope.d.ts +6 -0
  158. package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -1
  159. package/dist/testing/cross_backend/origin_scope.js +13 -12
  160. package/dist/testing/cross_backend/peer_ping_ws.d.ts +2 -5
  161. package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
  162. package/dist/testing/cross_backend/peer_ping_ws.js +14 -24
  163. package/dist/testing/cross_backend/postgres_database.d.ts +85 -0
  164. package/dist/testing/cross_backend/postgres_database.d.ts.map +1 -0
  165. package/dist/testing/cross_backend/postgres_database.js +140 -0
  166. package/dist/testing/cross_backend/provided_context.d.ts +28 -0
  167. package/dist/testing/cross_backend/provided_context.d.ts.map +1 -0
  168. package/dist/testing/cross_backend/provided_context.js +35 -0
  169. package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
  170. package/dist/testing/cross_backend/query_shape.js +10 -12
  171. package/dist/testing/cross_backend/ready.js +2 -2
  172. package/dist/testing/cross_backend/revocation_drivers.d.ts +4 -3
  173. package/dist/testing/cross_backend/revocation_drivers.d.ts.map +1 -1
  174. package/dist/testing/cross_backend/revocation_drivers.js +1 -1
  175. package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +3 -2
  176. package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -1
  177. package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts +13 -0
  178. package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts.map +1 -0
  179. package/dist/testing/cross_backend/role_grant_offer_lifecycle.js +203 -0
  180. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +2 -5
  181. package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
  182. package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +203 -111
  183. package/dist/testing/cross_backend/role_grant_participation.d.ts +13 -0
  184. package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
  185. package/dist/testing/cross_backend/role_grant_participation.js +32 -21
  186. package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -1
  187. package/dist/testing/cross_backend/role_grant_role_grammar.js +6 -9
  188. package/dist/testing/cross_backend/rpc_adversarial.d.ts +47 -0
  189. package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -0
  190. package/dist/testing/cross_backend/rpc_adversarial.js +302 -0
  191. package/dist/testing/cross_backend/rpc_success_fixtures.d.ts +24 -0
  192. package/dist/testing/cross_backend/rpc_success_fixtures.d.ts.map +1 -0
  193. package/dist/testing/cross_backend/rpc_success_fixtures.js +124 -0
  194. package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +101 -0
  195. package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts.map +1 -0
  196. package/dist/testing/cross_backend/rust_spine_consumer_surface.js +113 -0
  197. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +10 -0
  198. package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
  199. package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +33 -21
  200. package/dist/testing/cross_backend/session_cap.d.ts +9 -8
  201. package/dist/testing/cross_backend/session_cap.d.ts.map +1 -1
  202. package/dist/testing/cross_backend/session_cap.js +9 -4
  203. package/dist/testing/cross_backend/session_cookie_codec.js +1 -1
  204. package/dist/testing/cross_backend/setup.d.ts +58 -56
  205. package/dist/testing/cross_backend/setup.d.ts.map +1 -1
  206. package/dist/testing/cross_backend/setup.js +29 -29
  207. package/dist/testing/cross_backend/simple_request.d.ts.map +1 -1
  208. package/dist/testing/cross_backend/simple_request.js +4 -4
  209. package/dist/testing/cross_backend/spawn_backend.d.ts +59 -10
  210. package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
  211. package/dist/testing/cross_backend/spawn_backend.js +219 -60
  212. package/dist/testing/cross_backend/spine_suites.d.ts +311 -0
  213. package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -0
  214. package/dist/testing/cross_backend/spine_suites.js +897 -0
  215. package/dist/testing/cross_backend/spine_surface_constants.d.ts +44 -0
  216. package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
  217. package/dist/testing/cross_backend/spine_surface_constants.js +53 -0
  218. package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
  219. package/dist/testing/cross_backend/sse_round_trip.js +3 -4
  220. package/dist/testing/cross_backend/standard.d.ts +18 -1
  221. package/dist/testing/cross_backend/standard.d.ts.map +1 -1
  222. package/dist/testing/cross_backend/standard.js +2 -0
  223. package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts +24 -0
  224. package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
  225. package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +15 -0
  226. package/dist/testing/cross_backend/testing_backdoor.d.ts +29 -12
  227. package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
  228. package/dist/testing/cross_backend/testing_backdoor.js +143 -51
  229. package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -14
  230. package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
  231. package/dist/testing/cross_backend/testing_reset_actions.js +58 -37
  232. package/dist/testing/cross_backend/testing_server_bun.js +1 -1
  233. package/dist/testing/cross_backend/token_lifetime.js +1 -1
  234. package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
  235. package/dist/testing/cross_backend/token_scope_surface.js +9 -13
  236. package/dist/testing/cross_backend/transport_composition.d.ts +26 -2
  237. package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -1
  238. package/dist/testing/cross_backend/transport_composition.js +81 -51
  239. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +8 -0
  240. package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
  241. package/dist/testing/cross_backend/ts_spine_backend_config.js +23 -13
  242. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +2 -5
  243. package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
  244. package/dist/testing/cross_backend/ws_action_rate_limit.js +8 -14
  245. package/dist/testing/cross_backend/ws_connection_cap.d.ts +4 -9
  246. package/dist/testing/cross_backend/ws_connection_cap.d.ts.map +1 -1
  247. package/dist/testing/cross_backend/ws_connection_cap.js +11 -12
  248. package/dist/testing/cross_backend/ws_endpoint.d.ts +52 -0
  249. package/dist/testing/cross_backend/ws_endpoint.d.ts.map +1 -0
  250. package/dist/testing/cross_backend/ws_endpoint.js +54 -0
  251. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts +2 -5
  252. package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts.map +1 -1
  253. package/dist/testing/cross_backend/ws_inbound_dispatch.js +9 -15
  254. package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +2 -7
  255. package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -1
  256. package/dist/testing/cross_backend/ws_outbound_overflow.js +5 -9
  257. package/dist/testing/cross_backend/ws_role_gated.d.ts +4 -5
  258. package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -1
  259. package/dist/testing/cross_backend/ws_role_gated.js +12 -21
  260. package/dist/testing/cross_backend/ws_round_trip.d.ts +12 -9
  261. package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
  262. package/dist/testing/cross_backend/ws_round_trip.js +29 -34
  263. package/dist/testing/db_entities.d.ts +16 -3
  264. package/dist/testing/db_entities.d.ts.map +1 -1
  265. package/dist/testing/db_entities.js +28 -5
  266. package/dist/testing/integration_helpers.d.ts +61 -2
  267. package/dist/testing/integration_helpers.d.ts.map +1 -1
  268. package/dist/testing/integration_helpers.js +75 -18
  269. package/dist/testing/round_trip.d.ts +17 -0
  270. package/dist/testing/round_trip.d.ts.map +1 -1
  271. package/dist/testing/round_trip.js +67 -24
  272. package/dist/testing/rpc_attack_surface.d.ts +10 -0
  273. package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
  274. package/dist/testing/rpc_attack_surface.js +27 -140
  275. package/dist/testing/rpc_envelope_cases.d.ts +114 -0
  276. package/dist/testing/rpc_envelope_cases.d.ts.map +1 -0
  277. package/dist/testing/rpc_envelope_cases.js +243 -0
  278. package/dist/testing/rpc_helpers.d.ts +31 -0
  279. package/dist/testing/rpc_helpers.d.ts.map +1 -1
  280. package/dist/testing/rpc_helpers.js +35 -14
  281. package/dist/testing/rpc_round_trip.d.ts +62 -6
  282. package/dist/testing/rpc_round_trip.d.ts.map +1 -1
  283. package/dist/testing/rpc_round_trip.js +151 -39
  284. package/dist/testing/schema_generators.d.ts +99 -2
  285. package/dist/testing/schema_generators.d.ts.map +1 -1
  286. package/dist/testing/schema_generators.js +261 -73
  287. package/dist/testing/standard.d.ts +26 -0
  288. package/dist/testing/standard.d.ts.map +1 -1
  289. package/dist/testing/standard.js +4 -1
  290. package/dist/testing/stubs.d.ts +4 -3
  291. package/dist/testing/stubs.d.ts.map +1 -1
  292. package/dist/testing/stubs.js +6 -4
  293. package/dist/testing/transports/raw_http.d.ts +21 -0
  294. package/dist/testing/transports/raw_http.d.ts.map +1 -1
  295. package/dist/testing/transports/raw_http.js +30 -0
  296. package/dist/zod.d.ts +9 -0
  297. package/dist/zod.d.ts.map +1 -1
  298. package/dist/zod.js +20 -0
  299. package/package.json +6 -4
  300. package/dist/testing/cross_backend/actor_search.d.ts +0 -6
  301. package/dist/testing/cross_backend/actor_search.d.ts.map +0 -1
  302. package/dist/testing/cross_backend/actor_search.js +0 -90
  303. package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAW3E,OAAO,EAKN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AAmB1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,0BAA0B,CAAC;AAavE;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAm5BF,CAAC"}
1
+ {"version":3,"file":"admin_integration.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/admin_integration.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAgC7B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAW3E,OAAO,EAMN,KAAK,uBAAuB,EAC5B,MAAM,kBAAkB,CAAC;AA4B1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,0BAA0B,CAAC;AAavE;;GAEG;AACH,MAAM,WAAW,mCAAmC;IACnD;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,cAAc,EAAE,cAAc,CAAC;IAC/B,uFAAuF;IACvF,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACxC,4GAA4G;IAC5G,KAAK,EAAE,gBAAgB,CAAC;IACxB;;;OAGG;IACH,aAAa,EAAE,uBAAuB,CAAC;IACvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAiBD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yCAAyC,GACrD,SAAS,mCAAmC,KAC1C,IAw+BF,CAAC"}
@@ -32,10 +32,11 @@ import { DEFAULT_TEST_PASSWORD } from './test_credentials.js';
32
32
  import { role_grant_offer_and_accept } from './role_grant_helpers.js';
33
33
  import { find_auth_route } from './integration_helpers.js';
34
34
  import { ErrorCoverageCollector, assert_error_coverage, DEFAULT_INTEGRATION_ERROR_COVERAGE } from './error_coverage.js';
35
- import { rpc_call_for_spec, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup } from './rpc_helpers.js';
35
+ import { find_rpc_action, rpc_call_for_spec, require_rpc_endpoint_path, resolve_rpc_endpoints_for_setup } from './rpc_helpers.js';
36
36
  import { role_grant_offer_create_action_spec, role_grant_revoke_action_spec } from '../auth/role_grant_offer_action_specs.js';
37
- import { admin_account_list_action_spec, ADMIN_ACCOUNT_LIST_LIMIT_MAX, admin_session_list_action_spec, admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, audit_log_list_action_spec, audit_log_role_grant_history_action_spec } from '../auth/admin_action_specs.js';
38
- import { account_token_create_action_spec, account_verify_action_spec } from '../auth/account_action_specs.js';
37
+ import { admin_account_list_action_spec, ADMIN_ACCOUNT_LIST_LIMIT_MAX, app_settings_get_action_spec, app_settings_update_action_spec, AUDIT_LOG_LIST_LIMIT_MAX, invite_create_action_spec, invite_delete_action_spec, admin_session_list_action_spec, admin_session_revoke_all_action_spec, admin_token_revoke_all_action_spec, audit_log_list_action_spec, audit_log_role_grant_history_action_spec } from '../auth/admin_action_specs.js';
38
+ import { account_session_list_action_spec, account_session_revoke_action_spec, account_token_create_action_spec, account_token_revoke_action_spec, account_verify_action_spec } from '../auth/account_action_specs.js';
39
+ import { assert_audit_event_metadata } from './audit_drift_guard.js';
39
40
  import { to_route_content_type } from './schema_generators.js';
40
41
  /**
41
42
  * How long a failure-audit read waits for the pool-routed row to land.
@@ -151,6 +152,11 @@ export const describe_standard_admin_integration_tests = (options) => {
151
152
  headers: fixture.create_session_headers()
152
153
  });
153
154
  assert.ok(audit_res.ok, 'audit_log_list should succeed');
155
+ for (const event of audit_res.result.events) {
156
+ assert_audit_event_metadata(event, {
157
+ reject_unknown_keys: fixture.reject_unknown_audit_metadata_keys ?? false
158
+ });
159
+ }
154
160
  const failure = audit_res.result.events.find((e) => e.outcome === 'failure');
155
161
  if (failure || Date.now() >= deadline)
156
162
  return failure;
@@ -632,6 +638,58 @@ export const describe_standard_admin_integration_tests = (options) => {
632
638
  headers: fixture.create_session_headers()
633
639
  });
634
640
  assert.ok(token_res.ok, `account_token_create failed: ${token_res.ok ? '' : JSON.stringify(token_res.error)}`);
641
+ /** Call `spec` on the keeper's session, asserting success. */
642
+ const call_ok = async (spec, params, headers = fixture.create_session_headers()) => {
643
+ const res = await rpc_call_for_spec({
644
+ app: { request: fixture.transport },
645
+ path: rpc_path,
646
+ spec,
647
+ params,
648
+ headers
649
+ });
650
+ if (!res.ok)
651
+ assert.fail(`${spec.method} failed: ${JSON.stringify(res.error)}`);
652
+ return res.result;
653
+ };
654
+ // Steps 5a–5d each drive actions a consumer surface may not mount;
655
+ // a step whose actions are missing is skipped, and its event isn't
656
+ // expected.
657
+ const mounted = (...specs) => specs.every((spec) => find_rpc_action(rpc_endpoints_for_setup, spec.method));
658
+ const driven_types = [];
659
+ // 5a. revoke that token (RPC)
660
+ if (mounted(account_token_revoke_action_spec)) {
661
+ const token_revoked = await call_ok(account_token_revoke_action_spec, {
662
+ token_id: token_res.result.id
663
+ });
664
+ assert.strictEqual(token_revoked.revoked, true);
665
+ driven_types.push('token_revoke');
666
+ }
667
+ // 5b. user_two revokes its own session — the last use of that session
668
+ if (mounted(account_session_list_action_spec, account_session_revoke_action_spec)) {
669
+ const user_two_headers = user_two.create_session_headers();
670
+ const { sessions } = await call_ok(account_session_list_action_spec, undefined, user_two_headers);
671
+ assert.ok(sessions[0], 'user_two has a session to revoke');
672
+ const session_revoked = await call_ok(account_session_revoke_action_spec, { session_id: sessions[0].id }, user_two_headers);
673
+ assert.strictEqual(session_revoked.revoked, true);
674
+ driven_types.push('session_revoke');
675
+ }
676
+ // 5c. an invite created and deleted unclaimed
677
+ if (mounted(invite_create_action_spec, invite_delete_action_spec)) {
678
+ const { invite } = await call_ok(invite_create_action_spec, {
679
+ email: 'audit_invitee@example.com',
680
+ username: 'audit_invitee'
681
+ });
682
+ await call_ok(invite_delete_action_spec, { invite_id: invite.id });
683
+ driven_types.push('invite_create', 'invite_delete');
684
+ }
685
+ // 5d. open signup flipped and restored
686
+ if (mounted(app_settings_get_action_spec, app_settings_update_action_spec)) {
687
+ const { settings } = await call_ok(app_settings_get_action_spec, {});
688
+ for (const open_signup of [!settings.open_signup, settings.open_signup]) {
689
+ await call_ok(app_settings_update_action_spec, { open_signup });
690
+ }
691
+ driven_types.push('app_settings_update');
692
+ }
635
693
  // 6. password change
636
694
  await fixture.transport(password_route.path, {
637
695
  method: 'POST',
@@ -670,14 +728,23 @@ export const describe_standard_admin_integration_tests = (options) => {
670
728
  app: { request: fixture.transport },
671
729
  path: rpc_path,
672
730
  spec: audit_log_list_action_spec,
673
- params: {},
731
+ params: { limit: AUDIT_LOG_LIST_LIMIT_MAX },
674
732
  headers: relogin_headers
675
733
  });
676
734
  assert.ok(audit_res.ok, `audit_log_list failed: ${audit_res.ok ? '' : JSON.stringify(audit_res.error)}`);
677
735
  const events = audit_res.result.events;
736
+ // every row's metadata holds to its event type's schema — the
737
+ // wire leaves it a loose record
738
+ for (const event of events) {
739
+ assert_audit_event_metadata(event, {
740
+ reject_unknown_keys: fixture.reject_unknown_audit_metadata_keys ?? false
741
+ });
742
+ }
678
743
  // check that each operation produced at least one event.
679
744
  // `role_grant_offer_create` fires on the admin RPC; `role_grant_create`
680
745
  // fires when the recipient accepts (driven by offer_and_accept).
746
+ // No `signup` is expected: in-process, `create_account` inserts
747
+ // user_two directly, writing no audit row.
681
748
  const expected_types = [
682
749
  'login',
683
750
  'logout',
@@ -686,7 +753,8 @@ export const describe_standard_admin_integration_tests = (options) => {
686
753
  'role_grant_create',
687
754
  'role_grant_revoke',
688
755
  'token_create',
689
- 'password_change'
756
+ 'password_change',
757
+ ...driven_types
690
758
  ];
691
759
  for (const event_type of expected_types) {
692
760
  const found = events.filter((e) => e.event_type === event_type);
@@ -1,51 +1,5 @@
1
1
  import './assert_dev_env.js';
2
- import { z } from 'zod';
3
- import { ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_JSON_BODY } from '../http/error_schemas.js';
4
2
  import type { AdversarialTestOptions } from './attack_surface.js';
5
- interface InputTestCase {
6
- label: string;
7
- body: unknown;
8
- expected_error: typeof ERROR_INVALID_REQUEST_BODY | typeof ERROR_INVALID_JSON_BODY;
9
- }
10
- interface ParamsTestCase {
11
- label: string;
12
- params: Record<string, string>;
13
- }
14
- interface QueryTestCase {
15
- label: string;
16
- query: Record<string, string>;
17
- }
18
- /**
19
- * Generate adversarial test cases for a route's input schema.
20
- *
21
- * Produces focused, non-redundant cases:
22
- * - Whole-body: send array instead of object, extra unknown key
23
- * - Missing required fields (without defaults)
24
- * - One wrong-type value per field
25
- * - Null for required non-nullable fields
26
- * - One format violation per constrained field
27
- *
28
- * @throws Error if the seed body built by `generate_valid_value` fails
29
- * `input_schema.safeParse` — surfaces broken generation logic with the
30
- * Zod issues path rather than producing nonsense adversarial cases.
31
- */
32
- export declare const generate_input_test_cases: (input_schema: z.ZodType) => Array<InputTestCase>;
33
- /**
34
- * Generate adversarial test cases for a route's params schema.
35
- *
36
- * Params are always strings from URL segments. Only generates cases for
37
- * format-constrained fields (uuid, pattern) since unconstrained string
38
- * params accept any string value.
39
- */
40
- export declare const generate_params_test_cases: (params_schema: z.ZodObject) => Array<ParamsTestCase>;
41
- /**
42
- * Generate adversarial test cases for a route's query schema.
43
- *
44
- * Query params are always strings from the URL. Generates cases for:
45
- * - Missing required fields
46
- * - Format violations on constrained fields (uuid, pattern)
47
- */
48
- export declare const generate_query_test_cases: (query_schema: z.ZodObject) => Array<QueryTestCase>;
49
3
  /**
50
4
  * Generate adversarial input validation test suites.
51
5
  *
@@ -54,5 +8,4 @@ export declare const generate_query_test_cases: (query_schema: z.ZodObject) => A
54
8
  * middleware is actually exercised.
55
9
  */
56
10
  export declare const describe_adversarial_input: (options: AdversarialTestOptions) => void;
57
- export {};
58
11
  //# sourceMappingURL=adversarial_input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"adversarial_input.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_input.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAiB7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB,OAAO,EAEN,0BAA0B,EAC1B,uBAAuB,EAGvB,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAmDlE,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,EAAE,OAAO,0BAA0B,GAAG,OAAO,uBAAuB,CAAC;CACnF;AAED,UAAU,cAAc;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,aAAa;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAID;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,OAAO,KAAG,KAAK,CAAC,aAAa,CAsMtF,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,eAAe,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,cAAc,CA+B3F,CAAC;AAIF;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,GAAI,cAAc,CAAC,CAAC,SAAS,KAAG,KAAK,CAAC,aAAa,CA4CxF,CAAC;AAqBF;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS,sBAAsB,KAAG,IAyN5E,CAAC"}
1
+ {"version":3,"file":"adversarial_input.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/testing/adversarial_input.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AA0B7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AA2BlE;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,GAAI,SAAS,sBAAsB,KAAG,IAyN5E,CAAC"}
@@ -2,353 +2,17 @@ import './assert_dev_env.js';
2
2
  /**
3
3
  * Adversarial input validation testing for route specs.
4
4
  *
5
- * Walks Zod schemas directly to generate payloads that must fail validation.
6
- * Fires requests against a test app and asserts 400 responses before handlers
7
- * are reached.
8
- *
9
- * Tests are focused: one representative wrong-type value per field, one format
10
- * violation per constrained field, one null and one missing test per required
11
- * field, plus whole-body structural attacks (non-object body, extra unknown keys).
5
+ * Fires the payloads `adversarial_input_cases.ts` generates against a test
6
+ * app and asserts 400 responses before handlers are reached.
12
7
  *
13
8
  * @module
14
9
  */
15
10
  import { test, assert, describe } from 'vitest';
16
- import { z } from 'zod';
17
- import { zod_unwrap_to_object, zod_extract_fields } from '../zod.js';
18
- import { is_null_schema } from '../http/schema_helpers.js';
19
11
  import { filter_routes_with_input, filter_routes_with_params, filter_routes_with_query } from '../http/surface_query.js';
20
12
  import { ValidationError, ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_JSON_BODY, ERROR_INVALID_ROUTE_PARAMS, ERROR_INVALID_QUERY_PARAMS } from '../http/error_schemas.js';
21
13
  import { create_auth_test_apps, create_route_skip_filter, select_auth_app } from './auth_apps.js';
22
- import { detect_format, generate_valid_value, resolve_valid_path, to_route_content_type } from './schema_generators.js';
23
- // --- Payload generation ---
24
- /** One wrong-type value per base type — one representative is sufficient. */
25
- const wrong_type_for = (base_type) => {
26
- switch (base_type) {
27
- case 'string':
28
- case 'uuid':
29
- case 'email':
30
- return { label: 'number instead of string', value: 42 };
31
- case 'number':
32
- case 'int':
33
- return { label: 'string instead of number', value: 'not_a_number' };
34
- case 'boolean':
35
- return { label: 'number instead of boolean', value: 42 };
36
- case 'array':
37
- return { label: 'string instead of array', value: 'not_an_array' };
38
- case 'object':
39
- return { label: 'string instead of object', value: 'not_an_object' };
40
- case 'enum':
41
- return { label: 'number instead of enum', value: 42 };
42
- default:
43
- return null;
44
- }
45
- };
46
- /** Format violation payloads — one per constraint type. */
47
- const format_violation = (format) => {
48
- switch (format) {
49
- case 'uuid':
50
- return { label: 'malformed uuid', value: 'not-a-uuid' };
51
- case 'email':
52
- return { label: 'malformed email', value: 'not-an-email' };
53
- case 'date-time':
54
- return { label: 'malformed datetime', value: 'not-a-date' };
55
- case 'pattern':
56
- return { label: 'pattern violation', value: "'; DROP TABLE --" };
57
- default:
58
- return null;
59
- }
60
- };
61
- // --- Input test case generation ---
62
- /**
63
- * Generate adversarial test cases for a route's input schema.
64
- *
65
- * Produces focused, non-redundant cases:
66
- * - Whole-body: send array instead of object, extra unknown key
67
- * - Missing required fields (without defaults)
68
- * - One wrong-type value per field
69
- * - Null for required non-nullable fields
70
- * - One format violation per constrained field
71
- *
72
- * @throws Error if the seed body built by `generate_valid_value` fails
73
- * `input_schema.safeParse` — surfaces broken generation logic with the
74
- * Zod issues path rather than producing nonsense adversarial cases.
75
- */
76
- export const generate_input_test_cases = (input_schema) => {
77
- if (is_null_schema(input_schema))
78
- return [];
79
- const object_schema = zod_unwrap_to_object(input_schema);
80
- if (!object_schema)
81
- return [];
82
- const fields = zod_extract_fields(object_schema);
83
- const cases = [];
84
- // build a base object with valid-ish values — must pass validation itself
85
- // skip optional fields without defaults to avoid generating invalid nested values
86
- const base = {};
87
- for (const field of fields) {
88
- if (!field.required && !field.has_default)
89
- continue;
90
- base[field.name] = generate_valid_value(field, object_schema.shape[field.name]);
91
- }
92
- let base_result = input_schema.safeParse(base);
93
- if (!base_result.success) {
94
- // Fallback for schemas with a top-level `.refine()` that requires at
95
- // least one of N optional fields. Fill optional fields until the base
96
- // satisfies validation; surfaces a clear error if no combination works.
97
- for (const field of fields) {
98
- if (field.required || field.has_default || field.name in base)
99
- continue;
100
- base[field.name] = generate_valid_value(field, object_schema.shape[field.name]);
101
- base_result = input_schema.safeParse(base);
102
- if (base_result.success)
103
- break;
104
- }
105
- }
106
- if (!base_result.success) {
107
- throw new Error(`adversarial_input: generated base object fails validation for schema — ` +
108
- `fix generate_valid_value for: ${base_result.error.issues
109
- .map((i) => `${i.path.join('.')}: ${i.message}`)
110
- .join(', ')}`);
111
- }
112
- // whole-body structural: send array instead of object
113
- cases.push({
114
- label: 'non-object body (array)',
115
- body: [1, 2, 3],
116
- expected_error: ERROR_INVALID_JSON_BODY
117
- });
118
- // whole-body structural: extra unknown key (enforces strictObject)
119
- // only emit if the schema rejects unknown keys (i.e. uses z.strictObject)
120
- const extra_key_result = input_schema.safeParse({ ...base, __adversarial_extra: 'rejected' });
121
- if (!extra_key_result.success) {
122
- cases.push({
123
- label: 'extra unknown key',
124
- body: { ...base, __adversarial_extra: 'should_be_rejected' },
125
- expected_error: ERROR_INVALID_REQUEST_BODY
126
- });
127
- }
128
- for (const field of fields) {
129
- const field_schema = object_schema.shape[field.name];
130
- // missing required field (skip fields with defaults — Zod fills them)
131
- if (field.required && !field.has_default) {
132
- const without = {};
133
- for (const [k, v] of Object.entries(base)) {
134
- if (k !== field.name)
135
- without[k] = v;
136
- }
137
- cases.push({
138
- label: `missing: ${field.name}`,
139
- body: without,
140
- expected_error: ERROR_INVALID_REQUEST_BODY
141
- });
142
- }
143
- // one wrong-type value
144
- const wrong = wrong_type_for(field.base_type);
145
- if (wrong) {
146
- cases.push({
147
- label: `wrong type: ${field.name} (${wrong.label})`,
148
- body: { ...base, [field.name]: wrong.value },
149
- expected_error: ERROR_INVALID_REQUEST_BODY
150
- });
151
- }
152
- // null for required non-nullable fields
153
- if (field.required && !field.nullable && field.base_type !== 'null') {
154
- cases.push({
155
- label: `null: ${field.name}`,
156
- body: { ...base, [field.name]: null },
157
- expected_error: ERROR_INVALID_REQUEST_BODY
158
- });
159
- }
160
- // format violation for constrained string fields
161
- const format = detect_format(field_schema);
162
- if (format) {
163
- const violation = format_violation(format);
164
- if (violation) {
165
- cases.push({
166
- label: `format: ${field.name} (${violation.label})`,
167
- body: { ...base, [field.name]: violation.value },
168
- expected_error: ERROR_INVALID_REQUEST_BODY
169
- });
170
- }
171
- }
172
- // --- Boundary cases via JSON Schema introspection ---
173
- try {
174
- const json = z.toJSONSchema(field_schema);
175
- // string length boundaries
176
- if (field.base_type === 'string' ||
177
- field.base_type === 'uuid' ||
178
- field.base_type === 'email') {
179
- if (typeof json.minLength === 'number' && json.minLength > 0) {
180
- cases.push({
181
- label: `empty string: ${field.name}`,
182
- body: { ...base, [field.name]: '' },
183
- expected_error: ERROR_INVALID_REQUEST_BODY
184
- });
185
- }
186
- if (typeof json.maxLength === 'number') {
187
- cases.push({
188
- label: `over maxLength: ${field.name} (${json.maxLength + 1} chars)`,
189
- body: { ...base, [field.name]: 'x'.repeat(json.maxLength + 1) },
190
- expected_error: ERROR_INVALID_REQUEST_BODY
191
- });
192
- }
193
- }
194
- // numeric boundaries
195
- if (field.base_type === 'number' || field.base_type === 'int') {
196
- if (typeof json.minimum === 'number') {
197
- cases.push({
198
- label: `below minimum: ${field.name} (${json.minimum - 1})`,
199
- body: { ...base, [field.name]: json.minimum - 1 },
200
- expected_error: ERROR_INVALID_REQUEST_BODY
201
- });
202
- }
203
- if (typeof json.maximum === 'number') {
204
- cases.push({
205
- label: `above maximum: ${field.name} (${json.maximum + 1})`,
206
- body: { ...base, [field.name]: json.maximum + 1 },
207
- expected_error: ERROR_INVALID_REQUEST_BODY
208
- });
209
- }
210
- if (typeof json.exclusiveMinimum === 'number') {
211
- cases.push({
212
- label: `at exclusive minimum: ${field.name} (${json.exclusiveMinimum})`,
213
- body: { ...base, [field.name]: json.exclusiveMinimum },
214
- expected_error: ERROR_INVALID_REQUEST_BODY
215
- });
216
- }
217
- if (typeof json.exclusiveMaximum === 'number') {
218
- cases.push({
219
- label: `at exclusive maximum: ${field.name} (${json.exclusiveMaximum})`,
220
- body: { ...base, [field.name]: json.exclusiveMaximum },
221
- expected_error: ERROR_INVALID_REQUEST_BODY
222
- });
223
- }
224
- // 0 and negative for positive-only fields
225
- if (typeof json.minimum === 'number' && json.minimum > 0) {
226
- cases.push({
227
- label: `zero for positive-only: ${field.name}`,
228
- body: { ...base, [field.name]: 0 },
229
- expected_error: ERROR_INVALID_REQUEST_BODY
230
- });
231
- cases.push({
232
- label: `negative for positive-only: ${field.name}`,
233
- body: { ...base, [field.name]: -1 },
234
- expected_error: ERROR_INVALID_REQUEST_BODY
235
- });
236
- }
237
- }
238
- // array length boundaries
239
- if (field.base_type === 'array') {
240
- if (typeof json.minItems === 'number' && json.minItems > 0) {
241
- cases.push({
242
- label: `empty array for minItems > 0: ${field.name}`,
243
- body: { ...base, [field.name]: [] },
244
- expected_error: ERROR_INVALID_REQUEST_BODY
245
- });
246
- }
247
- if (typeof json.maxItems === 'number') {
248
- // generate an array one item over the max (items are null — schema-agnostic)
249
- cases.push({
250
- label: `over maxItems: ${field.name} (${json.maxItems + 1} items)`,
251
- body: { ...base, [field.name]: Array.from({ length: json.maxItems + 1 }, () => null) },
252
- expected_error: ERROR_INVALID_REQUEST_BODY
253
- });
254
- }
255
- }
256
- }
257
- catch {
258
- // schema can't be converted to JSON Schema, skip boundary cases
259
- }
260
- }
261
- return cases;
262
- };
263
- // --- Params test case generation ---
264
- /**
265
- * Generate adversarial test cases for a route's params schema.
266
- *
267
- * Params are always strings from URL segments. Only generates cases for
268
- * format-constrained fields (uuid, pattern) since unconstrained string
269
- * params accept any string value.
270
- */
271
- export const generate_params_test_cases = (params_schema) => {
272
- const fields = zod_extract_fields(params_schema);
273
- const cases = [];
274
- // build base params with valid-ish values
275
- const base_params = {};
276
- for (const field of fields) {
277
- const field_schema = params_schema.shape[field.name];
278
- const format = detect_format(field_schema);
279
- if (format === 'uuid' || field.base_type === 'uuid') {
280
- base_params[field.name] = '00000000-0000-0000-0000-000000000000';
281
- }
282
- else {
283
- base_params[field.name] = 'test_value';
284
- }
285
- }
286
- for (const field of fields) {
287
- const field_schema = params_schema.shape[field.name];
288
- const format = detect_format(field_schema);
289
- if (!format)
290
- continue; // unconstrained string — any value passes
291
- const violation = format_violation(format);
292
- if (violation) {
293
- cases.push({
294
- label: `${violation.label}: param ${field.name}`,
295
- params: { ...base_params, [field.name]: violation.value }
296
- });
297
- }
298
- }
299
- return cases;
300
- };
301
- // --- Query test case generation ---
302
- /**
303
- * Generate adversarial test cases for a route's query schema.
304
- *
305
- * Query params are always strings from the URL. Generates cases for:
306
- * - Missing required fields
307
- * - Format violations on constrained fields (uuid, pattern)
308
- */
309
- export const generate_query_test_cases = (query_schema) => {
310
- const fields = zod_extract_fields(query_schema);
311
- const cases = [];
312
- // build base query with valid-ish values
313
- const base_query = {};
314
- for (const field of fields) {
315
- const field_schema = query_schema.shape[field.name];
316
- const format = detect_format(field_schema);
317
- if (format === 'uuid' || field.base_type === 'uuid') {
318
- base_query[field.name] = '00000000-0000-0000-0000-000000000000';
319
- }
320
- else {
321
- base_query[field.name] = 'test_value';
322
- }
323
- }
324
- for (const field of fields) {
325
- // missing required field
326
- if (field.required && !field.has_default) {
327
- const without = {};
328
- for (const [k, v] of Object.entries(base_query)) {
329
- if (k !== field.name)
330
- without[k] = v;
331
- }
332
- cases.push({
333
- label: `missing query: ${field.name}`,
334
- query: without
335
- });
336
- }
337
- // format violation for constrained string fields
338
- const field_schema = query_schema.shape[field.name];
339
- const format = detect_format(field_schema);
340
- if (!format)
341
- continue;
342
- const violation = format_violation(format);
343
- if (violation) {
344
- cases.push({
345
- label: `${violation.label}: query ${field.name}`,
346
- query: { ...base_query, [field.name]: violation.value }
347
- });
348
- }
349
- }
350
- return cases;
351
- };
14
+ import { resolve_valid_path, to_route_content_type } from './schema_generators.js';
15
+ import { generate_input_test_cases, generate_params_test_cases, generate_query_test_cases } from './adversarial_input_cases.js';
352
16
  // --- URL helpers ---
353
17
  /** Build a URL path with adversarial param values. */
354
18
  const build_fuzz_url = (route_path, params) => {
@@ -0,0 +1,124 @@
1
+ import './assert_dev_env.js';
2
+ /**
3
+ * Schema-walk generation of adversarial inputs — payloads that must fail
4
+ * validation.
5
+ *
6
+ * Focused cases: one representative wrong-type value per field, one format
7
+ * violation per constrained field, one null and one missing case per required
8
+ * field, plus whole-body structural attacks (non-object body, extra unknown
9
+ * keys). Hono-free, so the cross-process suites reuse the generators the
10
+ * in-process `describe_adversarial_input` and `describe_rpc_attack_surface_tests`
11
+ * run.
12
+ *
13
+ * @module
14
+ */
15
+ import { z } from 'zod';
16
+ import { ERROR_INVALID_REQUEST_BODY, ERROR_INVALID_JSON_BODY } from '../http/error_schemas.js';
17
+ /** One adversarial body for an input schema, and the error code it owes. */
18
+ export interface InputTestCase {
19
+ label: string;
20
+ body: unknown;
21
+ /**
22
+ * The one top-level field the case breaks; absent on a whole-body case (a
23
+ * non-object body, an extra unknown key). An RPC refusal of the case owes
24
+ * the field's declared `invalid_reason` (`expected_invalid_reason`).
25
+ */
26
+ field?: string;
27
+ expected_error: typeof ERROR_INVALID_REQUEST_BODY | typeof ERROR_INVALID_JSON_BODY;
28
+ }
29
+ /** One adversarial params set for a route's params schema. */
30
+ export interface ParamsTestCase {
31
+ label: string;
32
+ params: Record<string, string>;
33
+ }
34
+ /** One adversarial query for a route's query schema. */
35
+ export interface QueryTestCase {
36
+ label: string;
37
+ query: Record<string, string>;
38
+ }
39
+ /** Options for `generate_input_test_cases`. */
40
+ export interface InputTestCaseOptions {
41
+ /**
42
+ * A valid body to build the cases from, in place of the generated one —
43
+ * for an input whose valid shape the generator can't reach, or one whose
44
+ * generated body the handler can't run. Each case is this body with one
45
+ * field broken, so it must pass the input schema itself: one that doesn't
46
+ * throws.
47
+ */
48
+ base?: Record<string, unknown>;
49
+ /** Names the input in error messages — the RPC method or route it belongs to. */
50
+ label?: string;
51
+ }
52
+ /**
53
+ * Generate adversarial test cases for a route's input schema.
54
+ *
55
+ * Produces focused, non-redundant cases:
56
+ * - Whole-body: send array instead of object, extra unknown key
57
+ * - Missing required fields (without defaults)
58
+ * - One wrong-type value per field
59
+ * - Null for required non-nullable fields
60
+ * - One format violation per constrained field
61
+ * - String length (empty, one under `minLength`, one over `maxLength`), numeric
62
+ * (out of range, non-integer, off a `multipleOf` grid) and array-length
63
+ * (empty, one under `minItems`, one over `maxItems`) boundaries
64
+ *
65
+ * Format and boundaries come from the field's input-side JSON Schema
66
+ * (`to_field_json_schema`), so a field carrying a `.transform()` or pipe and a
67
+ * `.nullable()` / `.nullish()` field get them too. A bound only a `.refine()`
68
+ * enforces generates nothing — JSON Schema can't express it.
69
+ *
70
+ * Each per-field case is single-fault: valid except for the field it breaks.
71
+ * It changes one field of a valid base body — `options.base` when given, else
72
+ * one built by `generate_valid_object` — or, for a field that base omits, of
73
+ * the valid body `generate_valid_object_with_field` builds around it, so a case
74
+ * can't also break an object-level rule (adding `scope_kind` without its
75
+ * paired `scope_id`, or `slug` beside an exactly-one-of `id`). A field no valid
76
+ * body carries keeps its wrong-type and null cases on the base and gets no
77
+ * format or boundary cases, which would test no bound. A per-field case is
78
+ * emitted only when the field refuses its value, so no case is accidentally
79
+ * valid.
80
+ *
81
+ * @param input_schema - the input schema to attack
82
+ * @param options - a base body to seed the cases, and a label for errors
83
+ * @throws Error if the base body fails `input_schema.safeParse` — a seeded
84
+ * base the schema refuses, or a generated one that surfaces broken
85
+ * generation logic — naming the issues rather than producing nonsense
86
+ * adversarial cases.
87
+ */
88
+ export declare const generate_input_test_cases: (input_schema: z.ZodType, options?: InputTestCaseOptions) => Array<InputTestCase>;
89
+ /**
90
+ * The `error.data.reason` an RPC refusal of `test_case` owes: the declared
91
+ * `invalid_reason` of the field it breaks, resolved as the dispatcher resolves
92
+ * a failure on that field (`resolve_invalid_reason`), or `undefined` — no
93
+ * reason — for an undeclared field or a whole-body case.
94
+ *
95
+ * @param input_schema - the input schema the case was generated from
96
+ * @param test_case - a case `generate_input_test_cases` produced from it
97
+ * @returns the owed reason, or `undefined` when the refusal carries none
98
+ */
99
+ export declare const expected_invalid_reason: (input_schema: z.ZodType, test_case: InputTestCase) => string | undefined;
100
+ /**
101
+ * Generate adversarial test cases for a route's params schema.
102
+ *
103
+ * Params are always strings from URL segments. Only generates cases for
104
+ * format-constrained fields (uuid, pattern) since unconstrained string
105
+ * params accept any string value, and only a violation the field refuses.
106
+ * Each case breaks one field of a valid params record.
107
+ *
108
+ * @throws Error if no valid params record can be generated
109
+ */
110
+ export declare const generate_params_test_cases: (params_schema: z.ZodObject) => Array<ParamsTestCase>;
111
+ /**
112
+ * Generate adversarial test cases for a route's query schema.
113
+ *
114
+ * Query params are always strings from the URL. Generates cases for:
115
+ * - Missing required fields the field refuses to go without (a preprocessed
116
+ * field with a default accepts its absence)
117
+ * - Format violations on constrained fields (uuid, pattern) the field refuses
118
+ *
119
+ * Each case breaks one field of a valid query record.
120
+ *
121
+ * @throws Error if no valid query record can be generated
122
+ */
123
+ export declare const generate_query_test_cases: (query_schema: z.ZodObject) => Array<QueryTestCase>;
124
+ //# sourceMappingURL=adversarial_input_cases.d.ts.map