AshSandbox.Internal.RefuseAllowlistChangeWhileLive (AshSandbox v0.1.0)

Copy Markdown View Source

Refuses a change to an Environment's network_allowlist while that environment has a live sandbox (029 T018 ruling, FR-011).

Why a refusal and not a silent success

A sandbox is policed by rules its mechanism installs at launch, from the allowlist as it read then; nothing re-reads it afterwards. So an accepted narrowing would be persisted while every already-running sandbox kept the wider rules — a control that reports success and changes nothing. Widening is the mirror: the destination is recorded and unreachable until the sandbox is replaced.

⚠️ Re-policing the running sandbox is the better product answer and was deliberately not built here. Rewriting a live ruleset is its own correctness problem — a narrowing must never be observable as a half-applied ruleset — and 029 has not yet demonstrated that the rules it installs at launch hold at all: the observation halves of its enforcement tasks need a Linux network namespace and have never run. Building live re-policing on top of enforcement whose boundary is unverified is the same inversion the spec exists to catch.

So the update either takes effect at the next launch, or it is refused in a sentence naming why.

The registry resource arrives as data

The host names its own registry binding at its own use AshSandbox.EnvironmentTemplate call site (012-FR-009); this library compiles knowing no host module. That is the same rule AshSandbox.Internal.CopyOwnerRefFromProject follows for the Project binding, reached differently only because there is no relationship to read it off: environment_ref is an opaque string on the registry row while Environment.id is a uuid, so a has_one would emit a uuid = text comparison the data layer refuses.

What "live" means

AshSandbox.RegistryTemplate.live_states/0, enumerated there rather than written here as "not stopped" — see that function for why.