Repository navigation
feat: forward Linux CPU quota events through v2.2 stream - #68
Merged
Merged
Conversation
Add a test asserting that a stream whose journal records a CPU quota termination cause emits a LimitHit event ahead of the Exited event, so the ordering of terminal events stays pinned. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a TerminationCause enum and an ExecutionObserver hook so backends can report resource-limit terminations backed by runtime evidence rather than inferring them from exit codes. The tinybus module records CPU quota hits and now derives terminal process events from a single helper, which also lets it emit a limit event alongside the exit status. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Re-export the TerminationCause type alongside the other runtime types so callers can inspect why a sandbox execution ended without reaching into the runtime module directly. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The jailed host now creates a private event file under the runtime directory and passes it to the sandboxed command, then reads the throttling counter after the process exits. When throttling is observed, the execution observer is notified with a CpuQuota termination cause so callers can distinguish quota exhaustion from other failures. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The launcher now wraps the workload in a small shell script that runs it, then copies the transient scope's cpu.stat into the internal report file before exiting. This captures CPU event counters from inside the scope, which would otherwise be lost once systemd stops the unit. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added a regression test asserting that the cpu.stat throttling counter is only parsed from a single well-formed nr_throttled line, and tightened the native jail command test to locate bubblewrap directly and check that the CPU event file and cpu.stat are passed through. Also reformatted a few expressions for rustfmt consistency. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The native jail test now checks that the argv contains the configured command path instead of searching for a bubblewrap binary, matching the command the sandbox actually builds. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Document that scoped cgroup-v2 CPU quota throttling now emits `LimitHit { limit: Cpu }` before the exit event, clarifying that it reports throttling rather than CPU exhaustion or process failure.
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the native jail command test to check for the CPU event scope wrapper constant instead of the hardcoded /bin/true path, keeping the assertion in sync with the wrapper the sandbox now injects. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the native jail command test to check for the cpu.stat argument instead of the CPU event scope wrapper, matching the current command construction. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The native jail command test no longer expects cpu.stat in the argv, since the command no longer passes it through. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The native jail command test now checks for the CPU event file environment variable using a substring match instead of an exact argument comparison, since the variable is passed as part of a larger argument rather than as a standalone token. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the assertion that checks for the internal CPU event file variable in the native jail command test so it matches rustfmt's line-breaking. No test behaviour changed. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The assertion now checks whether any argv entry contains "cpu.stat" rather than requiring an exact match, so the test still passes when the path is embedded in a longer argument. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Moved the CPU event report setup and termination reporting in the jailed host into small helper functions so the execution path reads more clearly. Behaviour is unchanged. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Move the process group, stdio, and environment configuration for the jailed command into a dedicated configure_jail_command function so the spawn path stays readable and the setup can be reused. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test no longer returns a Result since it contains no fallible operations, so the signature and trailing Ok(()) were removed to match. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Split the XDG_RUNTIME_DIR lookup out of CpuEventReport::prepare so the runtime directory can be injected, letting tests exercise the eligibility and report lifecycle logic against a temporary directory. Added a Linux test covering both the eligible scope and the unmetered case. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added an eprintln in the jailed test to print the command arguments, runtime path, and runtime metadata, making it easier to diagnose why the eligible scope check fails. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now sets the temporary runtime directory to mode 0700 before invoking systemd-run, and drops a leftover debug eprintln that printed the command arguments and directory metadata. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reordered the import so the test's setup reads in the order it executes, with the permissions trait imported before the temporary runtime directory is created. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
…vent report Canonicalize the runtime directory and require it to live under /run/ before creating a report, so paths that escape the expected location are refused. The test now asserts that an unmasked runtime path yields no report and no environment handoff. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The jailed test now also exercises the positive case where the runtime directory lives under a masked /run path, asserting the report is created, handed to the wrapper, and cleaned up on drop. The custom-path rejection case is kept alongside it, and the positive case is skipped when the environment does not provide a suitable XDG_RUNTIME_DIR. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reset the environment in the CPU event report test before spawning the unmetered systemd-run command, so leftover variables from the earlier masked run cannot influence the second half of the test. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds a test asserting that an observer can be handed a proven CPU quota termination cause, guarding the path that reports quota-driven termination to observers. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The default `termination_cause` implementation now passes the cause through `std::hint::black_box` so the parameter is considered used, avoiding an unused-variable warning without changing behaviour. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Mark the default termination_cause implementation as inline(never) so it stays a distinct frame in profiles and backtraces, making it easier to attribute provider-proven terminations during execution. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now binds the observer as a `&dyn ExecutionObserver` before calling `termination_cause`, so the call goes through the trait object rather than the concrete type. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
…c api Move the observer termination-cause check out of the internal runtime tests and into the public API suite, where it now exercises ExecutionObserver and TerminationCause as exported types. The new test also implements the observer trait directly, so the public trait surface is verified to be implementable outside the crate. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
ExecutionObserver::termination_cause now returns a bool indicating whether the observer recorded the cause, defaulting to false. OutputJournal reports true for CPU quota causes so callers can tell when the signal was consumed. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The ExecutionObserver trait now requires termination_cause instead of providing a default that returned false, so observers must explicitly handle proven termination causes rather than silently ignoring them. Callers no longer receive a boolean result, since the return value was only used to signal whether the cause was recorded. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a termination_cause method to the ExecutionObserver trait so observers can be told why an execution ended. The Docker and SSH observers forward the cause to their inner observers, and test observers implement the new method as a no-op. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Implement the new ExecutionObserver::termination_cause method on the mock and test observers across the docker, host, and ssh crates so the fixtures continue to satisfy the trait after the method was added. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `ExecutionObserver::termination_cause` method now has an empty default body, so implementors that don't care about termination causes no longer need to write a stub. All the redundant stubs across the test fixtures were removed, and a test was added to confirm the default implementation accepts a proven CPU quota cause. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Relocated the ExecutionObserver trait from the output module to the types module so it sits alongside the other runtime type definitions, and updated the re-exports accordingly. The trait's behaviour is unchanged. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Wire the existing output tests into the runtime types module and add a case asserting that the default observer accepts a provider-reported termination cause. This guards the observer contract against regressions. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test duplicated the coverage already provided by the default observer test above it, so it was dropped to keep the suite free of redundant cases. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now constructs DefaultTerminationObserver instead of the removed Observer unit struct and asserts that stdout output is accepted, covering the default observer's output path alongside termination causes. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Relocated the ExecutionObserver trait from the types module into the output module so it sits alongside the output stream and termination cause types it depends on. The public re-export is unchanged, so callers see no behavioural difference. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
Extend the capturing observer to record termination causes and add a test asserting that the Docker execution observer forwards a provider-reported cause to the inner observer. Auto-committed-on: cuttlefish Co-authored-by: Medulla <medulla@tinyhumans.ai>
This was referenced Oct 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Forward positive Linux cgroup-v2 CPU quota throttling evidence into the TinyBox v2.2 process-event stream. The native launcher samples
cpu.statinside its trusted transient systemd scope before teardown; a positivenr_throttledcounter is reported asLimitHit { limit: Cpu }beforeExited. This indicates quota throttling, not CPU exhaustion or process failure. Existing timeout ordering stays unchanged.Execution observers have a default no-op termination-cause hook for source compatibility, and observer wrappers forward it. The output journal carries the cause into the terminal event sequence. TinyBus v2.2 already defines the needed event and limit kind, so there is no TinyBus API or gitlink change.
The report file is created only under a private XDG runtime directory canonicalized beneath
/run. The target scope masks/run; accepting a custom or untrusted path would let the workload tamper with the handoff report before the host reads it. Regression coverage rejects custom paths and accepts the masked/runlocation.Red-first regression:
cpu_quota_observer_cause_is_forwarded_before_process_exitinitially failed to compile becauseTerminationCause, the observer callback, and terminal event forwarding did not exist. It passes after the implementation.Validation:
cargo fmt --all -- --checkcargo clippy --locked -p tinybox-core -p tinybox-host -p tinybox-linux -p tinybox-module --all-targets --all-features -- -D warningscargo llvm-cov --locked -p tinybox-core -p tinybox-host -p tinybox-linux -p tinybox-module --all-targets --all-features --json --output-path target/focused-coverage.json(all selected tests pass)runtime/output.rs100.00% (6/6);limited/jailed.rs91.24% (604/662);sandbox/args.rs92.04% (497/540);tinybus_module/mod.rs93.53% (477/510);tinybus_module/output.rs98.41% (124/126);tinybus_module/resources_stream.rs94.35% (701/743).Part of #27
Part of senamakel/openhuman#8369