Skip to content

feat(store): each object store sets how long its transfer grants last, 12 hours by default - #32

Open
earakely-scale wants to merge 7 commits into
edgararakelyan/local-provider-transfer-grantsfrom
edgararakelyan/store-grant-lifetime
Open

earakely-scale wants to merge 7 commits into
edgararakelyan/local-provider-transfer-grantsfrom
edgararakelyan/store-grant-lifetime

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Each object store now sets how long its transfer grants last, instead of agent-env asking for a fixed hour. The default is 12 hours. Stacked on #13.

  • A setting on every built-in store. S3ObjectStore, GcsObjectStore and LocalFilesystemObjectStore take grant_lifetime_seconds in their config table (default 43200), and it applies to read and write grants. A caller can still pass expires_in. ObjectStore.grant_lifetime_seconds carries the default for other stores.

    [stores.object]
    impl = "agent_env.store.object_store:S3ObjectStore"
    config = { bucket = "<bucket>", grant_lifetime_seconds = 3600 }
  • agent-env no longer picks the lifetime. write_object, read_object and the validator's probe call issue_write_grant / issue_read_grant without expires_in, whose default is now None, meaning the store's setting. GRANT_LIFETIME_SECONDS is gone.

    • Under @local routing, each grant is issued, and timed, by the store that owns its object. expires_in is passed on only when the caller named one, so a custom store's own default is left alone.
    • A custom store that kept its own expires_in default still behaves exactly as before.
  • Checked when the store is made. The value must be a whole number of seconds and at least 15 minutes (MIN_GRANT_LIFETIME_SECONDS), which outlasts the 10 minutes agent-env waits for a transfer. It can be no more than the store can sign: 7 days for S3's SigV4, for GCS 12 hours when signing through IAM or 7 days with a key, and 7 days for the local store. 12 hours is exactly the GCS IAM maximum, so the default is valid on every store.

    • An S3 grant signed with temporary credentials still ends when they do, and its expires_at says so.
    • Local grants still end when the process that issued them exits.
  • Unchanged: the changelog upload policy. It keeps lasting the agent's TTL, which it must cover for the whole capture.

Longer grants mean a leaked grant URL stays valid longer. Deployments that want the old window can set grant_lifetime_seconds = 3600.

Test plan

  • pytest tst/unit packages/agentenv-protocol/tests -n auto: 5775 passed.
    • The 12-hour default; a configured lifetime on S3, GCS and the local store (the local case through its real grant server); a caller's explicit expires_in still honoured.
    • Invalid values refused at construction: non-integers, anything under 15 minutes, S3's and the local store's 7-day cap, and GCS's IAM and key caps. The floor stays above the transfer timeout.
    • @local routing leaves a custom store's own expires_in default alone.
    • agent-env's read and write grants following the issuing store; @local routing following the owning store; and the setting read from [stores.object] config.
  • pytest -m 'not int_test_slow' tst/integration --ignore=tst/integration/env/gateway/gateway_test.py: 141 passed.
  • Plugin API check against the base: no break.

🤖 Generated with Claude Code

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no finding remains outstanding.

What we checked:

  • Short grants expire during transfers: The store rejects settings below 900 seconds; the transfer wait is 600 seconds.

Summary

Object stores now set the lifetime of their read and write grants, with a 12-hour default and a configurable setting. Agent-env leaves the duration to the store issuing each grant unless a caller names one.

  • Built-in stores check lifetime settings against transfer needs and signing limits.
  • Local-run routing uses the setting of the store that owns each object.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Agent transfer call] --> B[Object store]
    B --> C{Lifetime supplied?}
    C -->|Yes| D[Use supplied lifetime]
    C -->|No| E[Use issuing store's setting]
    D --> F[Issue grant]
    E --> F
Loading

Reviews (7) · Last reviewed commit: "Merge remote-tracking branch 'origin/edg..."

…, 12 hours by default

The built-in object stores (S3, GCS and the local store) take a grant_lifetime_seconds setting,
12 hours unless configured, and their read and write grants last that long when the caller names
no lifetime. agent-env no longer names one (it asked for a fixed hour), so a grant lasts what the
store that issues it says, and a local run's grants follow the store that owns each object.

A lifetime a store cannot sign is refused when the store is made: S3 caps SigV4 at 7 days, and GCS
at 12 hours when it signs through IAM or 7 days with a key. The changelog upload policy still lasts
the agent's TTL, which it must cover.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread src/agent_env/store/routing.py Outdated
Comment thread src/agent_env/store/object_store/object_store.py Outdated
Comment thread src/agent_env/store/object_store/local_object_store.py Outdated
earakely-scale and others added 2 commits September 30, 2026 12:34
… a lifetime must outlast a transfer

LocalRunObjectStore now passes expires_in on only when its caller named one, so a store whose grant
methods default it to a number of their own keeps that default instead of receiving None.

A store's grant_lifetime_seconds must be at least 15 minutes, longer than the 10 minutes agent-env
waits for an agent to move an object through a grant, and the local store's at most 7 days, as S3's,
so a value it could not turn into an expiry is refused when the store is made rather than at its
first grant.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ansfer-grants' into edgararakelyan/store-grant-lifetime
earakely-scale and others added 4 commits October 5, 2026 10:22
…ansfer-grants' into edgararakelyan/store-grant-lifetime
…etime

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ansfer-grants' into edgararakelyan/store-grant-lifetime
…ansfer-grants' into edgararakelyan/store-grant-lifetime

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant