control-plane, agent: move catalog authorization in-process against a pinned Snapshot (2/7) - #3342
Open
bbartman wants to merge 2 commits into
Open
Conversation
This was referenced Aug 11, 2026
… pinned Snapshot Every catalog authorization decision of publications and discovers moves from SQL (internal.user_roles() and the computed user_capability / spec_capabilities columns) to in-process evaluation against one Snapshot pinned per operation: - live_specs: fetch queries lose their authorization parameters; get_live_specs / get_connected_live_specs take a &Snapshot and filter by models::authz::CapabilitySet in-process. A denial under a Snapshot that is stale for the operation's freshness anchor raises the retryable AuthorizationSnapshotStale rather than silently dropping the spec. - publications: resolve_live_specs makes all four authorization decisions against the pinned Snapshot; data-plane-name authorization moves off internal.user_roles(). DraftPublication gains snapshot / started_at, threaded through Publisher::build and the Initialize trait. ExpandDraft filters by SpecEdit instead of legacy admin. - discovers: Discover pins snapshot / started_at across prechecks, the connector RPC, and the merge; live-capture reads filter by CatalogRead. - Executors pin one Snapshot per poll; controller and server paths anchor with started_at: None, preserving spec-relative staleness semantics. - Test harness: the Snapshot is backed by a manually-driven watch with explicit refresh points, and truncate_tables clears storage_mappings and data_planes for determinism next to a running local stack. Until the follow-up splits land, a denial under a genuinely stale Snapshot surfaces as a terminal failure carrying the retryable error message, rather than deferring automatically. Split 2 of 4 from #3155.
bbartman
force-pushed
the
bmb/2781-stack-2-inprocess-authz
branch
from
August 11, 2026 18:23
aba3aac to
6663bed
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Split 2 of 4 of #3155 (issue #2781): every catalog authorization decision of
publications and discovers moves from SQL (
internal.user_roles()/computed
user_capability+spec_capabilitiescolumns) to in-processevaluation against one
Snapshotpinned per operation.live_specs:fetch_live_specs/fetch_expanded_live_specslosetheir authorization parameters and computed-capability columns; the queries
become plain spec fetches.
get_live_specs/get_connected_live_specsgain a
&Snapshot(andstarted_atanchor) and filter bymodels::authz::CapabilitySetin-process. A denial under a Snapshot that isstale for the operation's anchor raises the retryable
AuthorizationSnapshotStaleinstead of silently dropping the spec;expansion (
get_connected_live_specs) keeps denials as final silentomissions.
publications:resolve_live_specsmakes all four authorizationdecisions (drafter
SpecEdit; spec read/write authorization tosources/targets; user
CatalogReadon referenced specs) against the pinnedSnapshot, with the same staleness policy. Data-plane-name authorization
moves off
internal.user_roles()ontoSnapshot::user_authorization.DraftPublicationgainssnapshotandstarted_at, threaded throughPublisher::buildand theInitializetrait;ExpandDraft's filterswitches from legacy
admintoSpecEdit(
filter_user_has_admin→filter_user_authz).discovers:Discoverpinssnapshot/started_atacross thewhole operation (prechecks → connector RPC → merge); the live-capture
fetch filters by
CatalogReadvia the Snapshot.agent): both executors pin one Snapshot perpoll and thread it through;
main.rswiressnapshot_watchinto them.Controller/system paths (
controlplane.rs,create_data_plane,update_l2_reporting) passstarted_at: None, anchoring staleness to eachspec's own
last_pub_id— preserving today's semantics of evaluatingagainst current-enough state.
manually-driven watch with explicit
refresh_snapshot()points (documentedas the "Snapshot testing model"), and
truncate_tablesclearsstorage_mappings/data_planesso tests are deterministic next to arunning local stack.
Behavior note (interim, until splits 3–4): a denial under a genuinely stale
Snapshot surfaces as a terminal task failure carrying the "please retry"
error, rather than deferring automatically. Splits 3 and 4 teach the two
executors to reschedule instead.
Tests
live_specs::tests(new,#[sqlx::test]on the newauthz_specsfixture): unfiltered fetches never stale; authorized specs included;
authoritative denials dropped; stale denials retryable; connected-spec
expansion filtering.
publications::specs::resolve_tests(new): each of the four in-processauthorization branches, a fully-authorized positive control, the
started_at: None/ zero-last_pub_idterminal-denial fallback, andspec-to-spec authorization under
verify_user_authz: false.signature updates in
locking_retries,source_captures,unknown_connectors).Stack