Skip to content

Add truthful sandbox constraint preflight and strict jail spawning - #28

Merged
senamakel merged 6 commits into
mainfrom
security-bus-7328
Oct 10, 2026
Merged

senamakel merged 6 commits into
mainfrom
security-bus-7328

Conversation

@senamakel

@senamakel senamakel commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Hosts can now inspect each sandbox constraint before execution and require complete enforcement. Strict preflight refuses unsupported or best-effort constraints. This implements the initial preflight portion of #27 and supports tinyhumansai/openhuman#7328.

Landlock reports filesystem-only confinement and rejects unsupported network/subprocess denials before spawning. Seatbelt launcher presence alone establishes no enforcement guarantee: restrictions are best effort and isolation is None. Docker, namespaces and MicroVMs report individual resource support instead of claiming complete resource-limit enforcement.

The new three-OS lane also exposed missing-child canonical-path bugs in jail registry deletion/spawning. The fix canonicalizes the trusted registry base and preserves legacy aliases without accepting corrupted suffix traversal. Spawning checks an existing canonical jail root once and passes that exact root to the backend; missing-path resolution is only used for cleanup or diagnostics. Registry parents must remain host-owned: this path-based API does not promise descriptor-atomic safety against independently privileged host writers. Tests now handle native directory-write error kinds and verify env_clear with a real inherited sentinel. Fixed the Unix-only import preventing Windows compilation, lowercase refusal labels, and pinned CI actions.

Validation: full all-feature suite passed (684 tests before the final Seatbelt followups; one preexisting ignored doctest), latest 107 jail tests and focused core tests pass, stable 1.99 strict Clippy, formatting, all-target Windows compilation, warning-denied rustdoc and >=90% coverage in every measured source file pass. Landlock, registry alias, lowercase-error and Seatbelt declaration regressions failed against the corresponding unfixed code. Hosted Linux/macOS/Windows jail jobs and all build jobs pass on the latest head. Automated re-review is pending. External Docker/SSH/MicroVM live suites remain environment gated.

Related PRs: tinyhumansai/tinysecurity#2 and tinyhumansai/openhuman#7331. OpenHuman remains a draft until the required upstream release and pin update.

Later backend/resource/network implementations, AppContainer, events, bus expansion and policy extraction remain tracked by #27. This PR does not close the tracker. OpenHuman must adopt the released upstream change before updating its gitlink.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

The change adds a truthful per-constraint preflight model to tinybox-core and wires it into the object-safe Sandbox trait and the tinybox-jail backends, downgrades several coarse resource-limit capability declarations, introduces strict spawn entry points for directory jails, and replaces lossy canonicalization in the jail registry with a failing-closed helper. CI now pins third-party actions to commit SHAs and adds a cross-platform jail test job. The prior critique and security lanes reported findings about registry canonicalization and test environment dependencies; the tests and description lanes judged those resolved. The evidence notes code retrieval and memory tooling were unavailable during review.

State: Changes requested
Priority: high
Reviewed head: 3e6e0be11a6a
Updated: 1791647657 (Unix time)

Review snapshot

Change surface Files Review signal Count
Production 14 Active findings 23
Tests 11 Noted findings 0
Documentation 4 Resolved findings 402
Configuration 1 Pending checks/questions 0

Completeness: Complete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

What changed

No supported behavioral explanation was produced.

Features

  • Added — Per-constraint preflight model in tinybox-core: Callers can inspect what a backend actually enforces per security boundary via plan_check (diagnostic, no execution) and refuse execution with a typed Error::ConstraintNotEnforced via require; unknown backends default to ConstraintSupport::NONE and best-effort support is never accepted as a hard requirement, so requests a backend cannot fully enforce fail before a workload starts. (crates/tinybox-core/src/constraint/mod.rs, crates/tinybox-core/src/lib.rs, crates/tinybox-core/src/error/mod.rs, docs/specs/constraint-preflight.md)
  • Modified — Sandbox trait gains constraint preflight hooks: The object-safe Sandbox trait gains defaulted constraint_support, plan_check, and require methods so implementations without explicit declarations are conservatively unsupported; callers must invoke require explicitly before create, since lifecycle methods do not automatically treat every BoxSpec resource field as a hard requirement, and backend setup failures must still propagate. (crates/tinybox-core/src/runtime/mod.rs)
  • Modified — Truthful per-constraint declarations across sandbox backends: DockerSandbox declares filesystem, network, cpu, memory, and pids enforced and drops the coarse resource-limit capability; NamespaceSandbox declares filesystem and network enforced with cpu/memory/pids only when cgroup limits are enabled; MicroVmSandbox declares filesystem and network enforced with cpu and memory best effort because hypervisor sizing rounds vCPUs and memory; no backend declares disk enforcement, so callers requiring all resource fields including default disk must expect refusal. (crates/tinybox-docker/src/sandbox/mod.rs, crates/tinybox-linux/src/sandbox/mod.rs, crates/tinybox-microvm/src/sandbox/mod.rs, docs/specs/constraint-preflight.md)
  • Modified — Coarse ResourceLimits capability retired in favor of per-constraint declarations: Docker, Namespaces, and MicroVM no longer declare the coarse ResourceLimits capability, documented as not implied by lifecycle capabilities; the README docker box description and the CLI inspection output drop the resource-limits claim, and namespace limits are documented as opt-in via with_cgroup_limits. (crates/tinybox-docker/src/sandbox/mod.rs, crates/tinybox-linux/src/sandbox/mod.rs, crates/tinybox-microvm/src/sandbox/mod.rs, README.md, docs/specs/constraint-preflight.md)
  • Added — Hard preflight and strict spawn entry points for directory jails: Jail derives its hard constraint list from grants and denial flags, and JailBackend exposes constraint_support, isolation, plan_check, require, and is_suitable_for_untrusted_code; spawn_required_with and spawn_required refuse partial or absent enforcement with io::ErrorKind::Unsupported before any child is spawned, while legacy spawn and spawn_with remain available as trusted, non-preflighted entry points. (crates/tinybox-jail/src/jail.rs, crates/tinybox-jail/src/lib.rs, crates/tinybox-jail/README.md)
  • Modified — Landlock backend refuses unsupported denial requests and probes both reads and writes: Landlock declares filesystem-only enforcement when available and its spawn path refuses network or subprocess denial requests before spawning rather than silently dropping them; the kernel support probe now handles both write and read access, and filesystem-only strict jails can spawn but the backend remains unsuitable for arbitrary untrusted code. (crates/tinybox-jail/src/linux.rs)
  • Modified — Seatbelt backend downgraded to best-effort with no isolation claim: Seatbelt now reports filesystem, network, and subprocess rules as best effort when the launcher is present, and isolation() returns None, because the launcher-presence check does not verify profile enforcement; strict preflight refuses Seatbelt denials while the legacy spawn path remains available, and the process-group wrapper is gated to unix targets. (crates/tinybox-jail/src/macos.rs, crates/tinybox-jail/README.md, docs/specs/constraint-preflight.md)
  • Modified — No-op backend repositioned as explicit trusted passthrough: The no-op backend is documented as an explicit trusted passthrough never selected automatically when OS enforcement is unavailable; it reports no isolation and no constraints, so hard preflight refuses it. (crates/tinybox-jail/src/noop.rs)
  • 2 additional supported feature(s) omitted by the configured limit.

