the-custodian/docs/changes/CUST-WP-0073/interactive-launch-r1
codex 903616f2b7
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 10s
Reject generated-only commits / generated-commit-guard (push) Successful in 11s
Retain interactive isolation target and identity review
2026-10-19 14:47:02 +02:00
..
observation.json Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
probe_identity.py Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
README.md Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
SHA256SUMS Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
source-pins.json Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
test_probe_identity.py Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00
validation.json Retain interactive isolation target and identity review 2026-10-19 14:47:02 +02:00

Actual interactive Custodian assignment: supported handoff proposal

2026-10-19; preparation only. User selected this interactive Codex assignment first. No host/user creation, authentication, handoff, sudo, deployment, daemon restart, or production mutation occurred. This adds evidence to CUST-WP-0073; it neither supersedes the original credential-boundary revision 2 nor proves admission. The protected k3s preflight remains separately reviewable at /tmp/cust73-privileged-preflight-r1; its earlier boundary-choice field is historical and is superseded by the user's explicit interactive-first choice.

Observed current execution boundary

observation.json records a UTC-bound, sanitized process ancestry. In the tool PID namespace, parent PID 1 executes the installed Codex 0.163.0 app-server-daemon binary and all observed UIDs are 1000. PATH resolves a different Codex installation. This does not establish the outer desktop frontend, transport endpoint, or daemon invocation: PID namespace ancestry ends at PID 1. No raw command line, environment, authentication file, session transcript, or credential was printed. The inspected user config has no explicit approval/sandbox override or MCP server entries; this does not describe managed settings, frontend apps, or dynamic tools.

Supported route and concrete operator integration

The official remote connections guide supports an SSH connection that starts Codex under the remote login user, then desktop handoff of an existing chat to a saved matching Git project. Select the chat's run location, choose destination, and confirm Hand off. Handoff transfers chat/Git state and interrupts an active response. This chat cannot self-handoff; the operator or a separate chat must perform it. Confirm the installed frontend exposes these controls before provisioning; this environment cannot inspect its UI.

Use a dedicated non-admin OS account on an approved target, with a private home and private Codex state, no inherited SSH agent/admin kubeconfig/OpenBao tokens, no sudo or container-control groups, and an isolated repo checkout. Choose the target in the proposal rather than assuming the current workstation or the live k3s server is already suitable. Do not copy the operator's .codex, .ssh, .kube, environment, or global Git credential helper. Authentication for this account requires its own approved owner route. SSH alias must specify the new account and pinned host identity, with agent forwarding disabled.

After account provisioning and owner-authentication approval: verify codex on that account's login PATH; add the alias in desktop Settings > Connections; save the same Git repository/subdirectory there; capture its version/digest, OS identity and policy. Use the native handoff UI for THIS chat. No custom Glas rein is required merely to obtain the documented interactive transport. Keep old chat paused after handoff until admission passes. Failure returns to supervised preparation; it does not enable the old credential-bearing execution path for assignment work. Preserve receipts and explicitly record any rollback.

The app-server approval protocol sends command/file approval requests to the client with thread and turn IDs. Retain this native approval UI, and capture both approved and denied canary outcomes in the destination chat. Its decision never grants OS sudo rights. Custom clients would need these request/response flows; building one is not the minimal route. Direct network exposure of app-server is unnecessary.

Concrete owner work

  • Host provisioning owner (railiance-infra for managed estate hosts): add dedicated account/private checkout and explicit no-admin group/sudo policy. Existing ansible/roles/ssh_ca_host/tasks/main.yml installs per-user principals but does not create or confine a Codex account. Add its principal mapping only alongside the new account; never map the agt principal to tegwick/admin. Resolve an unmanaged workstation owner explicitly if that is the selected target.
  • ops-warden: existing SSH certificate route, after exact account/principal and target approval. It does not vend Codex authentication or Kubernetes tokens.
  • Custodian assignment supervisor: bind proposal revision, actual chat identity, target and host account; operator performs native handoff and verifies the new chat execution receipt. A new unrelated CLI session is not this acceptance.
  • Glas: accept/record the externally attached interactive assignment's evidence if its existing admission API is used; add a truthful interactive capability only after proof. Current gateway/rein catalog and bounded sand-boxer runner do not implement this frontend transport. Do not gate this route on another Claude startup rehearsal or claim the old native lane proves Codex isolation.

Acceptance, without touching credential contents

Run probe_identity.py EXPECTED_UID EXPECTED_MACHINE_ID_SHA256 from a tool call in the handed-off chat, with expected values set by the supervisor's target receipt. It rejects UID 0 or the current UID 1000 and suppresses all credential values. This is a partial identity check, not admission by itself.

Then bind an external supervisor observation of the app-server/tool process identity and thread to that same receipt; child-only probes can be fabricated by launching a child and therefore never suffice. Verify: private state, denied admin kubeconfig/SSH socket/OpenBao access, no privileged group/socket/sudo paths, bounded Kubernetes credential and aggregate PLUS every-namespace RBAC denials from the original packet, actual denied/approved native UI canaries, and no old process receiving tool execution. Inventory frontend connectors and dynamic tools separately: moving the shell UID does not revoke frontend account capabilities. Disable or explicitly scope external privileged tools.

Unresolved concrete gates: selected target/account, installed UI handoff support, account/SSH/authentication approval, protected k3s selector preflight and host mode600 approval if targeting that host, authoritative namespace inventory, actual-chat identity/approval/credential-denial receipts, external-tool scope. No acceptance status should move to done from these fixture or documentation results.