Skip to content

fix: stop shipping a stale silkd, and unbreak the Python stdio paths - #84

Closed
CMGS wants to merge 2 commits into
codex/close-repo-reviewfrom
fix/ship-and-sdk-gaps
Closed

fix: stop shipping a stale silkd, and unbreak the Python stdio paths#84
CMGS wants to merge 2 commits into
codex/close-repo-reviewfrom
fix/ship-and-sdk-gaps

Conversation

@CMGS

@CMGS CMGS commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Stacked on #81. Five defects found by a whole-repo scan; none are introduced by that PR.

Ship-path

  • build-flavors never passed SILKD_IMAGE. Only build-base resolved it, so os-image/android/15/Dockerfile's ARG SILKD_IMAGE=…/silkd:0.1.0 default won every flavor rebuild — including rebuilds triggered because silkd changed. android has been shipping silkd 0.1.0 while the crate is at 0.1.5. The job now reads the version exactly as build-base does and honours the sha-pinned inputs.silkd_image on a changed-carrier run.
  • silkd/Dockerfile built without --locked (boot/init has it): a Cargo.toml bump without a matching cargo update would resolve and ship un-reviewed dependency versions into the guest binary.
  • boot/init had no PR gate. Its fmt/clippy/test only ran via images.yml on a push to main, so a PR could not fail on sandbox-init — PID 1 in every guest. New boot-init.yml mirrors silkd.yml.

Python SDK

  • run() deadlocked on large stdin. It sent every stdin chunk and stdin_close before reading any output. A guest that writes while reading blocks once its stdout buffer fills, stops draining stdin, and the SDK blocks forever in sendall — with no socket timeout. Go pumps stdin concurrently (go pumpStdin); Python now does the same. The regression test drives a conn whose send blocks until output is read: it fails with stdin send deadlocked against the old implementation.
  • proxy_port leaked a relay connection per stream. The happy path closed only the local socket, so every proxied TCP connection leaked the guest side until release. guest.close() moves to a finally. The OpenAI adapter inherited this leak.
  • kill(pid, 0) meant the opposite of Go's. encode_request drops only None, so an explicit 0 went on the wire and silkd's unwrap_or(SIGKILL) kept it — signal 0 is a POSIX existence probe, i.e. a no-op. Go maps sig == 0 to unset → SIGKILL.

Validation

  • ruff check clean; pytest 152 passed (151 + the new deadlock test)
  • mutation-tested: reverting the run() fix makes the new test fail as designed
  • make go-lint 0 issues, go test -race green across modules (unchanged by this PR)

CMGS added 2 commits August 14, 2026 03:10
The flavor build never passed SILKD_IMAGE, so android baked in whatever the
Dockerfile ARG defaulted to (silkd 0.1.0) on every rebuild, including rebuilds
triggered by a silkd change - the chain's whole purpose. It now resolves the
version the same way the base build does. silkd's own image built without
--locked, so a Cargo.toml bump could ship dependencies no one reviewed.
sandbox-init had no PR gate at all: its suite ran only after a push to main.

Python run() fed stdin to completion before reading a byte of output, so any
payload past the socket buffers deadlocked against a guest that had stopped
draining stdin - it now pumps stdin on its own thread, pinned by a test that
deadlocks on the old code. proxy_port leaked the relay connection on every
proxied stream, and kill(pid, 0) sent signal 0 (a POSIX existence probe, a
no-op) where Go sends SIGKILL.
@CMGS

CMGS commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Squash-merged into main as 8f615d5 (branch was stacked on #81, so only its own commits were cherry-picked). CI was green on the branch after the ruff SIM102 fold; ruff check and pytest (153) re-verified on main.

@CMGS CMGS closed this Aug 13, 2026
@CMGS
CMGS deleted the fix/ship-and-sdk-gaps branch August 13, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant