testing/cross_backend/testing_reset_actions.ts

Test-binary RPC actions for cross-process integration tests.

Six daemon-token-authed actions, bundled by create_testing_actions: _testing_reset (DB wipe + keeper re-seed), _testing_drain_effects (audit barrier), _testing_mint_session (forge an expired-by-construction server-side session for the expiry conformance cases), _testing_put_fact (seed an embedded fact for the fact-serving suite), _testing_schema_snapshot (introspect the live schema for cross-impl parity diffing against a Rust backend's fuz_db snapshot), and _testing_migration_tracker (dump the schema_version tracker rows for cross-impl migration-identity parity — the provenance half the snapshot gate excludes by design).

A further daemon-token action, _testing_action_manifest (dump the live RPC registry for cross-impl method-set + auth-shape parity), lives here too but is not bundled by create_testing_actions — it must enumerate *every* mounted method, so it's appended at the full-mount layer (build_full_spine_rpc_actions) where the complete list exists.

_testing_reset — full DB wipe + keeper re-seed + optional secondary-account seeding. The handler wipes every auth-namespace row (no keeper-preserve filter), flips bootstrap_lock back to its post-bootstrap shape, seeds a fresh keeper account inline (reusing create_test_account_with_credentials so cross-process matches in-process write semantics), seeds any caller-requested extra_accounts (also direct-inserted at this setup step), refreshes the daemon-token cache to point at the new keeper, and fires the consumer-supplied domain-state callback. The new keeper + secondary credentials return as the action output so the per-test fixture closes over them.

The redesign converges in-process and cross-process keeper lifetimes: both modes now run against a freshly bootstrapped keeper per test. Mutation-cascade tests (password change, revoke-all, hardcoded-username signup uniqueness) and direct keeper-vs-admin probes work uniformly cross-process.

Keeper ≠ admin. The keeper and admin roles are independent. Keeper authorizes daemon-token / bootstrap paths; admin authorizes the user-facing admin RPC surface. _testing_reset seeds the keeper account with [ROLE_KEEPER, ROLE_ADMIN] by default — matching the production bootstrap_account flow — plus any roles passed via extra_keeper_roles. Tests probing the keeper-vs-admin separation (a keeper-only account must 403 on admin RPCs) declare a secondary via extra_accounts: [{username, roles: [ROLE_KEEPER]}] so the account is seeded at this same bootstrap-equivalent step.

No free-form runtime bypass. Earlier drafts considered a separate _testing_seed_role_grant action for arbitrary direct grants; that was rejected because a runtime bypass would let tests skip the production consent flow's side-effects (audit emit, WS fan-out) and silently mask bugs in those paths. The bypass that does exist — extra_accounts — is framed as bootstrap-time seeding, the same shape bootstrap_account itself uses to grant the initial KEEPER + ADMIN pair. Tests that want a role on a *post-bootstrap* account must route through role_grant_offer_create + role_grant_offer_accept (the production path); they observe the full event chain.

Production safety: this module lives under cross_backend/ and starts with import '../assert_dev_env.ts'; — production bundles either tree-shake the module out or throw at startup. The Rust mirror (fuz_testing crate) ships a parallel action; `cargo xtask check-release blocks fuz_testing` from entering production dep graphs.

view source

Declarations
#

14 declarations

create_testing_action_manifest_action
#

create_testing_actions
#

testing/cross_backend/testing_reset_actions.ts view source

(deps: AppDeps, options: CreateTestingActionsOptions): RpcAction[] import {create_testing_actions} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

Build the testing RPC actions for a test binary's registry.

Returns _testing_reset — the single privileged action test binaries register. The test binary calls this at server-assembly time and registers the result on its dispatcher.

The reset action's table-wipe list mirrors auth_integration_truncate_tables from testing/db.ts — the canonical "auth tables a between-test reset must clear" set. testing_reset_actions.coverage.test.ts enforces the set-equality invariant so a future auth migration that adds a table to that list without updating this handler fails CI.

deps

type AppDeps

options

returns

RpcAction[]

create_testing_drain_effects_action
#

testing/cross_backend/testing_reset_actions.ts view source

(): RpcAction import {create_testing_drain_effects_action} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

Build the standalone _testing_drain_effects action. No deps — on TS the barrier is satisfied by await_pending_effects (see the spec doc), so the handler just returns {ok: true}. Mount it on any test endpoint whose suite asserts on audit rows (the spine binary bundles it via create_testing_actions; in-process suites mount it directly).

returns

RpcAction

create_testing_migration_tracker_action
#

create_testing_schema_snapshot_action
#

CreateTestingActionsOptions
#

testing/cross_backend/testing_reset_actions.ts view source

CreateTestingActionsOptions import type {CreateTestingActionsOptions} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

session_options

Session cookie options — the reset action uses these when signing the fresh keeper's (and any extra accounts') session cookies. Pass the same SessionOptions the live create_app_server call was wired with.

