Cross-backend parity suite for actor_search.
actor_search is an opt-in case-insensitive prefix search over
actor.name (`{query, scope_ids?, limit?} → {actors: [{id, username,
display_name?}]}`), not folded into the standard bundle. Like
actor_lookup / cells, it's live-mounted on the spine RPC path but kept
off the declared surface, so this dedicated suite is its validator. The
security property under test is the empty-scope_ids admin gate:
- anonymous → 401 — the account-grain auth gate refuses an
unauthenticated caller before the handler runs.
- non-admin + no
scope_ids → 400 actor_search_scope_required — an
unbounded global search is admin-only; a non-admin must scope the query.
This is the core security assertion, exercised against each impl's real
auth resolution. - non-admin +
scope_ids → 200 — passing a scope bypasses the admin
requirement (results are filtered to actors holding active role_grants on
those scopes); an unheld scope simply yields an empty result, not a
rejection — proving the gate keys on scope_ids presence, not identity. - admin + no
scope_ids → 200 — the admin path reaches the unbounded
search.
Cites security.md §Authorization (the actor_search scope gate).
Runs both legs via the shared {setup_test} protocol: in-process
(auth/actor_search_parity.db.test.ts) + cross-process
(cross_backend/actor_search.cross.test.ts, TS spine binaries + Rust
testing_spine_stub). Mounted on every spine, so the suite is ungated.
$lib-free by contract (relative specifiers only).