@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
@@ -32,7 +32,8 @@ import '../assert_dev_env.js';
32
32
  import { assert, describe, test } from 'vitest';
33
33
  import { ERROR_ROLE_NOT_WEB_GRANTABLE } from '../../http/error_schemas.js';
34
34
  import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
35
- import { cross_rpc_call, error_reason } from './cell_cross_helpers.js';
35
+ import { list_audit_events } from './audit_cross_helpers.js';
36
+ import { cross_rpc_call, error_reason } from './cross_rpc.js';
36
37
  import { SPINE_RPC_PATH } from './spine_surface_constants.js';
37
38
  const NIL_UUID = '00000000-0000-0000-0000-000000000000';
38
39
  /**
@@ -63,7 +64,7 @@ const GRANT_EVENT_TYPES = ['role_grant_create', 'role_grant_offer_create'];
63
64
  export const describe_role_grant_role_grammar_cross_tests = (options) => {
64
65
  const { setup_test } = options;
65
66
  const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
66
- describe('grant verbs refuse an off-grammar role at validation', { timeout: 30_000 }, () => {
67
+ describe('grant verbs refuse an off-grammar role at validation', () => {
67
68
  for (const method of GRANT_METHODS) {
68
69
  test(`${method}: an off-grammar role is invalid_params with no reason`, async () => {
69
70
  const fixture = await setup_test();
@@ -94,14 +95,10 @@ export const describe_role_grant_role_grammar_cross_tests = (options) => {
94
95
  // and the length cap is inclusive: a role exactly at it is on the grammar
95
96
  const at_length = await cross_rpc_call(t, rpc_path, 'role_grant_assign', { to_account_id: NIL_UUID, role: AT_LENGTH_ROLE }, session);
96
97
  assert.strictEqual(error_reason(at_length), ERROR_ROLE_NOT_WEB_GRANTABLE, 'a role at the length cap passes validation');
97
- // a barrier before reading the log: both spines write audit rows off
98
- // the request path
99
- const drained = await cross_rpc_call(fixture.fresh_transport({ origin: null }), rpc_path, '_testing_drain_effects', undefined, fixture.create_daemon_token_headers());
100
- assert.ok(drained.ok, `_testing_drain_effects failed: ${JSON.stringify(drained.error)}`);
98
+ // both spines write audit rows off the request path, so each read is
99
+ // behind the drain barrier
101
100
  for (const event_type of GRANT_EVENT_TYPES) {
102
- const listed = await cross_rpc_call(t, rpc_path, 'audit_log_list', { event_type }, session);
103
- assert.ok(listed.ok, `audit_log_list failed: ${JSON.stringify(listed.error)}`);
104
- const events = listed.result.events;
101
+ const events = await list_audit_events(fixture, { event_type }, rpc_path);
105
102
  const roles = events.map((event) => event.metadata?.role);
106
103
  for (const role of roles) {
107
104
  assert.ok(typeof role !== 'string' || !OFF_GRAMMAR_ROLES.includes(role), `${event_type}: an audit row records the off-grammar role ${JSON.stringify(role)}`);
@@ -0,0 +1,47 @@
1
+ import '../assert_dev_env.js';
2
+ import { type AppSurfaceSpec, type RpcEndpointSpec } from '../../http/surface.js';
3
+ import type { RpcPathCrossSuiteOptions } from './setup.js';
4
+ /** Options for `describe_rpc_adversarial_cross_tests`. */
5
+ export interface RpcAdversarialCrossTestOptions extends RpcPathCrossSuiteOptions {
6
+ /** The declared surface; the endpoint at `rpc_path` supplies the methods and their input schemas. */
7
+ readonly surface_source: AppSurfaceSpec;
8
+ /**
9
+ * The endpoints the backend live-mounts (resolved —
10
+ * `resolve_rpc_endpoints_for_setup` turns the factory form into this). The
11
+ * methods the one at `rpc_path` carries beyond the declared surface run
12
+ * through both groups too. Omitted, only declared methods run.
13
+ */
14
+ readonly live_rpc_endpoints?: ReadonlyArray<RpcEndpointSpec>;
15
+ /** Methods to leave out, beyond the protocol actions always skipped. */
16
+ readonly skip_methods?: ReadonlyArray<string>;
17
+ /**
18
+ * Valid params per method (method name → params) to build its params cases
19
+ * from, in place of the generated base — for an input whose valid shape
20
+ * the generator can't reach. Each must pass the method's input schema; one
21
+ * that doesn't throws at collection, naming the method. The cases are sent
22
+ * as a single-actor principal, so an override omits `acting`.
23
+ * `describe_spine_cross_suites` passes its `rpc_input_overrides` here.
24
+ */
25
+ readonly input_overrides?: ReadonlyMap<string, Record<string, unknown>>;
26
+ /**
27
+ * Generated params cases a backend is known to answer otherwise, each run
28
+ * as its own `xfail_until` test; the method's other cases keep their test.
29
+ * Pass it only for the backend that diverges.
30
+ */
31
+ readonly xfail_params?: ReadonlyArray<RpcParamsXfail>;
32
+ }
33
+ /** Generated params cases of one method marked `xfail_until`, by case label. */
34
+ export interface RpcParamsXfail {
35
+ readonly method: string;
36
+ /** `InputTestCase.label`s of `generate_rpc_params_test_cases(method's input)`. */
37
+ readonly labels: ReadonlyArray<string>;
38
+ readonly tracking_id: string;
39
+ readonly reason: string;
40
+ }
41
+ /**
42
+ * Run the cross-process malformed-envelope and invalid-params suite.
43
+ *
44
+ * @param options - the fixture, the declared surface and live mount, the RPC path, and methods to skip
45
+ */
46
+ export declare const describe_rpc_adversarial_cross_tests: (options: RpcAdversarialCrossTestOptions) => void;
47
+ //# sourceMappingURL=rpc_adversarial.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc_adversarial.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rpc_adversarial.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AA6E9B,OAAO,EAGN,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,MAAM,uBAAuB,CAAC;AAoB/B,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,YAAY,CAAC;AAKxE,0DAA0D;AAC1D,MAAM,WAAW,8BAA+B,SAAQ,wBAAwB;IAC/E,qGAAqG;IACrG,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC7D,wEAAwE;IACxE,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxE;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;CACtD;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAmGD;;;;GAIG;AACH,eAAO,MAAM,oCAAoC,GAChD,SAAS,8BAA8B,KACrC,IAqKF,CAAC"}
@@ -0,0 +1,302 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Cross-process malformed-envelope and invalid-params suite for a JSON-RPC
4
+ * endpoint.
5
+ *
6
+ * `describe_rpc_attack_surface_tests` runs its envelope and params groups
7
+ * in-process against stub apps, so they never reach a spawned backend — and
8
+ * the Rust spine parses envelopes and params by hand, while the
9
+ * action-manifest parity gate compares declarations and is blind to param
10
+ * schemas. This suite sends the same requests over `fixture.transport` to
11
+ * each backend.
12
+ *
13
+ * Two groups:
14
+ *
15
+ * - **Envelopes** — `create_rpc_envelope_cases`, the in-process group's set:
16
+ * non-JSON body, wrong or missing `jsonrpc`, missing `method` or `id`, a
17
+ * batch array, non-object POST params, an unknown method, `GET` missing
18
+ * `method` or `id`, `GET` invalid-JSON params, `GET` non-object params on
19
+ * every read, and a `GET` of a mutating method.
20
+ * Each is sent by the principal its method's auth admits, so the envelope
21
+ * check is what refuses, and each pins status, JSON-RPC code, the echoed
22
+ * `id`, and `data.reason` (exact where the TS dispatcher sets one, absent
23
+ * otherwise). Three ordering cases go without a credential: an anonymous
24
+ * `GET` of a mutating method is refused `invalid_request` rather than 401
25
+ * (the read restriction runs after the method lookup and before
26
+ * authorization), an anonymous batch array is refused `invalid_request`
27
+ * with `id: null` (the envelope parse runs before auth, and batches are
28
+ * unsupported), and an anonymous `GET` with non-object params is the 401
29
+ * (params validation runs after authorization).
30
+ * - **Params** — for each declared method (and each live-mounted one, below),
31
+ * `generate_rpc_params_test_cases`
32
+ * (the in-process generator minus its structural cases), each sent as the
33
+ * method's authorized principal and owing 400 `invalid_params` with the
34
+ * `data.reason` the broken field declares (`invalid_reason` in its
35
+ * `.meta()`, read by `expected_invalid_reason`) — none for an undeclared
36
+ * field or a whole-body case. One test per method, reporting every case that answers
37
+ * otherwise; `xfail_params` runs named cases of a method as their own
38
+ * `xfail_until` tests, for a known divergence on one backend.
39
+ *
40
+ * The authorized principal is the keeper on the first channel the method's
41
+ * auth admits: its session, else its daemon token or API token over a
42
+ * no-`Origin` transport (`resolve_conformance_principal`), mirroring the
43
+ * in-process `select_auth_app`. **Preconditions:** the keeper holds every
44
+ * role a declared method gates on (`default_cross_process_setup` seeds
45
+ * `keeper` and `admin`; pass `extra_keeper_roles` for others), and it has a
46
+ * single actor. No generated body carries a valid `acting` — the generator's
47
+ * base fills required and defaulted fields, and an optional one only where a
48
+ * refinement needs it (each alone first, so an `acting` declared ahead of an
49
+ * at-least-one or exactly-one-of pair stays out) — and a malformed `acting` is
50
+ * read as omitted ahead of validation on both spines, so a single-actor
51
+ * keeper resolves its actor and validation is what refuses. A keeper with a
52
+ * second actor answers `actor_required` first; such a suite lists the
53
+ * actor-required methods in `skip_methods`.
54
+ *
55
+ * **Off the declared surface.** `live_rpc_endpoints` adds the methods the
56
+ * backend live-mounts at `rpc_path` beyond the declared surface — cell verbs,
57
+ * opt-in resolvers, the `_testing_*` backdoors. Both groups run over them too:
58
+ * the envelope cases built from those methods, in a group of their own, and a
59
+ * params test per method, `_testing_*` included (a daemon-only backdoor is
60
+ * sent with the keeper's daemon token). A spine that keeps a method family off
61
+ * its declared surface still owes the twin's answer to bad params there.
62
+ *
63
+ * Skipped: `_testing_*` methods on the declared surface (a declared surface
64
+ * lists them only by accident; the live mount is where they are walked), and
65
+ * the protocol actions (`PROTOCOL_ACTION_METHODS`, fixed shared specs covered
66
+ * by the WS suites, which `generate_rpc_auth_conformance_cases` skips too).
67
+ *
68
+ * Cross-process only: in-process, `describe_rpc_attack_surface_tests` runs
69
+ * the same envelope cases and params generator.
70
+ *
71
+ * @module
72
+ */
73
+ import { assert, describe, test } from 'vitest';
74
+ import { generate_app_surface } from '../../http/surface.js';
75
+ import { is_public_auth } from '../../http/auth_shape.js';
76
+ import { JSONRPC_ERROR_CODES } from '../../http/jsonrpc_errors.js';
77
+ import { BUILTIN_CREDENTIAL_TYPES, CREDENTIAL_TYPE_API_TOKEN, CREDENTIAL_TYPE_DAEMON_TOKEN, CREDENTIAL_TYPE_SESSION } from '../../auth/credential_type_schema.js';
78
+ import { PROTOCOL_ACTION_METHODS } from '../../actions/action_codegen.js';
79
+ import { TESTING_METHOD_PREFIX } from '../surface_invariants.js';
80
+ import { create_rpc_post_init } from '../rpc_helpers.js';
81
+ import { assert_rpc_envelope_refusal, create_rpc_envelope_cases, generate_rpc_params_test_cases, to_rpc_envelope_request } from '../rpc_envelope_cases.js';
82
+ import { resolve_conformance_principal } from './conformance_table.js';
83
+ import { SPINE_RPC_PATH } from './spine_surface_constants.js';
84
+ import { xfail_until } from './xfail.js';
85
+ import { expected_invalid_reason } from '../adversarial_input_cases.js';
86
+ const PROTOCOL_METHODS = new Set(PROTOCOL_ACTION_METHODS);
87
+ /** The keeper principal on each builtin credential channel. */
88
+ const CHANNEL_PRINCIPALS = {
89
+ [CREDENTIAL_TYPE_SESSION]: 'keeper',
90
+ [CREDENTIAL_TYPE_DAEMON_TOKEN]: 'daemon',
91
+ [CREDENTIAL_TYPE_API_TOKEN]: 'token'
92
+ };
93
+ /**
94
+ * The principal a method's auth admits: the keeper's session where the
95
+ * method takes one, else the first builtin channel its credential gate
96
+ * names — the choice the in-process `select_auth_app` makes, minus its throw
97
+ * on a non-session channel paired with a role other than keeper (the keeper
98
+ * holds every builtin role, so sending its token there still passes the gate).
99
+ *
100
+ * @param auth - the method's declared auth
101
+ * @returns the principal to send as
102
+ */
103
+ const to_authorized_principal = (auth) => {
104
+ if (is_public_auth(auth))
105
+ return 'anonymous';
106
+ const credential_types = auth.credential_types;
107
+ if (!credential_types?.length || credential_types.includes(CREDENTIAL_TYPE_SESSION)) {
108
+ return 'keeper';
109
+ }
110
+ const channel = BUILTIN_CREDENTIAL_TYPES.find((t) => credential_types.includes(t));
111
+ const principal = channel === undefined ? undefined : CHANNEL_PRINCIPALS[channel];
112
+ if (!principal) {
113
+ throw new Error(`rpc_adversarial: no builtin channel admits credential types '${credential_types.join("', '")}'`);
114
+ }
115
+ return principal;
116
+ };
117
+ const send_as = async (fixture, auth, as, url, init) => {
118
+ const principal = as === 'anonymous' ? 'anonymous' : to_authorized_principal(auth);
119
+ const { transport, headers } = await resolve_conformance_principal(fixture, principal);
120
+ const res = await transport(url, {
121
+ ...init,
122
+ headers: { ...init.headers, ...headers }
123
+ });
124
+ const text = await res.text();
125
+ let body;
126
+ try {
127
+ body = JSON.parse(text);
128
+ }
129
+ catch {
130
+ body = text;
131
+ }
132
+ return { status: res.status, body };
133
+ };
134
+ const reason_of = (body) => {
135
+ const data = body?.error?.data;
136
+ return typeof data === 'object' && data !== null
137
+ ? data.reason
138
+ : undefined;
139
+ };
140
+ /**
141
+ * The live-mounted actions at `rpc_path` the declared endpoint lacks, each
142
+ * method once, in mount order, with their surface form.
143
+ */
144
+ const to_off_surface = (rpc_path, declared, live_rpc_endpoints) => {
145
+ const seen = new Set(declared);
146
+ const actions = [];
147
+ for (const live of live_rpc_endpoints ?? []) {
148
+ if (live.path !== rpc_path)
149
+ continue;
150
+ for (const action of live.actions) {
151
+ if (seen.has(action.spec.method))
152
+ continue;
153
+ seen.add(action.spec.method);
154
+ actions.push(action);
155
+ }
156
+ }
157
+ if (actions.length === 0)
158
+ return null;
159
+ const surface = generate_app_surface({
160
+ route_specs: [],
161
+ middleware_specs: [],
162
+ rpc_endpoints: [{ path: rpc_path, actions }]
163
+ });
164
+ const endpoint = surface.rpc_endpoints[0];
165
+ if (!endpoint)
166
+ throw new Error(`rpc_adversarial: no surface for the live mount at '${rpc_path}'`);
167
+ return { actions, endpoint };
168
+ };
169
+ /**
170
+ * Run the cross-process malformed-envelope and invalid-params suite.
171
+ *
172
+ * @param options - the fixture, the declared surface and live mount, the RPC path, and methods to skip
173
+ */
174
+ export const describe_rpc_adversarial_cross_tests = (options) => {
175
+ const { setup_test, surface_source } = options;
176
+ const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
177
+ const skip = new Set(options.skip_methods);
178
+ const endpoint = surface_source.surface.rpc_endpoints.find((e) => e.path === rpc_path);
179
+ const endpoint_spec = surface_source.rpc_endpoints.find((e) => e.path === rpc_path);
180
+ const off_surface = endpoint
181
+ ? to_off_surface(rpc_path,
182
+ // a `_testing_*` method listed on the declared surface is skipped there,
183
+ // so it must stay eligible here, where the live mount walks it
184
+ new Set(endpoint.methods
185
+ .map((m) => m.name)
186
+ .filter((name) => !name.startsWith(TESTING_METHOD_PREFIX))), options.live_rpc_endpoints)
187
+ : null;
188
+ describe('RPC adversarial envelopes (cross-process)', () => {
189
+ if (!endpoint || !endpoint_spec) {
190
+ test('the RPC endpoint is on the declared surface', () => {
191
+ assert.fail(`no RPC endpoint at '${rpc_path}' on the declared surface`);
192
+ });
193
+ return;
194
+ }
195
+ const cases = create_rpc_envelope_cases(endpoint, { skip_methods: options.skip_methods });
196
+ test('the envelope cases cover the endpoint', () => {
197
+ // both halves need a read and a mutation to choose; a surface
198
+ // lacking either loses cases silently otherwise
199
+ assert.ok(cases.some((c) => !c.method.side_effects), 'no read method to carry the POST and GET envelope cases');
200
+ assert.ok(cases.some((c) => c.method.side_effects), 'no authenticated mutation to carry the GET read-restriction cases');
201
+ });
202
+ for (const c of cases) {
203
+ test(c.name, async () => {
204
+ const fixture = await setup_test();
205
+ const { url, init } = to_rpc_envelope_request(rpc_path, c);
206
+ const { status, body } = await send_as(fixture, c.method.auth, c.as, url, init);
207
+ assert_rpc_envelope_refusal(status, body, c);
208
+ });
209
+ }
210
+ });
211
+ if (off_surface) {
212
+ describe('RPC adversarial envelopes, live-mounted methods off the declared surface (cross-process)', () => {
213
+ for (const c of create_rpc_envelope_cases(off_surface.endpoint, {
214
+ skip_methods: options.skip_methods
215
+ })) {
216
+ test(c.name, async () => {
217
+ const fixture = await setup_test();
218
+ const { url, init } = to_rpc_envelope_request(rpc_path, c);
219
+ const { status, body } = await send_as(fixture, c.method.auth, c.as, url, init);
220
+ assert_rpc_envelope_refusal(status, body, c);
221
+ });
222
+ }
223
+ });
224
+ }
225
+ describe('RPC adversarial params (cross-process)', () => {
226
+ if (!endpoint || !endpoint_spec)
227
+ return;
228
+ let total = 0;
229
+ const xfails = new Map();
230
+ for (const x of options.xfail_params ?? []) {
231
+ for (const label of x.labels)
232
+ xfails.set(`${x.method}\0${label}`, x);
233
+ }
234
+ const matched_xfails = new Set();
235
+ /** Send one case; a refusal message when it is not the canonical 400. */
236
+ const check_case = async (fixture, action, tc) => {
237
+ const { status, body } = await send_as(fixture, action.spec.auth, 'authorized', rpc_path, create_rpc_post_init(action.spec.method, tc.body));
238
+ const code = body?.error?.code;
239
+ const expected_reason = expected_invalid_reason(action.spec.input, tc);
240
+ if (status === 400 &&
241
+ code === JSONRPC_ERROR_CODES.invalid_params &&
242
+ reason_of(body) === expected_reason) {
243
+ return null;
244
+ }
245
+ const owed = expected_reason === undefined ? 'no reason' : `reason '${expected_reason}'`;
246
+ return `[${tc.label}] params ${JSON.stringify(tc.body)} → ${status} ${JSON.stringify(body)} (owed 400 invalid_params, ${owed})`;
247
+ };
248
+ // the declared methods, then the live-mounted ones the declared surface lacks
249
+ const declared_actions = endpoint_spec.actions.filter((action) => !action.spec.method.startsWith(TESTING_METHOD_PREFIX) &&
250
+ endpoint.methods.some((m) => m.name === action.spec.method));
251
+ for (const action of [...declared_actions, ...(off_surface?.actions ?? [])]) {
252
+ const { method, input } = action.spec;
253
+ if (PROTOCOL_METHODS.has(method))
254
+ continue;
255
+ if (skip.has(method))
256
+ continue;
257
+ const all_cases = generate_rpc_params_test_cases(input, {
258
+ base: options.input_overrides?.get(method),
259
+ label: method
260
+ });
261
+ if (all_cases.length === 0)
262
+ continue;
263
+ total += all_cases.length;
264
+ const param_cases = [];
265
+ for (const tc of all_cases) {
266
+ const key = `${method}\0${tc.label}`;
267
+ const xfail = xfails.get(key);
268
+ if (!xfail) {
269
+ param_cases.push(tc);
270
+ continue;
271
+ }
272
+ matched_xfails.add(key);
273
+ xfail_until(xfail.tracking_id, xfail.reason, `${method}: [${tc.label}] → 400 invalid_params`, async () => {
274
+ const failure = await check_case(await setup_test(), action, tc);
275
+ assert.strictEqual(failure, null);
276
+ });
277
+ }
278
+ if (param_cases.length === 0)
279
+ continue;
280
+ test(`${method}: every generated invalid params case → 400 invalid_params`, async () => {
281
+ const fixture = await setup_test();
282
+ const failures = [];
283
+ for (const tc of param_cases) {
284
+ const failure = await check_case(fixture, action, tc);
285
+ if (failure)
286
+ failures.push(failure);
287
+ }
288
+ assert.deepStrictEqual(failures, [], `${method}: ${failures.length} of ${param_cases.length} cases not refused invalid_params`);
289
+ });
290
+ }
291
+ test('every xfail_params entry names a generated case', () => {
292
+ // a stale entry would otherwise xfail nothing, silently
293
+ const unmatched = [...xfails.keys()]
294
+ .filter((key) => !matched_xfails.has(key))
295
+ .map((key) => key.replace('\0', ': '));
296
+ assert.deepStrictEqual(unmatched, []);
297
+ });
298
+ test('generated params cases exist', () => {
299
+ assert.ok(total > 0, 'no params cases generated — schema walking may be broken');
300
+ });
301
+ });
302
+ };
@@ -0,0 +1,24 @@
1
+ import '../assert_dev_env.js';
2
+ import type { RpcSuccessFixtures } from '../rpc_round_trip.js';
3
+ /** Options for `create_spine_rpc_success_fixtures`. */
4
+ export interface SpineRpcSuccessFixturesOptions {
5
+ /** The JSON-RPC endpoint path the standard actions are mounted on. Default `SPINE_RPC_PATH`. */
6
+ readonly rpc_path?: string;
7
+ }
8
+ /**
9
+ * Build the success-fixture map for the standard spine methods that need a
10
+ * real row id: `account_token_revoke`, `account_session_revoke`,
11
+ * `invite_delete`, `role_grant_revoke`, `role_grant_offer_accept`,
12
+ * `role_grant_offer_decline`, and `role_grant_offer_retract`.
13
+ *
14
+ * Each factory mints fresh accounts — a fresh `ROLE_ADMIN` holder as grantor
15
+ * where the setup step is admin-gated — and builds its row as a real client
16
+ * would, then returns the headers of the account that calls: the owner for
17
+ * token and session revoke, accept, decline, and retract; the fresh admin
18
+ * for invite delete and role grant revoke.
19
+ *
20
+ * @param options - the RPC endpoint path
21
+ * @returns the method → fixture-factory map
22
+ */
23
+ export declare const create_spine_rpc_success_fixtures: (options?: SpineRpcSuccessFixturesOptions) => RpcSuccessFixtures;
24
+ //# sourceMappingURL=rpc_success_fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rpc_success_fixtures.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rpc_success_fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqC9B,OAAO,KAAK,EAAqB,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAOlF,uDAAuD;AACvD,MAAM,WAAW,8BAA8B;IAC9C,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iCAAiC,GAC7C,UAAS,8BAAmC,KAC1C,kBAwHF,CAAC"}
@@ -0,0 +1,124 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * Success fixtures for the standard spine RPC methods that act on an existing
4
+ * row — revoke a token or a session, delete an invite, revoke a role grant,
5
+ * accept, decline, or retract an offer. The generic round-trip sends nil ids,
6
+ * so on its own it only ever sees these methods refuse with `not_found`; each
7
+ * fixture here builds the real row through the backend's own RPC surface and
8
+ * returns the params (and, where the row must belong to the caller, the
9
+ * caller's headers) that drive a **success** response, which
10
+ * `describe_rpc_round_trip_tests` then validates against the method's output
11
+ * schema on every backend.
12
+ *
13
+ * Spine-generic: the fixtures use only standard RPC actions and the builtin
14
+ * `ROLE_ADMIN`, so any consumer mounting `create_standard_rpc_actions` can
15
+ * pass the map to `describe_standard_cross_process_tests` (as
16
+ * `rpc_success_fixtures`), `describe_standard_tests`, or
17
+ * `describe_rpc_round_trip_tests` (as `success_fixtures`). Each fixture mints
18
+ * its own accounts and calls as one of them, so none touches or calls as the
19
+ * suite's shared identities.
20
+ *
21
+ * @module
22
+ */
23
+ import { assert } from 'vitest';
24
+ import { account_session_list_action_spec, account_token_create_action_spec } from '../../auth/account_action_specs.js';
25
+ import { invite_create_action_spec } from '../../auth/admin_action_specs.js';
26
+ import { role_grant_assign_action_spec, role_grant_offer_create_action_spec } from '../../auth/role_grant_offer_action_specs.js';
27
+ import { ROLE_ADMIN } from '../../auth/role_schema.js';
28
+ import { rpc_call_typed } from '../rpc_helpers.js';
29
+ import { SPINE_RPC_PATH } from './spine_surface_constants.js';
30
+ /**
31
+ * Build the success-fixture map for the standard spine methods that need a
32
+ * real row id: `account_token_revoke`, `account_session_revoke`,
33
+ * `invite_delete`, `role_grant_revoke`, `role_grant_offer_accept`,
34
+ * `role_grant_offer_decline`, and `role_grant_offer_retract`.
35
+ *
36
+ * Each factory mints fresh accounts — a fresh `ROLE_ADMIN` holder as grantor
37
+ * where the setup step is admin-gated — and builds its row as a real client
38
+ * would, then returns the headers of the account that calls: the owner for
39
+ * token and session revoke, accept, decline, and retract; the fresh admin
40
+ * for invite delete and role grant revoke.
41
+ *
42
+ * @param options - the RPC endpoint path
43
+ * @returns the method → fixture-factory map
44
+ */
45
+ export const create_spine_rpc_success_fixtures = (options = {}) => {
46
+ const { rpc_path = SPINE_RPC_PATH } = options;
47
+ const call = (fixture, spec, params, headers) => rpc_call_typed({ app: fixture.transport, path: rpc_path, method: spec.method, params, headers }, spec.output);
48
+ const create_grantor = (fixture) => fixture.create_account({ roles: [ROLE_ADMIN] });
49
+ const create_pending_offer = async (fixture) => {
50
+ const grantor = await create_grantor(fixture);
51
+ const recipient = await fixture.create_account();
52
+ const { offer } = await call(fixture, role_grant_offer_create_action_spec, { to_account_id: recipient.account.id, role: ROLE_ADMIN }, grantor.create_session_headers());
53
+ return { grantor, recipient, offer_id: offer.id };
54
+ };
55
+ const fixtures = new Map([
56
+ [
57
+ 'account_token_revoke',
58
+ async (fixture) => {
59
+ const owner = await fixture.create_account();
60
+ const headers = owner.create_session_headers();
61
+ const token = await call(fixture, account_token_create_action_spec, {
62
+ name: 'rpc success fixture',
63
+ scope: { kind: 'full' },
64
+ lifetime: { kind: 'eternal' }
65
+ }, headers);
66
+ return { params: { token_id: token.id }, headers };
67
+ }
68
+ ],
69
+ [
70
+ 'account_session_revoke',
71
+ async (fixture) => {
72
+ // a throwaway account revokes its own session, the one it calls with
73
+ const owner = await fixture.create_account();
74
+ const headers = owner.create_session_headers();
75
+ const { sessions } = await call(fixture, account_session_list_action_spec, undefined, headers);
76
+ const session = sessions[0];
77
+ assert.ok(session, 'account_session_revoke fixture: the fresh account lists no session');
78
+ return { params: { session_id: session.id }, headers };
79
+ }
80
+ ],
81
+ [
82
+ 'invite_delete',
83
+ async (fixture) => {
84
+ const grantor = await create_grantor(fixture);
85
+ const { invite } = await call(fixture, invite_create_action_spec, { username: `inv${crypto.randomUUID().replaceAll('-', '').slice(0, 24)}` }, grantor.create_session_headers());
86
+ return { params: { invite_id: invite.id }, headers: grantor.create_session_headers() };
87
+ }
88
+ ],
89
+ [
90
+ 'role_grant_revoke',
91
+ async (fixture) => {
92
+ const grantor = await create_grantor(fixture);
93
+ const grantee = await fixture.create_account();
94
+ const { role_grant_id } = await call(fixture, role_grant_assign_action_spec, { to_account_id: grantee.account.id, role: ROLE_ADMIN }, grantor.create_session_headers());
95
+ return {
96
+ params: { actor_id: grantee.actor.id, role_grant_id },
97
+ headers: grantor.create_session_headers()
98
+ };
99
+ }
100
+ ],
101
+ [
102
+ 'role_grant_offer_accept',
103
+ async (fixture) => {
104
+ const { recipient, offer_id } = await create_pending_offer(fixture);
105
+ return { params: { offer_id }, headers: recipient.create_session_headers() };
106
+ }
107
+ ],
108
+ [
109
+ 'role_grant_offer_decline',
110
+ async (fixture) => {
111
+ const { recipient, offer_id } = await create_pending_offer(fixture);
112
+ return { params: { offer_id }, headers: recipient.create_session_headers() };
113
+ }
114
+ ],
115
+ [
116
+ 'role_grant_offer_retract',
117
+ async (fixture) => {
118
+ const { grantor, offer_id } = await create_pending_offer(fixture);
119
+ return { params: { offer_id }, headers: grantor.create_session_headers() };
120
+ }
121
+ ]
122
+ ]);
123
+ return fixtures;
124
+ };
@@ -0,0 +1,101 @@
1
+ import '../assert_dev_env.js';
2
+ /**
3
+ * The declared surface of a consumer served by the Rust spine, for its cross
4
+ * suites — `create_rust_spine_consumer_surface_spec`.
5
+ *
6
+ * The usual Rust spine consumer server mounts the same spine routes whatever
7
+ * its domain: `/health`, `fuz_auth::account_router` under `/api/account`
8
+ * (`ACCOUNT_ROUTER_PATHS`), the bootstrap and signup routers beside it, and
9
+ * one RPC endpoint carrying the standard admin / role-grant-offer / account
10
+ * actions plus the consumer's own. This module builds that surface from the
11
+ * hono-free route shapes and the consumer's action specs, so a consumer
12
+ * supplies only what is its own. A server that mounts no signup router (a
13
+ * single-keeper daemon) is not this shape.
14
+ *
15
+ * The route shapes come from `create_account_route_shapes` and friends, never
16
+ * the live route factories, which statically pull `hono/cookie` and
17
+ * `hono/streaming`. Handlers are never invoked — the suites read `method`,
18
+ * `path`, `auth` and the schemas, and live dispatch happens in the spawned
19
+ * binary — so routes and actions carry no-op handlers.
20
+ *
21
+ * @module
22
+ */
23
+ import type { RpcAction } from '../../actions/action_rpc.js';
24
+ import type { ActionSpecUnion } from '../../actions/action_spec.js';
25
+ import type { RoleSchemaResult } from '../../auth/role_schema.js';
26
+ import type { SessionOptions } from '../../auth/session_cookie.js';
27
+ import type { AppSurfaceSpec, RpcEndpointSpec } from '../../http/surface.js';
28
+ import type { AppServerContext } from '../../server/app_server_context.js';
29
+ /**
30
+ * The routes `fuz_auth::account_router` mounts, relative to `/api/account`. An
31
+ * allowlist rather than every account route shape: `/verify` is a TS-only
32
+ * route the Rust router doesn't serve, so declaring it would have the suites
33
+ * probe a 404. A shape fuz_app renames or drops fails the surface build; one
34
+ * it adds stays off the surface until the Rust router mounts it and this list
35
+ * names it.
36
+ */
37
+ export declare const ACCOUNT_ROUTER_PATHS: readonly ["/status", "/login", "/logout", "/password"];
38
+ /** Options for `create_rust_spine_consumer_rpc_endpoints`. */
39
+ export interface RustSpineConsumerRpcEndpointsOptions {
40
+ /**
41
+ * The consumer's own action specs. The request-response specs that aren't
42
+ * protocol actions (`heartbeat`, `peer/ping`, …) go on the RPC endpoint, so a
43
+ * full registry like `all_action_specs` can be passed as it is.
44
+ */
45
+ readonly domain_action_specs: ReadonlyArray<ActionSpecUnion>;
46
+ /**
47
+ * Actions besides the standard set and the domain specs — opt-in families
48
+ * the consumer mounts (`create_actor_lookup_actions`,
49
+ * `create_self_service_role_actions`), built against the stub context.
50
+ */
51
+ readonly extra_rpc_actions?: (ctx: AppServerContext) => Array<RpcAction>;
52
+ /** The consumer's role schema, for the standard admin and role-grant-offer actions. */
53
+ readonly roles?: RoleSchemaResult;
54
+ /**
55
+ * Domain methods kept off the declared surface — ones the spec-derived
56
+ * suites can't drive (an input whose `.refine()` the generic body generator
57
+ * can't satisfy). They stay mounted on the backend; this only leaves them
58
+ * out of what the suites enumerate.
59
+ */
60
+ readonly exclude_methods?: ReadonlyArray<string>;
61
+ /** The RPC endpoint's path. Default `SPINE_RPC_PATH`. */
62
+ readonly rpc_path?: string;
63
+ }
64
+ /** Options for `create_rust_spine_consumer_surface_spec`. */
65
+ export interface RustSpineConsumerSurfaceSpecOptions extends RustSpineConsumerRpcEndpointsOptions {
66
+ /** The backend's session config — its cookie name above all. */
67
+ readonly session_options: SessionOptions<string>;
68
+ /**
69
+ * Whether the server turns on the spine's opt-in host gate
70
+ * (`fuz_http::StackOptions::host_gate`), declared as a `host_validation`
71
+ * layer at the head of the middleware list.
72
+ *
73
+ * @default false
74
+ */
75
+ readonly host_gate?: boolean;
76
+ }
77
+ /**
78
+ * The RPC endpoints a Rust spine consumer mounts: the standard admin /
79
+ * role-grant-offer / account actions, the extra families, then the domain
80
+ * specs — what `describe_spine_cross_suites` takes as `rpc_endpoints`.
81
+ *
82
+ * @param options - the consumer's action specs, extras and roles
83
+ * @returns the endpoints, as a factory of the stub context
84
+ * @throws Error when an `exclude_methods` entry names no domain spec
85
+ */
86
+ export declare const create_rust_spine_consumer_rpc_endpoints: (options: RustSpineConsumerRpcEndpointsOptions) => ((ctx: AppServerContext) => Array<RpcEndpointSpec>);
87
+ /**
88
+ * Build the declared surface of a Rust spine consumer for its cross suites,
89
+ * on `create_test_app_surface_spec`: the spine routes (health, the account
90
+ * router's paths, signup, and bootstrap as a `surface_only` shape), the RPC
91
+ * endpoint from `create_rust_spine_consumer_rpc_endpoints`, the daemon-token
92
+ * layer every consumer test binary wires, and — with `host_gate` — the
93
+ * `host_validation` layer at the head of the middleware list.
94
+ *
95
+ * @param options - the consumer's session config, action specs, extras and roles
96
+ * @returns the surface spec, for `describe_spine_cross_suites`'s `surface_source`
97
+ * @throws Error when an account route shape the Rust router mounts is missing,
98
+ * or an `exclude_methods` entry names no domain spec
99
+ */
100
+ export declare const create_rust_spine_consumer_surface_spec: (options: RustSpineConsumerSurfaceSpecOptions) => AppSurfaceSpec;
101
+ //# sourceMappingURL=rust_spine_consumer_surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rust_spine_consumer_surface.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/rust_spine_consumer_surface.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAA6B,MAAM,8BAA8B,CAAC;AAM/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAMnE,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAI3E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,wDAAyD,CAAC;AAU3F,8DAA8D;AAC9D,MAAM,WAAW,oCAAoC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC7D;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,SAAS,CAAC,CAAC;IACzE,uFAAuF;IACvF,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjD,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,6DAA6D;AAC7D,MAAM,WAAW,mCAAoC,SAAQ,oCAAoC;IAChG,gEAAgE;IAChE,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IACjD;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,wCAAwC,GACpD,SAAS,oCAAoC,KAC3C,CAAC,CAAC,GAAG,EAAE,gBAAgB,KAAK,KAAK,CAAC,eAAe,CAAC,CA+BpD,CAAC;AAiCF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uCAAuC,GACnD,SAAS,mCAAmC,KAC1C,cAeA,CAAC"}