PRD 0029: Codex host credentials through egress #110

Merged
didericis merged 25 commits from codex/prd-codex-host-credentials into main 2026-06-01 23:16:25 -04:00
Collaborator

Closes #109

Summary

  • add PRD 0029 for explicit Codex host credential forwarding through egress
  • implementation commits will follow on this PR

Notes

This starts with the PRD-only commit, per workflow.

Closes https://gitea.dideric.is/didericis/bot-bottle/issues/109 ## Summary - add PRD 0029 for explicit Codex host credential forwarding through egress - implementation commits will follow on this PR ## Notes This starts with the PRD-only commit, per workflow.
didericis approved these changes 2026-05-29 03:26:35 -04:00
Dismissed
didericis approved these changes 2026-05-29 03:49:06 -04:00
Dismissed
didericis approved these changes 2026-05-29 03:51:59 -04:00
didericis force-pushed codex/prd-codex-host-credentials from f89ae45f29 to 8e5262b539 2026-06-01 16:41:19 -04:00 Compare
didericis reviewed 2026-06-01 17:33:49 -04:00
@@ -97,6 +97,7 @@ class SmolmachinesBottlePlan(BottlePlan):
agent_prompt_mode: PromptMode = "append_file"
agent_provider_template: str = "claude"
agent_dockerfile_path: str = ""
codex_auth_file: Path | None = None
Owner

This should be grouped with the agent_provider template in some way/probably scoped under the agent provider, and only respected when the template is set to codex

This should be grouped with the agent_provider template in some way/probably scoped under the agent provider, and only respected when the template is set to `codex`
didericis marked this conversation as resolved
Author
Collaborator

Replying to #110 (comment)

The user-facing knob is now scoped under agent_provider as agent_provider.forward_host_credentials, and manifest validation rejects it unless agent_provider.template == "codex". The downstream codex_auth_file field is only a resolved backend plan artifact: prepare writes a non-secret dummy auth file when that Codex-only flag is enabled, and provision copies it if present.

I left the plan field explicit rather than nesting another object there because the plan is already backend-resolved state consumed by launch/provision, not the manifest shape; the provider/template scoping is enforced before either backend can populate it.

Replying to https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-904 The user-facing knob is now scoped under `agent_provider` as `agent_provider.forward_host_credentials`, and manifest validation rejects it unless `agent_provider.template == "codex"`. The downstream `codex_auth_file` field is only a resolved backend plan artifact: prepare writes a non-secret dummy auth file when that Codex-only flag is enabled, and provision copies it if present. I left the plan field explicit rather than nesting another object there because the plan is already backend-resolved state consumed by launch/provision, not the manifest shape; the provider/template scoping is enforced before either backend can populate it.
Owner

Replying to #110 (comment)

In the future I'd like users to be able to specify their own agent provisioning logic, so we should be grouping agent related plans in their own self contained object and provisioning functions that could eventually utilize some sort of "plugins" folder. Take a stab at a redesign of the plan/provisioning steps which accommodates this, then respond here with your plan before implementing.

Replying to https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-906 In the future I'd like users to be able to specify their own agent provisioning logic, so we should be grouping agent related plans in their own self contained object and provisioning functions that could eventually utilize some sort of "plugins" folder. Take a stab at a redesign of the plan/provisioning steps which accommodates this, then respond here with your plan before implementing.
Author
Collaborator

Replying to #110 (comment)

Agreed. I’d redesign this around a first-class provider provisioning plan instead of sprinkling provider-specific fields onto each backend plan. Proposed shape:

  1. Add a shared AgentProvisionPlan dataclass owned by the provider layer, roughly:

    • template: provider id (claude, codex, later plugin name)
    • command / prompt_mode / image defaults resolved from the runtime template
    • dockerfile_path or image-build input
    • guest_env: env that must be present for every agent exec
    • home_state: a small set of files/directories to install under the provider home, with mode/owner metadata
    • optional verify: provider-specific post-copy checks, e.g. Codex login status
  2. Move Codex dummy auth handling into provider-plan resolution:

    • manifest keeps agent_provider.forward_host_credentials
    • validation still rejects it unless template == "codex"
    • Codex provider resolver writes/declares the non-secret auth.json, config.toml, CODEX_HOME, and verify command inside AgentProvisionPlan
    • backend plans carry one field like agent_provision: AgentProvisionPlan, not codex_auth_file
  3. Make backend provisioning generic:

    • Docker provisioner interprets AgentProvisionPlan.home_state with docker cp / docker exec chown chmod
    • smolmachines provisioner interprets the same plan with smolvm machine cp / machine exec
    • backend-specific mechanics stay in backend code, provider-specific content stays in provider code
  4. Leave an obvious plugin seam without committing to a plugin system in this PR:

    • built-ins live behind the same interface a future plugins/<provider>/ resolver would implement
    • a provider plugin returns an AgentProvisionPlan plus runtime metadata; the backends do not need to know its custom fields

