@fuzdev/fuz_app 0.147.0 → 0.148.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 +6 -4
- 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/perform_action.js +1 -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 +3 -1
- 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 +20 -0
- package/dist/schema_meta.d.ts.map +1 -1
- package/dist/schema_meta.js +7 -1
- package/dist/testing/CLAUDE.md +720 -114
- 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 +64 -0
- package/dist/testing/adversarial_input_cases.d.ts.map +1 -0
- package/dist/testing/adversarial_input_cases.js +348 -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 +27 -1
- package/dist/testing/audit_drift_guard.d.ts.map +1 -1
- package/dist/testing/audit_drift_guard.js +50 -0
- 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 +51 -0
- package/dist/testing/cross_backend/audit_cross_helpers.d.ts.map +1 -0
- package/dist/testing/cross_backend/audit_cross_helpers.js +78 -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 +55 -59
- package/dist/testing/cross_backend/capabilities.d.ts.map +1 -1
- package/dist/testing/cross_backend/capabilities.js +20 -23
- 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 +57 -1
- 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} +12 -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 +56 -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 +38 -0
- package/dist/testing/cross_backend/rpc_adversarial.d.ts.map +1 -0
- package/dist/testing/cross_backend/rpc_adversarial.js +292 -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 +27 -18
- 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 +56 -54
- 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 +231 -0
- package/dist/testing/cross_backend/spine_suites.d.ts.map +1 -0
- package/dist/testing/cross_backend/spine_suites.js +626 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts +29 -0
- package/dist/testing/cross_backend/spine_surface_constants.d.ts.map +1 -1
- package/dist/testing/cross_backend/spine_surface_constants.js +29 -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 +2 -8
- package/dist/testing/cross_backend/testing_backdoor.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_backdoor.js +7 -10
- package/dist/testing/cross_backend/testing_reset_actions.d.ts +3 -2
- package/dist/testing/cross_backend/testing_reset_actions.d.ts.map +1 -1
- package/dist/testing/cross_backend/testing_reset_actions.js +8 -4
- 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 +17 -10
- 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.map +1 -1
- package/dist/testing/rpc_attack_surface.js +13 -138
- package/dist/testing/rpc_envelope_cases.d.ts +111 -0
- package/dist/testing/rpc_envelope_cases.d.ts.map +1 -0
- package/dist/testing/rpc_envelope_cases.js +240 -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.map +1 -1
- package/dist/testing/schema_generators.js +22 -2
- 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/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/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
|
@@ -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,9 @@
|
|
|
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
|
-
}
|
|
36
2
|
/**
|
|
37
3
|
* Optional behaviors a backend may support. Each flag's TSDoc names the
|
|
38
4
|
* 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
|
-
*
|
|
5
|
+
* a suite body, and document the gating tests inline. A wiring fact no
|
|
6
|
+
* suite reads doesn't belong here.
|
|
41
7
|
*/
|
|
42
8
|
export interface BackendCapabilities {
|
|
43
9
|
/**
|
|
@@ -93,15 +59,27 @@ export interface BackendCapabilities {
|
|
|
93
59
|
*/
|
|
94
60
|
readonly account_lifecycle: boolean;
|
|
95
61
|
/**
|
|
96
|
-
* The cell-gated fact-serving
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* `
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* the serve
|
|
62
|
+
* The cell-gated fact-serving route (`GET /api/cells/:cell_id/facts/:hash`)
|
|
63
|
+
* is live-mounted on the backend, its DB carries the `fuz_facts` migration
|
|
64
|
+
* namespace, and it registers the `_testing_put_fact` seeder. Gates
|
|
65
|
+
* `describe_fact_serving_cross_tests`' per-reference read model (cell-scoped
|
|
66
|
+
* admit via a viewable cell, cross-owner-dedup-no-leak, 404-mask),
|
|
67
|
+
* `describe_cell_ref_admission_cross_tests`, and the fact cases of the
|
|
68
|
+
* moderation suite. Like cells, the serve route stays off the standard
|
|
69
|
+
* declared surface. The admin bare-hash route is its own flag,
|
|
70
|
+
* `fact_serving_admin_hash`.
|
|
103
71
|
*/
|
|
104
72
|
readonly fact_serving: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The admin-only bare-hash fact route (`GET /api/facts/:hash`) is
|
|
75
|
+
* live-mounted. Gates the bare-hash cases of
|
|
76
|
+
* `describe_fact_serving_cross_tests` (with `fact_serving`, whose seeder
|
|
77
|
+
* they use), `describe_query_shape_cross_tests` and
|
|
78
|
+
* `describe_token_scope_surface_cross_tests`. A backend serving only the
|
|
79
|
+
* cell-gated route states `fact_serving: true, fact_serving_admin_hash:
|
|
80
|
+
* false`.
|
|
81
|
+
*/
|
|
82
|
+
readonly fact_serving_admin_hash: boolean;
|
|
105
83
|
/**
|
|
106
84
|
* The `/ready` readiness deploy gate (`GET /ready`) is live-mounted on the
|
|
107
85
|
* backend — the public column-presence schema-drift probe over the committed
|
|
@@ -130,13 +108,12 @@ export interface BackendCapabilities {
|
|
|
130
108
|
* rejection, per-connection id isolation, never-replying `Timeout`,
|
|
131
109
|
* wrong-shape reply rejection).
|
|
132
110
|
*
|
|
133
|
-
* `true`
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* endpoint (the no-transport refusal). Like ws/sse/cells, `peer/ping` stays
|
|
111
|
+
* `true` on fuz_app's own spine presets — the Rust `testing_spine_stub` and
|
|
112
|
+
* the TS spine (`BackendWebsocketTransport.request_connection` drives the
|
|
113
|
+
* round-trip, correlated by `register_action_ws`). A `MountFlag`: a backend
|
|
114
|
+
* states `true` once it mounts `peer/ping` on a WS endpoint **and** the HTTP
|
|
115
|
+
* RPC endpoint (the no-transport refusal).
|
|
116
|
+
* Like ws/sse/cells, `peer/ping` stays
|
|
140
117
|
* off the standard declared surface (it's a protocol action,
|
|
141
118
|
* manifest-excluded), so this flag is the only opt-in into the peer parity
|
|
142
119
|
* coverage.
|
|
@@ -171,9 +148,9 @@ export interface BackendCapabilities {
|
|
|
171
148
|
*
|
|
172
149
|
* `true` on fuz_app's own spine presets — the TS spine binary mounts its
|
|
173
150
|
* full action set on `/api/ws`, and the Rust `testing_spine_stub` serves
|
|
174
|
-
* one action registry on RPC and WS. `
|
|
175
|
-
*
|
|
176
|
-
*
|
|
151
|
+
* one action registry on RPC and WS. A `MountFlag`: a consumer's WS endpoint
|
|
152
|
+
* carries whatever its domain mounts, so it states `true` once the account
|
|
153
|
+
* actions are there.
|
|
177
154
|
*/
|
|
178
155
|
readonly ws_account_actions: boolean;
|
|
179
156
|
/**
|
|
@@ -215,6 +192,31 @@ export interface BackendCapabilities {
|
|
|
215
192
|
*/
|
|
216
193
|
readonly ws_refusal_body: boolean;
|
|
217
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* The capabilities that describe a backend's own mounts, never a runtime
|
|
197
|
+
* trait: what a consumer chooses to serve. They have no family default —
|
|
198
|
+
* state each flag in your backend config's `capabilities`; a missing one
|
|
199
|
+
* would silently skip its suites, so leaving one out is a type error.
|
|
200
|
+
*
|
|
201
|
+
* `Pick` keeps the list honest: a name that is not a `BackendCapabilities`
|
|
202
|
+
* flag fails to compile.
|
|
203
|
+
*/
|
|
204
|
+
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'>;
|
|
205
|
+
/**
|
|
206
|
+
* A family's default capabilities: every flag but the `MountFlag`s, which
|
|
207
|
+
* each backend config states itself. Spread one and add every mount flag:
|
|
208
|
+
*
|
|
209
|
+
* ```ts
|
|
210
|
+
* capabilities: {
|
|
211
|
+
* ...rust_default_capabilities,
|
|
212
|
+
* ws: true, sse: true, ready: true, peer_request: true,
|
|
213
|
+
* cell_crud: false, cell_relations: false, cell_gated_create: false,
|
|
214
|
+
* fact_serving: false, fact_serving_admin_hash: false,
|
|
215
|
+
* ws_account_actions: false, ws_role_gated: false,
|
|
216
|
+
* }
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export type FamilyDefaultCapabilities = Omit<BackendCapabilities, MountFlag>;
|
|
218
220
|
/**
|
|
219
221
|
* Capability declarations for the in-process Hono transport. Nearly every
|
|
220
222
|
* flag is `true` because in-process testing exercises the full backend
|
|
@@ -229,12 +231,6 @@ export interface BackendCapabilities {
|
|
|
229
231
|
* per backend.
|
|
230
232
|
*/
|
|
231
233
|
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
234
|
/**
|
|
239
235
|
* Conditional `test()` wrapper — registers a vitest case only when
|
|
240
236
|
* `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;AAiD9B;;;;;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;;;;;;;;;;OAUG;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;CAClC;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;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAC;AAE7E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,EAAE,mBAyBpC,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,28 @@ 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: the family defaults are
|
|
32
|
+
* `FamilyDefaultCapabilities`, which omits them, so every backend config states
|
|
33
|
+
* 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). A wiring fact no suite
|
|
42
|
+
* reads is not a capability.
|
|
37
43
|
*
|
|
38
44
|
* @module
|
|
39
45
|
*/
|
|
@@ -58,6 +64,7 @@ export const in_process_capabilities = Object.freeze({
|
|
|
58
64
|
cell_relations: true,
|
|
59
65
|
account_lifecycle: true,
|
|
60
66
|
fact_serving: true,
|
|
67
|
+
fact_serving_admin_hash: true,
|
|
61
68
|
ready: true,
|
|
62
69
|
account_status: true,
|
|
63
70
|
peer_request: false,
|
|
@@ -76,16 +83,6 @@ export const in_process_capabilities = Object.freeze({
|
|
|
76
83
|
// socket to upgrade); Hono's own refusals carry their bodies.
|
|
77
84
|
ws_refusal_body: true
|
|
78
85
|
});
|
|
79
|
-
/**
|
|
80
|
-
* Shape notes for the in-process Hono transport — every wiring fact present
|
|
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
|
|
88
|
-
});
|
|
89
86
|
/**
|
|
90
87
|
* Conditional `test()` wrapper — registers a vitest case only when
|
|
91
88
|
* `cond` is true; otherwise registers it as `.skip` so the run still
|
|
@@ -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"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import '../assert_dev_env.js';
|
|
2
|
+
/**
|
|
3
|
+
* Cargo-built test binaries for cross-backend projects — build before the
|
|
4
|
+
* spawn, then spawn the binary itself.
|
|
5
|
+
*
|
|
6
|
+
* A config that spawns `cargo run` builds inside `spawn_backend`'s health
|
|
7
|
+
* window, so a cold build can outlast the startup timeout, and the build's
|
|
8
|
+
* output is held in the spawn's stderr tail rather than shown.
|
|
9
|
+
* `prepare_cargo_binary` runs the build first, with its output inherited, as a
|
|
10
|
+
* pre-spawn hook (`create_cross_backend_global_setup`'s `before_spawn`), and
|
|
11
|
+
* the config's `start_command` names the built binary
|
|
12
|
+
* (`resolve_cargo_binary_path`), so the spawn starts at once.
|
|
13
|
+
*
|
|
14
|
+
* The binary's path comes from `cargo metadata`: under the workspace's
|
|
15
|
+
* resolved `target_directory`, so `CARGO_TARGET_DIR` and `build.target-dir`
|
|
16
|
+
* are honoured, in the profile's output directory.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
import { execFileSync } from 'node:child_process';
|
|
21
|
+
import { existsSync } from 'node:fs';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
/**
|
|
24
|
+
* Env var skipping the build, for iteration on a known-current binary: `1` or
|
|
25
|
+
* `true` skips it, any other value (`0`, `false`, empty) builds.
|
|
26
|
+
*/
|
|
27
|
+
export const NO_REBUILD_ENV = 'FUZ_TESTING_NO_REBUILD';
|
|
28
|
+
/**
|
|
29
|
+
* Whether an `NO_REBUILD_ENV` value asks to skip the build — only an explicit
|
|
30
|
+
* `1` / `true`, so `FUZ_TESTING_NO_REBUILD=0` still builds.
|
|
31
|
+
*
|
|
32
|
+
* @param value - the variable's value, `undefined` when unset
|
|
33
|
+
*/
|
|
34
|
+
export const is_no_rebuild_requested = (value) => value === '1' || value?.toLowerCase() === 'true';
|
|
35
|
+
/**
|
|
36
|
+
* The directory under the target directory a profile's output lands in —
|
|
37
|
+
* `debug` for `dev`, the profile's own name otherwise (`release`, a custom
|
|
38
|
+
* `cross-test`).
|
|
39
|
+
*
|
|
40
|
+
* @param profile - the Cargo profile
|
|
41
|
+
*/
|
|
42
|
+
export const to_cargo_profile_dir = (profile) => profile === 'dev' ? 'debug' : profile;
|
|
43
|
+
/**
|
|
44
|
+
* The binary path `cargo build --profile <profile> --bin <bin>` writes, from
|
|
45
|
+
* `cargo metadata --no-deps --format-version 1` output.
|
|
46
|
+
*
|
|
47
|
+
* @param metadata_json - the `cargo metadata` output
|
|
48
|
+
* @param bin - the binary's name
|
|
49
|
+
* @param profile - the Cargo profile
|
|
50
|
+
* @returns the binary's absolute path
|
|
51
|
+
* @throws Error when the output carries no `target_directory`
|
|
52
|
+
*/
|
|
53
|
+
export const to_cargo_binary_path = (metadata_json, bin, profile) => {
|
|
54
|
+
const metadata = JSON.parse(metadata_json);
|
|
55
|
+
if (typeof metadata.target_directory !== 'string' || !metadata.target_directory) {
|
|
56
|
+
throw new Error('`cargo metadata` output has no `target_directory`');
|
|
57
|
+
}
|
|
58
|
+
return join(metadata.target_directory, to_cargo_profile_dir(profile), bin);
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Per-process memo of each workspace's target directory metadata. On
|
|
62
|
+
* `globalThis` rather than in module scope, so every project's `globalSetup` in
|
|
63
|
+
* one vitest process shares it whether or not they share this module's
|
|
64
|
+
* instance.
|
|
65
|
+
*/
|
|
66
|
+
const CARGO_METADATA_MEMO_KEY = '__fuz_app_cargo_metadata_memo';
|
|
67
|
+
const get_metadata_memo = () => {
|
|
68
|
+
const holder = globalThis;
|
|
69
|
+
return (holder[CARGO_METADATA_MEMO_KEY] ??= new Map());
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* How long `cargo metadata` may take (ms). Usually well under a second, but
|
|
73
|
+
* the first run in a checkout can have rustup install the pinned toolchain.
|
|
74
|
+
*/
|
|
75
|
+
const CARGO_METADATA_TIMEOUT_MS = 120_000;
|
|
76
|
+
/**
|
|
77
|
+
* Throw naming the workspace when its directory is missing — a spawn with a
|
|
78
|
+
* missing `cwd` otherwise fails as `spawnSync cargo ENOENT`, which reads as
|
|
79
|
+
* cargo not being installed.
|
|
80
|
+
*/
|
|
81
|
+
const assert_workspace_dir = (workspace_dir) => {
|
|
82
|
+
if (!existsSync(workspace_dir)) {
|
|
83
|
+
throw new Error(`the Cargo workspace ${workspace_dir} does not exist`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const read_cargo_metadata = (workspace_dir) => {
|
|
87
|
+
const memo = get_metadata_memo();
|
|
88
|
+
let metadata_json = memo.get(workspace_dir);
|
|
89
|
+
if (metadata_json === undefined) {
|
|
90
|
+
assert_workspace_dir(workspace_dir);
|
|
91
|
+
try {
|
|
92
|
+
metadata_json = execFileSync('cargo', ['metadata', '--no-deps', '--format-version', '1'], {
|
|
93
|
+
cwd: workspace_dir,
|
|
94
|
+
encoding: 'utf-8',
|
|
95
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
96
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
97
|
+
timeout: CARGO_METADATA_TIMEOUT_MS
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
const code = error.code;
|
|
102
|
+
throw new Error(code === 'ETIMEDOUT'
|
|
103
|
+
? `\`cargo metadata\` in ${workspace_dir} took over ${CARGO_METADATA_TIMEOUT_MS}ms`
|
|
104
|
+
: `\`cargo metadata\` in ${workspace_dir} failed: ${error.message}`, { cause: error });
|
|
105
|
+
}
|
|
106
|
+
memo.set(workspace_dir, metadata_json);
|
|
107
|
+
}
|
|
108
|
+
return metadata_json;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The path of a Cargo-built binary, without building it — what a config's
|
|
112
|
+
* `start_command` names. Runs `cargo metadata` once per process per workspace,
|
|
113
|
+
* so it needs cargo on PATH.
|
|
114
|
+
*
|
|
115
|
+
* @param options - the workspace, package, binary and profile
|
|
116
|
+
* @returns the binary's absolute path
|
|
117
|
+
* @throws Error when the workspace is missing or `cargo metadata` fails
|
|
118
|
+
*/
|
|
119
|
+
export const resolve_cargo_binary_path = (options) => {
|
|
120
|
+
const { workspace_dir, package: pkg, bin = pkg, profile = 'dev' } = options;
|
|
121
|
+
return to_cargo_binary_path(read_cargo_metadata(workspace_dir), bin, profile);
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Build a Cargo binary before its backend spawns, unless `NO_REBUILD_ENV`
|
|
125
|
+
* asks to skip it, and return its path. The build's output is inherited, so a
|
|
126
|
+
* cold build shows its progress, and a failed build throws — the project fails
|
|
127
|
+
* loudly rather than spawning a stale binary. `cargo build` is incremental, so
|
|
128
|
+
* a build with nothing changed is quick.
|
|
129
|
+
*
|
|
130
|
+
* Synchronous: vitest awaits each project's `globalSetup` in turn, so one
|
|
131
|
+
* invocation selecting several projects builds once, then finds the build
|
|
132
|
+
* current.
|
|
133
|
+
*
|
|
134
|
+
* @param options - the workspace, package, binary and profile
|
|
135
|
+
* @returns the binary's absolute path (`resolve_cargo_binary_path`)
|
|
136
|
+
* @throws Error when the workspace is missing, the build fails, or `cargo metadata` fails
|
|
137
|
+
*/
|
|
138
|
+
export const prepare_cargo_binary = (options) => {
|
|
139
|
+
const { workspace_dir, package: pkg, bin = pkg, profile = 'dev' } = options;
|
|
140
|
+
if (!is_no_rebuild_requested(process.env[NO_REBUILD_ENV])) {
|
|
141
|
+
assert_workspace_dir(workspace_dir);
|
|
142
|
+
execFileSync('cargo', ['build', '-p', pkg, '--bin', bin, '--profile', profile], {
|
|
143
|
+
cwd: workspace_dir,
|
|
144
|
+
stdio: 'inherit'
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return resolve_cargo_binary_path(options);
|
|
148
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_crud.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_crud.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cell_crud.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_crud.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAiE9B,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,YAAY,CAAC;AAG1E,eAAO,MAAM,8BAA8B,GAC1C,SAAS,uCAAuC,KAC9C,IA6lBF,CAAC"}
|
|
@@ -23,6 +23,9 @@ import '../assert_dev_env.js';
|
|
|
23
23
|
* - a non-owner non-admin editing / reading / deleting another's private cell
|
|
24
24
|
* gets 404 (IDOR mask), never 403;
|
|
25
25
|
* - admin reaches any cell;
|
|
26
|
+
* - `cell_list` pages honor `limit` + `offset`, and a page is visible rows:
|
|
27
|
+
* a newer run of cells the caller can't see never crowds the visible ones
|
|
28
|
+
* out, for a non-owner and for anon, and an admin's pages tile every row;
|
|
26
29
|
* - duplicate active `path` → 409 (`cell_path_taken`);
|
|
27
30
|
* - `path` write by a non-admin → 403 (`cell_path_admin_only`), on both create
|
|
28
31
|
* and update (even by the owner);
|
|
@@ -47,7 +50,7 @@ import '../assert_dev_env.js';
|
|
|
47
50
|
import { describe, assert } from 'vitest';
|
|
48
51
|
import { CELL_KIND_LENGTH_MAX, CellCreateOutput, CellDeleteOutput, CellGetOutput, CellListOutput, CellUpdateOutput } from '../../auth/cell_action_specs.js';
|
|
49
52
|
import { test_if } from './capabilities.js';
|
|
50
|
-
import { cross_rpc_call, error_reason, expect_output } from './
|
|
53
|
+
import { cross_rpc_call, error_reason, expect_output } from './cross_rpc.js';
|
|
51
54
|
import { assert_iso8601_seconds, assert_iso8601_seconds_nullable } from './wire_shapes.js';
|
|
52
55
|
import { SPINE_RPC_PATH } from './spine_surface_constants.js';
|
|
53
56
|
export const describe_cell_crud_cross_tests = (options) => {
|
|
@@ -194,6 +197,59 @@ export const describe_cell_crud_cross_tests = (options) => {
|
|
|
194
197
|
assert.ok(!update_path.ok, 'non-admin set a path on update');
|
|
195
198
|
assert.strictEqual(error_reason(update_path), 'cell_path_admin_only');
|
|
196
199
|
});
|
|
200
|
+
test_if(capabilities.cell_crud, 'cell_list pages: limit + offset honored; hidden rows never crowd visible ones out of a page', async () => {
|
|
201
|
+
const fixture = await setup_test();
|
|
202
|
+
const owner = await fixture.create_account({ username: 'cell_page_owner' });
|
|
203
|
+
const other = await fixture.create_account({ username: 'cell_page_other' });
|
|
204
|
+
const viewer = await fixture.create_account({ username: 'cell_page_viewer' });
|
|
205
|
+
const t = fixture.fresh_transport();
|
|
206
|
+
const kind = 'page_probe';
|
|
207
|
+
const create = async (headers, visibility) => expect_output(await cross_rpc_call(t, rpc_path, 'cell_create', { kind, data: {}, visibility }, headers), CellCreateOutput).cell.id;
|
|
208
|
+
const owner_h = owner.create_session_headers();
|
|
209
|
+
const other_h = other.create_session_headers();
|
|
210
|
+
// oldest first: the visible rows, then a newer run of hidden ones —
|
|
211
|
+
// two owners' private cells — longer than a page, so the newest
|
|
212
|
+
// `limit` rows are all hidden from the viewer
|
|
213
|
+
const visible = [];
|
|
214
|
+
for (let i = 0; i < 5; i++) {
|
|
215
|
+
visible.push(await create(i % 2 === 0 ? owner_h : other_h, 'public'));
|
|
216
|
+
}
|
|
217
|
+
const hidden = [];
|
|
218
|
+
for (let i = 0; i < 6; i++) {
|
|
219
|
+
hidden.push(await create(i % 2 === 0 ? owner_h : other_h, 'private'));
|
|
220
|
+
}
|
|
221
|
+
const limit = 3;
|
|
222
|
+
const page = async (transport, headers, params) => expect_output(await cross_rpc_call(transport, rpc_path, 'cell_list', { kind, ...params }, headers), CellListOutput).cells.map((c) => c.id);
|
|
223
|
+
// newest first (the default order), so the visible rows, newest first
|
|
224
|
+
const visible_desc = [...visible].reverse();
|
|
225
|
+
for (const [label, transport, headers] of [
|
|
226
|
+
['a non-owner viewer', t, viewer.create_session_headers()],
|
|
227
|
+
['anon', fixture.fresh_transport({ origin: null }), {}]
|
|
228
|
+
]) {
|
|
229
|
+
const first = await page(transport, headers, { limit });
|
|
230
|
+
assert.deepStrictEqual(first, visible_desc.slice(0, limit), `${label}: the first page is the newest visible rows, full to limit`);
|
|
231
|
+
const second = await page(transport, headers, { limit, offset: limit });
|
|
232
|
+
assert.deepStrictEqual(second, visible_desc.slice(limit), `${label}: the next page is the rest of the visible rows`);
|
|
233
|
+
const past = await page(transport, headers, { limit, offset: visible.length });
|
|
234
|
+
assert.deepStrictEqual(past, [], `${label}: a page past the visible rows is empty`);
|
|
235
|
+
for (const id of [...first, ...second]) {
|
|
236
|
+
assert.ok(!hidden.includes(id), `${label}: a page leaked a hidden row`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// an admin sees every row, paged the same way
|
|
240
|
+
const admin_h = fixture.create_session_headers();
|
|
241
|
+
const all_desc = [...visible, ...hidden].reverse();
|
|
242
|
+
const admin_pages = [];
|
|
243
|
+
for (let offset = 0; offset < all_desc.length; offset += 4) {
|
|
244
|
+
const rows = await page(t, admin_h, { limit: 4, offset });
|
|
245
|
+
assert.ok(rows.length <= 4, `admin page at offset ${offset} exceeds limit`);
|
|
246
|
+
admin_pages.push(...rows);
|
|
247
|
+
}
|
|
248
|
+
assert.deepStrictEqual(admin_pages, all_desc, 'admin pages tile the whole list in order');
|
|
249
|
+
// the owner sees its own private rows beside every public one
|
|
250
|
+
const owner_rows = await page(t, owner_h, { limit: 50 });
|
|
251
|
+
assert.deepStrictEqual(owner_rows, all_desc.filter((id) => visible.includes(id) || hidden.indexOf(id) % 2 === 0), 'the owner reads public rows plus its own private ones');
|
|
252
|
+
});
|
|
197
253
|
test_if(capabilities.cell_crud, 'cell_get without id or path → invalid_params', async () => {
|
|
198
254
|
const fixture = await setup_test();
|
|
199
255
|
const bad = await cross_rpc_call(fixture.fresh_transport(), rpc_path, 'cell_get', {}, fixture.create_session_headers());
|
|
@@ -1,64 +1,4 @@
|
|
|
1
1
|
import '../assert_dev_env.js';
|
|
2
2
|
import type { RpcPathCapabilityGatedCrossSuiteOptions } from './setup.js';
|
|
3
3
|
export declare const describe_cell_gated_create_cross_tests: (options: RpcPathCapabilityGatedCrossSuiteOptions) => void;
|
|
4
|
-
/**
|
|
5
|
-
* Cross-backend parity for the **`cell_moderate` verb** (the `pending →
|
|
6
|
-
* approved | rejected` transition) — root-authority-gated.
|
|
7
|
-
*
|
|
8
|
-
* Builds a moderated public space (admin) + a `participant`'s `post` (born
|
|
9
|
-
* `pending` + private under the `moderation_required: true` policy), then
|
|
10
|
-
* proves both spines agree:
|
|
11
|
-
*
|
|
12
|
-
* - **a root manager (admin) approves** → `moderation: 'approved'` +
|
|
13
|
-
* `visibility: 'public'` (the contribution goes live).
|
|
14
|
-
* - **the author cannot self-approve** → `403 cell_moderate_forbidden` (the
|
|
15
|
-
* author can *view* their own pending cell, so they reach the gate, and are
|
|
16
|
-
* denied — moderation authority is over the governing root, not the
|
|
17
|
-
* contribution).
|
|
18
|
-
* - **a non-viewer is 404-masked** → a stranger who can't see the pending
|
|
19
|
-
* contribution gets `cell_not_found`, never learns it exists.
|
|
20
|
-
* - **reject** → `moderation: 'rejected'`, visibility stays private.
|
|
21
|
-
*
|
|
22
|
-
* And that moderation gates reads — a cell's effective audience is its
|
|
23
|
-
* visibility or grants **and** its moderation admission (unmoderated or
|
|
24
|
-
* `approved`), so a pending or rejected contribution reaches no one past its
|
|
25
|
-
* author and admins:
|
|
26
|
-
*
|
|
27
|
-
* - **an author's self-flip to public admits nobody** — a pending post its
|
|
28
|
-
* author makes public stays 404 to anon and a fresh non-admin on `cell_get`,
|
|
29
|
-
* and out of their `cell_list`; the author and admin still read it.
|
|
30
|
-
* - **rejection holds a public post back** — pending → rejected → public, and
|
|
31
|
-
* approved → rejected (approval made it public, rejection leaves visibility
|
|
32
|
-
* alone), both 404 past the author; a grant made while the post was approved
|
|
33
|
-
* stops admitting once it is rejected, on `cell_get` and `shared_with: 'me'`.
|
|
34
|
-
* - **an approved post is live** — the control.
|
|
35
|
-
* - **relation reads follow** — a pending post in a public collection is
|
|
36
|
-
* omitted from anon `cell_item_list`, beside a live sibling that isn't; at
|
|
37
|
-
* the far end of all four relation lists, a pending post is hidden from
|
|
38
|
-
* anon even flipped public, and a rejected one from its grant holder.
|
|
39
|
-
* - **fact serving follows** — a pending post's fact is 404 to anon, even
|
|
40
|
-
* with the post flipped public (also gated on `capabilities.fact_serving`).
|
|
41
|
-
*
|
|
42
|
-
* And the steward arm — the owner of a **non-admin** root (a parentless
|
|
43
|
-
* non-`space` kind carrying the same policy, which the test authorizer leaves
|
|
44
|
-
* open) reads the pending posts under it and moderates them:
|
|
45
|
-
*
|
|
46
|
-
* - **the queue** — `cell_list({root_id, moderation: 'pending'})` and
|
|
47
|
-
* `cell_get` (with `can_edit` / `can_grant` false) → 200; a stranger 404s.
|
|
48
|
-
* - **moderation** — the root owner approves → 200; the author 403, a
|
|
49
|
-
* stranger 404.
|
|
50
|
-
* - **the arm stops there** — the root owner's `cell_clone` of the pending
|
|
51
|
-
* post and a contribution under it are both 404.
|
|
52
|
-
* - **fact serving** — the root owner fetches a pending post's fact → 200,
|
|
53
|
-
* anon 404 (also gated on `capabilities.fact_serving`).
|
|
54
|
-
*
|
|
55
|
-
* And that `cell_grant_create` refuses a pending contribution — **403**
|
|
56
|
-
* `cell_grant_unapproved` for its author and an admin, actor- and role-shaped,
|
|
57
|
-
* while a non-manager keeps the **404** mask; the same grant lands once the
|
|
58
|
-
* post is approved.
|
|
59
|
-
*
|
|
60
|
-
* Gated on `capabilities.cell_gated_create` — a `pending` contribution only
|
|
61
|
-
* exists when the directory authorizer is mounted (reference spine binaries).
|
|
62
|
-
*/
|
|
63
|
-
export declare const describe_cell_moderate_cross_tests: (options: RpcPathCapabilityGatedCrossSuiteOptions) => void;
|
|
64
4
|
//# sourceMappingURL=cell_gated_create.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cell_gated_create.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_gated_create.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"cell_gated_create.d.ts","sourceRoot":"../src/lib/","sources":["../../../src/lib/testing/cross_backend/cell_gated_create.ts"],"names":[],"mappings":"AAAA,OAAO,sBAAsB,CAAC;AAsD9B,OAAO,KAAK,EAAE,uCAAuC,EAAE,MAAM,YAAY,CAAC;AAQ1E,eAAO,MAAM,sCAAsC,GAClD,SAAS,uCAAuC,KAC9C,IAuTF,CAAC"}
|