Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
22b2034
feat(bus): add platform shell selection to the host contract
senamakel Oct 11, 2026
6111075
feat(tinybus): add SelectShell method for platform shell discovery
senamakel Oct 11, 2026
aa07097
test(tinybox-bus): cover shell selection wire defaults and contract bump
senamakel Oct 11, 2026
4beca81
chore: files changed crates/tinybox-bus/src/shell_selection.rs
senamakel Oct 11, 2026
71f4fb4
Merge branch 'shrink-core-sandbox-7390' of https://github.com/tinyhum…
senamakel Oct 11, 2026
2dfea5f
test(tinybox-module): rename grant discovery e2e test
senamakel Oct 11, 2026
d97c464
Merge branch 'shrink-core-sandbox-7390' of https://github.com/tinyhum…
senamakel Oct 11, 2026
fcd5da1
Merge branch 'shrink-core-sandbox-7390' of https://github.com/tinyhum…
senamakel Oct 11, 2026
6334937
Merge remote-tracking branch 'origin/shrink-core-sandbox-7390' into t…
senamakel Oct 11, 2026
041943b
test(local): cover cmd quoting and shell startup flags
senamakel Oct 11, 2026
15bad6f
fix(host): harden shell selection for cmd and posix
senamakel Oct 11, 2026
8a89701
Merge remote-tracking branch 'origin/shrink-core-sandbox-7390' into t…
senamakel Oct 11, 2026
114679e
docs: record shell-selection contract and verification sequence
senamakel Oct 11, 2026
e0c8cee
test(shell): cover bash startup environment isolation
senamakel Oct 11, 2026
1322ae2
feat(shell): harden shell startup environment and cmd flags
senamakel Oct 11, 2026
d917523
Merge remote-tracking branch 'origin/shrink-core-sandbox-7390' into t…
senamakel Oct 11, 2026
855c81c
chore: files changed crates/tinybox-module/tests/grants_manifest_e2e.rs
senamakel Oct 11, 2026
996c75a
docs: add native shell execution plan and spec
senamakel Oct 11, 2026
59787fc
feat(bus): add native shell execution contract
senamakel Oct 11, 2026
3f37d57
chore: files changed crates/tinybox-bus/src/lib.rs,crates/tinybox-bus…
senamakel Oct 11, 2026
651a806
fix(tinybus-module): correct match arms for stream execution result
senamakel Oct 11, 2026
dc91f45
Merge branch 'shrink-core-sandbox-7390' of https://github.com/tinyhum…
senamakel Oct 11, 2026
00adb9d
test(shell): cover inherited bash options not aborting payload
senamakel Oct 11, 2026
6fe8ee2
test(tinybox-module): cover native shell replay, budget and timeout p…
senamakel Oct 11, 2026
24a9eea
fix(host): strip inherited SHELLOPTS and BASHOPTS from shell environment
senamakel Oct 11, 2026
dde0188
test(tinybus): update execution state assertions to struct variants
senamakel Oct 11, 2026
f44c028
refactor(tinybox-module): extract execution collector selection
senamakel Oct 11, 2026
e198ea2
Merge branch 'tinybox-shell-selection-7391' of https://github.com/tin…
senamakel Oct 11, 2026
64911ab
refactor(tinybox-module): extract owned collector check into helper
senamakel Oct 11, 2026
4eab081
test(native_shell): add test module for native shell
senamakel Oct 11, 2026
1ed18e3
fix(tinybox-module): validate spawn request ids before use
senamakel Oct 11, 2026
cd0e19c
docs: document native shell execution contract 1.11
senamakel Oct 11, 2026
c6dac81
refactor(native_shell): inject jail backend into shell context
senamakel Oct 11, 2026
2464f89
refactor(native_shell): move shell context types into a types module
senamakel Oct 11, 2026
fe26fa6
Merge branch 'shrink-core-sandbox-7390' of https://github.com/tinyhum…
senamakel Oct 11, 2026
b55f24a
docs(tinybus-module): document StartShellExec in the interface table
senamakel Oct 11, 2026
b7103f8
Merge branch 'tinybox-shell-selection-7391' of https://github.com/tin…
senamakel Oct 11, 2026
6c5fe06
test(tinybox-module): cover shell output limit termination and reaping
senamakel Oct 11, 2026
1e7aa0f
docs: update native shell execution status to implemented
senamakel Oct 11, 2026
118fb6e
test(grants-manifest): extract discovery checks into a helper
senamakel Oct 11, 2026
a3a2654
Merge branch 'tinybox-shell-selection-7391' of https://github.com/tin…
senamakel Oct 11, 2026
3de4381
Merge remote-tracking branch 'refs/remotes/upstream/shrink-core-sandb…
senamakel Oct 11, 2026
477d55d
test(tinybus-module): cover retryable close after failed scratch dele…
senamakel Oct 11, 2026
4f9b118
test(tinybus-module): cover native shell selection and execution over…
senamakel Oct 11, 2026
2618710
fix(native_shell): retry scratch cleanup after deletion failure
senamakel Oct 11, 2026
ba7ed28
fix(tinybus_module): read cleanup acknowledgement from the stream jou…
senamakel Oct 11, 2026
78249af
test(tinybox-module): include mode and status in descendant cleanup a…
senamakel Oct 11, 2026
6b577f6
test(tinybus-module): cover shell admission rejection for nonlocal an…
senamakel Oct 11, 2026
c9fce8e
test(shell): cover exported bash functions hiding pipeline failures
senamakel Oct 11, 2026
c8c4c96
fix(local): run bash with -p to ignore exported functions
senamakel Oct 11, 2026
88fdcd0
refactor(local): drop caching from bash path discovery
senamakel Oct 11, 2026
3250982
test(grants-manifest): relax shell argument assertions
senamakel Oct 11, 2026
e5a2a41
test(grants): cover shell execution through the compiled manifest
senamakel Oct 11, 2026
e285a0b
feat(bus): add supervised native shell execution
senamakel Oct 11, 2026
86ef52a
feat(tinybus): add StartShellExec for supervised native shell execution
senamakel Oct 11, 2026
5e06baf
test(tinybox-module): cover scratch retention for cancelled native shell
senamakel Oct 11, 2026
e38bd4c
test: update wire snapshot and stream fixtures for new fields
senamakel Oct 11, 2026
4ee9721
fix(native_shell): run scratch cleanup off the async worker
senamakel Oct 11, 2026
1badd56
fix(native_shell): run scratch cleanup on a blocking worker
senamakel Oct 11, 2026
801f727
refactor(tinybus-module): extract shell execution preparation
senamakel Oct 11, 2026
1af93d7
test(grants): use explicit BTreeMap default for env
senamakel Oct 11, 2026
6a2d6de
refactor(native_shell): use captured scratch handle in cleanup task
senamakel Oct 11, 2026
6755908
chore: files changed crates/tinybox-module/src/tinybus_module/mod_tes…
senamakel Oct 11, 2026
e2bf015
test(grants-manifest): build dynamic module under checkout target
senamakel Oct 11, 2026
4272dc5
chore: files changed crates/tinybox-host/src/local/shell.rs,crates/ti…
senamakel Oct 11, 2026
d9cfe26
fix(shell): use absolute /bin/sh for the posix fallback
senamakel Oct 11, 2026
9e3b9c6
Merge shell selection updates into native shell execution
senamakel Oct 11, 2026
ba6e2ff
Merge main and preserve additive shell contract ordering
senamakel Oct 11, 2026
8360865
test(shell): cover cmd selection and payload path isolation
senamakel Oct 11, 2026
85f1c4d
fix(local): resolve cmd.exe from SystemRoot instead of PATH
senamakel Oct 11, 2026
b07c281
refactor: use map_or_else for fallible path defaults
senamakel Oct 11, 2026
9779e16
docs(tinybus-module): document windows cmd.exe resolution
senamakel Oct 11, 2026
4d79180
test(tinybox-jail): canonicalize paths in git config grant assertions
senamakel Oct 11, 2026
1f37982
test(grants): isolate git config fixtures from xdg override
senamakel Oct 11, 2026
dff1091
chore: files changed crates/tinybox-module/tests/grants_manifest_e2e.rs
senamakel Oct 11, 2026
294c5fe
Merge latest base and preserve the existing shell execution contract
senamakel Oct 11, 2026
b2ebf59
test(git_config): canonicalize paths in xdg config home assertions
senamakel Oct 11, 2026
e88d382
test(tinybox-module): cover shell discovery and docker deadline valid…
senamakel Oct 11, 2026
e95d96a
Merge remote-tracking branch 'upstream/tinybox-shell-selection-7391' …
senamakel Oct 11, 2026
52fc1f9
Merge pull request #53 from tinyhumansai/tinybox-native-shell-7391
senamakel Oct 11, 2026
29880f0
test(tinybox-module): cover timeout status surviving failed cleanup
senamakel Oct 11, 2026
c3a6ea9
test(tinybox-module): remove unused timeout wait from fault host
senamakel Oct 11, 2026
53507c5
fix(tinybus): report timed out executions as timed out
senamakel Oct 11, 2026
b73cd91
docs(specs): clarify timeout outcome retention on cleanup retry
senamakel Oct 11, 2026
f728ea4
fix(native_shell): run scratch preparation off the async worker
senamakel Oct 11, 2026
049954e
fix(native-shell): run preparation on blocking workers
senamakel Oct 11, 2026
fa3f11d
fix(tinybus-module): reject unsupported providers before preparing ex…
senamakel Oct 11, 2026
b511bb7
Merge pull request #58 from tinyhumansai/tinybox-native-shell-7391
senamakel Oct 11, 2026
a46978e
test(host): cover bash discovery and posix mode edge cases
senamakel Oct 11, 2026
3f3c4d0
chore: files changed crates/tinybox-host/Cargo.toml,crates/tinybox-ho…
senamakel Oct 11, 2026
caa0ff4
fix(native_shell): run shell preparation on the blocking pool
senamakel Oct 11, 2026
ac3d305
test(tinybus): retry fake docker cli writes on etxtbsy
senamakel Oct 11, 2026
5756cf2
docs(shell-selection): document POSIXLY_CORRECT removal on unix
senamakel Oct 11, 2026
a9bf8b0
test(grants): expect POSIXLY_CORRECT in removed environment
senamakel Oct 11, 2026
f8438e7
test(native_shell): cover refused scratch preparation paths
senamakel Oct 11, 2026
1ef5d85
fix(tinybox-module): fence admission before shell preparation completes
senamakel Oct 11, 2026
9f0aae8
fix(tinybox-module): release resource lock during execution preparation
senamakel Oct 11, 2026
0822c5a
refactor(tinybox-module): box shell preparation and borrow replay inputs
senamakel Oct 11, 2026
7a1a10e
test(tinybox-module): use explicit BTreeMap default in stream test
senamakel Oct 11, 2026
db53a34
test(tinybox-module): cover replay ignoring rediscovered program
senamakel Oct 11, 2026
07a019d
fix(tinybus-module): treat native shell requests as unchanged across …
senamakel Oct 11, 2026
9b8ce06
Merge main and preserve hermetic Git grant tests
senamakel Oct 11, 2026
93ab2fa
test(tinybox-module): assert rejected preparation disposes scratch
senamakel Oct 11, 2026
cef2ae0
fix(tinybus): dispose rejected shell scratch on close and shutdown
senamakel Oct 11, 2026
0f03686
test(tinybox-module): cover rejected shell scratch cleanup retry
senamakel Oct 11, 2026
5309db5
test(tinybox-module): cover fixture probe retry behaviour
senamakel Oct 11, 2026
b87bb9a
refactor(tinybus): extract rejected collector disposal helper
senamakel Oct 11, 2026
6e5cb49
test(native_shell): add hook to inject scratch deletion failures
senamakel Oct 11, 2026
6bc60c8
refactor(native_shell): extract runtime validation into a helper
senamakel Oct 11, 2026
433a7d2
test(tinybus): cover shell env overrides and rejected scratch cleanup
senamakel Oct 11, 2026
f0ee6da
fix(native_shell): include resource env in shell environment
senamakel Oct 11, 2026
27dedcd
test(tinybus-module): cover bounded admission for concurrent preparat…
senamakel Oct 11, 2026
297c539
refactor(native_shell): extract environment name comparison helper
senamakel Oct 11, 2026
f614a38
chore: files changed crates/tinybox-module/src/tinybus_module/README.md
senamakel Oct 11, 2026
7649277
Merge branch 'main' into tinybox-shell-selection-7391
senamakel Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions crates/tinybox-bus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub use grants::{LocalGrantConfig, LocalGrants, ProtectedPaths, ResolveLocalGran
mod jail;
pub use jail::{JailEnforcement, NativeJailConfig};

mod shell_execution;
mod shell_selection;
pub use shell_execution::ShellExecRequest;
pub use shell_selection::{SelectShellRequest, ShellFlavor, ShellInvocation};

mod shell;
pub use shell::{CommandAnalysis, CommandClass, CommandSegment};
mod files;
Expand All @@ -42,8 +47,10 @@ pub use files::{
/// bounded, module-owned one-shot Docker operation. 1.9 adds bounded Docker
/// daemon status and label-scoped cleanup operations. 1.10 adds a bounded
/// Docker command that does not mount a host workspace. 1.11 adds local grant
/// discovery.
pub const CONTRACT_VERSION: (u32, u32) = (1, 11);
/// discovery. 1.12 adds platform shell selection. 1.13 adds supervised native
/// shell execution on local passthrough resources.
/// 1.14 adds native shell execution with owned scratch, timeout and optional jail.
pub const CONTRACT_VERSION: (u32, u32) = (1, 14);

/// Whether this host vocabulary can bind to a module's advertised version.
/// The major must match and the module's minor must include every host member.
Expand Down Expand Up @@ -117,6 +124,9 @@ pub const METHODS: &[&str] = &[
"CleanupDocker",
"RunDockerWithoutWorkspace",
"ResolveLocalGrants",
"SelectShell",
"StartShellExec",
"StartNativeShellExec",
];

/// Facts about the detected native directory-jail backend.
Expand Down Expand Up @@ -554,3 +564,6 @@ mod tests;

mod output;
pub use output::{ExecutionFailure, ExecutionState, OutputBatch, OutputChunk, OutputStream};

/// Invalid native shell execution inputs.
pub const INVALID_SHELL_EXEC: &str = "ai.tinyhumans.tinybox.Error.InvalidShellExec";
83 changes: 67 additions & 16 deletions crates/tinybox-bus/src/lib_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,12 @@ fn docker_run_vocabulary_is_typed_bounded_and_additive() -> Result<(), serde_jso
label: Some("openhuman.sandbox=true".into()),
timeout_ms: 120_000,
};
assert!(METHODS.contains(&"RunDocker"));
assert_eq!(METHODS.get(METHODS.len() - 3), Some(&"CleanupDocker"));
assert_eq!(
METHODS.get(METHODS.len() - 2),
Some(&"RunDockerWithoutWorkspace")
);
assert_eq!(METHODS.last(), Some(&"ResolveLocalGrants"));
assert!(METHODS.contains(&"RunDockerWithoutWorkspace"));
assert_eq!(CONTRACT_VERSION, (1, 11));
assert_eq!(METHODS[27], "RunDocker");
assert_eq!(METHODS[28], "DockerStatus");
assert_eq!(METHODS[29], "CleanupDocker");
assert_eq!(METHODS[30], "RunDockerWithoutWorkspace");
assert_eq!(METHODS.last(), Some(&"StartNativeShellExec"));
assert_eq!(CONTRACT_VERSION, (1, 14));
assert_eq!(MAX_DOCKER_RUN_TIMEOUT_MS, 86_400_000);
let serialized = serde_json::to_value(&request)?;
assert_eq!(serialized["read_only_rootfs"], false);
Expand Down Expand Up @@ -132,7 +129,7 @@ fn host_gateway_and_docker_facts_are_additive_and_default_safely() -> Result<(),
#[test]
fn version_and_capability_wire_snapshot_preserve_contract_compatibility()
-> Result<(), serde_json::Error> {
assert_eq!(CONTRACT_VERSION, (1, 11));
assert_eq!(CONTRACT_VERSION, (1, 14));
assert!(is_compatible(CONTRACT_VERSION));
assert!(!is_compatible((1, 8)));
assert!(!is_compatible((1, 7)));
Expand All @@ -150,7 +147,7 @@ fn version_and_capability_wire_snapshot_preserve_contract_compatibility()
exec_backends: Vec::new(),
spawn_backends: Vec::new(),
};
let snapshot = serde_json::json!({"contract_version":[1,11],"create_backends":["passthrough"],"exec_backends":[],"spawn_backends":[]});
let snapshot = serde_json::json!({"contract_version":[1,14],"create_backends":["passthrough"],"exec_backends":[],"spawn_backends":[]});
assert_eq!(serde_json::to_value(&capabilities)?, snapshot);
assert_eq!(
serde_json::from_value::<ModuleCapabilities>(snapshot)?,
Expand All @@ -161,18 +158,15 @@ fn version_and_capability_wire_snapshot_preserve_contract_compatibility()

#[test]
fn no_workspace_docker_operation_is_present_in_the_contract() {
assert_eq!(
METHODS.get(METHODS.len() - 2),
Some(&"RunDockerWithoutWorkspace")
);
assert_eq!(METHODS.get(30), Some(&"RunDockerWithoutWorkspace"));
assert_eq!(
METHODS
.iter()
.filter(|method| **method == "RunDockerWithoutWorkspace")
.count(),
1
);
assert_eq!(CONTRACT_VERSION, (1, 11));
assert_eq!(CONTRACT_VERSION, (1, 14));
}

#[test]
Expand Down Expand Up @@ -278,3 +272,60 @@ fn local_grant_configuration_defaults_and_floor_round_trip() -> Result<(), serde
);
Ok(())
}

