You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
emrg: a host cannot type a registry key — /sandbox add has no --registry flag and the writer refuses the kind Stage 2 made enforceable #2511
A host cannot name a registry key as a writable object. /sandbox add accepts a filesystem path and nothing else, and the writer-side judge refuses the registry kind outright — even on the one platform that now enforces it.
What is there today
emrg/sandbox/roots.py::judge_extra_root takes a kind argument and has a branch for it, but that branch ends in a refusal:
ifkind==GRANT_REGISTRY:
refusal=enforcement_refusal(GRANT_REGISTRY, path.strip())
ifrefusalisNone: # pragma: no cover - no platform reaches this in Stage 1refusal= (
"a registry grant is enforced on this platform but its key spelling is not ""validated yet — issue #2492 Stage 2 lands the validation and the enforcement ""together"
)
returnExtraRootVerdict("", refusal=refusal)
Two things are wrong with that block, and they are the same thing seen twice.
It is reachable now, and says it is not.emrg/sandbox/grants.py::ENFORCED_KINDS lists registry for win32, so enforcement_refusal(GRANT_REGISTRY, …) returns None there and the second branch is taken — the pragma: no cover above it claims a line no platform reaches, on the one platform that does. pytest --cov therefore reports a branch that executes as never executed.
Its sentence is false. The host reads that the key is not validated because Stage 2 has not landed, when the enforcement half has. A refusal is a boundary the host is owed a true reason for.
The client half is missing too: emrg/client/app.py builds set_sandbox_roots from op and path alone and never sends a kind, so even a writer that accepted a key could not be reached by typing one. The daemon already carries the field through (msg.get("kind") or None), and it already stores whatever typed grant the judge returns — so the wire and the storage are not the gap.
What the fix must satisfy
A key spelling is validated, not guessed.emrg/sandbox/win32/registry.py::split_key already decides which key a grant named — it refuses a bare hive, an unknown root, and an empty subkey, each with its own sentence. It is pure and imports on every platform, so the writer reuses it rather than growing a second parser with a second wording.
Validation is not enforcement. A key named on a platform whose dialects cannot apply it stays refused, with enforcement_refusal's own platform sentence — that sentence is right and stays the one producer of it. What changes is that a platform which can enforce the kind now validates the spelling instead of refusing it.
The accepted key is stored as a typed grant (kind="registry", the spelling the host typed as its target), so the derivation and the DACL applier read one word for it.
Naming a key already granted reports that rather than storing it twice — the same "already covered" outcome a path has.
One producer for the flag, so the client cannot spell a kind the model does not have.
It must be measurable on every platform: the spelling rules and the platform refusal do not need a Windows host, only the DACL application does.
Activity
argszero commentedon Oct 23, 2026
Handled by #2512