Skip to content

egress: a promoted-template claim takes the tenant policy alone - #99

Merged
CMGS merged 1 commit into
mainfrom
fix/promoted-template-tenant-egress
Aug 17, 2026
Merged

egress: a promoted-template claim takes the tenant policy alone#99
CMGS merged 1 commit into
mainfrom
fix/promoted-template-tenant-egress

Conversation

@CMGS

@CMGS CMGS commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Fixes #98.

What

Since #81, pool.effectivePolicy returns no evaluator unless a pool policy exists for the claim's key. A promoted template never has one — Promote/DeleteTemplate refuse keys a configured pool owns (pooledHash), and the refill loop would buildGolden a template name that is not an image — so every promoted-template claim was default-deny regardless of the tenant's egress block, and the none lane's only route out was closed for on-demand claims (a bake warmup through the guest's 127.0.0.1:3128 relay failed 45/45 on v0.1.6 and passed 45/45 on 218eee1 with the same config).

This keeps #81's contract for pooled keys and treats a missing pool layer as absent rather than empty:

  • key with a configured pool: unchanged — pool ∩ tenant; a pool without a policy grants nothing; root takes the pool policy whole.
  • key with no configured pool (a promoted template, or an image cold-booted on demand — the repro's rt:24.04 claim on a node without pools is the latter): a tenant claim takes the tenant policy alone; a root claim stays denied (no layer at all).

m.pools[key] is the discriminator, so a pool configured with warm: 0 and no egress still denies exactly as #81 intended. Residual, accepted: m.pools is API-mutable, so draining a policy-less pool via SetPools turns its key unpooled and a later tenant cold-boot claim of it takes the tenant policy — no secret is involved (a policy-less pool has none), it takes an operator drain, and the guest gets only the tenant's own allow-list.

Changes

  • sandboxd/pool/egress.go effectivePolicy.
  • sandboxd/pool/egress_test.go TestEffectivePolicyComposition: cases now say whether the key is pooled; adds "tenant on a promoted template" (armed with the tenant policy) and "root on a promoted template" (denied); "tenant on a policyless pool" keeps expecting deny.
  • docs/egress.md: the promoted-template rule next to the intersection rule.

Gates

go build ./..., go test ./... (sandboxd), make go-lint (golangci-lint run + fmt, GOOS linux+darwin) all clean.

#81 made the effective policy a strict pool ∩ tenant intersection, and a
key with no pool policy denies. A promoted template never has a pool —
Promote and DeleteTemplate refuse pooled keys, and refill would build a
golden for a name that is no image — so every promoted-template claim
became default-deny regardless of the tenant's allow-list, closing the
none lane's only route out for on-demand claims. Treat the missing pool
layer as absent rather than empty: with no pool configured for the key,
a tenant claim takes its own policy whole; a configured pool without a
policy still grants nothing, and root claims of promoted templates stay
denied for want of any layer.

Closes #98.
@CMGS
CMGS merged commit b991848 into main Aug 17, 2026
1 check passed
@CMGS
CMGS deleted the fix/promoted-template-tenant-egress branch August 17, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

egress: promoted-template claims can never obtain a policy after #81 (tenant-only egress is dead)

1 participant