@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.
- package/dist/actions/CLAUDE.md +8 -6
- package/dist/actions/action_codegen.d.ts +15 -1
- package/dist/actions/action_codegen.d.ts.map +1 -1
- package/dist/actions/action_codegen.js +23 -2
- package/dist/actions/action_event.d.ts.map +1 -1
- package/dist/actions/action_event.js +14 -1
- package/dist/actions/perform_action.d.ts +17 -1
- package/dist/actions/perform_action.d.ts.map +1 -1
- package/dist/actions/perform_action.js +23 -3
- package/dist/auth/CLAUDE.md +3 -2
- package/dist/auth/account_action_specs.d.ts +12 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +16 -2
- package/dist/auth/account_actions.d.ts.map +1 -1
- package/dist/auth/account_actions.js +7 -4
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +29 -8
- package/dist/auth/audit_emitter.d.ts +14 -0
- package/dist/auth/audit_emitter.d.ts.map +1 -1
- package/dist/auth/audit_emitter.js +5 -1
- package/dist/auth/cell_action_specs.d.ts +3 -1
- package/dist/auth/cell_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_action_specs.js +5 -5
- package/dist/auth/cell_actions.d.ts.map +1 -1
- package/dist/auth/cell_actions.js +2 -3
- package/dist/auth/cell_data_schema.d.ts +1 -1
- package/dist/auth/cell_data_schema.js +1 -1
- package/dist/auth/cell_field_action_specs.d.ts +4 -3
- package/dist/auth/cell_field_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_field_action_specs.js +5 -6
- package/dist/auth/cell_field_actions.d.ts.map +1 -1
- package/dist/auth/cell_field_actions.js +8 -1
- package/dist/auth/cell_item_action_specs.d.ts +4 -2
- package/dist/auth/cell_item_action_specs.d.ts.map +1 -1
- package/dist/auth/cell_item_action_specs.js +5 -5
- package/dist/auth/cell_item_actions.d.ts.map +1 -1
- package/dist/auth/cell_item_actions.js +8 -1
- package/dist/auth/role_grant_offer_action_specs.d.ts +2 -0
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +8 -4
- package/dist/http/CLAUDE.md +14 -2
- package/dist/http/error_schemas.d.ts +8 -0
- package/dist/http/error_schemas.d.ts.map +1 -1
- package/dist/http/error_schemas.js +12 -0
- package/dist/http/jsonrpc_errors.d.ts +40 -15
- package/dist/http/jsonrpc_errors.d.ts.map +1 -1
- package/dist/http/jsonrpc_errors.js +90 -35
- package/dist/primitive_schemas.d.ts +1 -1
- package/dist/primitive_schemas.d.ts.map +1 -1
- package/dist/primitive_schemas.js +2 -1
- package/dist/schema_meta.d.ts +80 -0
- package/dist/schema_meta.d.ts.map +1 -1
- package/dist/schema_meta.js +71 -1
- package/dist/testing/CLAUDE.md +853 -146
- package/dist/testing/admin_integration.d.ts.map +1 -1
- package/dist/testing/admin_integration.js +73 -5
- package/dist/testing/adversarial_input.d.ts +0 -47
- package/dist/testing/adversarial_input.d.ts.map +1 -1
- package/dist/testing/adversarial_input.js +4 -340
- package/dist/testing/adversarial_input_cases.d.ts +124 -0
- package/dist/testing/adversarial_input_cases.d.ts.map +1 -0
- package/dist/testing/adversarial_input_cases.js +393 -0
- package/dist/testing/audit_completeness.d.ts.map +1 -1
- package/dist/testing/audit_completeness.js +24 -20
- package/dist/testing/audit_drift_guard.d.ts +30 -3
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +55 -3
- package/dist/testing/cross_backend/account_lifecycle.d.ts.map +1 -1
- package/dist/testing/cross_backend/account_lifecycle.js +29 -12
- package/dist/testing/cross_backend/actor_lookup.d.ts.map +1 -1
- package/dist/testing/cross_backend/actor_lookup.js +7 -25
- package/dist/testing/cross_backend/app_settings.d.ts.map +1 -1
- package/dist/testing/cross_backend/app_settings.js +4 -6
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts +57 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/audit_cross_helpers.js +89 -0
- package/dist/testing/cross_backend/backend_config.d.ts +2 -1
- package/dist/testing/cross_backend/backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.d.ts +6 -0
- package/dist/testing/cross_backend/body_size.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size.js +26 -44
- package/dist/testing/cross_backend/body_size_smuggling.d.ts +5 -0
- package/dist/testing/cross_backend/body_size_smuggling.d.ts.map +1 -1
- package/dist/testing/cross_backend/body_size_smuggling.js +7 -14
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts +3 -1
- package/dist/testing/cross_backend/build_test_backend_paths.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.d.ts +78 -59
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +25 -24
- package/dist/testing/cross_backend/cargo_binary.d.ts +70 -0
- package/dist/testing/cross_backend/cargo_binary.d.ts.map +1 -0
- package/dist/testing/cross_backend/cargo_binary.js +148 -0
- package/dist/testing/cross_backend/cell_crud.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_crud.js +174 -3
- package/dist/testing/cross_backend/cell_gated_create.d.ts +0 -60
- package/dist/testing/cross_backend/cell_gated_create.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_gated_create.js +9 -487
- package/dist/testing/cross_backend/cell_grant_role.d.ts +14 -2
- package/dist/testing/cross_backend/cell_grant_role.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_grant_role.js +22 -12
- package/dist/testing/cross_backend/cell_moderate.d.ts +66 -0
- package/dist/testing/cross_backend/cell_moderate.d.ts.map +1 -0
- package/dist/testing/cross_backend/cell_moderate.js +511 -0
- package/dist/testing/cross_backend/cell_ref_admission.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_ref_admission.js +1 -1
- package/dist/testing/cross_backend/cell_relations.d.ts.map +1 -1
- package/dist/testing/cross_backend/cell_relations.js +40 -19
- package/dist/testing/cross_backend/conformance_case.d.ts +43 -4
- package/dist/testing/cross_backend/conformance_case.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_case.js +29 -1
- package/dist/testing/cross_backend/conformance_rpc_auth.d.ts +93 -0
- package/dist/testing/cross_backend/conformance_rpc_auth.d.ts.map +1 -0
- package/dist/testing/cross_backend/conformance_rpc_auth.js +125 -0
- package/dist/testing/cross_backend/conformance_table.d.ts +144 -4
- package/dist/testing/cross_backend/conformance_table.d.ts.map +1 -1
- package/dist/testing/cross_backend/conformance_table.js +297 -65
- package/dist/testing/cross_backend/cookie_attributes.d.ts.map +1 -1
- package/dist/testing/cross_backend/cookie_attributes.js +3 -2
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts +38 -5
- package/dist/testing/cross_backend/create_cross_backend_global_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/create_cross_backend_global_setup.js +24 -3
- package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts +5 -5
- package/dist/testing/cross_backend/create_dual_spawn_global_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_deadline.d.ts +10 -6
- package/dist/testing/cross_backend/credential_deadline.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_deadline.js +32 -31
- package/dist/testing/cross_backend/credential_header_robustness.d.ts.map +1 -1
- package/dist/testing/cross_backend/credential_header_robustness.js +4 -6
- package/dist/testing/cross_backend/{cell_cross_helpers.d.ts → cross_rpc.d.ts} +14 -2
- package/dist/testing/cross_backend/cross_rpc.d.ts.map +1 -0
- package/dist/testing/cross_backend/{cell_cross_helpers.js → cross_rpc.js} +31 -7
- package/dist/testing/cross_backend/default_backend_configs.d.ts +58 -61
- package/dist/testing/cross_backend/default_backend_configs.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_backend_configs.js +97 -91
- package/dist/testing/cross_backend/default_spine_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/default_spine_surface.js +2 -2
- package/dist/testing/cross_backend/differential.d.ts +126 -0
- package/dist/testing/cross_backend/differential.d.ts.map +1 -0
- package/dist/testing/cross_backend/differential.js +201 -0
- package/dist/testing/cross_backend/differential_normalize.d.ts +150 -0
- package/dist/testing/cross_backend/differential_normalize.d.ts.map +1 -0
- package/dist/testing/cross_backend/differential_normalize.js +153 -0
- package/dist/testing/cross_backend/fact_serving.d.ts.map +1 -1
- package/dist/testing/cross_backend/fact_serving.js +27 -17
- package/dist/testing/cross_backend/full_spine_mount.d.ts +15 -0
- package/dist/testing/cross_backend/full_spine_mount.d.ts.map +1 -1
- package/dist/testing/cross_backend/full_spine_mount.js +55 -1
- package/dist/testing/cross_backend/identity_parity.d.ts.map +1 -1
- package/dist/testing/cross_backend/identity_parity.js +6 -5
- package/dist/testing/cross_backend/in_process_setup.d.ts +12 -2
- package/dist/testing/cross_backend/in_process_setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/in_process_setup.js +10 -7
- package/dist/testing/cross_backend/login_security.d.ts.map +1 -1
- package/dist/testing/cross_backend/login_security.js +13 -18
- package/dist/testing/cross_backend/origin.js +1 -1
- package/dist/testing/cross_backend/origin_conformance.js +1 -1
- package/dist/testing/cross_backend/origin_scope.d.ts +6 -0
- package/dist/testing/cross_backend/origin_scope.d.ts.map +1 -1
- package/dist/testing/cross_backend/origin_scope.js +13 -12
- package/dist/testing/cross_backend/peer_ping_ws.d.ts +2 -5
- package/dist/testing/cross_backend/peer_ping_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/peer_ping_ws.js +14 -24
- package/dist/testing/cross_backend/postgres_database.d.ts +85 -0
- package/dist/testing/cross_backend/postgres_database.d.ts.map +1 -0
- package/dist/testing/cross_backend/postgres_database.js +140 -0
- package/dist/testing/cross_backend/provided_context.d.ts +28 -0
- package/dist/testing/cross_backend/provided_context.d.ts.map +1 -0
- package/dist/testing/cross_backend/provided_context.js +35 -0
- package/dist/testing/cross_backend/query_shape.d.ts.map +1 -1
- package/dist/testing/cross_backend/query_shape.js +10 -12
- package/dist/testing/cross_backend/ready.js +2 -2
- package/dist/testing/cross_backend/revocation_drivers.d.ts +4 -3
- package/dist/testing/cross_backend/revocation_drivers.d.ts.map +1 -1
- package/dist/testing/cross_backend/revocation_drivers.js +1 -1
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts +3 -2
- package/dist/testing/cross_backend/role_grant_cross_helpers.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts +13 -0
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.d.ts.map +1 -0
- package/dist/testing/cross_backend/role_grant_offer_lifecycle.js +203 -0
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts +2 -5
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_offer_notification_ws.js +203 -111
- package/dist/testing/cross_backend/role_grant_participation.d.ts +13 -0
- package/dist/testing/cross_backend/role_grant_participation.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_participation.js +32 -21
- package/dist/testing/cross_backend/role_grant_role_grammar.d.ts.map +1 -1
- package/dist/testing/cross_backend/role_grant_role_grammar.js +6 -9
- package/dist/testing/cross_backend/rpc_adversarial.d.ts +47 -0
- package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -0
- package/dist/testing/cross_backend/rpc_adversarial.js +302 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.d.ts +24 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.d.ts.map +1 -0
- package/dist/testing/cross_backend/rpc_success_fixtures.js +124 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts +101 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.d.ts.map +1 -0
- package/dist/testing/cross_backend/rust_spine_consumer_surface.js +113 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts +10 -0
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/rust_spine_stub_backend_config.js +33 -21
- package/dist/testing/cross_backend/session_cap.d.ts +9 -8
- package/dist/testing/cross_backend/session_cap.d.ts.map +1 -1
- package/dist/testing/cross_backend/session_cap.js +9 -4
- package/dist/testing/cross_backend/session_cookie_codec.js +1 -1
- package/dist/testing/cross_backend/setup.d.ts +58 -56
- package/dist/testing/cross_backend/setup.d.ts.map +1 -1
- package/dist/testing/cross_backend/setup.js +29 -29
- package/dist/testing/cross_backend/simple_request.d.ts.map +1 -1
- package/dist/testing/cross_backend/simple_request.js +4 -4
- package/dist/testing/cross_backend/spawn_backend.d.ts +59 -10
- package/dist/testing/cross_backend/spawn_backend.d.ts.map +1 -1
- package/dist/testing/cross_backend/spawn_backend.js +219 -60
- package/dist/testing/cross_backend/spine_suites.d.ts +311 -0
- package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -0
- package/dist/testing/cross_backend/spine_suites.js +897 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +44 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +53 -0
- package/dist/testing/cross_backend/sse_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/sse_round_trip.js +3 -4
- package/dist/testing/cross_backend/standard.d.ts +18 -1
- package/dist/testing/cross_backend/standard.d.ts.map +1 -1
- package/dist/testing/cross_backend/standard.js +2 -0
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts +24 -0
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.d.ts.map +1 -1
- package/dist/testing/cross_backend/test_cell_gated_create_authorize.js +15 -0
- package/dist/testing/cross_backend/testing_backdoor.d.ts +29 -12
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +143 -51
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +30 -14
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +58 -37
- package/dist/testing/cross_backend/testing_server_bun.js +1 -1
- package/dist/testing/cross_backend/token_lifetime.js +1 -1
- package/dist/testing/cross_backend/token_scope_surface.d.ts.map +1 -1
- package/dist/testing/cross_backend/token_scope_surface.js +9 -13
- package/dist/testing/cross_backend/transport_composition.d.ts +26 -2
- package/dist/testing/cross_backend/transport_composition.d.ts.map +1 -1
- package/dist/testing/cross_backend/transport_composition.js +81 -51
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts +8 -0
- package/dist/testing/cross_backend/ts_spine_backend_config.d.ts.map +1 -1
- package/dist/testing/cross_backend/ts_spine_backend_config.js +23 -13
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts +2 -5
- package/dist/testing/cross_backend/ws_action_rate_limit.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_action_rate_limit.js +8 -14
- package/dist/testing/cross_backend/ws_connection_cap.d.ts +4 -9
- package/dist/testing/cross_backend/ws_connection_cap.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_connection_cap.js +11 -12
- package/dist/testing/cross_backend/ws_endpoint.d.ts +52 -0
- package/dist/testing/cross_backend/ws_endpoint.d.ts.map +1 -0
- package/dist/testing/cross_backend/ws_endpoint.js +54 -0
- package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts +2 -5
- package/dist/testing/cross_backend/ws_inbound_dispatch.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_inbound_dispatch.js +9 -15
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts +2 -7
- package/dist/testing/cross_backend/ws_outbound_overflow.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_outbound_overflow.js +5 -9
- package/dist/testing/cross_backend/ws_role_gated.d.ts +4 -5
- package/dist/testing/cross_backend/ws_role_gated.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_role_gated.js +12 -21
- package/dist/testing/cross_backend/ws_round_trip.d.ts +12 -9
- package/dist/testing/cross_backend/ws_round_trip.d.ts.map +1 -1
- package/dist/testing/cross_backend/ws_round_trip.js +29 -34
- package/dist/testing/db_entities.d.ts +16 -3
- package/dist/testing/db_entities.d.ts.map +1 -1
- package/dist/testing/db_entities.js +28 -5
- package/dist/testing/integration_helpers.d.ts +61 -2
- package/dist/testing/integration_helpers.d.ts.map +1 -1
- package/dist/testing/integration_helpers.js +75 -18
- package/dist/testing/round_trip.d.ts +17 -0
- package/dist/testing/round_trip.d.ts.map +1 -1
- package/dist/testing/round_trip.js +67 -24
- package/dist/testing/rpc_attack_surface.d.ts +10 -0
- package/dist/testing/rpc_attack_surface.d.ts.map +1 -1
- package/dist/testing/rpc_attack_surface.js +27 -140
- package/dist/testing/rpc_envelope_cases.d.ts +114 -0
- package/dist/testing/rpc_envelope_cases.d.ts.map +1 -0
- package/dist/testing/rpc_envelope_cases.js +243 -0
- package/dist/testing/rpc_helpers.d.ts +31 -0
- package/dist/testing/rpc_helpers.d.ts.map +1 -1
- package/dist/testing/rpc_helpers.js +35 -14
- package/dist/testing/rpc_round_trip.d.ts +62 -6
- package/dist/testing/rpc_round_trip.d.ts.map +1 -1
- package/dist/testing/rpc_round_trip.js +151 -39
- package/dist/testing/schema_generators.d.ts +99 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +261 -73
- package/dist/testing/standard.d.ts +26 -0
- package/dist/testing/standard.d.ts.map +1 -1
- package/dist/testing/standard.js +4 -1
- package/dist/testing/stubs.d.ts +4 -3
- package/dist/testing/stubs.d.ts.map +1 -1
- package/dist/testing/stubs.js +6 -4
- package/dist/testing/transports/raw_http.d.ts +21 -0
- package/dist/testing/transports/raw_http.d.ts.map +1 -1
- package/dist/testing/transports/raw_http.js +30 -0
- package/dist/zod.d.ts +9 -0
- package/dist/zod.d.ts.map +1 -1
- package/dist/zod.js +20 -0
- package/package.json +6 -4
- package/dist/testing/cross_backend/actor_search.d.ts +0 -6
- package/dist/testing/cross_backend/actor_search.d.ts.map +0 -1
- package/dist/testing/cross_backend/actor_search.js +0 -90
- package/dist/testing/cross_backend/cell_cross_helpers.d.ts.map +0 -1
|
@@ -4,7 +4,8 @@ import '../assert_dev_env.js';
|
|
|
4
4
|
*
|
|
5
5
|
* `create_app_server` (TS) and the Rust spine both cap the request body at a
|
|
6
6
|
* 1 MiB default (`DEFAULT_MAX_BODY_SIZE` / `fuz_http`'s
|
|
7
|
-
* `DEFAULT_BODY_LIMIT_BYTES
|
|
7
|
+
* `DEFAULT_BODY_LIMIT_BYTES`; a backend capping its RPC path elsewhere passes
|
|
8
|
+
* `rpc_max_body_bytes`) and reject oversized payloads with `413` and the
|
|
8
9
|
* canonical flat REST body `{error: 'payload_too_large'}`. A declared
|
|
9
10
|
* `Content-Length` over the cap is refused on the header, *before* auth,
|
|
10
11
|
* origin, or dispatch run (middleware step 4). Each impl unit-tests this in
|
|
@@ -55,7 +56,7 @@ import '../assert_dev_env.js';
|
|
|
55
56
|
*
|
|
56
57
|
* - a **declared** over-cap length is sent as the request head alone —
|
|
57
58
|
* `Content-Length` one over the cap and not one body byte. The 413 must
|
|
58
|
-
* arrive within `
|
|
59
|
+
* arrive within `RAW_HTTP_READ_TIMEOUT_MS`, which also pins that the refusal is
|
|
59
60
|
* made on the header: a backend that reads the body before refusing, or has
|
|
60
61
|
* no cap, waits for bytes that never come and fails the case.
|
|
61
62
|
* - the **chunked** body is sent up to one byte past the cap and never
|
|
@@ -72,7 +73,7 @@ import '../assert_dev_env.js';
|
|
|
72
73
|
* imperative suite, not a `conformance_table` row. Runs both legs via the
|
|
73
74
|
* shared `setup_test` protocol: the in-process leg
|
|
74
75
|
* (`auth/body_size_parity.db.test.ts`, plain `gro test`) and the cross-process
|
|
75
|
-
* leg (`cross_backend/
|
|
76
|
+
* leg (`cross_backend/spine_suites.cross.test.ts`, the TS spine binaries + Rust
|
|
76
77
|
* `testing_spine_stub` over real HTTP). The body-size limit is on every spine,
|
|
77
78
|
* so the suite is ungated.
|
|
78
79
|
*
|
|
@@ -83,16 +84,8 @@ import '../assert_dev_env.js';
|
|
|
83
84
|
import { describe, test, assert } from 'vitest';
|
|
84
85
|
import { account_verify_action_spec } from '../../auth/account_action_specs.js';
|
|
85
86
|
import { ERROR_PAYLOAD_TOO_LARGE } from '../../http/error_schemas.js';
|
|
86
|
-
import { raw_http_exchange, raw_http_parse_response } from '../transports/raw_http.js';
|
|
87
|
-
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
88
|
-
/**
|
|
89
|
-
* The shared 1 MiB default both impls ship (`DEFAULT_MAX_BODY_SIZE` in TS,
|
|
90
|
-
* `DEFAULT_BODY_LIMIT_BYTES` in `fuz_http`). Kept as a local cross-impl
|
|
91
|
-
* contract value rather than imported from either impl — the boundary it
|
|
92
|
-
* pins is the shared default, and a change to either is a deliberate
|
|
93
|
-
* cross-impl decision that would revisit this suite regardless.
|
|
94
|
-
*/
|
|
95
|
-
const BODY_LIMIT_DEFAULT_BYTES = 1024 * 1024;
|
|
87
|
+
import { raw_http_exchange, raw_http_header_lines, raw_http_parse_json, raw_http_parse_response, RAW_HTTP_READ_TIMEOUT_MS } from '../transports/raw_http.js';
|
|
88
|
+
import { SPINE_BODY_LIMIT_DEFAULT_BYTES, SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
96
89
|
/**
|
|
97
90
|
* Build an `account_verify` JSON-RPC envelope whose serialized length is
|
|
98
91
|
* *exactly* `target_bytes`, by growing a `params.pad` string to fill. Every
|
|
@@ -101,6 +94,10 @@ const BODY_LIMIT_DEFAULT_BYTES = 1024 * 1024;
|
|
|
101
94
|
* middleware measures. `account_verify` takes no params, but at/over the cap
|
|
102
95
|
* the size check fires before input validation, so the padded shape is never
|
|
103
96
|
* reached on the rejection path.
|
|
97
|
+
*
|
|
98
|
+
* The envelope with an empty pad is already 70-odd bytes (more with a longer
|
|
99
|
+
* `id`), so a smaller target overshoots: the body comes out at that floor, not
|
|
100
|
+
* at `target_bytes`.
|
|
104
101
|
*/
|
|
105
102
|
const sized_envelope = (id, target_bytes) => {
|
|
106
103
|
const method = account_verify_action_spec.method;
|
|
@@ -131,28 +128,10 @@ const streamed_body = (total_bytes) => {
|
|
|
131
128
|
}
|
|
132
129
|
});
|
|
133
130
|
};
|
|
134
|
-
/**
|
|
135
|
-
* How long a raw over-cap exchange waits for the refusal. The server has every
|
|
136
|
-
* byte it will get when the wait starts, so a backend that refuses on what it
|
|
137
|
-
* has answers at once and one that waits for more runs the whole window.
|
|
138
|
-
*/
|
|
139
|
-
const RAW_READ_TIMEOUT_MS = 2000;
|
|
140
131
|
const to_sized_response = async (res) => ({
|
|
141
132
|
status: res.status,
|
|
142
133
|
body: await res.json().catch(() => undefined)
|
|
143
134
|
});
|
|
144
|
-
const parse_json = (text) => {
|
|
145
|
-
try {
|
|
146
|
-
return JSON.parse(text);
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return undefined;
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
/** Render request headers as raw header lines. */
|
|
153
|
-
const to_header_lines = (headers) => Object.entries(headers)
|
|
154
|
-
.map(([name, value]) => `${name}: ${value}\r\n`)
|
|
155
|
-
.join('');
|
|
156
135
|
/**
|
|
157
136
|
* Write `request_bytes` to the backend's socket and read the one response it
|
|
158
137
|
* must answer with — without being sent anything more.
|
|
@@ -161,17 +140,17 @@ const to_header_lines = (headers) => Object.entries(headers)
|
|
|
161
140
|
*/
|
|
162
141
|
const exchange_withholding = async (base_url, request_bytes, withheld) => {
|
|
163
142
|
const { received, closed_by_server } = await raw_http_exchange(base_url, request_bytes, {
|
|
164
|
-
read_timeout_ms:
|
|
143
|
+
read_timeout_ms: RAW_HTTP_READ_TIMEOUT_MS,
|
|
165
144
|
until: 'response'
|
|
166
145
|
});
|
|
167
146
|
const response = raw_http_parse_response(received);
|
|
168
147
|
assert.ok(response, `expected a whole response with ${withheld} withheld; ` +
|
|
169
148
|
(closed_by_server
|
|
170
149
|
? `the server closed the connection first`
|
|
171
|
-
: `none arrived within ${
|
|
150
|
+
: `none arrived within ${RAW_HTTP_READ_TIMEOUT_MS}ms — the backend is waiting for bytes ` +
|
|
172
151
|
`it should refuse without`) +
|
|
173
152
|
`. Received: ${received ? received.slice(0, 120) : 'nothing'}`);
|
|
174
|
-
return { status: response.status, body:
|
|
153
|
+
return { status: response.status, body: raw_http_parse_json(response.body) };
|
|
175
154
|
};
|
|
176
155
|
/** Assert a response is the canonical over-cap refusal. */
|
|
177
156
|
const assert_payload_too_large = (res, message) => {
|
|
@@ -181,6 +160,7 @@ const assert_payload_too_large = (res, message) => {
|
|
|
181
160
|
export const describe_body_size_cross_tests = (options) => {
|
|
182
161
|
const { setup_test, base_url } = options;
|
|
183
162
|
const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
|
|
163
|
+
const cap = options.rpc_max_body_bytes ?? SPINE_BODY_LIMIT_DEFAULT_BYTES;
|
|
184
164
|
/** POST `body` to the RPC path as the keeper. */
|
|
185
165
|
const post = (fixture, body) => fixture.transport(rpc_path, {
|
|
186
166
|
method: 'POST',
|
|
@@ -194,7 +174,7 @@ export const describe_body_size_cross_tests = (options) => {
|
|
|
194
174
|
*/
|
|
195
175
|
const post_over_limit_declared = async (fixture, id) => {
|
|
196
176
|
const headers = fixture.create_session_headers();
|
|
197
|
-
const content_length =
|
|
177
|
+
const content_length = cap + 1;
|
|
198
178
|
if (base_url === null) {
|
|
199
179
|
return to_sized_response(await fixture.transport(rpc_path, {
|
|
200
180
|
method: 'POST',
|
|
@@ -204,7 +184,7 @@ export const describe_body_size_cross_tests = (options) => {
|
|
|
204
184
|
}
|
|
205
185
|
const url = new URL(base_url);
|
|
206
186
|
return exchange_withholding(base_url, `POST ${rpc_path} HTTP/1.1\r\n` +
|
|
207
|
-
|
|
187
|
+
raw_http_header_lines({
|
|
208
188
|
host: url.host,
|
|
209
189
|
origin: url.origin,
|
|
210
190
|
...headers,
|
|
@@ -223,18 +203,19 @@ export const describe_body_size_cross_tests = (options) => {
|
|
|
223
203
|
return to_sized_response(await fixture.transport(rpc_path, {
|
|
224
204
|
method: 'POST',
|
|
225
205
|
headers: { ...fixture.create_session_headers(), 'content-type': 'application/json' },
|
|
226
|
-
body: streamed_body(
|
|
206
|
+
body: streamed_body(cap + 1024),
|
|
227
207
|
// a streamed request body needs half-duplex `fetch`
|
|
228
208
|
duplex: 'half'
|
|
229
209
|
}));
|
|
230
210
|
}
|
|
231
211
|
const url = new URL(base_url);
|
|
232
|
-
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
const
|
|
212
|
+
// chunks up to exactly the cap, then a one-byte chunk's size line and its
|
|
213
|
+
// byte — and neither that chunk's closing CRLF nor the terminating chunk,
|
|
214
|
+
// so the last byte sent is the first one past the cap
|
|
215
|
+
const to_chunk = (size) => `${size.toString(16)}\r\n${'x'.repeat(size)}\r\n`;
|
|
216
|
+
const remainder = cap % STREAM_CHUNK_BYTES;
|
|
236
217
|
return exchange_withholding(base_url, `POST ${rpc_path} HTTP/1.1\r\n` +
|
|
237
|
-
|
|
218
|
+
raw_http_header_lines({
|
|
238
219
|
host: url.host,
|
|
239
220
|
origin: url.origin,
|
|
240
221
|
...fixture.create_session_headers(),
|
|
@@ -242,7 +223,8 @@ export const describe_body_size_cross_tests = (options) => {
|
|
|
242
223
|
'transfer-encoding': 'chunked'
|
|
243
224
|
}) +
|
|
244
225
|
`\r\n` +
|
|
245
|
-
|
|
226
|
+
to_chunk(STREAM_CHUNK_BYTES).repeat(Math.floor(cap / STREAM_CHUNK_BYTES)) +
|
|
227
|
+
(remainder === 0 ? '' : to_chunk(remainder)) +
|
|
246
228
|
`1\r\nx`, `the chunked body's end`);
|
|
247
229
|
};
|
|
248
230
|
describe('body-size limit parity', () => {
|
|
@@ -259,7 +241,7 @@ export const describe_body_size_cross_tests = (options) => {
|
|
|
259
241
|
// Exactly at the cap is one byte under the `>` threshold, so it clears
|
|
260
242
|
// the size gate and reaches the dispatcher. Whatever the dispatcher
|
|
261
243
|
// then returns, it must not be the 413 — that's the lower boundary.
|
|
262
|
-
const res = await post(fixture, sized_envelope('at-limit',
|
|
244
|
+
const res = await post(fixture, sized_envelope('at-limit', cap));
|
|
263
245
|
assert.notStrictEqual(res.status, 413, 'a body exactly at the cap must not be size-rejected');
|
|
264
246
|
});
|
|
265
247
|
test('under-limit POST (small) → 200', async () => {
|
|
@@ -5,6 +5,11 @@ export interface BodySizeSmugglingCrossTestOptions {
|
|
|
5
5
|
readonly base_url: string;
|
|
6
6
|
/** RPC endpoint path to target. Default `/api/rpc`. */
|
|
7
7
|
readonly rpc_path?: string;
|
|
8
|
+
/**
|
|
9
|
+
* The backend's request-body cap on `rpc_path`, in bytes; the oversized
|
|
10
|
+
* `POST` declares a length past it. Default `SPINE_BODY_LIMIT_DEFAULT_BYTES`.
|
|
11
|
+
*/
|
|
12
|
+
readonly rpc_max_body_bytes?: number;
|
|
8
13
|
}
|
|
9
14
|
export declare const describe_body_size_smuggling_cross_tests: (options: BodySizeSmugglingCrossTestOptions) => void;
|
|
10
15
|
//# sourceMappingURL=body_size_smuggling.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"body_size_smuggling.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size_smuggling.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"body_size_smuggling.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/body_size_smuggling.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAuE9B,4EAA4E;AAC5E,MAAM,WAAW,iCAAiC;IACjD,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,eAAO,MAAM,wCAAwC,GACpD,SAAS,iCAAiC,KACxC,IA4GF,CAAC"}
|
|
@@ -59,15 +59,8 @@ import '../assert_dev_env.js';
|
|
|
59
59
|
* @module
|
|
60
60
|
*/
|
|
61
61
|
import { describe, test, assert } from 'vitest';
|
|
62
|
-
import { raw_http_count_responses, raw_http_exchange } from '../transports/raw_http.js';
|
|
63
|
-
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
64
|
-
/** The shared 1 MiB cap (see `body_size.ts` for why it's a local constant). */
|
|
65
|
-
const BODY_LIMIT_DEFAULT_BYTES = 1024 * 1024;
|
|
66
|
-
/**
|
|
67
|
-
* How long each raw exchange waits for the server to finish answering. An
|
|
68
|
-
* exchange the backend does not end by closing runs the whole window.
|
|
69
|
-
*/
|
|
70
|
-
const RAW_READ_TIMEOUT_MS = 2000;
|
|
62
|
+
import { raw_http_count_responses, raw_http_exchange, RAW_HTTP_READ_TIMEOUT_MS } from '../transports/raw_http.js';
|
|
63
|
+
import { SPINE_BODY_LIMIT_DEFAULT_BYTES, SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
71
64
|
export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
72
65
|
const { base_url } = options;
|
|
73
66
|
const rpc_path = options.rpc_path ?? SPINE_RPC_PATH;
|
|
@@ -81,7 +74,7 @@ export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
|
81
74
|
const two_requests = `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\n\r\n` +
|
|
82
75
|
`GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\nConnection: close\r\n\r\n`;
|
|
83
76
|
const { received: response } = await raw_http_exchange(base_url, two_requests, {
|
|
84
|
-
read_timeout_ms:
|
|
77
|
+
read_timeout_ms: RAW_HTTP_READ_TIMEOUT_MS
|
|
85
78
|
});
|
|
86
79
|
const n = raw_http_count_responses(response);
|
|
87
80
|
assert.ok(n >= 2, `expected ≥2 responses on one keep-alive connection (got ${n}); without ` +
|
|
@@ -89,7 +82,7 @@ export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
|
89
82
|
`assertion below is not a real signal. Raw head: ${response.slice(0, 120)}`);
|
|
90
83
|
});
|
|
91
84
|
test('oversized POST + pipelined GET → no request smuggled', async () => {
|
|
92
|
-
const oversized_len =
|
|
85
|
+
const oversized_len = (options.rpc_max_body_bytes ?? SPINE_BODY_LIMIT_DEFAULT_BYTES) + 1024;
|
|
93
86
|
const pipelined_get = `GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\n\r\n`;
|
|
94
87
|
// One write: an over-cap POST (rejected on Content-Length) immediately
|
|
95
88
|
// followed by a GET.
|
|
@@ -101,7 +94,7 @@ export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
|
101
94
|
'x'.repeat(oversized_len) +
|
|
102
95
|
pipelined_get;
|
|
103
96
|
const { received: response } = await raw_http_exchange(base_url, payload, {
|
|
104
|
-
read_timeout_ms:
|
|
97
|
+
read_timeout_ms: RAW_HTTP_READ_TIMEOUT_MS
|
|
105
98
|
});
|
|
106
99
|
const n = raw_http_count_responses(response);
|
|
107
100
|
// The reject closes the connection, so the pipelined GET is never
|
|
@@ -140,7 +133,7 @@ export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
|
140
133
|
chunked_envelope +
|
|
141
134
|
`GET ${rpc_path} HTTP/1.1\r\nHost: ${host}\r\n\r\n`;
|
|
142
135
|
const { received, closed_by_server } = await raw_http_exchange(base_url, payload, {
|
|
143
|
-
read_timeout_ms:
|
|
136
|
+
read_timeout_ms: RAW_HTTP_READ_TIMEOUT_MS
|
|
144
137
|
});
|
|
145
138
|
const n = raw_http_count_responses(received);
|
|
146
139
|
// Refused with 400 or answered — the status is the implementation's.
|
|
@@ -151,7 +144,7 @@ export const describe_body_size_smuggling_cross_tests = (options) => {
|
|
|
151
144
|
`Raw head: ${received.slice(0, 120)}`);
|
|
152
145
|
assert.ok(closed_by_server, `expected the server to close the connection after a request carrying both ` +
|
|
153
146
|
`Content-Length and Transfer-Encoding; it was still open after ` +
|
|
154
|
-
`${
|
|
147
|
+
`${RAW_HTTP_READ_TIMEOUT_MS}ms. Raw head: ${received.slice(0, 120)}`);
|
|
155
148
|
});
|
|
156
149
|
}
|
|
157
150
|
});
|
|
@@ -8,7 +8,9 @@ import '../assert_dev_env.js';
|
|
|
8
8
|
* - `bootstrap_token_path` — `FUZ_BOOTSTRAP_TOKEN_PATH`; harness writes
|
|
9
9
|
* the bootstrap token here before spawn.
|
|
10
10
|
* - `daemon_token_path` — where `init_daemon_token` (Rust) and the TS
|
|
11
|
-
* server's daemon-token writer land the token (under `{root}/run/`)
|
|
11
|
+
* server's daemon-token writer land the token (under `{root}/run/`);
|
|
12
|
+
* `spawn_backend` deletes it before each spawn, so a token a previous run
|
|
13
|
+
* left is never read.
|
|
12
14
|
*/
|
|
13
15
|
export interface TestBackendPaths {
|
|
14
16
|
readonly root: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build_test_backend_paths.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/build_test_backend_paths.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqB9B
|
|
1
|
+
{"version":3,"file":"build_test_backend_paths.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/build_test_backend_paths.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAqB9B;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACnC;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,QAAQ,MAAM,KAAG,gBASzD,CAAC"}
|
|
@@ -1,43 +1,10 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
|
-
|
|
3
|
-
* Backend wiring facts recorded for documentation — **not** gating flags.
|
|
4
|
-
*
|
|
5
|
-
* The companion to `BackendCapabilities`: where each capability flag is read
|
|
6
|
-
* by a suite (a `test_if(capabilities.X, ...)` gate, or a fork of one case's
|
|
7
|
-
* assertion), nothing reads these. They record middleware / limiter wiring that
|
|
8
|
-
* differs between the TS and Rust families (a backend-shape record) but gates
|
|
9
|
-
* no cross test today. They live in their own type precisely so
|
|
10
|
-
* `BackendCapabilities` stops claiming gating power it doesn't have — fold a
|
|
11
|
-
* flag in here the moment it has no `test_if` reader, and promote it back the
|
|
12
|
-
* day a suite genuinely gates on it.
|
|
13
|
-
*/
|
|
14
|
-
export interface BackendShapeNotes {
|
|
15
|
-
/**
|
|
16
|
-
* Bearer-token auth (`Authorization: Bearer <token>`) is wired through the
|
|
17
|
-
* backend's middleware stack. `true` on every spine — the bearer-token cases
|
|
18
|
-
* in `describe_standard_integration_tests` / `describe_rate_limiting_tests`
|
|
19
|
-
* run unconditionally.
|
|
20
|
-
*/
|
|
21
|
-
readonly bearer_auth: boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Trusted-proxy XFF parsing (`X-Forwarded-For` etc.) is wired. Records the
|
|
24
|
-
* proxy-default difference between the TS family (`false` — the test binary
|
|
25
|
-
* leaves proxy parsing off) and the Rust family (`true` — the client-IP
|
|
26
|
-
* middleware is always wired; the env-gate only chooses XFF vs the TCP peer).
|
|
27
|
-
*/
|
|
28
|
-
readonly trusted_proxy: boolean;
|
|
29
|
-
/**
|
|
30
|
-
* Per-account login rate limiting is wired. `false` for the TS family (the
|
|
31
|
-
* canonical path leaves the limiter null in test mode), `true` for the Rust
|
|
32
|
-
* family (env-gated bucket on `/login` + `/password`).
|
|
33
|
-
*/
|
|
34
|
-
readonly login_rate_limit: boolean;
|
|
35
|
-
}
|
|
2
|
+
import type { TestingBackdoorMethod } from './spine_surface_constants.js';
|
|
36
3
|
/**
|
|
37
4
|
* Optional behaviors a backend may support. Each flag's TSDoc names the
|
|
38
5
|
* tests that gate on it; add a new flag here before referencing it from
|
|
39
|
-
* a suite body, and document the gating tests inline.
|
|
40
|
-
*
|
|
6
|
+
* a suite body, and document the gating tests inline. A wiring fact no
|
|
7
|
+
* suite reads doesn't belong here.
|
|
41
8
|
*/
|
|
42
9
|
export interface BackendCapabilities {
|
|
43
10
|
/**
|
|
@@ -93,15 +60,28 @@ export interface BackendCapabilities {
|
|
|
93
60
|
*/
|
|
94
61
|
readonly account_lifecycle: boolean;
|
|
95
62
|
/**
|
|
96
|
-
* The cell-gated fact-serving
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* `
|
|
100
|
-
*
|
|
101
|
-
* cross-owner-dedup-no-leak, 404-mask
|
|
102
|
-
* the
|
|
63
|
+
* The cell-gated fact-serving route (`GET /api/cells/:cell_id/facts/:hash`)
|
|
64
|
+
* is live-mounted on the backend, its DB carries the `fuz_facts` migration
|
|
65
|
+
* namespace, and it mounts the `_testing_put_fact` seeder — declared in
|
|
66
|
+
* `testing_backdoors`, which `describe_spine_cross_suites` requires. Gates
|
|
67
|
+
* `describe_fact_serving_cross_tests`' per-reference read model (cell-scoped
|
|
68
|
+
* admit via a viewable cell, cross-owner-dedup-no-leak, 404-mask),
|
|
69
|
+
* `describe_cell_ref_admission_cross_tests`, and the fact cases of the
|
|
70
|
+
* moderation suite. Like cells, the serve route stays off the standard
|
|
71
|
+
* declared surface. The admin bare-hash route is its own flag,
|
|
72
|
+
* `fact_serving_admin_hash`.
|
|
103
73
|
*/
|
|
104
74
|
readonly fact_serving: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The admin-only bare-hash fact route (`GET /api/facts/:hash`) is
|
|
77
|
+
* live-mounted. Gates the bare-hash cases of
|
|
78
|
+
* `describe_fact_serving_cross_tests` (with `fact_serving`, whose seeder
|
|
79
|
+
* they use), `describe_query_shape_cross_tests` and
|
|
80
|
+
* `describe_token_scope_surface_cross_tests`. A backend serving only the
|
|
81
|
+
* cell-gated route states `fact_serving: true, fact_serving_admin_hash:
|
|
82
|
+
* false`.
|
|
83
|
+
*/
|
|
84
|
+
readonly fact_serving_admin_hash: boolean;
|
|
105
85
|
/**
|
|
106
86
|
* The `/ready` readiness deploy gate (`GET /ready`) is live-mounted on the
|
|
107
87
|
* backend — the public column-presence schema-drift probe over the committed
|
|
@@ -130,13 +110,12 @@ export interface BackendCapabilities {
|
|
|
130
110
|
* rejection, per-connection id isolation, never-replying `Timeout`,
|
|
131
111
|
* wrong-shape reply rejection).
|
|
132
112
|
*
|
|
133
|
-
* `true`
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* endpoint (the no-transport refusal). Like ws/sse/cells, `peer/ping` stays
|
|
113
|
+
* `true` on fuz_app's own spine presets — the Rust `testing_spine_stub` and
|
|
114
|
+
* the TS spine (`BackendWebsocketTransport.request_connection` drives the
|
|
115
|
+
* round-trip, correlated by `register_action_ws`). A `MountFlag`: a backend
|
|
116
|
+
* states `true` once it mounts `peer/ping` on a WS endpoint **and** the HTTP
|
|
117
|
+
* RPC endpoint (the no-transport refusal).
|
|
118
|
+
* Like ws/sse/cells, `peer/ping` stays
|
|
140
119
|
* off the standard declared surface (it's a protocol action,
|
|
141
120
|
* manifest-excluded), so this flag is the only opt-in into the peer parity
|
|
142
121
|
* coverage.
|
|
@@ -171,9 +150,9 @@ export interface BackendCapabilities {
|
|
|
171
150
|
*
|
|
172
151
|
* `true` on fuz_app's own spine presets — the TS spine binary mounts its
|
|
173
152
|
* full action set on `/api/ws`, and the Rust `testing_spine_stub` serves
|
|
174
|
-
* one action registry on RPC and WS. `
|
|
175
|
-
*
|
|
176
|
-
*
|
|
153
|
+
* one action registry on RPC and WS. A `MountFlag`: a consumer's WS endpoint
|
|
154
|
+
* carries whatever its domain mounts, so it states `true` once the account
|
|
155
|
+
* actions are there.
|
|
177
156
|
*/
|
|
178
157
|
readonly ws_account_actions: boolean;
|
|
179
158
|
/**
|
|
@@ -214,7 +193,53 @@ export interface BackendCapabilities {
|
|
|
214
193
|
* Deno, Bun, and the Rust spine, which send the response as built.
|
|
215
194
|
*/
|
|
216
195
|
readonly ws_refusal_body: boolean;
|
|
196
|
+
/**
|
|
197
|
+
* The `_testing_*` backdoors the backend mounts on its RPC endpoint, from
|
|
198
|
+
* `TESTING_BACKDOOR_METHODS` (a consumer's own seams stay off it). Not a
|
|
199
|
+
* flag, but declared like a `MountFlag`: no family default, so every config
|
|
200
|
+
* states it. `describe_testing_backdoor_cross_tests` checks the declaration
|
|
201
|
+
* against the backend — a declared method must be mounted, an undeclared one
|
|
202
|
+
* must answer `method_not_found` — and runs its credential-gate rows over
|
|
203
|
+
* the declared ones; `describe_spine_cross_suites` requires `_testing_reset`
|
|
204
|
+
* and `_testing_drain_effects` (the per-test reset and the audit barrier),
|
|
205
|
+
* skips a suite whose backdoor is undeclared, naming it — `credential_deadline`
|
|
206
|
+
* (`_testing_shorten_credential_expiry`), `origin_conformance`
|
|
207
|
+
* (`_testing_origin_check`), `ws_outbound_overflow`
|
|
208
|
+
* (`_testing_flood_notifications`) — and requires `_testing_put_fact` of a
|
|
209
|
+
* backend declaring `fact_serving`.
|
|
210
|
+
*
|
|
211
|
+
* fuz_app's spine presets declare every one; the in-process transport none
|
|
212
|
+
* (the backdoor suites are cross-process only).
|
|
213
|
+
*/
|
|
214
|
+
readonly testing_backdoors: ReadonlyArray<TestingBackdoorMethod>;
|
|
217
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* The capabilities that describe a backend's own mounts, never a runtime
|
|
218
|
+
* trait: what a consumer chooses to serve. They have no family default —
|
|
219
|
+
* state each flag in your backend config's `capabilities`; a missing one
|
|
220
|
+
* would silently skip its suites, so leaving one out is a type error.
|
|
221
|
+
*
|
|
222
|
+
* `Pick` keeps the list honest: a name that is not a `BackendCapabilities`
|
|
223
|
+
* flag fails to compile.
|
|
224
|
+
*/
|
|
225
|
+
export type MountFlag = keyof Pick<BackendCapabilities, 'ws' | 'sse' | 'cell_crud' | 'cell_relations' | 'cell_gated_create' | 'fact_serving' | 'fact_serving_admin_hash' | 'ready' | 'peer_request' | 'ws_account_actions' | 'ws_role_gated'>;
|
|
226
|
+
/**
|
|
227
|
+
* A family's default capabilities: every flag but the `MountFlag`s and the
|
|
228
|
+
* `testing_backdoors` list, which each backend config states itself. Spread
|
|
229
|
+
* one and add every mount flag and the backdoor list:
|
|
230
|
+
*
|
|
231
|
+
* ```ts
|
|
232
|
+
* capabilities: {
|
|
233
|
+
* ...rust_default_capabilities,
|
|
234
|
+
* ws: true, sse: true, ready: true, peer_request: true,
|
|
235
|
+
* cell_crud: false, cell_relations: false, cell_gated_create: false,
|
|
236
|
+
* fact_serving: false, fact_serving_admin_hash: false,
|
|
237
|
+
* ws_account_actions: false, ws_role_gated: false,
|
|
238
|
+
* testing_backdoors: ['_testing_reset', '_testing_drain_effects'],
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
export type FamilyDefaultCapabilities = Omit<BackendCapabilities, MountFlag | 'testing_backdoors'>;
|
|
218
243
|
/**
|
|
219
244
|
* Capability declarations for the in-process Hono transport. Nearly every
|
|
220
245
|
* flag is `true` because in-process testing exercises the full backend
|
|
@@ -229,12 +254,6 @@ export interface BackendCapabilities {
|
|
|
229
254
|
* per backend.
|
|
230
255
|
*/
|
|
231
256
|
export declare const in_process_capabilities: BackendCapabilities;
|
|
232
|
-
/**
|
|
233
|
-
* Shape notes for the in-process Hono transport — every wiring fact present
|
|
234
|
-
* (the in-process app exercises the full middleware stack). Documentation
|
|
235
|
-
* only, like every `BackendShapeNotes` (nothing reads it).
|
|
236
|
-
*/
|
|
237
|
-
export declare const in_process_shape_notes: BackendShapeNotes;
|
|
238
257
|
/**
|
|
239
258
|
* Conditional `test()` wrapper — registers a vitest case only when
|
|
240
259
|
* `cond` is true; otherwise registers it as `.skip` so the run still
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAkD9B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,CAAC;IAC1C;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC;;;;;;;;;OASG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;CACjE;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,IAAI,CACjC,mBAAmB,EACjB,IAAI,GACJ,KAAK,GACL,WAAW,GACX,gBAAgB,GAChB,mBAAmB,GACnB,cAAc,GACd,yBAAyB,GACzB,OAAO,GACP,cAAc,GACd,oBAAoB,GACpB,eAAe,CACjB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,mBAAmB,EAAE,SAAS,GAAG,mBAAmB,CAAC,CAAC;AAEnG;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBA4BpC,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,OAAO,EAAE,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAG,IAMrF,CAAC"}
|
|
@@ -18,22 +18,29 @@ import '../assert_dev_env.js';
|
|
|
18
18
|
* - `in_process_capabilities` — here; every flag `true` except the
|
|
19
19
|
* cross-process-only ones.
|
|
20
20
|
* - `ts_default_capabilities` / `rust_default_capabilities` — consumer-facing
|
|
21
|
-
* family defaults, in `default_backend_configs.ts`
|
|
22
|
-
*
|
|
21
|
+
* family defaults, in `default_backend_configs.ts` — every flag but the
|
|
22
|
+
* `MountFlag`s (`FamilyDefaultCapabilities`), as full literals, so adding a
|
|
23
|
+
* non-mount capability is a compile error until each family declares it.
|
|
23
24
|
* - `ts_spine_capabilities` / `ts_spine_bun_capabilities` — fuz_app's own TS
|
|
24
|
-
* spine presets, in `ts_spine_backend_config.ts` (
|
|
25
|
-
* default; Bun flips `ws_handshake_pipelining`).
|
|
25
|
+
* spine presets, in `ts_spine_backend_config.ts` (the family
|
|
26
|
+
* default plus every mount flag; Bun flips `ws_handshake_pipelining`).
|
|
26
27
|
* - `rust_spine_stub_capabilities` — fuz_app's Rust spine-stub preset, in
|
|
27
|
-
* `rust_spine_stub_backend_config.ts` (
|
|
28
|
+
* `rust_spine_stub_backend_config.ts` (the rust family default plus every mount flag).
|
|
28
29
|
*
|
|
29
|
-
* **
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `
|
|
36
|
-
*
|
|
30
|
+
* **Mount flags have no default.** A flag naming something a backend mounts
|
|
31
|
+
* (a `MountFlag`) is never inherited, nor is the `testing_backdoors` list: the
|
|
32
|
+
* family defaults are `FamilyDefaultCapabilities`, which omits them, so every
|
|
33
|
+
* backend config states each one. The family defaults carry only what the family guarantees — the
|
|
34
|
+
* declared spine surface's mounts (`account_lifecycle`, `account_status`) and
|
|
35
|
+
* the runtime behavior of its reference runtime (`ws_handshake_pipelining`,
|
|
36
|
+
* `ws_refusal_body`: Node for TS, hyper for Rust), which a backend on another
|
|
37
|
+
* runtime overrides.
|
|
38
|
+
*
|
|
39
|
+
* **Gating flags only.** `BackendCapabilities` holds only flags a suite
|
|
40
|
+
* actually gates on (each has a `test_if(capabilities.X, ...)` reader, or —
|
|
41
|
+
* `ws_refusal_body` — picks how a case reads a refusal), plus the
|
|
42
|
+
* `testing_backdoors` list the backdoor suite and `describe_spine_cross_suites`
|
|
43
|
+
* read. A wiring fact no suite reads is not a capability.
|
|
37
44
|
*
|
|
38
45
|
* @module
|
|
39
46
|
*/
|
|
@@ -58,6 +65,7 @@ export const in_process_capabilities = Object.freeze({
|
|
|
58
65
|
cell_relations: true,
|
|
59
66
|
account_lifecycle: true,
|
|
60
67
|
fact_serving: true,
|
|
68
|
+
fact_serving_admin_hash: true,
|
|
61
69
|
ready: true,
|
|
62
70
|
account_status: true,
|
|
63
71
|
peer_request: false,
|
|
@@ -74,17 +82,10 @@ export const in_process_capabilities = Object.freeze({
|
|
|
74
82
|
ws_role_gated: false,
|
|
75
83
|
// Read only by the front-door table's WS rows, which skip in-process (no
|
|
76
84
|
// socket to upgrade); Hono's own refusals carry their bodies.
|
|
77
|
-
ws_refusal_body: true
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* (the in-process app exercises the full middleware stack). Documentation
|
|
82
|
-
* only, like every `BackendShapeNotes` (nothing reads it).
|
|
83
|
-
*/
|
|
84
|
-
export const in_process_shape_notes = Object.freeze({
|
|
85
|
-
bearer_auth: true,
|
|
86
|
-
trusted_proxy: true,
|
|
87
|
-
login_rate_limit: true
|
|
85
|
+
ws_refusal_body: true,
|
|
86
|
+
// The in-process app mounts no `_testing_*` action; the suites reading this
|
|
87
|
+
// are cross-process only.
|
|
88
|
+
testing_backdoors: Object.freeze([])
|
|
88
89
|
});
|
|
89
90
|
/**
|
|
90
91
|
* Conditional `test()` wrapper — registers a vitest case only when
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Env var skipping the build, for iteration on a known-current binary: `1` or
|
|
4
|
+
* `true` skips it, any other value (`0`, `false`, empty) builds.
|
|
5
|
+
*/
|
|
6
|
+
export declare const NO_REBUILD_ENV = "FUZ_TESTING_NO_REBUILD";
|
|
7
|
+
/**
|
|
8
|
+
* Whether an `NO_REBUILD_ENV` value asks to skip the build — only an explicit
|
|
9
|
+
* `1` / `true`, so `FUZ_TESTING_NO_REBUILD=0` still builds.
|
|
10
|
+
*
|
|
11
|
+
* @param value - the variable's value, `undefined` when unset
|
|
12
|
+
*/
|
|
13
|
+
export declare const is_no_rebuild_requested: (value: string | undefined) => boolean;
|
|
14
|
+
/** Options naming one Cargo-built binary. */
|
|
15
|
+
export interface CargoBinaryOptions {
|
|
16
|
+
/** The Cargo workspace (or package) directory the build runs in. */
|
|
17
|
+
readonly workspace_dir: string;
|
|
18
|
+
/** The Cargo package holding the binary (`cargo build -p`). */
|
|
19
|
+
readonly package: string;
|
|
20
|
+
/** The binary target (`cargo build --bin`). Default the package name. */
|
|
21
|
+
readonly bin?: string;
|
|
22
|
+
/** The Cargo profile. Default `'dev'`, whose output is `debug/`. */
|
|
23
|
+
readonly profile?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The directory under the target directory a profile's output lands in —
|
|
27
|
+
* `debug` for `dev`, the profile's own name otherwise (`release`, a custom
|
|
28
|
+
* `cross-test`).
|
|
29
|
+
*
|
|
30
|
+
* @param profile - the Cargo profile
|
|
31
|
+
*/
|
|
32
|
+
export declare const to_cargo_profile_dir: (profile: string) => string;
|
|
33
|
+
/**
|
|
34
|
+
* The binary path `cargo build --profile <profile> --bin <bin>` writes, from
|
|
35
|
+
* `cargo metadata --no-deps --format-version 1` output.
|
|
36
|
+
*
|
|
37
|
+
* @param metadata_json - the `cargo metadata` output
|
|
38
|
+
* @param bin - the binary's name
|
|
39
|
+
* @param profile - the Cargo profile
|
|
40
|
+
* @returns the binary's absolute path
|
|
41
|
+
* @throws Error when the output carries no `target_directory`
|
|
42
|
+
*/
|
|
43
|
+
export declare const to_cargo_binary_path: (metadata_json: string, bin: string, profile: string) => string;
|
|
44
|
+
/**
|
|
45
|
+
* The path of a Cargo-built binary, without building it — what a config's
|
|
46
|
+
* `start_command` names. Runs `cargo metadata` once per process per workspace,
|
|
47
|
+
* so it needs cargo on PATH.
|
|
48
|
+
*
|
|
49
|
+
* @param options - the workspace, package, binary and profile
|
|
50
|
+
* @returns the binary's absolute path
|
|
51
|
+
* @throws Error when the workspace is missing or `cargo metadata` fails
|
|
52
|
+
*/
|
|
53
|
+
export declare const resolve_cargo_binary_path: (options: CargoBinaryOptions) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Build a Cargo binary before its backend spawns, unless `NO_REBUILD_ENV`
|
|
56
|
+
* asks to skip it, and return its path. The build's output is inherited, so a
|
|
57
|
+
* cold build shows its progress, and a failed build throws — the project fails
|
|
58
|
+
* loudly rather than spawning a stale binary. `cargo build` is incremental, so
|
|
59
|
+
* a build with nothing changed is quick.
|
|
60
|
+
*
|
|
61
|
+
* Synchronous: vitest awaits each project's `globalSetup` in turn, so one
|
|
62
|
+
* invocation selecting several projects builds once, then finds the build
|
|
63
|
+
* current.
|
|
64
|
+
*
|
|
65
|
+
* @param options - the workspace, package, binary and profile
|
|
66
|
+
* @returns the binary's absolute path (`resolve_cargo_binary_path`)
|
|
67
|
+
* @throws Error when the workspace is missing, the build fails, or `cargo metadata` fails
|
|
68
|
+
*/
|
|
69
|
+
export declare const prepare_cargo_binary: (options: CargoBinaryOptions) => string;
|
|
70
|
+
//# sourceMappingURL=cargo_binary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cargo_binary.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cargo_binary.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAyB9B;;;GAGG;AACH,eAAO,MAAM,cAAc,2BAA2B,CAAC;AAEvD;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,OACnB,CAAC;AAElD,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IAClC,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,MACjB,CAAC;AAEvC;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAChC,eAAe,MAAM,EACrB,KAAK,MAAM,EACX,SAAS,MAAM,KACb,MAMF,CAAC;AA2DF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GAAI,SAAS,kBAAkB,KAAG,MAGvE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,GAAI,SAAS,kBAAkB,KAAG,MAUlE,CAAC"}
|