Raxx · internal docs

internal · gated ↑ index

ADR-0025 — Env Switcher: RBAC gate on switching vs gate on mutation

Status: Accepted
Date: 2026-04-28 UTC
Refs: #353, console-env-switcher.md, rbac-design.md


Context

The environment switcher introduces a question: should the RBAC gate fire when the operator switches to a given environment, or when they execute a mutation against that environment?

Two models: 1. Gate-on-switch: Only superadmin (or equivalent) may switch to prod. Other roles can only switch to staging. 2. Gate-on-mutation: Any authenticated operator may switch to either env (can see prod data, see prod banner). The RBAC gate fires only when a mutating action targets prod.


Decision

Gate-on-mutation (option 2). Switching environment context is unrestricted for authenticated operators. The console:env:mutate_prod permission is required only to execute a prod-targeting mutation.


Consequences

Positive: - Operators with readonly or support roles can observe the prod environment (status grid, audit log, drill-downs). This is the desired behavior: read-only observability is not dangerous. - The gate is co-located with the danger: mutation endpoints. Adding @require_env_match("prod") to a new mutating route is explicit and discoverable. - Simpler UX: the switcher itself never 403s. Operators learn their permission boundary when they try to act, not when they try to look. - Composable with existing @require_role decorators: both decorators are present on the route, in the correct order.

Negative: - A support operator could switch to prod and see prod data. If observing prod status data without permission is a concern, this needs a separate read-gating layer. The current design considers prod status reads non-sensitive (they expose infrastructure health, not user PII). - The env_mismatch 403 at mutation time may surprise operators who did not see a gate at switch time. Mitigated by the banner making the current env visually obvious at all times.


Alternatives Considered

Option 1: Gate-on-switch

Simpler mental model: "you can only be in prod if you're superadmin." However, this means a support agent monitoring a prod outage cannot switch to prod to observe the status grid. It also adds complexity: the switch endpoint itself needs an RBAC check that differs by target env value, which is an unusual pattern. The fail behavior (403 on the switch, not on the action) is also harder to explain to operators. Rejected.

Hybrid: gate-on-switch for mutations, unrestricted for reads

Requires the switch endpoint to know whether the switching operator intends to read or mutate — it cannot know this. Rejected as unimplementable cleanly.