type SessionOptions<string>

readonly

daemon_token_state

Daemon-token runtime state — the reset action mutates state.keeper_account_id to point at the freshly seeded keeper after the old row is wiped. Pass the same DaemonTokenState instance the daemon-token middleware reads.

type DaemonTokenState

readonly

reset_state?

Consumer-supplied callback invoked after the auth-table reset, passed the same transactional Db the auth wipes ran on. DB-domain consumers (e.g. fuz_forge truncating its cell / fact / file tables) MUST use this db rather than a separately-pooled connection — under PGlite's single connection a second connection deadlocks against this still-open transaction. testing_zzz_server clears in-memory workspace registry + terminals + scoped-FS scratch (ignores db); testing_spine_stub has no domain layer and omits the option. Runs inside the same RPC dispatch as the auth-table writes, so a throw surfaces to the caller as a JSON-RPC error and the per-test fixture short-circuits.

type (db: Db) => Promise<void> | void

readonly

testing_action_manifest_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_action_manifest"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: string; } import {testing_action_manifest_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_action_manifest — dump the backend's live RPC method set as a normalized ActionManifest (one entry per method: `{method, side_effects, account, actor, roles, credential_types}`) for cross-impl parity diffing. The action-surface twin of _testing_schema_snapshot: where that introspects the live *database*, this introspects the live *RPC registry*. The cross-backend harness calls it on each backend, then assert_action_manifests_equals the results (the Rust mirror is fuz_testing::create_testing_action_manifest_action_spec, whose normalization matches by design). Complements the in-repo spine_method_coverage gate (mounted ⟹ covered) by proving the TS mount-set ≡ the Rust mount-set, method-for-method and auth-shape-for-shape.

Unlike its _testing_* siblings this action is not bundled by create_testing_actions — the manifest must enumerate *every* mounted method, which create_testing_actions (one sub-factory among many) can't see. It's appended at the full-mount layer (build_full_spine_rpc_actions) via create_testing_action_manifest_action, where the complete list exists.

auth gates on the daemon-token credential, matching _testing_reset.

