Real Codex app-server native proof inside the #78 OCI boundary (#53) #84

Merged
adrian.tkacz merged 11 commits from issue-53-codex-oci-worker-proof into develop 2026-10-10 01:18:29 +00:00
Member

Summary

Bounded #53 continuation (owner directive): prove that the actual Codex app-server and its native tool paths run inside the exact #78 rootless OCI worker boundary, with enforcement independent of Codex approval callbacks — followed by owner-directed security corrections of the collection trust boundary, the container-state lifecycle observation, and the shared worker-status reader. No synthetic worker substitutes for the harness; no src/ product behavior changes; #50/#78 boundaries and evidence preserved.

Native isolation proof (observed)

CREATIDY_TEST_OCI_TOOLROOT=/tmp/kilo/kernel78-tooling make codex-oci-proof — observed 2026-10-10 at the delivered HEAD 9466187: 22 items passed, 0 failed, 0 native skips (11 native cells + 7 host-side collection-safety cells + 4 host-side lifecycle-observation cells; skips are explicit UNPROVED without the pinned toolroot/binary). The fail-closed worker-status reader is gated by 3 further host-side cells under make oci-worker-proof (29 passed there, #78 regression included).

  1. Real codex-cli 0.159.3 app-server startup, initialize handshake (production CodexStdio transport via a generated per-attempt wrapper), thread/start/turn/start/turn/completed inside OCI; native rollout JSONL in a fresh synthetic CODEX_HOME.
  2. Genuine native exec_command tool op reading and modifying only the disposable candidate workspace; read-only rootfs write refused (Read-only file system observed in-boundary).
  3. Native terminal via two channels — model-driven exec_command PTY and direct command/exec (no thread) — plus setsid detached descendant; turn/interrupt is not settlement; podman stop settles the tree (host /proc scan); bystander survives.
  4. Forbidden host FS/network denied with approvalPolicy: "never" + sandbox: "danger-full-access" (recorded verbatim in evidence) — enforcement comes from the boundary, not native approvals or Codex's own sandbox.
  5. Controller-owned interrupt/expiry/termination/settlement (graceful and grace-0 stops).
  6. New unauthorized external operations refused after expiry/revocation: relay refusals (replay, mid-run revocation, expiry, unknown grant) and controller-level AttemptExpired for turn/start/command/exec.
  7. Recovery: monitor SIGKILL → terminality unknown (requests fail closed) → reconciled by observation; dropped relay reply = executed at relay, reply_lost at worker (receipt log is truth).
  8. Fail-closed post-settlement collection with independent digest verification — plus the in-flight-writes cell (bytes persist, never roll back; stream bounded by termination).

Security corrections (owner-directed)

Collection trust boundary (symlink-following collector). The original collector traversed the worker-controlled workspace with rglob/is_file/stat — a worker-created symlink to a host path could cause an unauthorized host-side read during collection. Reproduced safely with synthetic files, remediated fail-closed (tools/codex_oci_proof/collect.py): authorized candidate roots only; regular-file-only; symlinks refused in every component; descriptor-pinned single-component lookups with fstat on the exact descriptor read; O_NONBLOCK; bounded reads/entries/depth; refusals as recorded failures. Publishable artifacts (only from candidate/) have exact bytes preserved and digest-bound under the controller-owned collected/ tree; private runtime state is inventoried separately. Native regression: worker-side symlinks refused by name with the prohibited host target never opened; no worker-controlled path is kernel-resolved after enumeration anywhere in the delivery.

Container-state lifecycle observation. The shared observer mapped every nonzero podman container exists exit to "absent", conflating confirmed absence (exit 1) with podman 125-style engine/storage errors, timeouts and lost observations. It now returns a typed outcome — exists (0) / absent (1, confirmed) / unknown (everything else) — and all callers are reconciled: CodexAttempt.collect() authorizes only on confirmed absent (unknown is a typed refusal); dispose() terminates on every non-absent observation; #78 harness callers follow the same rule. Deterministic synthetic cells cover exit codes 0, 1, 125, other nonzeros, timeout and lost observation, and prove code 125 can neither authorize collection nor count as settlement.

Worker-status reader. The #78 harness worker_status() read its worker-controlled status path with symlink-following primitives. The bounded-regular reader was extracted into the #78 package (tools/oci_worker_poc/saferead.py — dependency direction preserved: the #78 harness imports only its own package; the #53 collector re-exports the same primitives) and worker_status() now routes through it: a planted symlink is refused before any open, non-regular replacements and oversized files raise, absence stays truthful, malformed JSON raises. Regression cells prove a worker-created symlink cannot cause worker_status() to read a host-only JSON file.

Versions / provenance

Codex 0.159.3 standalone musl (hash-pinned, mounted read-only, fresh synthetic CODEX_HOME, owner Codex state never read); podman 6.1.3 / crun 1.30.1 / conmon 2.2.1 / busybox from the #78 toolroot provenance.json; deterministic controller-built image; protocol inventory generated by the pinned binary. Isolation policy flags flag-for-flag identical to #78; cgroup budget larger by design (disclosed). Seccomp: identical deny set, clone3 ENOSYS instead of EPERM (upstream practice; review-verified) — compatibility correction, not a weakening.

Dispositions for the five #78 limitations

docs/architecture/codex-oci-native-proof.md: seccomp clone-flags residual UNPROVEN (named owner decision); settlement REMEDIATED (authoritative container lifecycle + non-cooperative argv markers); instantaneous FD revocation unsupported by design, recorded as fact; single-UID mapping unchanged (deployment prerequisite); relay↔durable-authority integration named remaining work.

Gates (all at delivered HEAD 9466187)

make check (1428 passed / 85 skipped / 81 subtests; secrets clean; git diff --check clean), make package-check, make audit (clean), make oci-worker-proof (29 passed), make codex-oci-proof (22 passed). Canonical CI #2414 SUCCESS on exact HEAD 9466187 (2407–2412 success on prior commits).

Review status (owner exception: budget 10 → 12; 11/12 consumed; ordinal 12 unused)

All ten pre-exception ordinals preserved (1–3 COMMENT remediated; 4 APPROVE at 7e2a021; 5–8 COMMENT on each security HEAD with the trust findings independently confirmed resolved; 9 APPROVE at 7aad45e; 10 REQUEST_CHANGES with two non-blocking P3s). Under the owner exception:

  • Ordinal 11 (9466187/73e3af4): APPROVE, findings[] empty — all three owner-directed trust-boundary findings independently confirmed genuinely resolved (collector; container-state observation; worker-status reader with dependency direction preserved); receipt inventory matches the delivered test inventory exactly (22 = 11+7+4, plus 3 worker-status cells); sanitized gates reproduced exactly (1428/85, package-check PASS); canonical CI #2414 SUCCESS on the exact reviewed HEAD verified via Forgejo MCP.
  • Ordinal 12 was not consumed (directive: do not consume unnecessarily).

Non-goals

#53 stays open and gated; not merged by this work; no release/deploy/GO; no live or paid inference; no privileged host changes; no product contract changes; no complete-AC4 conformance claim. Pre-existing symlink-following reads in #78 native-only synthetic cells (whose in-boundary worker is the repository's own deterministic script) are recorded as an owner-decision residual outside this delivery's authorized scope.

Refs: #53, #78, #50, #79, #80.

## Summary Bounded #53 continuation (owner directive): prove that the **actual Codex app-server and its native tool paths** run inside the exact #78 rootless OCI worker boundary, with enforcement **independent of Codex approval callbacks** — followed by owner-directed security corrections of the collection trust boundary, the container-state lifecycle observation, and the shared worker-status reader. No synthetic worker substitutes for the harness; no `src/` product behavior changes; #50/#78 boundaries and evidence preserved. ## Native isolation proof (observed) `CREATIDY_TEST_OCI_TOOLROOT=/tmp/kilo/kernel78-tooling make codex-oci-proof` — observed 2026-10-10 at the delivered HEAD 9466187: **22 items passed, 0 failed, 0 native skips** (11 native cells + 7 host-side collection-safety cells + 4 host-side lifecycle-observation cells; skips are explicit UNPROVED without the pinned toolroot/binary). The fail-closed worker-status reader is gated by 3 further host-side cells under `make oci-worker-proof` (29 passed there, #78 regression included). 1. Real codex-cli **0.159.3** app-server startup, `initialize` handshake (production `CodexStdio` transport via a generated per-attempt wrapper), `thread/start`/`turn/start`/`turn/completed` inside OCI; native rollout JSONL in a fresh synthetic `CODEX_HOME`. 2. Genuine native `exec_command` tool op reading and modifying only the disposable candidate workspace; read-only rootfs write refused (`Read-only file system` observed in-boundary). 3. Native terminal via **two** channels — model-driven `exec_command` PTY and direct `command/exec` (no thread) — plus `setsid` detached descendant; `turn/interrupt` is not settlement; `podman stop` settles the tree (host `/proc` scan); bystander survives. 4. Forbidden host FS/network denied **with `approvalPolicy: "never"` + `sandbox: "danger-full-access"`** (recorded verbatim in evidence) — enforcement comes from the boundary, not native approvals or Codex's own sandbox. 5. Controller-owned interrupt/expiry/termination/settlement (graceful and grace-0 stops). 6. New unauthorized external operations refused after expiry/revocation: relay refusals (replay, mid-run revocation, expiry, unknown grant) and controller-level `AttemptExpired` for `turn/start`/`command/exec`. 7. Recovery: monitor SIGKILL → terminality unknown (requests fail closed) → reconciled by observation; dropped relay reply = `executed` at relay, `reply_lost` at worker (receipt log is truth). 8. **Fail-closed** post-settlement collection with independent digest verification — plus the in-flight-writes cell (bytes persist, never roll back; stream bounded by termination). ## Security corrections (owner-directed) **Collection trust boundary (symlink-following collector).** The original collector traversed the worker-controlled workspace with `rglob`/`is_file`/`stat` — a worker-created symlink to a host path could cause an unauthorized host-side read during collection. Reproduced safely with synthetic files, remediated fail-closed (`tools/codex_oci_proof/collect.py`): authorized candidate roots only; regular-file-only; symlinks refused in every component; descriptor-pinned single-component lookups with `fstat` on the exact descriptor read; `O_NONBLOCK`; bounded reads/entries/depth; refusals as recorded failures. Publishable artifacts (only from `candidate/`) have exact bytes preserved and digest-bound under the controller-owned `collected/` tree; private runtime state is inventoried separately. Native regression: worker-side symlinks refused by name with the prohibited host target never opened; no worker-controlled path is kernel-resolved after enumeration anywhere in the delivery. **Container-state lifecycle observation.** The shared observer mapped every nonzero `podman container exists` exit to "absent", conflating confirmed absence (exit 1) with podman 125-style engine/storage errors, timeouts and lost observations. It now returns a typed outcome — `exists` (0) / `absent` (1, confirmed) / `unknown` (everything else) — and all callers are reconciled: `CodexAttempt.collect()` authorizes **only** on confirmed absent (unknown is a typed refusal); `dispose()` terminates on every non-absent observation; #78 harness callers follow the same rule. Deterministic synthetic cells cover exit codes 0, 1, 125, other nonzeros, timeout and lost observation, and prove code 125 can neither authorize collection nor count as settlement. **Worker-status reader.** The #78 harness `worker_status()` read its worker-controlled status path with symlink-following primitives. The bounded-regular reader was extracted into the #78 package (`tools/oci_worker_poc/saferead.py` — dependency direction preserved: the #78 harness imports only its own package; the #53 collector re-exports the same primitives) and `worker_status()` now routes through it: a planted symlink is refused before any open, non-regular replacements and oversized files raise, absence stays truthful, malformed JSON raises. Regression cells prove a worker-created symlink cannot cause `worker_status()` to read a host-only JSON file. ## Versions / provenance Codex `0.159.3` standalone musl (hash-pinned, mounted read-only, fresh synthetic `CODEX_HOME`, owner Codex state never read); podman 6.1.3 / crun 1.30.1 / conmon 2.2.1 / busybox from the #78 toolroot `provenance.json`; deterministic controller-built image; protocol inventory generated by the pinned binary. Isolation policy flags flag-for-flag identical to #78; cgroup budget larger by design (disclosed). Seccomp: identical deny set, `clone3` ENOSYS instead of EPERM (upstream practice; review-verified) — compatibility correction, not a weakening. ## Dispositions for the five #78 limitations [docs/architecture/codex-oci-native-proof.md](docs/architecture/codex-oci-native-proof.md): seccomp clone-flags residual **UNPROVEN (named owner decision)**; settlement **REMEDIATED** (authoritative container lifecycle + non-cooperative argv markers); instantaneous FD revocation **unsupported by design, recorded as fact**; single-UID mapping **unchanged (deployment prerequisite)**; relay↔durable-authority integration **named remaining work**. ## Gates (all at delivered HEAD 9466187) `make check` (1428 passed / 85 skipped / 81 subtests; secrets clean; `git diff --check` clean), `make package-check`, `make audit` (clean), `make oci-worker-proof` (29 passed), `make codex-oci-proof` (22 passed). Canonical CI **#2414 SUCCESS on exact HEAD 9466187** (2407–2412 success on prior commits). ## Review status (owner exception: budget 10 → 12; 11/12 consumed; ordinal 12 unused) All ten pre-exception ordinals preserved (1–3 COMMENT remediated; 4 APPROVE at 7e2a021; 5–8 COMMENT on each security HEAD with the trust findings independently confirmed resolved; 9 APPROVE at 7aad45e; 10 REQUEST_CHANGES with two non-blocking P3s). Under the owner exception: - **Ordinal 11 (9466187/73e3af4): APPROVE, findings[] empty** — all three owner-directed trust-boundary findings independently confirmed genuinely resolved (collector; container-state observation; worker-status reader with dependency direction preserved); receipt inventory matches the delivered test inventory exactly (22 = 11+7+4, plus 3 worker-status cells); sanitized gates reproduced exactly (1428/85, package-check PASS); canonical CI #2414 SUCCESS on the exact reviewed HEAD verified via Forgejo MCP. - Ordinal 12 was **not consumed** (directive: do not consume unnecessarily). ## Non-goals #53 stays **open and gated**; not merged by this work; no release/deploy/GO; no live or paid inference; no privileged host changes; no product contract changes; no complete-AC4 conformance claim. Pre-existing symlink-following reads in #78 native-only synthetic cells (whose in-boundary worker is the repository's own deterministic script) are recorded as an owner-decision residual outside this delivery's authorized scope. Refs: #53, #78, #50, #79, #80.
feat: prove real Codex app-server native paths inside the #78 OCI boundary (#53)
All checks were successful
ci / check (pull_request) Successful in 2m24s
359c63222a
Bounded #53 slice: launch the real, version-pinned codex-cli 0.159.3
app-server inside the exact #78 rootless OCI worker boundary, drive it
through its native app-server protocol (handshake, thread/turn lifecycle,
model-driven exec_command, direct command/exec terminal) against a
controller-authored synthetic Responses backend (offline, loopback-only,
no paid inference), and record per-path evidence for the eight required
proof points plus the in-flight-effects cell.

- tools/codex_oci_proof/: pinned binary resolution + schema-derived
  protocol inventory, in-boundary launcher and synthetic model backend,
  controller boundary/profile/wrapper reusing the #78 toolroot and
  profile policy, deterministic codex-worker image, attempt driver over
  the production CodexStdio transport.
- tests/test_codex_oci_isolation.py: native reception (UNPROVED skips
  without the pinned toolroot/binary, never synthetic passes), including
  approval-independent denials (thread created with approvalPolicy never
  + danger-full-access so only the boundary enforces), relay expiry/
  revocation refusals, monitor-loss reconciliation, settlement with
  bystander preservation, and immutable collection with independent
  digest verification.
- seccomp correction recorded in the decision record: clone3 returns
  ENOSYS (upstream OCI practice) instead of EPROV-style EPERM so glibc
  pthread_create can fall back to clone; the syscall remains denied.
- docs/architecture/codex-oci-native-proof.md: bounded verdict, exact
  provenance, per-proof observations, dispositions for the five carried
  #78 limitations, and the named residuals for full #53 reception.
- Makefile: codex-oci-proof native target alongside oci-worker-proof.

No src/ product behavior changed; #50/#78 boundaries and evidence are
preserved. #53 stays open and gated.
fix: address ordinal-1 review precision findings (#53)
All checks were successful
ci / check (pull_request) Successful in 2m23s
b1bca99e00
- Tighten the rootfs-write denial assertion to the observed EROFS text
  (drop the bare rc=1 disjunct) and reword the comment to claim only the
  observed refusal output; the container is gone post-run, so /bin state
  is asserted in-boundary only.
- Replace the tautological pre-stop state assertion in the recovery cell
  with the intent it documented; the post-reconciliation state assertion
  already carries the cell.
- Disclose the cgroup budget (pids 256 / 1 GiB / 1.0 cpu vs #78 synthetic
  64 / 256 MiB / 0.5) in the decision record as a deliberate, disclosed
  delta; isolation policy flags remain flag-for-flag identical.

Remediation for review ordinal 1 (COMMENT, 3 P3, no blocking findings):
frozen HEAD 359c63222a, base
73e3af45c9. No gate weakened; native suite
re-run 10/10 after remediation.
fix: address ordinal-2 review accuracy/coverage findings (#53)
All checks were successful
ci / check (pull_request) Successful in 2m19s
e52904c2e0
- Correct the mock-model docstring: the scenario is controller-authored
  and written into the disposable writable workspace before launch; the
  read-only mount covers only the module source. No enforcement or test
  outcome depended on the earlier wording.
- Replace the committed real host-home path with a synthetic unmounted
  probe path so the host-home denial cell is host-independent and
  carries no real username.
- Assert the doc-claimed closure facts in the committed lifecycle cell:
  the in-boundary environment is exactly the controller allowlist plus
  the four runtime-injected container basics, and the cgroup bounds
  travel with the attempt (256 pids / 1 GiB observed in-container).

Remediation for review ordinal 2 (COMMENT, 3 P3, no blocking findings):
frozen HEAD b1bca99e00, base
73e3af45c9. Native suite re-run 10/10
after remediation; no gate weakened.
fix: address ordinal-3 review coverage/accuracy findings (#53)
All checks were successful
ci / check (pull_request) Successful in 2m24s
7e2a02135b
- Assert the mount-allowlist and single-UID properties the decision
  record cites in the committed lifecycle cell: uid_map maps container
  root 1:1 (size-1 range), and no mount point lies at or under a
  FORBIDDEN_BIND_PREFIXES prefix except the controller-issued synthetic
  HOME tmpfs at /home/worker — parsed by mount point, since substring
  matching false-positives on that intended tmpfs.
- Correct the resource-budget comment: tighter-limit denial cells live
  in the #78 record; every codex Attempt in this slice runs the single
  default budget (per-attempt override available, none tighter here).

Remediation for review ordinal 3 (COMMENT, 2 P3, no blocking findings):
frozen HEAD e52904c2e0, base
73e3af45c9. Native suite re-run 10/10
after remediation; no gate weakened.
security: fail-closed worker-controlled collection in the codex OCI proof (#53)
All checks were successful
ci / check (pull_request) Successful in 2m19s
dcf321d3d6
Owner-directed trust-boundary correction. The previous post-settlement
collector traversed the worker-controlled workspace with Path.rglob /
is_file / stat / read — all symlink-following — so a worker-created
symlink to a host path (invisible inside OCI, readable to the
controller) caused an unauthorized host-side read during collection.
Reproduced safely before remediation with synthetic files only: a
workspace symlink to a synthetic host-only file was collected with the
target's digest.

Delivered fail-closed collection (tools/codex_oci_proof/collect.py):
- explicitly authorized candidate roots only; publication draws
  exclusively from the controller-declared candidate/ root
- regular-file-only inputs; symbolic links refused in every component
  (lstat classification plus O_NOFOLLOW / O_DIRECTORY opens, so a
  mid-traversal swap to a symlink fails closed with ELOOP)
- descriptor-pinned single-component lookups; fstat validation on the
  exact descriptor read — no path-validation/open race
- bounded reads (8 MiB/file) and entry budget (4096); refusals recorded
  with reasons and never silently skipped
- publishable candidate artifacts are exact-bytes-preserved under the
  controller-owned collected/ tree and digest-bound to each record (a
  collected artifact snapshot, not a bare digest manifest); private
  Codex runtime state (codex-home incl. sessions, mock records, attempt
  spec, launcher observations) is inventoried separately under
  controller authority and never published
- the launcher-observations reader is routed through the same safe
  bounded reader (worker can replace or symlink that file post-launch)
- collection refuses to run before observed container settlement

Native regression: worker-side symlinks to a host-only secret, runtime
state, self-links, dangling links and symlinked directory components are
refused by name; the prohibited host target is never opened (its digest
absent from every record; no preserved bytes). Host-side TestCollectionSafety
gates the same collector in every make check without the toolroot.

Evidence record updated; real Codex/OCI proof, architecture, branch,
commits and review history preserved. Gates at this commit: make check
1419/85, package-check, audit clean, oci-worker-proof 26, codex-oci-proof
16 (incl. the new native symlink-regression cell).
security: close ordinal-5 review hardening findings (#53)
All checks were successful
ci / check (pull_request) Successful in 2m28s
3c2a2e96b6
- O_NONBLOCK on every fail-closed open (collector file opens and the
  bounded regular reader): a live racer swapping a workspace entry to a
  FIFO can no longer block the controller's open; post-open fstat
  S_ISREG still refuses non-regular objects, and O_NONBLOCK is a no-op
  for regular reads.
- worker_observations now distinguishes absence (pre-exec launcher never
  ran: {}) from tampering (planted symlink, non-regular replacement,
  oversized file: raises) so evidence fidelity cannot mask worker
  tampering as absence.
- All test-side reads of worker-controlled workspace/codex-home paths
  routed through the same trust boundary as collection: a fail-closed
  bounded reader for fixed paths, collector-based discovery plus bounded
  reads for session rollouts, and lstat-based existence/size checks so
  planted symlinks never count and targets are never followed.

Remediation for review ordinal 5 (COMMENT: trust-boundary finding
confirmed resolved; 2 non-blocking P3): frozen HEAD
dcf321d3d6, base
73e3af45c9. Gates at this commit: make
check 1419/85, package-check, audit clean, codex-oci-proof 16,
oci-worker-proof 26; native suite re-run 16/16 after remediation.
security: bound traversal depth, directory budget and read-limit accuracy (#53)
All checks were successful
ci / check (pull_request) Successful in 2m25s
03d623817e
Closes the two ordinal-6 accuracy findings in the fail-closed collector:
- read_bounded_fd (promoted from _read_bounded) threads the caller's
  declared limit into the read loop, so a file that grows after fstat —
  the concurrent-growth race on a live worker's file — is refused at the
  declared bound instead of silently over-reading up to the 8 MiB cap;
  host-side cell covers the growth race directly.
- traversal work is now bounded, not just output: streamed scandir
  entries (no full-listing materialization), every descended directory
  spends entry budget, and depth is capped (MAX_DEPTH 32) with explicit
  max-depth-exceeded refusals; host-side cells cover a beyond-cap
  directory chain and a directory-heavy tree exhausting the budget.

Both findings were fail-closed already (no unauthorized read, no false
pass); these fixes make the bounds match their claims. Gates at this
commit: make check 1421/85 (two added safety cells), codex-oci-proof 18
(16 + 2), package-check, audit clean; basedpyright/ruff clean.

Remediation for review ordinal 6 (COMMENT, 2 P3, no blocking findings):
frozen HEAD 3c2a2e96b6, base
73e3af45c9.
fix: pin rollout evidence reads to collector sinks; refresh recorded receipts (#53)
All checks were successful
ci / check (pull_request) Successful in 2m25s
ba078f95ce
Closes the two ordinal-7 findings:
- _rollout_texts now captures native session rollout bytes through the
  collector's sink in the same fd-pinned pass that enumerates them — no
  path is ever re-resolved by the kernel after enumeration, closing the
  intermediate-component swap-race window against a live worker.
- Decision record receipt refreshed at the delivered HEAD: 18 items
  (11 native cells incl. the remediated symlink-refusal/hardened-
  collection cells + 7 host-side safety cells), 0 failed, 0 skips,
  observed via make codex-oci-proof; make check 1421/86, package-check,
  audit clean, oci-worker-proof 26 all re-run at this content.

Remediation for review ordinal 7 (COMMENT, 2 P3, no blocking findings):
frozen HEAD 03d623817e, base
73e3af45c9.
fix: read the in-container digest from the sink-preserved copy (#53)
All checks were successful
ci / check (pull_request) Successful in 2m24s
7aad45e8d7
Closes the ordinal-8 finding: the collection cell's digest cross-check
read the worker-controlled multi-component path
candidate/candidate.sha256 through the kernel (read_bounded_regular
defends only the final component). The digest is now read from the
collector's sink-preserved copy under the controller-owned collected/
tree — captured through pinned descriptors in the same pass that
enumerated it, so no worker-controlled path component is ever resolved
by the kernel after enumeration, anywhere in the delivery.

Gates at this commit: make check 1421/85, codex-oci-proof 18,
package-check, audit clean, oci-worker-proof 26.

Remediation for review ordinal 8 (COMMENT, 1 P3, no blocking findings):
frozen HEAD ba078f95ce, base
73e3af45c9.
security: fail-closed container-state observation (exists/absent/unknown) (#53)
All checks were successful
ci / check (pull_request) Successful in 2m19s
a494e2328b
Owner-directed lifecycle correction. The shared observer mapped every
nonzero 'podman container exists' exit code to 'absent', conflating
confirmed absence (exit 1) with podman 125-style engine/storage/access
errors, timeouts and lost observations — so CodexAttempt.collect() could
authorize artifact collection while container state was actually
unknown, and dispose() could skip owned-container termination after a
failed state query.

- harness.container_state now returns a typed outcome: exists (exit 0),
  absent (exit 1, confirmed), unknown (any other code, timeout, or
  lost/unavailable observation). Unknown never collapses into a
  confirmed state.
- CodexAttempt.collect() authorizes only on confirmed absent: an
  unknown observation is a typed refusal naming the observed state and
  can never be silently treated as settlement.
- CodexAttempt.dispose() treats every non-absent observation as
  requiring bounded termination of the owned container; only confirmed
  absence justifies skipping it.
- #78 synthetic harness callers reconciled: AttemptRunner.dispose_all
  stops on exists-or-unknown (skip only on confirmed absent); the
  monitor-death cell accepts unknown as an inconclusive pre-stop
  observation while still requiring confirmed absence after
  reconciliation.
- #53 recovery cell reconciled to the same rule.
- Deterministic synthetic regression cells (host-side, no podman):
  exit codes 0, 1, 125, other nonzeros and -9, TimeoutExpired and
  OSError (lost observation/unavailable storage) map correctly; a
  probe attempt proves code 125 (and exists) cannot authorize
  collection and that unknown triggers bounded termination in dispose
  while confirmed absence is the only skip justification.

The no-symlink-following collector, preserved artifact copies and all
prior native evidence are unchanged. Gates at this commit: make check
1425/85 (4 new synthetic cells), package-check, audit clean,
codex-oci-proof 22, oci-worker-proof 26.

Remediation for owner directive 2026-10-10; review ordinal 10/10 is the
next and final whole-PR review for this delivery.
security: fail-closed worker_status read; refresh decision-record receipt (#53)
All checks were successful
ci / check (pull_request) Successful in 2m24s
9466187eed
Resolves the two ordinal-10 findings under the owner's one-time review-
budget exception (10 → 12 maximum, this delivery only):

- Extract the shared bounded-regular reader into
  tools/oci_worker_poc/saferead.py (read_bounded_regular /
  read_bounded_fd) so the #78 harness and the #53 collector share one
  implementation without a reverse dependency: the #78 harness imports
  only from its own package; the #53 collector re-exports the same
  primitives. harness.worker_status() now reads its worker-controlled
  path through this primitive — a planted symlink is refused before any
  open, non-regular replacements and oversized files raise, absence
  stays truthful ({'observed': False}), malformed JSON raises
  JSONDecodeError — never masked as absence.
- Deterministic host-side regression cells (TestWorkerStatusFailClosed):
  a worker-created symlink cannot cause worker_status() to read a
  host-only JSON file (refused before open; target bytes unchanged),
  plus absence, malformed-content, valid-content and oversize cells.
- Decision-record receipt refreshed to the actual executed inventory at
  the delivered HEAD: codex-oci-proof 22 items (11 native + 7
  collection-safety + 4 lifecycle-observation cells), plus the 3
  worker-status cells under oci-worker-proof.

Gates at this commit: make check 1428/85, package-check, audit clean,
codex-oci-proof 22, oci-worker-proof 29. Review ordinal 11/12 is the
next whole-PR review under the owner exception.
adrian.tkacz deleted branch issue-53-codex-oci-worker-proof 2026-10-10 01:18:29 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Creatidy/creatidy-kernel!84
No description provided.