Tests

  • unit — Constraint module tests iterate every constraint and enforcement level, asserting plan_check reports the declared pair and require accepts only Enforced while returning the typed ConstraintNotEnforced error for unsupported and best-effort, and that every constraint and enforcement has its lowercase operator label.: Directly pins the core preflight semantics and the user-facing label contract; a meaningful regression guard for the new model. (crates/tinybox-core/src/constraint/mod_tests.rs)
  • unit — Error tests assert that ConstraintNotEnforced renders as a lowercase user-facing message such as 'sandbox seatbelt cannot enforce filesystem: best effort'.: Covers the display formatting of the new error variant. (crates/tinybox-core/src/error/mod_tests.rs)
  • unit — Runtime trait-object test verifies an unknown sandbox reports ConstraintSupport::NONE, plan_check over all seven constraints, and require fails with ConstraintNotEnforced for each constraint through a &dyn Sandbox.: Pins the conservative default for trait objects, the key safety property of the defaulted trait methods. (crates/tinybox-core/src/runtime/mod_tests.rs)
  • unit — Backend preflight tests assert each backend's enforcement matrix, including Docker and namespaces declaring filesystem/network enforced, namespace cgroup-enabled cpu/memory/pids, MicroVM best-effort cpu/memory, and persistent disk/subprocess refusals.: Pins each backend's truthful declarations against the documented matrix. (crates/tinybox-docker/src/sandbox/mod_tests.rs, crates/tinybox-linux/src/sandbox/mod_tests.rs, crates/tinybox-microvm/src/sandbox/mod_tests.rs)
  • unit — Registry path tests cover canonicalize_missing for existing and missing components, rejection of parent traversal even inside the base, following existing but not dangling symlinks, non-directory ancestor errors, and registry-level tests for symlinked bases, corrupt suffix traversal, and legacy alias records.: Pins the failing-closed path resolution and traversal boundaries, addressing the earlier path-validation findings. (crates/tinybox-jail/src/registry_path_tests.rs, crates/tinybox-jail/src/registry_tests.rs)

Findings

  • high · critique · Make jail validation and spawn atomic — The directory is canonicalized and checked against `self.base`, then the resulting path is returned in a `Jail` for a later backend spawn. An attacker can replace the directory or (crates/tinybox\-jail/src/registry\.rs:475)
  • high · critique · Preserve the resource-limit capability declaration — The new `constraint_support` method declares CPU, memory, and PID constraints as enforced, but `declared_capabilities()` no longer advertises `ResourceLimits`. Callers that select (crates/tinybox\-docker/src/sandbox/mod\.rs:127)
  • high · critique · Preserve the resource-limit capability declaration — Removing `.with_resource_limits()` changes the public capability contract: callers that select or validate backends using the coarse resource-limit capability will now see this bac (crates/tinybox\-microvm/src/sandbox/mod\.rs:129)
  • high · critique · Preserve the resource-limit capability declaration — This changes the contract test to require that the microVM does not support resource limits. The surrounding test says the hypervisor gives the guest fixed vCPUs and fixed memory, (crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs:114)
  • high · critique · Make deletion atomic with path validation — `canonicalize_missing` verifies that the recorded path resolves under `self.base`, but the later deletion still uses the original path after that check. An attacker can rename the (crates/tinybox\-jail/src/registry\.rs:361)
  • high · critique · Restore the resource-limit capability assertion — This changes the expected Docker capability from supported to unsupported, allowing the backend's resource-limit declaration to regress. The same backend still declares CPU, memory (crates/tinybox\-docker/src/sandbox/mod\_tests\.rs:124)
  • medium · critique · Return test errors instead of unwrapping — This newly added test panics instead of returning the filesystem error, contrary to the repository rule that tests use `Result` and `?`. The added regression tests also contain sev (crates/tinybox\-jail/src/registry\_tests\.rs:252)
  • medium · critique · Keep resource limits in the Docker capability assertion — Docker's sandbox code translates resource limits into enforced Docker flags, so the inspection output should continue to advertise `resource limits`. Removing it from this assertio (crates/tinybox\-cli/src/command/mod\_tests\.rs:790)
  • medium · critique · Use an executable guaranteed to exist in the test environment — This regression test relies on an external `true` executable being discoverable through `PATH`. `true` may be a shell builtin or absent from a minimal test environment, causing the (crates/tinybox\-jail/src/registry\_tests\.rs:446)
  • high · security · Preserve the backend capability preflight — This direct backend call still bypasses the separate capability check that the previous helper performed. A caller can reach this path with a jail requiring capabilities the select (crates/tinybox\-jail/src/registry\.rs:450)
  • high · security · Preserve the resource-limit capability declaration — This changes the Docker backend test to require that `ResourceLimits` is not supported, weakening the capability contract and allowing the backend to stop advertising a limit that (crates/tinybox\-docker/src/sandbox/mod\_tests\.rs:124)
  • high · security · Preserve the resource-limit capability declaration — When `limits` is enabled, this function now returns capabilities without `with_resource_limits()`, even though the backend still configures cgroup CPU, memory, and process limits. (crates/tinybox\-linux/src/sandbox/mod\.rs:94)
  • high · security · Preserve the resource-limit capability declaration — This changes the microVM's declared contract to say that resource limits are unsupported, even though the hypervisor is configured with fixed vCPU and memory limits and the surroun (crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs:114)
  • high · security · Preserve the resource-limit capability declaration — When cgroup limits are requested, this change now codifies that `ResourceLimits` is unsupported even though `with_cgroup_limits()` provides enforced CPU, memory, and PID constraint (crates/tinybox\-linux/src/sandbox/mod\_tests\.rs:104)
  • high · security · Preserve the backend capability preflight — This replaces the previous `spawn_with` helper with a direct `JailBackend::spawn` call. The backend trait exposes `require` separately from `spawn`, so this path can launch a comma (crates/tinybox\-jail/src/registry\.rs:430)
  • high · security · Make canonicalization and deletion atomic — This function returns a separately resolved `PathBuf`, but the deletion path validates that result and then removes the original `record.dir`. An attacker who can modify the regist (crates/tinybox\-jail/src/registry\_path\.rs:8)
  • high · security · Keep the resource-limit capability assertion — This removes `resource limits` from the expected capability list, allowing the test to pass when the Docker backend silently loses its resource-limit capability. Keep the assertion (crates/tinybox\-cli/src/command/mod\_tests\.rs:790)
  • high · security · Make jail validation and spawn atomic — The resolved path is checked against the registry base before constructing the `Jail`, but the backend opens or otherwise uses that path later. A concurrent filesystem rename or re (crates/tinybox\-jail/src/registry\.rs:510)
  • medium · security · Return test errors instead of unwrapping — This newly added test returns `io::Result<()>`, but it still unwraps the registry mutex and record lookup. The repository rule forbids `unwrap()` in tests; propagate or convert bot (crates/tinybox\-jail/src/registry\_tests\.rs:463)
  • medium · security · Place module-local tests in mod_tests.rs — The repository rule requires module-local unit tests to live in a sibling `mod_tests.rs` file. Rename `registry_path_tests.rs` to `mod_tests.rs` and update this path accordingly. (crates/tinybox\-jail/src/registry\_path\.rs:58)
  • medium · security · Use an executable guaranteed to exist in the test environment — This test helper still assumes that `true` is installed at one of two host-specific coreutils paths. Minimal Linux images, nonstandard distributions, and some CI environments do no (crates/tinybox\-jail/src/mod\_tests\.rs:167)
  • medium · security · Avoid requiring a host-provided coreutils executable — This new test invokes `true` on Unix and therefore depends on a host-provided coreutils command being present and discoverable via `PATH`. The test should use an executable control (crates/tinybox\-jail/src/registry\_tests\.rs:497)
  • medium · tests · Return test errors instead of unwrapping in the new registry tests — The repository rule forbids `unwrap()` anywhere, including tests, which must return `Result` and use `?`. The new tests `removed_jail_under_symlinked_base_reports_missing_not_outsi (crates/tinybox\-jail/src/registry\_tests\.rs:463)

Resolved this pass

  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • high — Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Preserve the backend capability declaration
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • high — Preserve the resource-limit capability declaration
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • high — Make jail validation and spawn atomic
  • high — Make canonicalization and deletion atomic
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Add the declared constraint module
  • Add the declared constraint module
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Preserve the resource-limit capability declaration
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • high — Preserve the resource-limit capability declaration
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Return test errors instead of unwrapping
  • Use an executable guaranteed to exist in the test environment
  • Use an executable available inside the Landlock policy
  • Avoid requiring a host-provided coreutils executable
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Make jail validation and spawn atomic
  • Make canonicalization and deletion atomic
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • high — Preserve the backend capability preflight
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Preserve the resource-limit capability declaration
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Use an executable available inside the Landlock policy
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • high — Preserve the resource-limit capability declaration
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • high — Make canonicalization and use atomic
  • medium — Use an executable guaranteed to exist in the test environment
  • high — Make jail validation and spawn atomic
  • medium — Return test errors instead of unwrapping
  • high — Make canonicalization and deletion atomic
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Use an executable guaranteed to exist in the test environment
  • Make jail validation and spawn atomic
  • Return test errors instead of unwrapping
  • Make canonicalization and deletion atomic
  • Avoid requiring a host-provided coreutils executable
  • Preserve the backend capability preflight
  • critical — Add the declared constraint module
  • high — Preserve the resource-limit capability declaration
  • medium — Pin the checkout action to a commit
  • medium — Pin the Rust toolchain action to a commit
  • medium — Pin the Rust cache action to a commit
  • medium — Use an executable available inside the Landlock policy
  • medium — Use an executable guaranteed to exist in the test environment
  • medium — Return test errors instead of unwrapping
  • medium — Avoid requiring a host-provided coreutils executable
  • high — Preserve the backend capability preflight
  • Add the declared constraint module
  • Preserve the resource-limit capability declaration
  • Pin the checkout action to a commit
  • Pin the Rust toolchain action to a commit
  • Pin the Rust cache action to a commit
  • Use an executable available inside the Landlock policy
  • Make canonicalization and use atomic
  • Make jail validation and spawn atomic
  • Use an executable guaranteed to exist in the test environment
  • Avoid requiring a host-provided coreutils executable
  • Make canonicalization and deletion atomic
  • Preserve the backend capability preflight

Before merge

  • Address Make jail validation and spawn atomic (crates/tinybox\-jail/src/registry\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-docker/src/sandbox/mod\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-microvm/src/sandbox/mod\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs).
  • Address Make deletion atomic with path validation (crates/tinybox\-jail/src/registry\.rs).
  • Address Restore the resource-limit capability assertion (crates/tinybox\-docker/src/sandbox/mod\_tests\.rs).
  • Address Preserve the backend capability preflight (crates/tinybox\-jail/src/registry\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-docker/src/sandbox/mod\_tests\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-linux/src/sandbox/mod\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs).
  • Address Preserve the resource-limit capability declaration (crates/tinybox\-linux/src/sandbox/mod\_tests\.rs).
  • Address Preserve the backend capability preflight (crates/tinybox\-jail/src/registry\.rs).
  • Address Make canonicalization and deletion atomic (crates/tinybox\-jail/src/registry\_path\.rs).
  • Address Keep the resource-limit capability assertion (crates/tinybox\-cli/src/command/mod\_tests\.rs).
  • Address Make jail validation and spawn atomic (crates/tinybox\-jail/src/registry\.rs).

How this fits together

flowchart LR
  n0["Error<br/>changed"]:::changed
  n1["DockerSandbox<br/>changed<br/>1 finding"]:::blocking
  n2["Result"]:::impacted
  n3["Sandbox"]:::impacted
  n4["JailBackend"]:::impacted
  n5["io"]:::impacted
  n6["spawn"]:::impacted
  n1 -->|implements| n3
  n2 -->|uses| n0
  n4 -->|uses| n2
  n4 -->|uses| n5
  n5 -->|uses| n0
  n6 -->|uses| n0
  n6 -->|uses| n2
  n6 -->|uses| n5
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 30 files; 14 findings. (5 already reported on an earlier push) (2 observation(s) grouped into shared inline comments) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinybox\-jail/src/registry\.rs — Make jail validation and spawn atomic
  • Evidence: crates/tinybox\-docker/src/sandbox/mod\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-microvm/src/sandbox/mod\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-jail/src/registry\.rs — Make deletion atomic with path validation
  • Evidence: crates/tinybox\-docker/src/sandbox/mod\_tests\.rs — Restore the resource-limit capability assertion
  • Evidence: crates/tinybox\-jail/src/registry\_tests\.rs — Return test errors instead of unwrapping
  • Evidence: crates/tinybox\-cli/src/command/mod\_tests\.rs — Keep resource limits in the Docker capability assertion
  • Evidence: crates/tinybox\-jail/src/registry\_tests\.rs — Use an executable guaranteed to exist in the test environment

security

  • Conclusion: Failure
  • Scope reviewed: all assigned evidence
  • Lane summary: Reviewed 26 files; 16 findings. 4 files were not security-reviewed: README.md (prose or tabular data), crates/tinybox-core/src/constraint/README.md (prose or tabular data), crates/tinybox-jail/README.md (prose or tabular data), docs/specs/constraint-preflight.md (prose or tabular data). (2 already reported on an earlier push) (1 observation(s) grouped into shared inline comments) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinybox\-jail/src/registry\.rs — Preserve the backend capability preflight
  • Evidence: crates/tinybox\-docker/src/sandbox/mod\_tests\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-linux/src/sandbox/mod\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-microvm/src/sandbox/mod\_tests\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-linux/src/sandbox/mod\_tests\.rs — Preserve the resource-limit capability declaration
  • Evidence: crates/tinybox\-jail/src/registry\.rs — Preserve the backend capability preflight
  • Evidence: crates/tinybox\-jail/src/registry\_path\.rs — Make canonicalization and deletion atomic
  • Evidence: crates/tinybox\-cli/src/command/mod\_tests\.rs — Keep the resource-limit capability assertion
  • Evidence: crates/tinybox\-jail/src/registry\.rs — Make jail validation and spawn atomic
  • Evidence: crates/tinybox\-jail/src/registry\_tests\.rs — Return test errors instead of unwrapping
  • Evidence: crates/tinybox\-jail/src/registry\_path\.rs — Place module-local tests in mod_tests.rs
  • Evidence: crates/tinybox\-jail/src/mod\_tests\.rs — Use an executable guaranteed to exist in the test environment
  • Evidence: crates/tinybox\-jail/src/registry\_tests\.rs — Avoid requiring a host-provided coreutils executable

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The preflight model, backend declarations, registry canonicalization hardening, and CI action pinning all look sound, and every earlier finding is either fixed (constraint module added, actions pinned, capability declarations made honest, canonicalization failures no longer silently fall back) or superseded by a deliberate, tested and documented design change. One repo-rule violation remains: new test code in registry_tests.rs uses unwrap() instead of returning Result and using ?. (1 earlier finding(s) still open) (1 observation(s) grouped into shared inline comments) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._
  • Evidence: crates/tinybox\-jail/src/registry\_tests\.rs — Return test errors instead of unwrapping in the new registry tests

commits

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: Nothing sensitive found in what this pull request commits.

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: This revision resolves all previously raised findings: the constraint preflight module exists with tests, resource-limit capability claims were removed from Docker/namespaces/MicroVM, all CI third-party actions are pinned to commits, the Landlock preflight refuses network/subprocess denials before spawning, registry base canonicalization and the existing-root spawn check are in place with alias/traversal coverage, and the test executables come from the documented jail baseline. The description matches the diff, including the honest Seatbelt best-effort and isolation-None declarations. The change looks sound. (17 earlier finding(s) still open) _Code retrieval was unavailable (model: ladder embeddings returned 400 Bad Request: {"error":{"message":"unknown ladder vectors; known ladders are flash (also chat-v1, flash-v1), instant (also no-think, instant-v1), reasoning (also deepseek), max-reasoning (also max-reasoning-v1), deepseek-flash (also reasoning-v1, agentic-v1), deep (also luna), scribe, uncensored, vectors-oai3 (also embeddings-oai3-v1), vision (also vision-v1, multimodal-v1), image (also images-v1, image-v1), vi), so this review saw the diff alone._ _Memory was unavailable (model: cortex: v1/recall: error sending request for url (http://cortexdb:3141/v1/recall\)\), so this review ran without it._

e2e

  • Conclusion: Neutral
  • Scope reviewed: all assigned evidence
  • Lane summary: No end-to-end harness in this repository: no e2e test files and no e2e workflow.
Evidence and run details
  • Models: gpt-5.6-luna, glm-5.3-flash
  • Spend: $0.113388
  • Tokens: 1325238 input · 127473 output · 198003 cached · 0 embedding
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
e1d0d6c69bf1 changes requested 9 active finding(s), 0 resolved finding(s) (at 1791645685)
a8e532bdf38f changes requested 5 active finding(s), 139 resolved finding(s) (at 1791646531)
3e6e0be11a6a changes requested 7 active finding(s), 54 resolved finding(s) (at 1791647205)
3e6e0be11a6a changes requested 23 active finding(s), 402 resolved finding(s) (at 1791647657)

tinysweeper 0.1.0

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T15:46:15.842984Z 3e6e0be New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b51156dd-6d27-404f-b7b3-eea30bbc6bf2








📥 Commits

Reviewing files that changed from the base of the PR and between 65c5f7a and e1d0d6c.









📒 Files selected for processing (24)
  • .github/workflows/ci.yml
  • README.md
  • crates/tinybox-cli/src/command/mod_tests.rs
  • crates/tinybox-core/src/constraint/README.md
  • crates/tinybox-core/src/constraint/mod.rs
  • crates/tinybox-core/src/constraint/mod_tests.rs
  • crates/tinybox-core/src/error/mod.rs
  • crates/tinybox-core/src/lib.rs
  • crates/tinybox-core/src/runtime/mod.rs
  • crates/tinybox-core/src/runtime/mod_tests.rs
  • crates/tinybox-docker/src/sandbox/mod.rs
  • crates/tinybox-docker/src/sandbox/mod_tests.rs
  • crates/tinybox-jail/README.md
  • crates/tinybox-jail/src/jail.rs
  • crates/tinybox-jail/src/lib.rs
  • crates/tinybox-jail/src/linux.rs
  • crates/tinybox-jail/src/macos.rs
  • crates/tinybox-jail/src/mod_tests.rs
  • crates/tinybox-jail/src/noop.rs
  • crates/tinybox-linux/src/sandbox/mod.rs
  • crates/tinybox-linux/src/sandbox/mod_tests.rs
  • crates/tinybox-microvm/src/sandbox/mod.rs
  • crates/tinybox-microvm/src/sandbox/mod_tests.rs
  • docs/specs/constraint-preflight.md








Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.










📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough
📝 Walkthrough

Walkthrough

The change adds constraint-level support reporting and preflight checks to sandbox and jail APIs. Backends declare enforcement levels, and strict jail-spawn functions reject requests that are not fully enforced. Tests, documentation, capability expectations, and CI coverage are updated.

Changes

Constraint Preflight

Layer / File(s) Summary
Core constraint preflight contract
crates/tinybox-core/src/constraint/*, crates/tinybox-core/src/error/mod.rs, crates/tinybox-core/src/lib.rs, crates/tinybox-core/src/runtime/*
The core crate adds constraint and enforcement types, planning and requirement checks, a typed refusal error, and default preflight methods on Sandbox. Tests and documentation cover these APIs.
Sandbox backend enforcement declarations
crates/tinybox-docker/src/sandbox/*, crates/tinybox-linux/src/sandbox/*, crates/tinybox-microvm/src/sandbox/*, crates/tinybox-cli/src/command/mod_tests.rs, README.md
Docker, Linux namespace, and MicroVM sandboxes report per-constraint enforcement levels. Their capability declarations and tests no longer treat ResourceLimits as a generic declared capability. The README example and CLI test reflect the capability change.
Jail preflight and required spawning
crates/tinybox-jail/src/*, crates/tinybox-jail/README.md, docs/specs/constraint-preflight.md, .github/workflows/ci.yml, README.md
The jail API derives requested constraints from jail settings and checks backend support before strict spawning. Platform backends report enforcement levels, and tests cover strict-spawn outcomes and backend limitations. Documentation and CI coverage are updated.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~50 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant spawn_required_with
  participant JailBackend
  participant Jail
  participant spawn_with
  Caller->>spawn_required_with: backend, jail, command
  spawn_required_with->>JailBackend: require(jail)
  JailBackend->>Jail: constraints()
  JailBackend-->>spawn_required_with: preflight result
  alt constraints are enforced
    spawn_required_with->>spawn_with: backend, jail, command
    spawn_with-->>Caller: io::Result<Child>
  else constraints are not enforced
    spawn_required_with-->>Caller: Unsupported error
  end
Loading





























Merge Risk: ⚪ Minimal · up to e1d0d

No demonstrated issue blocks merging. Run the planned platform CI checks before release.

Security Architecture Review

Security architecture risk: 🔵 Low · up to e1d0d

The changes strengthen execution admission and make backend limitations explicit. No introduced security bypass was established. Residual risk lies in callers adopting the strict APIs correctly, matching mandatory constraints to workload configuration, and validating enforcement on supported host environments.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • observed — A strict filesystem-only Landlock jail is not general untrusted-code isolation. Jail defaults allow networking and subprocess creation, and the new suitability predicate also requires kernel-level process isolation. Landlock does not declare that isolation, so strict filesystem acceptance does not establish protection from process-level attacks.

Trust Boundaries and Controls

  • observed — Strict jail spawning derives mandatory constraints from the same jail supplied for execution and uses the same backend reference for preflight and spawn. The backend remains trusted enforcement code: declarations authorize admission, while concrete backend setup must establish confinement before workload execution.

Resilience and Maintainability Implications

  • observed — Backend detection does not automatically fall back to Noop when confinement is unavailable. It returns an unsupported backend whose spawn fails. Noop remains an explicit trusted passthrough, and the strict refusal regression checks that no command marker is created.

Hardening Proposals

  • proposed — For downstream integrations handling untrusted workload specifications, consider a checked execution-plan API that binds mandatory constraints, the selected backend and the actual BoxSpec together. In particular, require a denial-compatible network policy when network denial is mandatory. This is an integration-hardening proposal, not an observed bypass.













Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 63 functions across 19 files. (5 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely summarizes the main changes: truthful sandbox constraint preflight and strict jail spawning.

Full details: Docstring Coverage

Explanation

Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 63 functions across 19 files. (5 skipped: 5 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR








🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR















  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

I’m a rabbit checking paths before the leap,
I sort each promise, firm or incomplete.
The jail asks what its backend can enforce,
And turns away a request that lacks that force.
Across three platforms, tests now run,
Then I hop home when checks are done.

Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is critical.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0589 · 780,204 in / 43,607 out · 79,510 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0322 · 393,369 in / 23,449 out · 48,200 cached (12%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0260 · 320,720 in / 13,214 out · 29,326 cached (9%)  · gpt-5.6-luna
tests:       $0.0003 · 33,191 in  / 3,407 out  · 1,856 cached (6%)   · glm-5.3-flash
description: $0.0001 · 15,973 in  / 948 out    · 0 cached (0%)       · glm-5.3-flash

Comment thread crates/tinybox-core/src/lib.rs
Comment thread crates/tinybox-linux/src/sandbox/mod.rs
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread crates/tinybox-jail/src/mod_tests.rs
@tinysweeper tinysweeper Bot added the priority: p0 Drop what you are doing. Data loss, a live break, or an exploitable hole. label Oct 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1d0d6c69b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinybox-jail/src/macos.rs Outdated
Comment thread crates/tinybox-core/src/error/mod.rs Outdated
senamakel and others added 4 commits October 10, 2026 18:27
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8e532bdf3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinybox-jail/src/registry_path.rs

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 1 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0501 · 621,200 in / 63,139 out · 118,871 cached (19%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0277 · 315,185 in / 32,633 out · 68,257 cached (22%)  · gpt-5.6-luna, glm-5.3-flash
security:    $0.0197 · 208,464 in / 22,247 out · 50,614 cached (24%)  · gpt-5.6-luna
tests:       $0.0014 · 49,831 in  / 3,952 out  · 0 cached (0%)        · glm-5.3-flash
description: $0.0006 · 23,116 in  / 1,196 out  · 0 cached (0%)        · glm-5.3-flash

Comment thread crates/tinybox-linux/src/sandbox/mod_tests.rs
Comment thread crates/tinybox-jail/src/registry_path.rs
Comment thread crates/tinybox-jail/src/mod_tests.rs Outdated
Comment thread crates/tinybox-jail/src/mod_tests.rs
@tinysweeper tinysweeper Bot added priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition. and removed priority: p0 Drop what you are doing. Data loss, a live break, or an exploitable hole. labels Oct 10, 2026
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e6e0be11a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +520 to +521
let mut index = reg.index.lock().unwrap();
index.records.get_mut(&record.id).unwrap().dir = lexical.join(&record.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Replace the new test unwraps with error propagation

When the registry mutex is poisoned or the expected record is unexpectedly absent, these new tests panic through unwrap() instead of returning their existing io::Result; the same pattern appears in the other newly added registry migration tests. The repository explicitly forbids unwrap() in test targets and requires tests to return Result and use ?, so convert these lookups to propagated errors rather than relying on the crate's pre-existing test-only lint allowance.

AGENTS.md reference: AGENTS.md:L193-L195

Useful? React with 👍 / 👎.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.0235 · 340,841 in / 27,971 out · 33,495 cached (10%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0132 · 168,250 in / 13,815 out · 22,065 cached (13%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0096 · 88,744 in  / 10,750 out · 11,302 cached (13%) · gpt-5.6-luna
tests:       $0.0002 · 27,124 in  / 906 out    · 0 cached (0%)       · glm-5.3-flash
description: $0.0002 · 26,609 in  / 640 out    · 0 cached (0%)       · glm-5.3-flash

let mut jail = Jail::new(&record.dir, &record.label);
jail.canonicalize()?;
Ok(jail)
Ok(Jail::new(&resolved, &record.label))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique likely

Make jail validation and spawn atomic

The jail path is canonicalized and checked for containment before a path-based Jail is returned, but the backend uses that path later. A process that can replace or rename the validated directory between canonicalize() and backend use can cause the backend to operate on a different target, defeating the check. Keep the validated directory identity open through spawn, or use an equivalent atomic directory-handle-based confinement mechanism rather than passing a re-resolved path.

[RULE] toctou-path-validation ·

std::os::unix::fs::symlink(outside.path(), &link)?;
reg.index
.lock()
.unwrap()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium critique confident

Return test errors instead of unwrapping

The added tests use unwrap() despite the repository rule requiring fallible tests to return Result and use ?. An unexpected lock, lookup, or persistence failure will panic instead of reporting the actual test error, and this also violates the workspace-wide no-unwrap policy. Convert these tests to return io::Result<()> and propagate failures with ?.

[RULE] no-unwrap ·

.base
.canonicalize()
.unwrap_or_else(|_| self.base.clone());
let resolved = path::canonicalize_missing(&record.dir)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security confident

Make canonicalization and deletion atomic

The containment check resolves record.dir, but deletion later uses the original path. A local attacker who can modify entries under the registry can replace an intermediate component after this check with a symlink or otherwise redirect the path, causing remove_dir_all to operate outside the validated target. Perform the validation and removal using an OS-level directory handle or another operation that binds the checked object to the deleted object.

[RULE] path-check-use-race ·

let jail = self.jail_for(id)?;
log::debug!("[cwd_jail] registry.spawn_in id={id}");
spawn_with(default_backend().as_ref(), &jail, cmd)
default_backend().spawn(&jail, cmd)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security confident

Preserve the resource-limit capability declaration

This replaces the existing spawn_with path with a direct backend call. The wrapper is responsible for preserving the declared resource-limit capability contract; bypassing it lets registry spawning use a backend without enforcing or advertising that capability consistently. Route this through the capability-aware spawn path, or otherwise make the declaration and enforcement explicit before calling the backend.


Additional critique observation

priority high confident

Preserve the backend capability preflight

[RULE] capability-preflight

This replaces the previous spawn_with wrapper with a direct backend call. The wrapper is where the registry's declared jail constraints and backend capability checks are preserved; calling spawn directly allows a backend to run without that preflight, including when a requested resource limit or other constraint is unsupported. Keep the wrapper or perform the same capability validation before invoking the backend.

[RULE] capability-contract ·

let record = reg.create("removed")?;
fs::remove_dir_all(&record.dir)?;
assert_eq!(
reg.spawn_in_with(&record.id, &super::super::NoopBackend, Command::new("true"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Use an executable guaranteed to exist in the test environment

These new tests invoke the ambient true executable by name, making the test suite depend on the host PATH and on an executable that is not guaranteed by the test environment. Use a repository-controlled executable or a backend/test seam that does not require an external command.

[RULE] environment-dependent-test ·

}

/// Locate `true` only in the documented Landlock baseline, never in raw PATH.
fn permitted_true() -> std::io::Result<std::path::PathBuf> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Avoid requiring a host-provided coreutils executable

This test returns an error when neither /usr/bin/true nor /bin/true exists, so the Linux test suite fails on minimal or non-coreutils environments even though Landlock itself may be available. Use a test executable guaranteed by the test environment or skip this test when no suitable executable is present.

[RULE] test-environment-dependency ·

@senamakel
senamakel merged commit b61c6bc into main Oct 10, 2026
20 of 22 checks passed

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: 2 lane(s) blocking, worst finding is high.

Fix or reply to the findings below and push. The next review clears this automatically once they are gone — you should not need to dismiss anything by hand.

             $0.1134 · 1,325,238 in / 127,473 out · 198,003 cached (15%) · gpt-5.6-luna, glm-5.3-flash
critique:    $0.0597 · 719,822 in   / 67,526 out  · 122,822 cached (17%) · gpt-5.6-luna, glm-5.3-flash
security:    $0.0530 · 520,815 in   / 55,382 out  · 71,725 cached (14%)  · gpt-5.6-luna
tests:       $0.0002 · 27,162 in    / 1,476 out   · 1,856 cached (7%)    · glm-5.3-flash
description: $0.0002 · 26,707 in    / 548 out     · 1,472 cached (6%)    · glm-5.3-flash

}
// Spawning requires an existing root. Never make a synthetic missing
// path pass containment and then resolve it to a different target.
let resolved = match record.dir.canonicalize() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Make jail validation and spawn atomic

The directory is canonicalized and checked against self.base, then the resulting path is returned in a Jail for a later backend spawn. An attacker can replace the directory or a path component after this check, so the backend may operate on a different target, including one outside the registry. Keep validation and backend setup/use in one operation, or enforce an invariant that prevents the root from being replaced during the gap.

[RULE] toctou-path-validation ·

@@ -125,7 +125,6 @@ impl DockerSandbox {
pub const fn declared_capabilities() -> SandboxCapabilities {
SandboxCapabilities::new(IsolationLevel::Kernel, SnapshotSupport::Filesystem)
.with_fork()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Preserve the resource-limit capability declaration

The new constraint_support method declares CPU, memory, and PID constraints as enforced, but declared_capabilities() no longer advertises ResourceLimits. Callers that select or preflight backends using capabilities() will therefore treat this Docker backend as unable to handle resource-limited specs, despite the backend declaring support for those constraints. Restore the capability declaration until all callers have migrated away from this capability.

[RULE] capability-consistency ·

@@ -127,7 +127,6 @@ impl MicroVmSandbox {
#[must_use]
pub const fn declared_capabilities() -> SandboxCapabilities {
SandboxCapabilities::new(IsolationLevel::Hardware, SnapshotSupport::None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Preserve the resource-limit capability declaration

Removing .with_resource_limits() changes the public capability contract: callers that select or validate backends using the coarse resource-limit capability will now see this backend as unsupported, even though the VM still has fixed CPU and memory sizing. The new ConstraintSupport declaration does not restore that capability; it reports CPU and memory only as best effort. Keep the resource-limit capability declared alongside the hardware isolation capability.

[RULE] capability-declaration ·

// The guest is given fixed vCPUs and fixed memory by the hypervisor and
// cannot see that any more exists, which is a stronger limit than a cgroup.
assert!(caps.supports(Capability::ResourceLimits));
assert!(!caps.supports(Capability::ResourceLimits));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Preserve the resource-limit capability declaration

This changes the contract test to require that the microVM does not support resource limits. The surrounding test says the hypervisor gives the guest fixed vCPUs and fixed memory, and the existing resource-configuration coverage exercises those limits; those are resource limits rather than an absence of the capability. Keeping this assertion false allows the backend to advertise no resource-limit support despite enforcing the requested CPU and memory bounds. Restore the positive capability assertion.


Additional security observation

priority high confident

Preserve the resource-limit capability declaration

[RULE] capability-contract-regression

This changes the microVM's declared contract to say that resource limits are unsupported, even though the hypervisor is configured with fixed vCPU and memory limits and the surrounding test documents those as enforced limits. Callers use this capability declaration to reject otherwise supported resource-constrained workloads, so the changed assertion either makes the test fail against the implementation or codifies an incorrect capability contract. Keep the resource-limit capability declared.

Suggested change for this observation (reference only)

assert!(caps.supports(Capability::ResourceLimits));

Suggested change for the opening observation

Suggested change
assert!(!caps.supports(Capability::ResourceLimits));
assert!(caps.supports(Capability::ResourceLimits));

[RULE] capability-contract ·

.base
.canonicalize()
.unwrap_or_else(|_| self.base.clone());
let resolved = path::canonicalize_missing(&record.dir)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high critique confident

Make deletion atomic with path validation

canonicalize_missing verifies that the recorded path resolves under self.base, but the later deletion still uses the original path after that check. An attacker can rename the validated directory and replace it with a directory outside the registry before remove_dir_all runs, causing deletion of the replacement target. Perform validation and removal on an object whose identity is held across the operation, or otherwise prevent the directory from being replaced between the check and deletion.

[RULE] toctou-filesystem-race ·

let mut jail = Jail::new(&record.dir, &record.label);
jail.canonicalize()?;
Ok(jail)
Ok(Jail::new(&resolved, &record.label))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority high security likely

Make jail validation and spawn atomic

The resolved path is checked against the registry base before constructing the Jail, but the backend opens or otherwise uses that path later. A concurrent filesystem rename or replacement can change what the backend applies confinement to after the check. Bind the validated directory to the spawned process through an atomic or descriptor-based mechanism, or have the backend perform validation and use as one operation.

[RULE] time-of-check-to-time-of-use ·

let record = reg.create("corrupt")?;
let link = root.path().join("outside");
std::os::unix::fs::symlink(outside.path(), &link)?;
reg.index

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Return test errors instead of unwrapping

This newly added test returns io::Result<()>, but it still unwraps the registry mutex and record lookup. The repository rule forbids unwrap() in tests; propagate or convert both failures so a test failure is reported as an error instead of panicking.


Additional tests observation

priority medium confident

Return test errors instead of unwrapping in the new registry tests

[RULE] no-unwrap-in-tests

The repository rule forbids unwrap() anywhere, including tests, which must return Result and use ?. The new tests removed_jail_under_symlinked_base_reports_missing_not_outside, missing_jail_through_outside_symlink_remains_forbidden, old_records_inherit_only_normalized_trusted_base_components and normalized_trusted_base_does_not_adopt_corrupt_suffix_traversal reach into reg.index.lock().unwrap() and unwrap the record lookup. Make the tests return io::Result<()> and map the poisoned-lock and missing-record cases into errors, or add a small helper that does so.

Suggested change for this observation (reference only)

let mut index = reg.index.lock().map_err(|_| io::Error::other("poisoned index"))?;
    let record_dir = index
        .records
        .get_mut(&record.id)
        .ok_or_else(|| io::Error::other("record vanished"))?;
    record_dir.dir = link.join("missing/nested");

[RULE] unchecked-error ·

}

#[cfg(test)]
#[path = "registry_path_tests.rs"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Place module-local tests in mod_tests.rs

The repository rule requires module-local unit tests to live in a sibling mod_tests.rs file. Rename registry_path_tests.rs to mod_tests.rs and update this path accordingly.

[RULE] test-module-naming ·

}

/// Locate `true` only in the documented Landlock baseline, never in raw PATH.
fn permitted_true() -> std::io::Result<std::path::PathBuf> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Use an executable guaranteed to exist in the test environment

This test helper still assumes that true is installed at one of two host-specific coreutils paths. Minimal Linux images, nonstandard distributions, and some CI environments do not provide either path, so strict_landlock_filesystem_only_spawn_still_works fails before exercising the backend. Avoid requiring a host-provided coreutils binary; use a repository-built test executable or skip the capability test when no suitable executable is available.

[RULE] environment-dependent-test ·

reg.jail_for(&record.id)?.root,
base.canonicalize()?.join(&record.id)
);
let mut command = Command::new(if cfg!(windows) { "cmd" } else { "true" });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

priority medium security confident

Avoid requiring a host-provided coreutils executable

This new test invokes true on Unix and therefore depends on a host-provided coreutils command being present and discoverable via PATH. The test should use an executable controlled by the test suite rather than an external system utility.

[RULE] host-executable-dependency ·

@senamakel
senamakel deleted the security-bus-7328 branch October 11, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p1 Next. Wrong behaviour a user will hit, or a security weakness behind a condition.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant