Skip to content

feat(sandbox): resolve manifest environment values from the process environment - #4399

Closed
xumaple wants to merge 1 commit into
openai:mainfrom
xumaple:feat/sandbox-os-env-value
Closed

feat(sandbox): resolve manifest environment values from the process environment#4399
xumaple wants to merge 1 commit into
openai:mainfrom
xumaple:feat/sandbox-os-env-value

Conversation

@xumaple

@xumaple xumaple commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Environment can only hold literal values today. StrEnvValue is the only concrete EnvValue, so anything a sandbox needs in its environment has to be written into the manifest itself, and it travels with the manifest wherever that gets persisted or handed across a boundary.

This adds OsEnvValue, which names a variable instead. The backend clients pick it up where they already call manifest.environment.resolve(), at create, exec and resume, so the value is read on the machine actually building the sandbox. It also seemed like the obvious second implementation of an interface whose resolve() is async, which only earns the keyword if resolution can do more than return a field.

Three choices I would rather hear your view on than assume:

  • an unset variable resolves to "" rather than raising, matching shell expansion instead of adding a new failure mode to sandbox creation
  • "os_env" for the discriminator, which departs from StrEnvValue's class-name-minus-suffix rule but reads better in a serialized manifest. "os" is just as easy if consistency matters more, and it is a wire string, so cheaper to settle now than later
  • name for the field, since no existing model carries a single variable name and name is the identifier field used elsewhere in the package

Note: this touches test_core_discriminator_type_strings_are_stable, because that table maps every core discriminated class and leaving OsEnvValue out would have made it the only one missing. I left the members list in docs/ref/sandbox/manifest.md alone under the Documentation Release Timing rule in AGENTS.md; let me know if you would like that as a separate PR when it is due.

Test plan

Five tests in tests/sandbox/test_manifest.py: resolving a variable that is set, unset and empty both resolving to "", round-tripping through Manifest serialization with the discriminator intact and coming back as OsEnvValue, and resolving through Environment.resolve() alongside a bare literal and an EnvEntry wrapper.

.agents/skills/code-change-verification/scripts/run.sh passes: format, lint, typecheck and tests all green.

Two notes about my environment rather than the change, in case they show up elsewhere: building cffi needed libffi-dev installed, and my container sets no_proxy to a value httpx2 cannot parse (Invalid port: ':1]'), which takes out around 138 unrelated tests in test_config.py, tracing/, mcp/ and voice/ until those variables are cleared.

Issue number

None.

Checks

  • I've added new tests, if relevant
  • I've run .agents/skills/code-change-verification/scripts/run.sh
  • I've confirmed all verification steps pass
  • If using Codex, I've run /review before submitting this PR

…he process environment

Environment can only hold literals today: StrEnvValue is the only concrete
EnvValue, so anything a sandbox needs in its environment has to be written
into the manifest itself. That is awkward wherever the manifest is persisted
or handed across a boundary, because the value travels with it.

OsEnvValue names a variable instead. The backend clients pick it up where
they already call manifest.environment.resolve(), at create, exec and
resume, so the value is read on the machine actually building the sandbox.

An unset variable resolves to the empty string, matching shell expansion
rather than introducing a new failure mode into sandbox creation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e8ee09632

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

name: str

async def resolve(self) -> str:
return os.environ.get(self.name, "")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Require trusted host-env bindings

When a manifest or serialized session-state payload is not fully trusted, this lets that payload choose any variable name and have the SDK process read it during manifest.environment.resolve() before create/exec/resume, so a manifest containing {"type":"os_env","name":"OPENAI_API_KEY"} would copy the host API key into the sandbox environment. That makes serialized manifest data itself authorize host secret access; keep OS environment references as trusted application-side configuration or require an explicit allowlist/rebind before resolving them.

AGENTS.md reference: AGENTS.md:L125-L125

Useful? React with 👍 / 👎.

@seratch

seratch commented Aug 16, 2026

Copy link
Copy Markdown
Member

Thanks for putting this together. The underlying need is real: StrEnvValue serializes the concrete value, so a late-bound environment reference is useful.

This approach can make sense when another layer already owns and enforces the trust boundary. For the SDK’s built-in generic mechanism, though, the trust boundary needs to live in trusted sandbox runtime configuration rather than in serialized manifest data.

We are pursuing that direction in #4408, where the manifest contains only references and the sandbox client owns the allowed destination/source bindings.

Closing this PR in favor of #4408 for the core SDK implementation. Thanks again for the proposal.

@seratch seratch closed this Aug 16, 2026
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.

2 participants