#[test]
fn shell_selection_wire_defaults_preserve_safe_pipeline_behavior() -> Result<(), serde_json::Error>
{
let request: SelectShellRequest =
serde_json::from_value(serde_json::json!({"command":"false | true"}))?;
assert!(!request.preserve_pipeline_status);
let invocation = ShellInvocation {
flavor: ShellFlavor::Cmd,
program: "cmd".into(),
arguments: vec!["/C".into()],
raw_arguments: Some(r#"echo "quoted payload""#.into()),
bootstrap_environment: vec!["SystemRoot".into()],
remove_environment: Vec::new(),
};
let value = serde_json::to_value(&invocation)?;
assert_eq!(value["flavor"], "cmd");
assert_eq!(value["raw_arguments"], r#"echo "quoted payload""#);
assert_eq!(
serde_json::from_value::<ShellInvocation>(value)?,
invocation
);
assert_eq!(METHODS[31], "ResolveLocalGrants");
assert_eq!(METHODS[32], "SelectShell");
assert!(!is_compatible((1, 9)));
Ok(())
}

#[test]
fn older_shell_invocations_default_the_startup_removal_vocabulary() -> Result<(), serde_json::Error>
{
let invocation: ShellInvocation = serde_json::from_value(serde_json::json!({
"flavor":"posix", "program":"sh", "arguments":["-c","true"],
"raw_arguments":null, "bootstrap_environment":[]
}))?;
assert_eq!(invocation.remove_environment, Vec::<String>::new());
Ok(())
}

#[test]
fn native_shell_wire_defaults_close_stdin_and_keep_a_bounded_runtime()
-> Result<(), serde_json::Error> {
let request: ShellExecRequest = serde_json::from_value(serde_json::json!({
"process":"process", "resource":"resource", "shell":{"command":"true"},
"state_dir":"/state"
}))?;
assert_eq!(request.timeout_ms, 30_000);
assert_eq!(request.stdin, None);
assert_eq!(request.cwd, None);
assert_eq!(request.jail, None);
assert_eq!(request.extra_env, std::collections::BTreeMap::new());
assert_eq!(METHODS[33], "StartShellExec");
assert_eq!(METHODS[34], "StartNativeShellExec");
assert!(!is_compatible((1, 13)));
assert!(!is_compatible((1, 10)));
Ok(())
}
2 changes: 2 additions & 0 deletions crates/tinybox-bus/src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub struct OutputChunk {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ExecutionFailure {
/// The runtime budget elapsed; supervised native cleanup is acknowledged.
TimedOut,
/// The native operation could not start.
StartFailed,
/// Combined output exceeded the execution budget.
Expand Down
35 changes: 35 additions & 0 deletions crates/tinybox-bus/src/shell_execution.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//! Reserved native shell execution; authorization remains caller-owned.
use crate::{NativeJailConfig, ResourceId, SelectShellRequest};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

/// Start a local shell under module-owned supervision and output replay.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShellExecRequest {
/// Caller-known process reservation.
pub process: ResourceId,
/// Existing local passthrough resource.
pub resource: ResourceId,
/// Shell payload and pipeline-status convention.
pub shell: SelectShellRequest,
/// Working directory inside the resource; absent means its root.
#[serde(default)]
pub cwd: Option<String>,
/// Approved overrides on the module's safe parent environment snapshot.
#[serde(default)]
pub extra_env: BTreeMap<String, String>,
/// Approved existing absolute private state directory for owned scratch.
pub state_dir: String,
/// Positive runtime budget, default thirty seconds, at most twenty-four hours.
#[serde(default = "default_timeout")]
pub timeout_ms: u64,
/// Binary input; absent closes stdin.
#[serde(default)]
pub stdin: Option<Vec<u8>>,
/// Explicit native confinement; absent is ordinary local execution.
#[serde(default)]
pub jail: Option<NativeJailConfig>,
}
const fn default_timeout() -> u64 {
30_000
}
45 changes: 45 additions & 0 deletions crates/tinybox-bus/src/shell_selection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! Platform shell invocation vocabulary; selecting a shell grants no execution access.

use serde::{Deserialize, Serialize};

/// Command text and the desired pipeline exit-status convention.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SelectShellRequest {
/// Text interpreted by the platform shell.
pub command: String,
/// Preserve the shell's ordinary last-stage pipeline status rather than
/// enabling Bash pipefail. Windows cmd has no pipefail mode.
#[serde(default)]
pub preserve_pipeline_status: bool,
}

/// Shell syntax used by the module machine.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ShellFlavor {
/// Windows cmd syntax, including percent-variable expansion.
Cmd,
/// POSIX shell syntax, using Bash when available.
Posix,
}

/// Selected invocation, returned for discovery and consumed inside `TinyBox`.
/// Hosts execute commands through the module rather than spawning this plan.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ShellInvocation {
/// Syntax understood by the selected shell.
pub flavor: ShellFlavor,
/// Shell executable on the module machine.
pub program: String,
/// Ordinary process arguments, excluding the executable.
pub arguments: Vec<String>,
/// Windows command payload appended verbatim after ordinary arguments.
/// Rust's ordinary argument escaping is incompatible with cmd quotes.
pub raw_arguments: Option<String>,
/// Parent environment names needed to bootstrap Windows child tools.
/// Values are never returned by shell discovery.
pub bootstrap_environment: Vec<String>,
/// Remove these startup-hook variables after applying the approved environment.
#[serde(default)]
pub remove_environment: Vec<String>,
}
6 changes: 4 additions & 2 deletions crates/tinybox-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ publish = false

