Summary
OpenShell has no native way to make an approved policy grant time-bounded or single-use. Once a draft/chunk is approved and applied, the resulting allow rule stays in effect until a client explicitly calls the API to revoke it. There is no expires_at, ttl, or max_uses on the grant itself, so OpenShell will neither auto-expire nor one-shot-limit it.
Motivation
We are integrating an external policy-recommendation service with OpenShell (the external service produces a recommendation; OpenShell remains the enforcement authority). Many of these grants should be tightly bounded in time and usage — e.g. "allow this sandbox one egress call to an approved external endpoint, valid for the next 10 minutes."
Today we emulate that with apply-then-revoke: approve/apply the rule, then issue a follow-up API call to remove it after the window or after a single use. It works, but it pushes all single-use/expiry/replay enforcement into the external service and leaves a gap — nothing at the OpenShell layer bounds the grant to exactly one use or a fixed lifetime before the external caller revokes it.
Broader use cases:
- Just-in-time, least-privilege grants that auto-expire.
- Single-use grants scoped to one action (submit one envelope, run one query).
- Break-glass / exception approvals that should lapse automatically.
- Any third-party policy advisor that wants OpenShell to enforce the time/use bound rather than trusting the advisor to call back and revoke.
Proposed capability
Add optional expiration / usage bounds to an approved policy grant (the draft/chunk or its resulting rule):
expires_at (absolute) or ttl (relative): the grant auto-lapses (reverts to prior state) when it passes.
max_uses: the grant is consumed after N matching requests (default unlimited).
- optional
nonce / idempotency key: prevents replay of the same grant.
Enforced server-side, so the grant is bounded even if the external service never calls back. Expiry vs. manual revocation should be distinguishable in status/events.
Prior art
#2591 — feat(sandbox): add server-managed expiration leases applies the same server-managed TTL/expiration-lease pattern at the sandbox level (a reconciler auto-terminates expired sandboxes). This request is the policy-grant analog: the same lease model, but the grant auto-reverts instead of the sandbox being deleted.
Current workaround
Apply-then-revoke from the external decision layer: our decision store tracks expiry/nonce/uses and issues a follow-up deny/drop API call. Functional, but the guarantee lives outside OpenShell and is subject to a revoke race.
Acceptance criteria (rough)
- A grant can be created with
expires_at/ttl and/or max_uses (and optionally nonce).
- OpenShell auto-reverts/denies once the bound is hit, with no external call required.
- Status and events distinguish auto-expiry from manual revocation.
Related: #2591 (sandbox expiration leases); the draft/chunk approval flow (ApproveDraftChunk, policy reload).
Summary
OpenShell has no native way to make an approved policy grant time-bounded or single-use. Once a draft/chunk is approved and applied, the resulting allow rule stays in effect until a client explicitly calls the API to revoke it. There is no
expires_at,ttl, ormax_useson the grant itself, so OpenShell will neither auto-expire nor one-shot-limit it.Motivation
We are integrating an external policy-recommendation service with OpenShell (the external service produces a recommendation; OpenShell remains the enforcement authority). Many of these grants should be tightly bounded in time and usage — e.g. "allow this sandbox one egress call to an approved external endpoint, valid for the next 10 minutes."
Today we emulate that with apply-then-revoke: approve/apply the rule, then issue a follow-up API call to remove it after the window or after a single use. It works, but it pushes all single-use/expiry/replay enforcement into the external service and leaves a gap — nothing at the OpenShell layer bounds the grant to exactly one use or a fixed lifetime before the external caller revokes it.
Broader use cases:
Proposed capability
Add optional expiration / usage bounds to an approved policy grant (the draft/chunk or its resulting rule):
expires_at(absolute) orttl(relative): the grant auto-lapses (reverts to prior state) when it passes.max_uses: the grant is consumed after N matching requests (default unlimited).nonce/ idempotency key: prevents replay of the same grant.Enforced server-side, so the grant is bounded even if the external service never calls back. Expiry vs. manual revocation should be distinguishable in status/events.
Prior art
#2591 — feat(sandbox): add server-managed expiration leases applies the same server-managed TTL/expiration-lease pattern at the sandbox level (a reconciler auto-terminates expired sandboxes). This request is the policy-grant analog: the same lease model, but the grant auto-reverts instead of the sandbox being deleted.
Current workaround
Apply-then-revoke from the external decision layer: our decision store tracks expiry/nonce/uses and issues a follow-up deny/drop API call. Functional, but the guarantee lives outside OpenShell and is subject to a revoke race.
Acceptance criteria (rough)
expires_at/ttland/ormax_uses(and optionallynonce).Related: #2591 (sandbox expiration leases); the draft/chunk approval flow (
ApproveDraftChunk, policy reload).