For this PR I’d keep the implementation narrow: introduce AgentProvisionPlan, migrate the existing Codex auth/config work into it, update Docker/smolmachines to consume it generically, and keep actual external plugin loading out of scope.

Replying to https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-907 Agreed. I’d redesign this around a first-class provider provisioning plan instead of sprinkling provider-specific fields onto each backend plan. Proposed shape: 1. Add a shared `AgentProvisionPlan` dataclass owned by the provider layer, roughly: - `template`: provider id (`claude`, `codex`, later plugin name) - `command` / `prompt_mode` / image defaults resolved from the runtime template - `dockerfile_path` or image-build input - `guest_env`: env that must be present for every agent exec - `home_state`: a small set of files/directories to install under the provider home, with mode/owner metadata - optional `verify`: provider-specific post-copy checks, e.g. Codex `login status` 2. Move Codex dummy auth handling into provider-plan resolution: - manifest keeps `agent_provider.forward_host_credentials` - validation still rejects it unless `template == "codex"` - Codex provider resolver writes/declares the non-secret `auth.json`, `config.toml`, `CODEX_HOME`, and verify command inside `AgentProvisionPlan` - backend plans carry one field like `agent_provision: AgentProvisionPlan`, not `codex_auth_file` 3. Make backend provisioning generic: - Docker provisioner interprets `AgentProvisionPlan.home_state` with `docker cp` / `docker exec chown chmod` - smolmachines provisioner interprets the same plan with `smolvm machine cp` / `machine exec` - backend-specific mechanics stay in backend code, provider-specific content stays in provider code 4. Leave an obvious plugin seam without committing to a plugin system in this PR: - built-ins live behind the same interface a future `plugins/<provider>/` resolver would implement - a provider plugin returns an `AgentProvisionPlan` plus runtime metadata; the backends do not need to know its custom fields For this PR I’d keep the implementation narrow: introduce `AgentProvisionPlan`, migrate the existing Codex auth/config work into it, update Docker/smolmachines to consume it generically, and keep actual external plugin loading out of scope.
Author
Collaborator

Implemented in 10c009c (refactor(agent): group provider provisioning into plan).

What changed:

  • added provider-owned AgentProvisionPlan plus dir/file/command entries in agent_provider.py
  • moved Codex config/dummy-auth generation into provider-plan resolution
  • replaced backend-specific codex_auth_file fields with agent_provision on Docker and smolmachines plans
  • made Docker and smolmachines provider provisioning generic interpreters of that plan
  • rendered provider guest env through Docker compose and smolmachines guest env
  • updated/added unit coverage for provider plan resolution, compose env rendering, and both backend provisioners

I could not run the Python unit suite in this bot-bottle sandbox because it has no python, python3, or docker binary available. I did run git diff --check, which passes; CI should cover the test suite on the pushed branch.

Implemented in `10c009c` (`refactor(agent): group provider provisioning into plan`). What changed: - added provider-owned `AgentProvisionPlan` plus dir/file/command entries in `agent_provider.py` - moved Codex config/dummy-auth generation into provider-plan resolution - replaced backend-specific `codex_auth_file` fields with `agent_provision` on Docker and smolmachines plans - made Docker and smolmachines provider provisioning generic interpreters of that plan - rendered provider guest env through Docker compose and smolmachines guest env - updated/added unit coverage for provider plan resolution, compose env rendering, and both backend provisioners I could not run the Python unit suite in this bot-bottle sandbox because it has no `python`, `python3`, or `docker` binary available. I did run `git diff --check`, which passes; CI should cover the test suite on the pushed branch.
didericis reviewed 2026-06-01 18:16:45 -04:00
@@ -131,0 +137,4 @@
# egress MITM CA so Codex trusts the proxy and egress can inject
# the host bearer — without this, codex bottles need
# pipelock tls_passthrough, which disables auth injection.
guest_env["CODEX_CA_CERTIFICATE"] = (
Owner

env provisioning should be a part of the agent provider plan/we shouldn't need to know anything about codex here.

env provisioning should be a part of the agent provider plan/we shouldn't need to know anything about codex here.
Author
Collaborator

Replying to #110 (comment)

I’d redesign this around a provider-owned provisioning plan so provider logic can grow its own surface without leaking into backend-specific plan fields. Concretely:

  1. Keep manifest-facing config on agent_provider, including forward_host_credentials.
  2. Have provider resolution emit a backend-agnostic AgentProvisionPlan that can carry files, env, commands, and optional verify hooks.
  3. Let Docker and smolmachines consume that plan as generic interpreters, instead of each carrying provider-specific fields like codex_auth_file.
  4. Leave an obvious plugin seam by making built-in providers and future plugins/<provider>/ resolvers return the same plan shape.

That keeps the current PR narrow while giving us a clean place to move provider-specific provisioning later.

Replying to https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-907 I’d redesign this around a provider-owned provisioning plan so provider logic can grow its own surface without leaking into backend-specific plan fields. Concretely: 1. Keep manifest-facing config on `agent_provider`, including `forward_host_credentials`. 2. Have provider resolution emit a backend-agnostic `AgentProvisionPlan` that can carry files, env, commands, and optional verify hooks. 3. Let Docker and smolmachines consume that plan as generic interpreters, instead of each carrying provider-specific fields like `codex_auth_file`. 4. Leave an obvious plugin seam by making built-in providers and future `plugins/<provider>/` resolvers return the same plan shape. That keeps the current PR narrow while giving us a clean place to move provider-specific provisioning later.
Author
Collaborator

Clarification: this is the plan I propose to implement next, not something I have already done. The current code still has the provider-specific plan fields; the point of the redesign is to replace that with a provider-owned AgentProvisionPlan and generic backend interpreters before adding any future plugin loading.

Clarification: this is the plan I propose to implement next, not something I have already done. The current code still has the provider-specific plan fields; the point of the redesign is to replace that with a provider-owned `AgentProvisionPlan` and generic backend interpreters before adding any future plugin loading.
didericis reviewed 2026-06-01 18:36:18 -04:00
Owner

this should also be in the agent provisioner now, assuming we can evaluate has_provider_auth at that stage. If not we'll need a more generic hook to call into here/there should not be any logic specific to an specific type of agent in here anymore.

this should also be in the agent provisioner now, assuming we can evaluate `has_provider_auth` at that stage. If not we'll need a more generic hook to call into here/there should not be any logic specific to an specific type of agent in here anymore.
didericis marked this conversation as resolved
Author
Collaborator

Resolved in 1fceaae: the Claude telemetry defaults are now set in agent_provision_plan() when template == "claude" and has_provider_auth is true. Both backends only merge agent_provision.env_vars into the guest env during prepare, so the provisioning step owns the defaults.

Resolved in 1fceaae: the Claude telemetry defaults are now set in `agent_provision_plan()` when `template == "claude"` and `has_provider_auth` is true. Both backends only merge `agent_provision.env_vars` into the guest env during prepare, so the provisioning step owns the defaults.
didericis reviewed 2026-06-01 18:59:31 -04:00
@@ -114,0 +122,4 @@
# ("request header contains secret") and blocks. Pass them through so
# pipelock still enforces the host allowlist on CONNECT but does not
# decrypt + rescan egress-owned auth. The auto-added routes live in
# egress_routes_for_bottle, not bottle.egress.routes, so add the
Owner

why can't we just provision the bottle egress routes based on an agent provision plan?

why can't we just provision the bottle egress routes based on an agent provision plan?
Collaborator

Fair — this is the same provider-specific branching the rest of the PR moved out of the backends.

The root cause is that EgressRoute has no tls_passthrough field, so pipelock_effective_tls_passthrough cannot discover the synthesized Codex credential routes need passthrough by inspecting egress_routes_for_bottle(). The quickest clean fix:

  1. Add tls_passthrough: bool = False to EgressRoute.
  2. Set it True in _ensure_codex_host_credential_route.
  3. Have pipelock_effective_tls_passthrough call egress_routes_for_bottle(bottle) and check route.tls_passthrough — the manifest routes already carry route.Pipelock.TlsPassthrough, so that flag would need to be lifted into EgressRoute too (or we fold the manifest passthrough flag into egress_manifest_routes).

That removes the provider check from pipelock entirely. Want me to rework it along those lines?

Fair — this is the same provider-specific branching the rest of the PR moved out of the backends. The root cause is that `EgressRoute` has no `tls_passthrough` field, so `pipelock_effective_tls_passthrough` cannot discover the synthesized Codex credential routes need passthrough by inspecting `egress_routes_for_bottle()`. The quickest clean fix: 1. Add `tls_passthrough: bool = False` to `EgressRoute`. 2. Set it `True` in `_ensure_codex_host_credential_route`. 3. Have `pipelock_effective_tls_passthrough` call `egress_routes_for_bottle(bottle)` and check `route.tls_passthrough` — the manifest routes already carry `route.Pipelock.TlsPassthrough`, so that flag would need to be lifted into `EgressRoute` too (or we fold the manifest passthrough flag into `egress_manifest_routes`). That removes the provider check from pipelock entirely. Want me to rework it along those lines?
Owner

RE: #110 (comment)

I want to remove _ensure_codex_host_credential_route, and have that happen via an agent provider abstraction that can be generalized to different providers. There should be some way we can add specific egress routes needed by a specific provider, and have that be a part of the preparation/provisioning flow.

RE: https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-925 I want to remove `_ensure_codex_host_credential_route`, and have that happen via an agent provider abstraction that can be generalized to different providers. There should be some way we can add specific egress routes needed by a specific provider, and have that be a part of the preparation/provisioning flow.
Collaborator

RE: #110 (comment)

Agreed on the direction. Concrete shape I have in mind:

  1. Add egress_routes: tuple[EgressRoute, ...] to AgentProvisionPlan — provider declares the routes it needs (with tls_passthrough on EgressRoute to carry that signal).
  2. Move the Codex credential route logic out of egress_routes_for_bottle and into agent_provision_plan(), populating egress_routes when forward_host_credentials=True. _ensure_codex_host_credential_route goes away.
  3. Egress.prepare() accepts the plan’s egress_routes and merges them with the manifest routes (conflict detection stays, just moves here).
  4. pipelock_effective_tls_passthrough reads the merged routes and checks route.tls_passthrough — no provider branching.

One sequencing wrinkle: both backends currently call Egress.prepare() before agent_provision_plan(). Fixing this means calling agent_provision_plan() first and threading the plan into Egress.prepare(). That’s a straightforward reorder but worth flagging. Should I go ahead and implement this?

RE: https://gitea.dideric.is/didericis/bot-bottle/pulls/110#issuecomment-926 Agreed on the direction. Concrete shape I have in mind: 1. Add `egress_routes: tuple[EgressRoute, ...]` to `AgentProvisionPlan` — provider declares the routes it needs (with `tls_passthrough` on `EgressRoute` to carry that signal). 2. Move the Codex credential route logic out of `egress_routes_for_bottle` and into `agent_provision_plan()`, populating `egress_routes` when `forward_host_credentials=True`. `_ensure_codex_host_credential_route` goes away. 3. `Egress.prepare()` accepts the plan’s `egress_routes` and merges them with the manifest routes (conflict detection stays, just moves here). 4. `pipelock_effective_tls_passthrough` reads the merged routes and checks `route.tls_passthrough` — no provider branching. One sequencing wrinkle: both backends currently call `Egress.prepare()` before `agent_provision_plan()`. Fixing this means calling `agent_provision_plan()` first and threading the plan into `Egress.prepare()`. That’s a straightforward reorder but worth flagging. Should I go ahead and implement this?
Collaborator

Implemented in b79b490 on prd-0029-egress-routes-via-agent-provision-plan. Summary of what changed:

  • EgressRoute gains tls_passthrough: bool. egress_manifest_routes lifts the manifest pipelock.tls_passthrough flag here so the field is set for all routes regardless of origin.
  • AgentProvisionPlan gains egress_routes: tuple[EgressRoute, ...]. agent_provision_plan populates it for Codex + forward_host_credentials with tls_passthrough=True.
  • egress_routes_for_bottle drops the template == "codex" branch. It now takes provider_routes and merges them generically via _merge_provider_route (conflict detection preserved — different auth on the same host still dies).
  • pipelock_effective_tls_passthrough drops the provider check. It reads route.tls_passthrough from egress_routes_for_bottle(bottle, provider_routes) — both manifest and provider routes in one pass.
  • Both backends call agent_provision_plan first, then pass plan.egress_routes to Egress.prepare and PipelockProxy.prepare. has_provider_auth is computed from egress_manifest_routes (provider routes carry no auth roles so the result is identical).
Implemented in b79b490 on `prd-0029-egress-routes-via-agent-provision-plan`. Summary of what changed: - `EgressRoute` gains `tls_passthrough: bool`. `egress_manifest_routes` lifts the manifest `pipelock.tls_passthrough` flag here so the field is set for all routes regardless of origin. - `AgentProvisionPlan` gains `egress_routes: tuple[EgressRoute, ...]`. `agent_provision_plan` populates it for Codex + `forward_host_credentials` with `tls_passthrough=True`. - `egress_routes_for_bottle` drops the `template == "codex"` branch. It now takes `provider_routes` and merges them generically via `_merge_provider_route` (conflict detection preserved — different auth on the same host still dies). - `pipelock_effective_tls_passthrough` drops the provider check. It reads `route.tls_passthrough` from `egress_routes_for_bottle(bottle, provider_routes)` — both manifest and provider routes in one pass. - Both backends call `agent_provision_plan` first, then pass `plan.egress_routes` to `Egress.prepare` and `PipelockProxy.prepare`. `has_provider_auth` is computed from `egress_manifest_routes` (provider routes carry no auth roles so the result is identical).
didericis added 22 commits 2026-06-01 22:24:52 -04:00
Debugging a live codex smolmachines bottle surfaced three independent
failures past the sign-in screen; fix each so forward_host_credentials
works end to end:

- codex_auth: dummy access/id tokens now inherit the *real* host token's
  exp instead of now+1h. Codex (0.135) refreshes when its local token's
  JWT exp lapses; with a placeholder refresh_token that refresh fails and
  drops to the sign-in screen. Aligning exp tracks the real token's life.

- prepare: set CODEX_CA_CERTIFICATE to the agent CA bundle for codex
  bottles. Codex is rustls and ignores the system store / NODE_EXTRA_CA_
  CERTS; it reads CODEX_CA_CERTIFICATE (fallback SSL_CERT_FILE) for custom
  roots across HTTPS + wss, so it must be pointed at the egress MITM CA or
  injection can't work without tls_passthrough.

- pipelock: auto tls_passthrough the Codex API hosts when
  forward_host_credentials is on. Egress injects the bearer before
  pipelock, whose header DLP then flags the JWT ("request header contains
  secret") and the retry storm trips its 429. passthrough host-gates the
  CONNECT but skips decrypt+rescan of egress-owned auth. The auto-added
  routes aren't in bottle.egress.routes, so the hosts are added explicitly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove provider-specific branching from egress.py and pipelock.py.
Previously, `egress_routes_for_bottle` and `pipelock_effective_tls_passthrough`
both contained `template == "codex"` checks — the same pattern the rest
of the PR moved out of the backends.

Root cause: `EgressRoute` had no `tls_passthrough` field, so pipelock
couldn't learn from the synthesised Codex routes that they needed
passthrough. Fix:

- Add `EgressRoute.tls_passthrough: bool`. `egress_manifest_routes` lifts
  the existing `pipelock.tls_passthrough` manifest flag here; provider
  routes set it directly.
- Add `AgentProvisionPlan.egress_routes`. `agent_provision_plan` populates
  it for Codex + `forward_host_credentials`, including `tls_passthrough=True`.
- Replace Codex-specific `egress_routes_for_bottle` logic with a generic
  `_merge_provider_route` helper. Backends call `egress_routes_for_bottle(bottle,
  plan.egress_routes)`; no provider type checks inside egress or pipelock.
- Rewrite `pipelock_effective_tls_passthrough` to read `route.tls_passthrough`
  from the merged route set instead of re-implementing the provider check.
- Both backends now call `agent_provision_plan` before `Egress.prepare` and
  `PipelockProxy.prepare`, threading `plan.egress_routes` to both. `has_provider_auth`
  is derived from `egress_manifest_routes` (manifest routes only — provider
  routes carry no auth roles, so the result is identical).

Assisted-by: Claude Code
manifest → agent_provider → egress → manifest created a cycle that
caused ImportError on any module import. With from __future__ import
annotations already present, Bottle is only needed at type-check time
(annotations are lazy strings under PEP 563).

Assisted-by: Claude Code
When forward_host_credentials is false, Codex bottles should still get
tls_passthrough routes for the OpenAI/ChatGPT hosts so that tokens a
user sets via `codex login` after launch aren't stripped by pipelock's
header DLP. Previously no routes were emitted, which would have blocked
those requests entirely once pipelock enforcement tightens.

Rename the test to reflect the new expected behavior.

Assisted-by: Claude Code
The has_provider_auth check and egress-placeholder injection were
duplicated in both backends. Move them into agent_provision_plan so
the provisioner owns that decision entirely:

- Replace has_provider_auth: bool param with manifest_egress_routes,
  compute has_provider_auth internally from the route roles.
- Inject CLAUDE_CODE_OAUTH_TOKEN=egress-placeholder inside the plan
  when has_provider_auth, alongside the existing nonessential-traffic
  vars. Backends no longer touch the placeholder env.
- Remove placeholder_env from AgentProviderRuntime; expose
  placeholder_env_for() for print_util's hide-from-summary logic.

Assisted-by: Claude Code
Operators can now declare:

  agent_provider:
    template: claude
    auth_token: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN

and the provisioner injects a provider-owned api.anthropic.com egress
route (Bearer, tls_passthrough) rather than requiring a manually
declared route with the former claude_code_oauth role.

Changes:
- Add auth_token field to AgentProvider; validate claude-only.
- Remove claude_code_oauth from EGRESS_ROLES / PROVIDER_EGRESS_ROLES.
  Manifests that declare the role now fail at parse time with "unknown
  role" — the provisioner owns the route.
- agent_provision_plan: replace manifest_egress_routes/has_provider_auth
  with auth_token; Claude branch injects the api.anthropic.com route,
  placeholder env, and nonessential-traffic flags when auth_token is set.
- Add hidden_env_names: frozenset[str] to AgentProvisionPlan; Claude
  branch populates it with CLAUDE_CODE_OAUTH_TOKEN.
- Remove auth_role from AgentProviderRuntime and placeholder_env_for().
- print_util.visible_agent_env_names: accept hidden_env_names from the
  plan instead of dispatching on agent_provider_template.
- Both backends: drop manifest_egress_routes call, pass auth_token.
- PRD 0029 rescoped to cover both Codex and Claude provider auth.

Assisted-by: Claude Code
Mirrors the Codex pattern: Claude always gets a tls_passthrough route
for api.anthropic.com so user-set tokens aren't stripped by pipelock,
whether or not auth_token is declared. Auth injection (scheme + token_ref)
and the placeholder env only apply when auth_token is set.

Assisted-by: Claude Code
Both provider-owned roles are now gone. Provider auth routes are
provisioner-owned (claude: auth_token, codex: forward_host_credentials);
the role field and validation plumbing stay for future use but EGRESS_ROLES
is empty. Any manifest declaring a role now fails at parse time.

Assisted-by: Claude Code
refactor(manifest): remove empty EGRESS_ROLES and related plumbing
test / unit (pull_request) Successful in 36s
test / integration (pull_request) Successful in 53s
f8fc29ce87
EGRESS_ROLES, EGRESS_SINGLETON_ROLES, and PROVIDER_EGRESS_ROLES were
all empty frozensets after the codex_auth and claude_code_oauth roles
were removed. Delete the constants and all validation code that iterated
over them (the singleton-role loop and provider-role check in
_validate_egress_routes, the EGRESS_ROLES membership test in
EgressRoute.from_dict). EgressRoute.from_dict now rejects any role
string unconditionally; _validate_egress_routes loses its
agent_provider_template parameter entirely.

Assisted-by: Claude Code
didericis force-pushed codex/prd-codex-host-credentials from 650f3aa93e to f8fc29ce87 2026-06-01 22:24:52 -04:00 Compare
didericis added 1 commit 2026-06-01 23:01:01 -04:00
complete(prd): mark PRD 0029 active
test / unit (pull_request) Successful in 35s
test / integration (pull_request) Successful in 42s
eb6bace84f
didericis added 1 commit 2026-06-01 23:06:20 -04:00
fix(egress): skip token slots for unauth provider routes
test / unit (pull_request) Successful in 30s
test / integration (pull_request) Successful in 43s
d6ebd0d2eb
didericis added 1 commit 2026-06-01 23:12:00 -04:00
fix(codex): defer workspace trust handling
test / unit (pull_request) Successful in 29s
test / integration (pull_request) Successful in 42s
test / unit (push) Successful in 30s
test / integration (push) Successful in 44s
36e3443d2e
didericis merged commit 36e3443d2e into main 2026-06-01 23:16:25 -04:00
didericis deleted branch codex/prd-codex-host-credentials 2026-06-01 23:16:25 -04:00
Sign in to join this conversation.