68e5097534
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>
50 lines
1.6 KiB
Python
50 lines
1.6 KiB
Python
"""Provision non-secret provider auth markers into a smolmachines bottle."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
from ....log import die
|
|
from .. import smolvm as _smolvm
|
|
from ..bottle_plan import SmolmachinesBottlePlan
|
|
|
|
|
|
_DEFAULT_GUEST_HOME = "/home/node"
|
|
|
|
|
|
def provision_provider_auth(plan: SmolmachinesBottlePlan, target: str) -> None:
|
|
"""Copy a dummy Codex auth marker when host credentials are
|
|
forwarded through egress.
|
|
|
|
The real host access token remains in the egress bundle env; this
|
|
file only selects Codex's user/device auth code path.
|
|
"""
|
|
if not plan.codex_auth_file:
|
|
return
|
|
guest_home = os.environ.get("BOT_BOTTLE_GUEST_HOME", _DEFAULT_GUEST_HOME)
|
|
auth_dir = f"{guest_home}/.codex"
|
|
auth_path = f"{auth_dir}/auth.json"
|
|
|
|
_smolvm.machine_exec(target, ["mkdir", "-p", auth_dir])
|
|
_smolvm.machine_cp(str(plan.codex_auth_file), f"{target}:{auth_path}")
|
|
_smolvm.machine_exec(target, ["chown", "node:node", auth_path])
|
|
_smolvm.machine_exec(target, ["chmod", "600", auth_path])
|
|
result = _smolvm.machine_exec(
|
|
target,
|
|
[
|
|
"runuser", "-u", "node", "--",
|
|
"env",
|
|
f"HOME={guest_home}",
|
|
f"CODEX_HOME={auth_dir}",
|
|
"codex", "login", "status",
|
|
],
|
|
)
|
|
if result.returncode != 0:
|
|
detail = (result.stderr or result.stdout).strip()
|
|
if detail:
|
|
detail = f": {detail}"
|
|
die(
|
|
"codex host credentials: dummy auth was copied into the "
|
|
f"smolmachine, but Codex did not accept it{detail}"
|
|
)
|