testing_drain_effects_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_drain_effects"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: "Test-binary only — await in-flight fire-and-forge... import {testing_drain_effects_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_drain_effects — await in-flight fire-and-forget audit writes so a following audit_log_list is authoritative. The deterministic barrier the cross-backend conformance suite uses in place of a poll/sleep before asserting on audit rows.

On the TS spine the barrier is satisfied by construction: the test binary runs await_pending_effects: true, so every mutation's fire-and- forget audit emits are awaited before its response returns — by the time a later drain call runs, prior emits are already durable. The action still exists so the cross-backend test body calls the same method on every backend; the Rust spine (whose audit writes are detached tokio tasks) does the real await in AuditEmitter::drain_inflight.

auth gates on the daemon-token credential, matching _testing_reset.

testing_migration_tracker_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_migration_tracker"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: string; } import {testing_migration_tracker_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_migration_tracker — dump the schema_version tracker rows as a normalized MigrationTracker ([{namespace, name, sequence}]) for cross-impl migration-identity diffing. The provenance half of _testing_schema_snapshot: where that captures the resulting *schema* (and excludes the tracker by design), this captures the tracker *itself*, so the cross-backend harness can assert the two spines record byte-identical migration identity. This closes the gap that let the cell/fact migration-name divergence reach the visiones cutover undetected (name-divergence-at-N — same schema, divergent recorded names).

auth gates on the daemon-token credential, matching _testing_reset. The Rust mirror is fuz_testing::create_testing_migration_tracker_action_spec.

testing_mint_session_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_mint_session"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: string; } import {testing_mint_session_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_mint_session — mint an expired-by-construction server-side session for an existing account and return its signed cookie value.

expires_in_seconds is constrained negative (z.number().int().negative()) so the action is structurally incapable of minting a *usable* session: it can only produce an already-backdated, already-dead auth_session row. The daemon-token gate + loopback binding already fence the backdoor, but the negative constraint is the make-impossible-states floor — even a misuse can't forge a valid session for an arbitrary account_id. The Rust mirror (fuz_testing::create_testing_mint_session_action_spec) enforces the same floor.

The minted auth_session row's expires_at is backdated while the returned cookie's own signed payload stays valid (future). Cross-process auth resolution therefore passes the cookie-payload gate (parse_session) and is refused by the authoritative DB-row gate (query_session_get_validWHERE expires_at > NOW()) — the gate the in-process payload-expiry tests never reach and the one that structurally needs a server-side mint (the cross-process driver has no keyring / DB access). The expired_session conformance principal drives this.

auth gates on the daemon-token credential, matching _testing_reset — effectively keeper-only. Like its siblings the action is internally privileged (a direct auth_session insert the production wire never exposes); daemon-token auth is the structural fence and the module's assert_dev_env import (TS) plus the Rust cargo xtask check-release dep-graph audit keep the _testing_ surface out of every shipped build.

testing_put_fact_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_put_fact"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: string; } import {testing_put_fact_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_put_fact — seed an embedded fact (fact.bytes) for the cross-process fact-serving suite, which drives over real HTTP and has no PgFactStore to call. Hashes the UTF-8 content (blake3, via fact_hash_bytes — the same hash the Rust _testing_put_fact computes), inserts the row idempotently, and returns {hash}. The referencing cell is seeded separately via the cell_create RPC. Embedded-only is enough for the authz assertions (cell-scoped admit, cross-owner-no-leak, 404-mask, bare-hash admin-only); external / X-Accel parity stays covered by the forge's own gate.

auth gates on the daemon-token credential, matching _testing_reset — the action does a direct fact insert the production wire never exposes. The Rust mirror is fuz_testing::create_testing_put_fact_action_spec.

testing_reset_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_reset"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: "Test-binary only — wipe auth tables, re-bootstrap a fresh... import {testing_reset_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

The _testing_reset action spec.

Input:

  • extra_keeper_roles — roles to grant the fresh keeper *in addition to* [ROLE_KEEPER, ROLE_ADMIN] (matching production bootstrap).
  • extra_accounts — additional accounts to seed at this same bootstrap-equivalent step. Each entry's roles are direct-granted (bypassing offer/accept) because the seed is *part of bootstrap*, not a post-bootstrap action. Use this for accounts whose required roles aren't admin-grantable via offer/accept (e.g. ROLE_KEEPER, whose RoleSpec.grant_paths is bootstrap-only). For admin-grantable roles, prefer fixture.create_account({roles}) (offer/accept production path).

Output: keeper credentials plus a parallel array of seeded extra_accounts (same order as input). The per-test fixture closes over the returned values; subsequent calls in the same test see the fresh keeper and any requested secondaries.

auth gates on the daemon-token credential — the keeper holds it exclusively. The action is internally privileged (it runs direct DB writes the production wire never exposes); daemon-token auth is the structural fence.

testing_reset_wiped_tables
#

testing_schema_snapshot_action_spec
#

testing/cross_backend/testing_reset_actions.ts view source

{ readonly method: "_testing_schema_snapshot"; readonly kind: "request_response"; readonly initiator: "frontend"; readonly auth: { readonly account: "required"; readonly actor: "none"; readonly credential_types: readonly [...]; }; ... 4 more ...; readonly description: "Test-binary only — introspect the live schema i... import {testing_schema_snapshot_action_spec} from '@fuzdev/fuz_app/testing/cross_backend/testing_reset_actions.js';

_testing_schema_snapshot — introspect the live database into a normalized SchemaSnapshot for cross-impl parity diffing. The cross-backend harness calls this on each backend, then assert_schema_snapshots_equals the results (a Rust backend answers from fuz_db::query_schema_snapshot; the shapes match by design). Optional exclude_tables drops documented divergences from both sides before comparison.

auth gates on the daemon-token credential, matching _testing_reset.

Depends on
#

Imported by
#