Skip to content

feat(supervisor): record launch and exit of sandbox sessions - #5252

Draft
krishicks wants to merge 1 commit into
feat/4268-network-event-process/krishicksfrom
feat/4268-session-process-events/krishicks
Draft

krishicks wants to merge 1 commit into
feat/4268-network-event-process/krishicksfrom
feat/4268-session-process-events/krishicks

Conversation

@krishicks

@krishicks krishicks commented Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The entrypoint's launch reached only the sandbox container's stdout, and no process the runtime started had an exit event. The runtime now keeps a bounded log of the launches and exits of the entrypoint and each exec or SSH session, and the supervisor emits them as OCSF Process Activity.

Second of a stack of four for #4268 (based on #5251):

  1. feat(supervisor): identify the process behind each network event #5251 Identify the process behind each network event
  2. feat(supervisor): record launch and exit of sandbox sessions #5252 This PR: record launch and exit of sandbox sessions
  3. feat(supervisor): record each exec in the workload and its exit #5253 Record each exec in the workload and its exit
  4. feat(supervisor): record the command line of each process #5254 Record the command line of each process

Related Issue

Refs #4268

Changes

  • The runtime records the launch and exit of every process it spawns and reaps (entrypoint, exec and SSH sessions) in a bounded, sequence-numbered log.
  • New ReadProcessEvents long-poll RPC on the sandbox protocol (capability openshell.sandbox.process-events): sequence cursor, size-capped responses, and a count of events no longer retained.
  • The supervisor reads it for the life of the boundary and emits Process Activity Launch (pid, start time, parent) and Terminate (exit code; 128 + signal for signal exits).
  • Each event keeps the runtime's observation time and a deterministic metadata.uid derived from the process instance, so a replacement supervisor's re-read produces duplicates that consumers can drop.

Before: no Process Activity in the supervisor's OCSF output.

After:

PROC:LAUNCH    [INFO] /usr/bin/bash(78)
NET:OPEN       [INFO] ALLOWED /usr/bin/bash(82) -> example.com:443 [policy:demo engine:opa]
PROC:TERMINATE [INFO] /usr/bin/bash(78) [exit:0]
PROC:LAUNCH    [INFO] /usr/bin/bash(91)
PROC:TERMINATE [INFO] /usr/bin/bash(91) [exit:3]
PROC:LAUNCH    [INFO] /usr/bin/bash(93)
PROC:TERMINATE [INFO] /usr/bin/bash(93) [exit:137]
{"activity_name":"Terminate","message":"Process exited: pid=93 signal=9","exit_code":137,"process":{"name":"/usr/bin/bash","pid":93,"created_time":1793758508670,"parent_pid":1},"actor":{"name":"openshell-sandbox","pid":1}}

The network actor (pid 82, parent 78) joins to the session's Launch on pid + created_time.

Known limitations:

  • Terminate reports status: Success for any observed exit, including non-zero and signal exits, so filtering on status=Failure won't find crashed sessions. Use exit_code.
  • The runtime still writes its own entrypoint Launch to container stdout for older supervisors, so stdout collectors see two entrypoint Launches.
  • After a supervisor takeover the log is re-read; duplicates repeat metadata.uid and the original time.
  • There is no bounded drain at teardown; the final exit relies on the long poll waking first, which it does in practice.
  • created_time is within about 1 s of wall-clock time (btime has whole-second resolution). It is consistent across process and network events, so it still works as a join key.
  • A lost > 0 count is only a warning log here; PR 3 turns it into a record.

Testing

  • Lockfile checks, rust:format:check, and every CI clippy invocation (--locked, including perf-harness) pass on macOS and the aarch64 Linux target for this commit
  • Unit tests added/updated; sandbox, sandbox-backend, and supervisor suites pass in an Ubuntu 24.04 guest (kernel 6.8)
  • Manual end-to-end: gateway + Docker sandbox (kernel 7.0), before/after OCSF output above

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

The entrypoint's launch reached only the sandbox container's stdout, and
no process the runtime started had an exit event: the entrypoint's exit
code reached the gateway only as sandbox state, and an exec or SSH
session's status went only to its caller.

The runtime is the parent of the entrypoint and of each exec or SSH
session process and reaps each with its exact status, so it records their
launches and exits, with the time it observed them, in a bounded log with
sequence numbers. Runtimes that advertise openshell.sandbox.process-events
serve the log through ReadProcessEvents, a long poll with a sequence
cursor that caps each response by size and reports how many events it no
longer retains. The supervisor reads it for the life of the boundary and
emits OCSF Process Activity: Launch with the process's pid, start time,
and parent, and Terminate with its exit code, 128 plus the signal number
when a signal ended it. Each event keeps the time the runtime observed it
and a metadata.uid derived from the process instance, so a replacement
supervisor that reads the log again reports duplicates consumers can drop.

Terminate reports status Success for any observed exit, including non-zero
and signal exits. The runtime still writes its own entrypoint Launch to
stdout for supervisors that do not read the log.

Refs #4268

Signed-off-by: Kris Hicks <[email protected]>
@copy-pr-bot

copy-pr-bot Bot commented Nov 4, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown

This branch has not been deployed

No deployments
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