[dependencies]
tinybox-core.workspace = true
# Shell selection shares the module's serialized invocation vocabulary.
tinybox-bus.workspace = true
Comment thread
senamakel marked this conversation as resolved.
tinybox-jail.workspace = true
async-trait.workspace = true
# `Dir` keeps workspace file handles beneath the approved root without
Expand All @@ -25,8 +27,8 @@ cap-std = "4"
tokio = { workspace = true, features = ["process", "io-util", "sync"] }

[target.'cfg(unix)'.dependencies]
# Safe process-group signalling keeps shell descendants within supervised cleanup.
nix = { version = "0.30", default-features = false, features = ["signal", "process"] }
# Safe process-group signalling supervises descendants; access checks select executable shells.
nix = { version = "0.30", default-features = false, features = ["signal", "process", "fs"] }

[target.'cfg(windows)'.dependencies]
# Job Objects keep supervised Windows descendants inside one killable process tree.
Expand Down
3 changes: 3 additions & 0 deletions crates/tinybox-host/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ mod local;
pub use limited::{JailLocalHost, LimitedLocalHost, ManagedProcess};

pub use local::{LocalHost, NAME as LOCAL};

/// Platform shell discovery and command construction owned by the local host.
pub use local::shell::{build_shell_command, select_shell};
29 changes: 28 additions & 1 deletion crates/tinybox-host/src/limited/jailed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,34 @@ impl JailLocalHost {
let mut command = crate::LocalHost::command(request)?.into_std();
// The host explicitly supplies the approved environment for jailed code.
command.env_clear().envs(&request.env);
self.collect_command(command, request.stdin.clone(), observer)
.await
}

/// Collect a prepared shell inside this host's explicit native jail.
/// The caller clears and supplies the approved environment before invocation.
/// # Errors
/// Reports unavailable spawn, output bounds and retained kill/reap failures.
pub async fn run_command_observed(
&self,
mut command: std::process::Command,
payload: Option<Vec<u8>>,
observer: Arc<dyn ExecutionObserver>,
) -> Result<ExecOutput> {
command.stdin(if payload.is_some() {
std::process::Stdio::piped()
} else {
std::process::Stdio::null()
});
self.collect_command(command, payload, Some(observer)).await
}

async fn collect_command(
&self,
mut command: std::process::Command,
payload: Option<Vec<u8>>,
observer: Option<Arc<dyn ExecutionObserver>>,
) -> Result<ExecOutput> {
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
Expand All @@ -181,7 +209,6 @@ impl JailLocalHost {
.stderr(std::process::Stdio::piped());
let jail = self.jail.clone();
let backend = self.backend.clone();
let payload = request.stdin.clone();
let state = self.state.clone();
let limit = self.limit;
let runtime = tokio::runtime::Handle::try_current()
Expand Down
Loading
Loading