const std = @import("std");
const builtin = @import("builtin");
const command_effect = @import("../shell_command/command_effect.zig");
const command_contract = @import("../execution/command_contract.zig");
const command_runner = @import("../execution/command_runner.zig");
const debug_trace = @import("../shared/debug_trace.zig");
const io_mod = @import("../shared/io.zig");
const mem_utils = @import("../shared/mem_utils.zig");
const types = @import("../shared/types.zig");
pub const direct_output_limit_bytes: usize = 65_536;
const direct_output_read_chunk_bytes: usize = 4096;
const DirectOutputProjector = struct {
utf8_pending: [3]u8 = undefined,
utf8_pending_len: u2 = 0,
escaped_controls: usize = 0,
escaped_invalid: usize = 0,
fn push(
self: *DirectOutputProjector,
alloc: std.mem.Allocator,
raw: []const u8,
projected: *std.ArrayList(u8),
) !void {
var combined: [direct_output_read_chunk_bytes + 3]u8 = undefined;
const pending_len: usize = self.utf8_pending_len;
@memcpy(combined[0..pending_len], self.utf8_pending[0..pending_len]);
@memcpy(combined[pending_len .. pending_len + raw.len], raw);
const bytes = combined[0 .. pending_len + raw.len];
self.utf8_pending_len = 0;
var index: usize = 0;
while (index < bytes.len) {
const byte = bytes[index];
if (byte < 0x80) {
if (byte == '\n') {
try projected.append(alloc, byte);
} else if (byte < 0x20 or byte == 0x7f) {
self.escaped_controls += 1;
try appendByteEscape(alloc, projected, byte);
} else {
try projected.append(alloc, byte);
}
index += 1;
continue;
}
const sequence_len: usize = std.unicode.utf8ByteSequenceLength(byte) catch {
self.escaped_invalid += 1;
try appendByteEscape(alloc, projected, byte);
index += 1;
continue;
};
if (bytes.len - index < sequence_len) {
const remainder = bytes[index..];
@memcpy(self.utf8_pending[0..remainder.len], remainder);
self.utf8_pending_len = @intCast(remainder.len);
break;
}
const sequence = bytes[index .. index + sequence_len];
const scalar = std.unicode.utf8Decode(sequence) catch {
self.escaped_invalid += 1;
try appendByteEscape(alloc, projected, byte);
index += 1;
continue;
};
if (scalar >= 0x80 and scalar <= 0x9f) {
self.escaped_controls += 1;
try appendC1Escape(alloc, projected, @intCast(scalar));
} else {
try projected.appendSlice(alloc, sequence);
}
index += sequence_len;
}
}
fn finish(
self: *DirectOutputProjector,
alloc: std.mem.Allocator,
projected: *std.ArrayList(u8),
) !void {
for (self.utf8_pending[0..self.utf8_pending_len]) |byte| {
self.escaped_invalid += 1;
try appendByteEscape(alloc, projected, byte);
}
self.utf8_pending_len = 0;
}
};
fn appendByteEscape(
alloc: std.mem.Allocator,
projected: *std.ArrayList(u8),
byte: u8,
) !void {
const digits = "0123456789abcdef";
try projected.appendSlice(alloc, &.{
'\\',
'x',
digits[byte >> 4],
digits[byte & 0x0f],
});
}
fn appendC1Escape(
alloc: std.mem.Allocator,
projected: *std.ArrayList(u8),
byte: u8,
) !void {
const digits = "0123456789abcdef";
try projected.appendSlice(alloc, &.{
'\\',
'u',
'{',
'0',
'0',
digits[byte >> 4],
digits[byte & 0x0f],
'}',
});
}
const DirectOutputBudget = struct {
limit: usize,
admitted: usize = 0,
tripped: bool = false,
lock: std.Io.Mutex = .init,
const Charge = struct {
admit_chunk: bool,
trip_owner: bool,
};
fn charge(self: *DirectOutputBudget, observed_len: usize) Charge {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
if (self.tripped) {
return .{ .admit_chunk = false, .trip_owner = false };
}
if (observed_len <= self.limit - self.admitted) {
self.admitted += observed_len;
return .{ .admit_chunk = true, .trip_owner = false };
}
self.tripped = true;
return .{ .admit_chunk = false, .trip_owner = true };
}
fn remaining(self: *DirectOutputBudget) usize {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
return self.limit - self.admitted;
}
};
pub fn executeDirectReadOnly(
cfg: command_runner.Config,
alloc: std.mem.Allocator,
plan: command_effect.DirectReadOnlyPlan,
) !command_contract.RunCommandResult {
return executeDirectReadOnlyWithLimit(cfg, alloc, plan, direct_output_limit_bytes);
}
fn executeDirectReadOnlyWithLimit(
cfg: command_runner.Config,
alloc: std.mem.Allocator,
plan: command_effect.DirectReadOnlyPlan,
output_limit: usize,
) !command_contract.RunCommandResult {
return executeDirectReadOnlyWithLimitAndTestControls(cfg, alloc, plan, output_limit, .{});
}
const DirectExecutionTestControls = struct {
context: ?*anyopaque = null,
after_spawn: ?*const fn (*anyopaque, usize, *const std.process.Child) void = null,
};
fn executeDirectReadOnlyWithLimitAndTestControls(
cfg: command_runner.Config,
alloc: std.mem.Allocator,
plan: command_effect.DirectReadOnlyPlan,
output_limit: usize,
test_controls: DirectExecutionTestControls,
) !command_contract.RunCommandResult {
if (plan.stages.len == 0) return error.InvalidDirectPlan;
if (plan.stages.len > command_effect.max_direct_pipeline_stages) {
return error.InvalidDirectPlan;
}
var execution_cfg = cfg;
if (execution_cfg.timeout_ms != null and execution_cfg.timeout_started_ms == null) {
execution_cfg.timeout_started_ms = io_mod.milliTimestamp();
}
try checkControl(execution_cfg);
if (builtin.os.tag != .macos and builtin.os.tag != .linux) {
return error.UnsupportedDirectPlatform;
}
var scratch_state = std.heap.ArenaAllocator.init(alloc);
defer mem_utils.deinit_arena(scratch_state);
const scratch = scratch_state.allocator();
var children = try scratch.alloc(std.process.Child, plan.stages.len);
var child_count: usize = 0;
var group_id: ?std.posix.pid_t = null;
var pre_worker_cleanup_pending = true;
errdefer if (pre_worker_cleanup_pending) {
cleanupChildren(children[0..child_count], group_id);
};
const started_ms = io_mod.milliTimestamp();
while (child_count < plan.stages.len) : (child_count += 1) {
try checkControl(execution_cfg);
const stage = plan.stages[child_count];
var environment = try environmentForProfile(scratch, stage.environment_profile);
defer environment.deinit();
const child = std.process.spawn(io_mod.getIo(), .{
.argv = stage.argv,
.cwd = .{ .path = plan.cwd },
.environ_map = &environment,
.stdin = if (child_count == 0) .ignore else .pipe,
.stdout = .pipe,
.stderr = .pipe,
.pgid = if (builtin.os.tag != .windows and builtin.os.tag != .wasi)
(if (child_count == 0) 0 else group_id)
else
null,
}) catch |err| {
return switch (err) {
error.FileNotFound => error.DirectExecutableUnavailable,
else => err,
};
};
children[child_count] = child;
if (child_count == 0 and builtin.os.tag != .windows and builtin.os.tag != .wasi) {
group_id = child.id;
}
if (test_controls.after_spawn) |after_spawn| {
after_spawn(test_controls.context.?, child_count, &children[child_count]);
}
}
var output = DirectOutput.init(alloc, execution_cfg);
defer output.deinit();
var shared: SharedExecution = .{
.cfg = execution_cfg,
.budget = .{ .limit = output_limit },
.output = &output,
};
const worker_count = plan.stages.len * 2;
const workers = try scratch.alloc(OutputWorker, worker_count);
var initialized_workers: usize = 0;
for (0..plan.stages.len - 1) |index| {
workers[initialized_workers] = .{
.shared = &shared,
.source = children[index].stdout.?,
.destination = children[index + 1].stdin.?,
.kind = .relay,
};
children[index].stdout = null;
children[index + 1].stdin = null;
initialized_workers += 1;
}
workers[initialized_workers] = .{
.shared = &shared,
.source = children[plan.stages.len - 1].stdout.?,
.kind = .{ .projected = .stdout },
};
children[plan.stages.len - 1].stdout = null;
initialized_workers += 1;
for (children[0..child_count]) |*child| {
workers[initialized_workers] = .{
.shared = &shared,
.source = child.stderr.?,
.kind = .{ .projected = .stderr },
};
child.stderr = null;
initialized_workers += 1;
}
std.debug.assert(initialized_workers == worker_count);
pre_worker_cleanup_pending = false;
var started_workers: usize = 0;
while (started_workers < workers.len) : (started_workers += 1) {
workers[started_workers].thread = std.Thread.spawn(
.{},
OutputWorker.run,
.{&workers[started_workers]},
) catch |err| {
shared.commit(.output_failure, err);
signalGroup(group_id, true);
for (workers[started_workers..]) |*worker| worker.closeUnstarted();
for (workers[0..started_workers]) |*worker| worker.thread.?.join();
waitChildren(children[0..child_count]);
const failure = shared.failure() orelse err;
debug_trace.logf(
"core",
"direct command worker start failed route=direct_read_only cause={s} limit={d} admitted_raw_bytes={d} remaining_raw_bytes={d} children_reaped={d} workers_joined={d} artifact=false",
.{
@tagName(shared.cause.?),
shared.budget.limit,
shared.budget.admitted,
shared.budget.remaining(),
child_count,
started_workers,
},
);
return failure;
};
}
var termination_started_ms: ?i64 = null;
var force_kill_sent = false;
while (!allWorkersDone(workers)) {
if (!shared.isStopping()) {
if (execution_cfg.cancel_flag) |flag| {
if (flag.load(.seq_cst)) shared.commit(.cancelled, error.Cancelled);
}
if (!shared.isStopping() and deadlineExpired(execution_cfg)) {
shared.commit(.timed_out, error.TimeoutExpired);
}
}
if (shared.isStopping()) {
const now = io_mod.milliTimestamp();
if (termination_started_ms == null) {
signalGroup(group_id, false);
termination_started_ms = now;
} else if (!force_kill_sent and now - termination_started_ms.? >= 800) {
signalGroup(group_id, true);
force_kill_sent = true;
}
}
io_mod.sleep(5 * std.time.ns_per_ms);
}
for (workers) |*worker| worker.thread.?.join();
var final_term: std.process.Child.Term = .{ .unknown = 0 };
for (children[0..child_count], 0..) |*child, index| {
const term = child.wait(io_mod.getIo()) catch |err| {
shared.commit(.output_failure, err);
continue;
};
if (index + 1 == child_count) final_term = term;
}
if (shared.failure()) |failure| {
if (shared.cause == .timed_out) {
output.flushCallbacks() catch |err| debug_trace.logf(
"core",
"direct command timeout callback flush failed err={s}",
.{@errorName(err)},
);
}
debug_trace.logf(
"core",
"direct command terminated route=direct_read_only cause={s} limit={d} admitted_raw_bytes={d} remaining_raw_bytes={d} projected_bytes={d} escaped_controls={d} escaped_invalid={d} children_reaped={d} workers_joined={d} artifact=false",
.{
@tagName(shared.cause.?),
shared.budget.limit,
shared.budget.admitted,
shared.budget.remaining(),
output.stdout.items.len + output.stderr.items.len,
output.escaped_controls,
output.escaped_invalid,
child_count,
workers.len,
},
);
return failure;
}
try output.flushCallbacks();
const duration_ms = elapsedMs(started_ms, io_mod.milliTimestamp());
debug_trace.logf(
"core",
"direct command completed route=direct_read_only limit={d} admitted_raw_bytes={d} remaining_raw_bytes={d} projected_bytes={d} escaped_controls={d} escaped_invalid={d} children_reaped={d} workers_joined={d} artifact=false",
.{
shared.budget.limit,
shared.budget.admitted,
shared.budget.remaining(),
output.stdout.items.len + output.stderr.items.len,
output.escaped_controls,
output.escaped_invalid,
child_count,
workers.len,
},
);
return formatDirectResult(
alloc,
plan,
final_term,
output.stdout.items,
output.stderr.items,
output.stdout_bytes,
output.stderr_bytes,
duration_ms,
);
}
fn environmentForProfile(
alloc: std.mem.Allocator,
profile: command_effect.EnvironmentProfile,
) !std.process.Environ.Map {
var environment = std.process.Environ.Map.init(alloc);
errdefer environment.deinit();
switch (profile) {
.basic_read_only, .git_read_only => {
try environment.put("PATH", "/usr/bin:/bin");
try environment.put("LC_ALL", "C");
try environment.put("LANG", "C");
},
}
if (profile == .git_read_only) {
try environment.put("GIT_CONFIG_NOSYSTEM", "1");
try environment.put("GIT_CONFIG_GLOBAL", "/dev/null");
try environment.put("GIT_OPTIONAL_LOCKS", "0");
try environment.put("GIT_TERMINAL_PROMPT", "0");
try environment.put("GIT_PAGER", "cat");
try environment.put("PAGER", "cat");
}
return environment;
}
const DirectTerminationCause = enum {
cancelled,
timed_out,
output_limit,
output_failure,
};
const SharedExecution = struct {
cfg: command_runner.Config,
budget: DirectOutputBudget,
output: *DirectOutput,
lock: std.Io.Mutex = .init,
stopping: std.atomic.Value(bool) = .init(false),
cause: ?DirectTerminationCause = null,
failure_value: ?anyerror = null,
fn commit(
self: *SharedExecution,
reported: DirectTerminationCause,
failure_value: anyerror,
) void {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
if (self.cause != null) return;
if (self.cfg.cancel_flag) |flag| {
if (flag.load(.seq_cst)) {
self.cause = .cancelled;
self.failure_value = error.Cancelled;
self.stopping.store(true, .release);
return;
}
}
if (deadlineExpired(self.cfg)) {
self.cause = .timed_out;
self.failure_value = error.TimeoutExpired;
self.stopping.store(true, .release);
return;
}
self.cause = reported;
self.failure_value = failure_value;
self.stopping.store(true, .release);
}
fn isStopping(self: *SharedExecution) bool {
return self.stopping.load(.acquire);
}
fn failure(self: *SharedExecution) ?anyerror {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
return self.failure_value;
}
};
const WorkerKind = union(enum) {
relay,
projected: command_contract.CommandOutputStream,
};
const RelayWriteResult = enum {
forwarded,
downstream_closed,
};
fn writeRelayChunk(destination: std.Io.File, raw: []const u8) !RelayWriteResult {
destination.writeStreamingAll(io_mod.getIo(), raw) catch |err| switch (err) {
error.BrokenPipe => return .downstream_closed,
else => return err,
};
return .forwarded;
}
const OutputWorker = struct {
shared: *SharedExecution,
source: std.Io.File,
destination: ?std.Io.File = null,
kind: WorkerKind,
done: std.atomic.Value(bool) = .init(false),
thread: ?std.Thread = null,
fn run(self: *OutputWorker) void {
defer self.done.store(true, .release);
defer self.source.close(io_mod.getIo());
defer if (self.destination) |destination| destination.close(io_mod.getIo());
self.runFallible() catch |err| self.shared.commit(.output_failure, err);
}
fn runFallible(self: *OutputWorker) !void {
var projector: DirectOutputProjector = .{};
defer self.shared.output.addProjectionStats(projector.escaped_controls, projector.escaped_invalid);
var projected: std.ArrayList(u8) = .empty;
defer projected.deinit(self.shared.output.alloc);
var buffer: [direct_output_read_chunk_bytes]u8 = undefined;
while (!self.shared.isStopping()) {
const count = self.source.readStreaming(io_mod.getIo(), &.{buffer[0..]}) catch |err| switch (err) {
error.EndOfStream => break,
else => return err,
};
if (count == 0) break;
const raw = buffer[0..count];
const charge = self.shared.budget.charge(raw.len);
if (!charge.admit_chunk) {
if (charge.trip_owner) {
debug_trace.logf(
"core",
"direct_output_limit_exceeded route=direct_read_only limit={d} admitted_raw_bytes={d} remaining_raw_bytes={d} stream={s}",
.{
self.shared.budget.limit,
self.shared.budget.admitted,
self.shared.budget.remaining(),
@tagName(self.kind),
},
);
self.shared.commit(.output_limit, error.DirectOutputLimitExceeded);
}
break;
}
switch (self.kind) {
.relay => switch (try writeRelayChunk(self.destination.?, raw)) {
.forwarded => {},
.downstream_closed => {
const remaining = self.shared.budget.remaining();
debug_trace.logf(
"core",
"direct relay route=direct_read_only downstream_closed=true admitted_raw_bytes={d} remaining_raw_bytes={d}",
.{ self.shared.budget.limit - remaining, remaining },
);
break;
},
},
.projected => |stream| {
try projector.push(self.shared.output.alloc, raw, &projected);
try self.shared.output.append(stream, raw, projected.items);
projected.clearRetainingCapacity();
},
}
}
if (!self.shared.isStopping()) {
switch (self.kind) {
.relay => {},
.projected => |stream| {
try projector.finish(self.shared.output.alloc, &projected);
try self.shared.output.append(stream, "", projected.items);
},
}
}
}
fn closeUnstarted(self: *OutputWorker) void {
self.source.close(io_mod.getIo());
if (self.destination) |destination| destination.close(io_mod.getIo());
self.done.store(true, .release);
}
};
const DirectOutput = struct {
alloc: std.mem.Allocator,
cfg: command_runner.Config,
lock: std.Io.Mutex = .init,
stdout: std.ArrayList(u8) = .empty,
stderr: std.ArrayList(u8) = .empty,
stdout_pending: std.ArrayList(u8) = .empty,
stderr_pending: std.ArrayList(u8) = .empty,
stdout_bytes: usize = 0,
stderr_bytes: usize = 0,
escaped_controls: usize = 0,
escaped_invalid: usize = 0,
fn init(alloc: std.mem.Allocator, cfg: command_runner.Config) DirectOutput {
return .{ .alloc = alloc, .cfg = cfg };
}
fn deinit(self: *DirectOutput) void {
self.stdout.deinit(self.alloc);
self.stderr.deinit(self.alloc);
self.stdout_pending.deinit(self.alloc);
self.stderr_pending.deinit(self.alloc);
}
fn append(
self: *DirectOutput,
stream: command_contract.CommandOutputStream,
raw: []const u8,
projected: []const u8,
) !void {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
try self.emitAcceptedCallback(stream, raw);
switch (stream) {
.stdout => {
self.stdout_bytes += raw.len;
try self.stdout.appendSlice(self.alloc, projected);
try self.emitCallback(&self.stdout_pending, stream, raw, projected, false);
},
.stderr => {
self.stderr_bytes += raw.len;
try self.stderr.appendSlice(self.alloc, projected);
try self.emitCallback(&self.stderr_pending, stream, raw, projected, false);
},
}
}
fn flushCallbacks(self: *DirectOutput) !void {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
try self.emitCallback(&self.stdout_pending, .stdout, "", "", true);
try self.emitCallback(&self.stderr_pending, .stderr, "", "", true);
}
fn addProjectionStats(
self: *DirectOutput,
escaped_controls: usize,
escaped_invalid: usize,
) void {
const io = io_mod.getIo();
self.lock.lockUncancelable(io);
defer self.lock.unlock(io);
self.escaped_controls += escaped_controls;
self.escaped_invalid += escaped_invalid;
}
fn emitCallback(
self: *DirectOutput,
pending: *std.ArrayList(u8),
stream: command_contract.CommandOutputStream,
raw: []const u8,
projected: []const u8,
flush: bool,
) !void {
const bytes = switch (self.cfg.callback_projection) {
.model_safe => projected,
.raw => raw,
};
if (bytes.len > 0) try pending.appendSlice(self.alloc, bytes);
const ctx = self.cfg.output_chunk_ctx orelse return;
const callback = self.cfg.on_output_chunk orelse return;
while (std.mem.findScalar(u8, pending.items, '\n')) |newline| {
try callback(ctx, self.cfg.output_chunk_lifecycle_id, stream, pending.items[0 .. newline + 1]);
const remaining = pending.items.len - newline - 1;
std.mem.copyForwards(u8, pending.items[0..remaining], pending.items[newline + 1 ..]);
pending.items.len = remaining;
}
if (!flush and pending.items.len >= direct_output_read_chunk_bytes) {
try callback(ctx, self.cfg.output_chunk_lifecycle_id, stream, pending.items);
pending.clearRetainingCapacity();
}
if (flush and pending.items.len > 0) {
try callback(ctx, self.cfg.output_chunk_lifecycle_id, stream, pending.items);
pending.clearRetainingCapacity();
}
}
fn emitAcceptedCallback(
self: *DirectOutput,
stream: command_contract.CommandOutputStream,
raw: []const u8,
) !void {
if (raw.len == 0) return;
const ctx = self.cfg.accepted_output_chunk_ctx orelse return;
const callback = self.cfg.on_accepted_output_chunk orelse return;
try callback(ctx, self.cfg.output_chunk_lifecycle_id, stream, raw);
}
};
fn allWorkersDone(workers: []const OutputWorker) bool {
for (workers) |*worker| {
if (!worker.done.load(.acquire)) return false;
}
return true;
}
fn checkControl(cfg: command_runner.Config) !void {
if (cfg.cancel_flag) |flag| {
if (flag.load(.seq_cst)) return error.Cancelled;
}
if (deadlineExpired(cfg)) return error.TimeoutExpired;
}
fn deadlineExpired(cfg: command_runner.Config) bool {
const timeout_ms = cfg.timeout_ms orelse return false;
const started_ms = cfg.timeout_started_ms orelse return false;
return io_mod.milliTimestamp() - started_ms >= @as(i64, @intCast(timeout_ms));
}
fn signalGroup(group_id: ?std.posix.pid_t, force: bool) void {
if (builtin.os.tag == .windows or builtin.os.tag == .wasi) return;
const pid = group_id orelse return;
std.posix.kill(-pid, if (force) std.posix.SIG.KILL else std.posix.SIG.TERM) catch |err| switch (err) {
error.ProcessNotFound => {},
else => debug_trace.logf("core", "direct command signal failed err={s}", .{@errorName(err)}),
};
}
fn closeChildPipes(child: *std.process.Child) void {
if (child.stdin) |file| file.close(io_mod.getIo());
if (child.stdout) |file| file.close(io_mod.getIo());
if (child.stderr) |file| file.close(io_mod.getIo());
child.stdin = null;
child.stdout = null;
child.stderr = null;
}
fn cleanupChildren(children: []std.process.Child, group_id: ?std.posix.pid_t) void {
signalGroup(group_id, true);
for (children) |*child| closeChildPipes(child);
waitChildren(children);
}
fn waitChildren(children: []std.process.Child) void {
for (children) |*child| {
_ = child.wait(io_mod.getIo()) catch |err| {
debug_trace.logf("core", "direct command cleanup wait failed err={s}", .{@errorName(err)});
};
}
}
fn elapsedMs(started_ms: i64, finished_ms: i64) u64 {
if (finished_ms <= started_ms) return 0;
return @intCast(finished_ms - started_ms);
}
fn formatDirectResult(
alloc: std.mem.Allocator,
plan: command_effect.DirectReadOnlyPlan,
term: std.process.Child.Term,
stdout_projected: []const u8,
stderr_projected: []const u8,
stdout_bytes: usize,
stderr_bytes: usize,
duration_ms: u64,
) !command_contract.RunCommandResult {
return command_contract.formatCommandResult(alloc, .{
.command = plan.command,
.cwd = plan.cwd,
.status = commandStatusFromTerm(term),
.stdout_display = stdout_projected,
.stderr_display = stderr_projected,
.stdout_bytes = stdout_bytes,
.stderr_bytes = stderr_bytes,
.duration_ms = duration_ms,
});
}
fn commandStatusFromTerm(term: std.process.Child.Term) command_contract.CommandStatus {
return switch (term) {
.exited => |code| .{ .exit_code = @intCast(code) },
.signal => |sig| .{ .signal = @intFromEnum(sig) },
else => .finished,
};
}
fn projectForTest(alloc: std.mem.Allocator, chunks: []const []const u8) ![]u8 {
var projector: DirectOutputProjector = .{};
var projected: std.ArrayList(u8) = .empty;
errdefer projected.deinit(alloc);
for (chunks) |chunk| try projector.push(alloc, chunk, &projected);
try projector.finish(alloc, &projected);
return projected.toOwnedSlice(alloc);
}
test "direct projector renders terminal controls invalid bytes and split utf8 visibly" {
const chunks = [_][]const u8{
"ok\n\x00\x07\x08\x09\x0d\x1b\x7f",
"\xc2",
"\x85",
"\xe2\x82",
"\xac",
"\xff\xf0\x9f",
};
const projected = try projectForTest(std.testing.allocator, &chunks);
defer std.testing.allocator.free(projected);
try std.testing.expectEqualStrings(
"ok\n\\x00\\x07\\x08\\x09\\x0d\\x1b\\x7f\\u{0085}\u{20ac}\\xff\\xf0\\x9f",
projected,
);
try std.testing.expect(std.unicode.utf8ValidateSlice(projected));
}
test "direct projector covers every c0 byte del and preserves non-control utf8" {
var raw: [128]u8 = undefined;
var len: usize = 0;
for (0..32) |byte| {
raw[len] = @intCast(byte);
len += 1;
}
raw[len] = 0x7f;
len += 1;
const suffix = "ASCII \u{00e9} \u{1f642}\n";
@memcpy(raw[len .. len + suffix.len], suffix);
len += suffix.len;
const projected = try projectForTest(std.testing.allocator, &.{raw[0..len]});
defer std.testing.allocator.free(projected);
try std.testing.expect(std.mem.find(u8, projected, "\\x00") != null);
try std.testing.expect(std.mem.find(u8, projected, "\\x1f") != null);
try std.testing.expect(std.mem.find(u8, projected, "\\x7f") != null);
try std.testing.expect(std.mem.find(u8, projected, "ASCII \u{00e9} \u{1f642}\n") != null);
try std.testing.expect(projected.len <= raw[0..len].len * 4);
}
test "direct output budget admits whole chunks and trips exactly once" {
var budget: DirectOutputBudget = .{ .limit = 8 };
try std.testing.expectEqual(
DirectOutputBudget.Charge{ .admit_chunk = true, .trip_owner = false },
budget.charge(4),
);
try std.testing.expectEqual(@as(usize, 4), budget.remaining());
try std.testing.expectEqual(
DirectOutputBudget.Charge{ .admit_chunk = true, .trip_owner = false },
budget.charge(4),
);
try std.testing.expectEqual(@as(usize, 0), budget.remaining());
try std.testing.expectEqual(
DirectOutputBudget.Charge{ .admit_chunk = false, .trip_owner = true },
budget.charge(1),
);
try std.testing.expectEqual(
DirectOutputBudget.Charge{ .admit_chunk = false, .trip_owner = false },
budget.charge(1),
);
try std.testing.expectEqual(@as(usize, 8), budget.admitted);
}
test "direct output budget synchronizes concurrent producers and has one trip owner" {
var budget: DirectOutputBudget = .{ .limit = 16 };
var trip_owners = std.atomic.Value(usize).init(0);
const Producer = struct {
fn run(shared_budget: *DirectOutputBudget, owners: *std.atomic.Value(usize)) void {
const charge = shared_budget.charge(1);
if (charge.trip_owner) _ = owners.fetchAdd(1, .seq_cst);
}
};
var threads: [32]std.Thread = undefined;
for (&threads) |*thread| {
thread.* = try std.Thread.spawn(.{}, Producer.run, .{ &budget, &trip_owners });
}
for (threads) |thread| thread.join();
try std.testing.expectEqual(@as(usize, 16), budget.admitted);
try std.testing.expect(budget.tripped);
try std.testing.expectEqual(@as(usize, 1), trip_owners.load(.seq_cst));
}
test "direct termination arbiter gives cancellation and timeout precedence" {
var output = DirectOutput.init(std.testing.allocator, .{
.max_command_output_bytes = 1,
});
defer output.deinit();
var cancel = std.atomic.Value(bool).init(true);
var cancelled: SharedExecution = .{
.cfg = .{
.max_command_output_bytes = 1,
.cancel_flag = &cancel,
},
.budget = .{ .limit = 1 },
.output = &output,
};
cancelled.commit(.output_limit, error.DirectOutputLimitExceeded);
try std.testing.expectEqual(error.Cancelled, cancelled.failure().?);
var timed_out: SharedExecution = .{
.cfg = .{
.max_command_output_bytes = 1,
.timeout_ms = 1,
.timeout_started_ms = io_mod.milliTimestamp() - 10,
},
.budget = .{ .limit = 1 },
.output = &output,
};
timed_out.commit(.output_failure, error.BrokenPipe);
try std.testing.expectEqual(error.TimeoutExpired, timed_out.failure().?);
var first_failure: SharedExecution = .{
.cfg = .{
.max_command_output_bytes = 1,
},
.budget = .{ .limit = 1 },
.output = &output,
};
first_failure.commit(.output_limit, error.DirectOutputLimitExceeded);
first_failure.commit(.output_failure, error.BrokenPipe);
try std.testing.expectEqual(error.DirectOutputLimitExceeded, first_failure.failure().?);
}
test "direct executor runs fixed argv with sanitized environment and no artifact" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{"/usr/bin/env"};
const stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/env",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
const result = executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, .{
.command = "/usr/bin/env",
.cwd = "/tmp",
.stages = &stages,
}) catch |err| {
std.debug.print("sanitized environment execution failed: {s}\n", .{@errorName(err)});
return err;
};
defer std.testing.allocator.free(result.output);
try std.testing.expect(std.mem.find(u8, result.output, "PATH=/usr/bin:/bin") != null);
try std.testing.expect(std.mem.find(u8, result.output, "LC_ALL=C") != null);
try std.testing.expect(std.mem.find(u8, result.output, "LANG=C") != null);
try std.testing.expect(std.mem.find(u8, result.output, "HOME=") == null);
try std.testing.expectEqual(@as(?[]const u8, null), result.command_result.?.output_file);
}
test "git direct profile removes ambient authority and disables optional mutation" {
var environment = try environmentForProfile(std.testing.allocator, .git_read_only);
defer environment.deinit();
try std.testing.expectEqualStrings("/usr/bin:/bin", environment.get("PATH").?);
try std.testing.expectEqualStrings("1", environment.get("GIT_CONFIG_NOSYSTEM").?);
try std.testing.expectEqualStrings("/dev/null", environment.get("GIT_CONFIG_GLOBAL").?);
try std.testing.expectEqualStrings("0", environment.get("GIT_OPTIONAL_LOCKS").?);
try std.testing.expectEqualStrings("0", environment.get("GIT_TERMINAL_PROMPT").?);
try std.testing.expectEqualStrings("cat", environment.get("GIT_PAGER").?);
try std.testing.expect(environment.get("HOME") == null);
}
test "direct executor runs a supported pipeline and reports final output" {
var admission = try command_effect.plan(
std.testing.allocator,
"printf x | wc -c",
"/tmp",
false,
@import("builtin").os.tag,
);
defer admission.deinit(std.testing.allocator);
const plan = admission.direct_read_only;
const result = executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, plan) catch |err| {
std.debug.print("pipeline execution failed: {s}\n", .{@errorName(err)});
return err;
};
defer std.testing.allocator.free(result.output);
try std.testing.expect(std.mem.find(u8, result.output, "\n1\n") != null);
const foreground = result.command_result.?;
try std.testing.expectEqualStrings("printf x | wc -c", foreground.command);
try std.testing.expectEqual(@as(?i64, 0), foreground.exit_code);
const expected_stdout_bytes: usize = if (builtin.os.tag == .linux) 2 else 9;
try std.testing.expectEqual(expected_stdout_bytes, foreground.stdout_bytes);
try std.testing.expectEqual(@as(?[]const u8, null), foreground.output_file);
try std.testing.expectEqual(@as(?[]const u8, null), foreground.stdout_file);
try std.testing.expectEqual(@as(?[]const u8, null), foreground.stderr_file);
}
test "direct executor rejects plans above the pipeline stage limit" {
const argv = [_][]const u8{ "/usr/bin/wc", "-c" };
var stages: [command_effect.max_direct_pipeline_stages + 1]command_effect.DirectStage = undefined;
for (&stages) |*stage| {
stage.* = .{
.executable = "/usr/bin/wc",
.argv = &argv,
.environment_profile = .basic_read_only,
};
}
try std.testing.expectError(
error.InvalidDirectPlan,
executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stages)),
);
}
test "direct executor uses the canonical production output limit" {
try std.testing.expectEqual(@as(usize, 65_536), direct_output_limit_bytes);
try std.testing.expectEqual(@as(usize, 4096), direct_output_read_chunk_bytes);
}
fn createListingFiles(
dir: std.Io.Dir,
full_length_count: usize,
include_254_byte_name: bool,
include_one_byte_name: bool,
) !void {
for (0..full_length_count) |index| {
var name: [255]u8 = undefined;
@memset(&name, 'x');
_ = try std.fmt.bufPrint(name[0..4], "{d:0>4}", .{index});
var file = try dir.createFile(io_mod.getIo(), &name, .{ .truncate = true });
file.close(io_mod.getIo());
}
if (include_254_byte_name) {
var name: [254]u8 = undefined;
@memset(&name, 'y');
var file = try dir.createFile(io_mod.getIo(), &name, .{ .truncate = true });
file.close(io_mod.getIo());
}
if (include_one_byte_name) {
var file = try dir.createFile(io_mod.getIo(), "z", .{ .truncate = true });
file.close(io_mod.getIo());
}
}
test "direct executor enforces canonical capacity with native large ls output" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const alloc = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
try tmp.dir.createDir(io_mod.getIo(), "above-32k", .default_dir);
try tmp.dir.createDir(io_mod.getIo(), "exact-64k", .default_dir);
try tmp.dir.createDir(io_mod.getIo(), "above-64k", .default_dir);
var above_32k = try tmp.dir.openDir(io_mod.getIo(), "above-32k", .{});
defer above_32k.close(io_mod.getIo());
var exact_64k = try tmp.dir.openDir(io_mod.getIo(), "exact-64k", .{});
defer exact_64k.close(io_mod.getIo());
var above_64k = try tmp.dir.openDir(io_mod.getIo(), "above-64k", .{});
defer above_64k.close(io_mod.getIo());
try createListingFiles(above_32k, 127, true, true);
try createListingFiles(exact_64k, 256, false, false);
try createListingFiles(above_64k, 255, true, true);
const cwd = try io_mod.dirRealpathAlloc(alloc, tmp.dir, ".");
defer alloc.free(cwd);
const SuccessCase = struct {
command: []const u8,
expected_bytes: usize,
};
for ([_]SuccessCase{
.{ .command = "ls above-32k", .expected_bytes = 32_769 },
.{ .command = "ls exact-64k", .expected_bytes = direct_output_limit_bytes },
}) |case| {
var admission = try command_effect.plan(
alloc,
case.command,
cwd,
false,
builtin.os.tag,
);
defer admission.deinit(alloc);
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, alloc, admission.direct_read_only);
defer alloc.free(result.output);
try std.testing.expectEqual(
case.expected_bytes,
result.command_result.?.stdout_bytes,
);
try std.testing.expectEqualStrings(
case.command,
result.command_result.?.command,
);
try std.testing.expectEqual(
@as(?[]const u8, null),
result.command_result.?.output_file,
);
}
var over_admission = try command_effect.plan(
alloc,
"ls above-64k",
cwd,
false,
builtin.os.tag,
);
defer over_admission.deinit(alloc);
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnly(.{
.max_command_output_bytes = std.math.maxInt(usize),
}, alloc, over_admission.direct_read_only),
);
}
fn injectedPlan(
cwd: []const u8,
stages: []const command_effect.DirectStage,
) command_effect.DirectReadOnlyPlan {
return .{
.command = stages[0].executable,
.cwd = cwd,
.stages = stages,
};
}
test "direct executor admits exact output limit and rejects limit plus one without artifacts" {
const exact_argv = [_][]const u8{ "/usr/bin/printf", "12345678" };
const exact_stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/printf",
.argv = &exact_argv,
.environment_profile = .basic_read_only,
}};
const exact = try executeDirectReadOnlyWithLimit(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &exact_stages), 8);
defer std.testing.allocator.free(exact.output);
try std.testing.expectEqual(@as(usize, 8), exact.command_result.?.stdout_bytes);
try std.testing.expectEqual(@as(?[]const u8, null), exact.command_result.?.output_file);
const over_argv = [_][]const u8{ "/usr/bin/printf", "123456789" };
const over_stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/printf",
.argv = &over_argv,
.environment_profile = .basic_read_only,
}};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnlyWithLimit(.{
.max_command_output_bytes = 1_000_000,
}, std.testing.allocator, injectedPlan("/tmp", &over_stages), 8),
);
}
test "direct executor canonical limit covers stderr and counted pipeline relays" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const exact_stderr_argv = [_][]const u8{
"/usr/bin/awk",
"BEGIN { for (i = 0; i < 65536; i++) printf \"x\" > \"/dev/stderr\" }",
};
const exact_stderr_stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/awk",
.argv = &exact_stderr_argv,
.environment_profile = .basic_read_only,
}};
const exact_stderr = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &exact_stderr_stages));
defer std.testing.allocator.free(exact_stderr.output);
try std.testing.expectEqual(
direct_output_limit_bytes,
exact_stderr.command_result.?.stderr_bytes,
);
try std.testing.expectEqual(
@as(?[]const u8, null),
exact_stderr.command_result.?.stderr_file,
);
const over_stderr_argv = [_][]const u8{
"/usr/bin/awk",
"BEGIN { for (i = 0; i < 65537; i++) printf \"x\" > \"/dev/stderr\" }",
};
const over_stderr_stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/awk",
.argv = &over_stderr_argv,
.environment_profile = .basic_read_only,
}};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnly(.{
.max_command_output_bytes = std.math.maxInt(usize),
}, std.testing.allocator, injectedPlan("/tmp", &over_stderr_stages)),
);
const exact_relay_bytes = direct_output_limit_bytes / 2;
const exact_data = try std.testing.allocator.alloc(u8, exact_relay_bytes);
defer std.testing.allocator.free(exact_data);
@memset(exact_data, 'r');
const exact_producer_argv = [_][]const u8{ "/usr/bin/printf", "%s", exact_data };
const cat_argv = [_][]const u8{"/bin/cat"};
const exact_pipeline = [_]command_effect.DirectStage{
.{
.executable = "/usr/bin/printf",
.argv = &exact_producer_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/bin/cat",
.argv = &cat_argv,
.environment_profile = .basic_read_only,
},
};
const exact_relay = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &exact_pipeline));
defer std.testing.allocator.free(exact_relay.output);
try std.testing.expectEqual(
exact_relay_bytes,
exact_relay.command_result.?.stdout_bytes,
);
const over_data = try std.testing.allocator.alloc(u8, exact_relay_bytes + 1);
defer std.testing.allocator.free(over_data);
@memset(over_data, 'r');
const over_producer_argv = [_][]const u8{ "/usr/bin/printf", "%s", over_data };
const over_pipeline = [_]command_effect.DirectStage{
.{
.executable = "/usr/bin/printf",
.argv = &over_producer_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/bin/cat",
.argv = &cat_argv,
.environment_profile = .basic_read_only,
},
};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnly(.{
.max_command_output_bytes = std.math.maxInt(usize),
}, std.testing.allocator, injectedPlan("/tmp", &over_pipeline)),
);
}
test "direct executor charges non-final pipeline bytes before relay" {
const producer_argv = [_][]const u8{ "/usr/bin/printf", "123456789" };
const consumer_argv = [_][]const u8{ "/usr/bin/wc", "-c" };
const stages = [_]command_effect.DirectStage{
.{
.executable = "/usr/bin/printf",
.argv = &producer_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/usr/bin/wc",
.argv = &consumer_argv,
.environment_profile = .basic_read_only,
},
};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnlyWithLimit(.{
.max_command_output_bytes = 1_000_000,
}, std.testing.allocator, injectedPlan("/tmp", &stages), 8),
);
}
test "direct executor enforces one budget across concurrent stdout and stderr" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const exact_argv = [_][]const u8{
"/bin/sh",
"-c",
"(printf 12345678) & (printf abcdefgh >&2) & wait",
};
const exact_stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &exact_argv,
.environment_profile = .basic_read_only,
}};
const exact = try executeDirectReadOnlyWithLimit(.{
.max_command_output_bytes = 1_000_000,
}, std.testing.allocator, injectedPlan("/tmp", &exact_stages), 16);
defer std.testing.allocator.free(exact.output);
try std.testing.expectEqual(@as(usize, 8), exact.command_result.?.stdout_bytes);
try std.testing.expectEqual(@as(usize, 8), exact.command_result.?.stderr_bytes);
const over_argv = [_][]const u8{
"/bin/sh",
"-c",
"(printf 123456789) & (printf abcdefgh >&2) & wait",
};
const over_stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &over_argv,
.environment_profile = .basic_read_only,
}};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnlyWithLimit(.{
.max_command_output_bytes = 1_000_000,
}, std.testing.allocator, injectedPlan("/tmp", &over_stages), 16),
);
}
test "direct executor reaps partial spawn and output-limit process groups" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const PidCapture = struct {
pid: ?std.posix.pid_t = null,
fn afterSpawn(raw: *anyopaque, stage_index: usize, child: *const std.process.Child) void {
if (stage_index != 0) return;
const self: *@This() = @ptrCast(@alignCast(raw));
self.pid = child.id;
}
fn expectReaped(self: *const @This()) !void {
const pid = self.pid.?;
defer {
std.posix.kill(-pid, std.posix.SIG.KILL) catch {};
_ = std.c.waitpid(pid, null, 0);
}
try std.testing.expectError(
error.ProcessNotFound,
std.posix.kill(pid, @enumFromInt(0)),
);
}
};
const sleep_argv = [_][]const u8{ "/bin/sleep", "10" };
const missing_argv = [_][]const u8{"/definitely/missing/fx-direct-second-stage"};
const partial_stages = [_]command_effect.DirectStage{
.{
.executable = "/bin/sleep",
.argv = &sleep_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/definitely/missing/fx-direct-second-stage",
.argv = &missing_argv,
.environment_profile = .basic_read_only,
},
};
var partial_capture = PidCapture{};
try std.testing.expectError(
error.DirectExecutableUnavailable,
executeDirectReadOnlyWithLimitAndTestControls(
.{
.max_command_output_bytes = 1,
},
std.testing.allocator,
injectedPlan("/tmp", &partial_stages),
direct_output_limit_bytes,
.{ .context = &partial_capture, .after_spawn = PidCapture.afterSpawn },
),
);
try partial_capture.expectReaped();
const limit_argv = [_][]const u8{
"/bin/sh",
"-c",
"printf 123456789; sleep 10",
};
const limit_stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &limit_argv,
.environment_profile = .basic_read_only,
}};
var limit_capture = PidCapture{};
try std.testing.expectError(
error.DirectOutputLimitExceeded,
executeDirectReadOnlyWithLimitAndTestControls(
.{
.max_command_output_bytes = 1_000_000,
},
std.testing.allocator,
injectedPlan("/tmp", &limit_stages),
8,
.{ .context = &limit_capture, .after_spawn = PidCapture.afterSpawn },
),
);
try limit_capture.expectReaped();
}
test "direct executor cleans up cancellation after the first pipeline spawn" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
var cancel = std.atomic.Value(bool).init(false);
const CancelAfterSpawn = struct {
cancel: *std.atomic.Value(bool),
pid: ?std.posix.pid_t = null,
fn run(raw: *anyopaque, stage_index: usize, child: *const std.process.Child) void {
if (stage_index != 0) return;
const self: *@This() = @ptrCast(@alignCast(raw));
self.pid = child.id;
self.cancel.store(true, .seq_cst);
}
};
var test_control = CancelAfterSpawn{ .cancel = &cancel };
const sleep_argv = [_][]const u8{ "/bin/sleep", "10" };
const wc_argv = [_][]const u8{ "/usr/bin/wc", "-c" };
const stages = [_]command_effect.DirectStage{
.{
.executable = "/bin/sleep",
.argv = &sleep_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/usr/bin/wc",
.argv = &wc_argv,
.environment_profile = .basic_read_only,
},
};
try std.testing.expectError(
error.Cancelled,
executeDirectReadOnlyWithLimitAndTestControls(
.{
.max_command_output_bytes = 1,
.cancel_flag = &cancel,
},
std.testing.allocator,
injectedPlan("/tmp", &stages),
direct_output_limit_bytes,
.{ .context = &test_control, .after_spawn = CancelAfterSpawn.run },
),
);
const pid = test_control.pid.?;
defer {
std.posix.kill(-pid, std.posix.SIG.KILL) catch {};
_ = std.c.waitpid(pid, null, 0);
}
try std.testing.expectError(
error.ProcessNotFound,
std.posix.kill(pid, @enumFromInt(0)),
);
}
test "direct executor projects hostile final stdout and stderr" {
const hostile_stdout = "\x1b]52;c;secret\x07\xff";
const stdout_argv = [_][]const u8{ "/usr/bin/printf", "%s", hostile_stdout };
const stdout_stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/printf",
.argv = &stdout_argv,
.environment_profile = .basic_read_only,
}};
const stdout_result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stdout_stages));
defer std.testing.allocator.free(stdout_result.output);
try std.testing.expect(std.mem.find(u8, stdout_result.output, "\\x1b]52;c;secret\\x07\\xff") != null);
try std.testing.expect(std.mem.findScalar(u8, stdout_result.output, 0x1b) == null);
const stderr_argv = [_][]const u8{
"/bin/sh",
"-c",
"printf '\\033[31m-missing' >&2; exit 2",
};
const stderr_stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &stderr_argv,
.environment_profile = .basic_read_only,
}};
const stderr_result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stderr_stages));
defer std.testing.allocator.free(stderr_result.output);
try std.testing.expect(std.mem.findScalar(u8, stderr_result.output, 0x1b) == null);
try std.testing.expect(std.mem.find(u8, stderr_result.output, "\\x1b[31m-missing") != null);
try std.testing.expect(stderr_result.command_result.?.stderr_bytes > 0);
}
const CallbackCapture = struct {
stdout: [512]u8 = undefined,
stdout_len: usize = 0,
stderr: [512]u8 = undefined,
stderr_len: usize = 0,
streams: [16]command_contract.CommandOutputStream = undefined,
stream_len: usize = 0,
fn onChunk(
raw_ctx: *anyopaque,
_: ?types.ToolLifecycleId,
stream: command_contract.CommandOutputStream,
chunk: []const u8,
) !void {
const self: *CallbackCapture = @ptrCast(@alignCast(raw_ctx));
std.debug.assert(self.stream_len < self.streams.len);
self.streams[self.stream_len] = stream;
self.stream_len += 1;
switch (stream) {
.stdout => {
std.debug.assert(self.stdout_len + chunk.len <= self.stdout.len);
@memcpy(self.stdout[self.stdout_len .. self.stdout_len + chunk.len], chunk);
self.stdout_len += chunk.len;
},
.stderr => {
std.debug.assert(self.stderr_len + chunk.len <= self.stderr.len);
@memcpy(self.stderr[self.stderr_len .. self.stderr_len + chunk.len], chunk);
self.stderr_len += chunk.len;
},
}
}
};
test "direct executor callbacks receive only bounded projected output" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{
"/bin/sh",
"-c",
"printf '\\033]52;c;stdout\\007'; printf '\\033[31mstderr\\377' >&2",
};
const stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
var capture = CallbackCapture{};
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
.output_chunk_ctx = &capture,
.on_output_chunk = CallbackCapture.onChunk,
}, std.testing.allocator, injectedPlan("/tmp", &stages));
defer std.testing.allocator.free(result.output);
const stdout = capture.stdout[0..capture.stdout_len];
const stderr = capture.stderr[0..capture.stderr_len];
try std.testing.expect(std.mem.findScalar(u8, stdout, 0x1b) == null);
try std.testing.expect(std.mem.findScalar(u8, stderr, 0x1b) == null);
try std.testing.expect(std.mem.find(u8, stdout, "\\x1b]52;c;stdout\\x07") != null);
try std.testing.expect(std.mem.find(u8, stderr, "\\x1b[31mstderr\\xff") != null);
const foreground = result.command_result.?;
try std.testing.expect(
stdout.len + stderr.len <=
4 * (foreground.stdout_bytes + foreground.stderr_bytes),
);
}
test "direct executor raw callback projection keeps projected result isolated" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{
"/bin/sh",
"-c",
"printf '\\033[31mraw\\000\\377'",
};
const stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
var capture = CallbackCapture{};
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
.output_chunk_ctx = &capture,
.on_output_chunk = CallbackCapture.onChunk,
.callback_projection = .raw,
}, std.testing.allocator, injectedPlan("/tmp", &stages));
defer std.testing.allocator.free(result.output);
const stdout = capture.stdout[0..capture.stdout_len];
try std.testing.expect(std.mem.findScalar(u8, stdout, 0x1b) != null);
try std.testing.expect(std.mem.findScalar(u8, stdout, 0x00) != null);
try std.testing.expect(std.mem.findScalar(u8, stdout, 0xff) != null);
try std.testing.expect(std.mem.findScalar(u8, result.output, 0x1b) == null);
try std.testing.expect(std.mem.find(u8, result.output, "\\x1b[31mraw\\x00\\xff") != null);
}
test "direct executor accepted callbacks preserve repeated newline-free stream order" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{
"/bin/sh",
"-c",
"printf E1 >&2; sleep 0.15; printf O1; sleep 0.15; printf E2 >&2; sleep 0.15; printf O2",
};
const stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
var capture = CallbackCapture{};
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 4096,
.accepted_output_chunk_ctx = &capture,
.on_accepted_output_chunk = CallbackCapture.onChunk,
}, std.testing.allocator, injectedPlan("/tmp", &stages));
defer std.testing.allocator.free(result.output);
try std.testing.expectEqual(@as(usize, 4), capture.stream_len);
try std.testing.expectEqual(.stderr, capture.streams[0]);
try std.testing.expectEqual(.stdout, capture.streams[1]);
try std.testing.expectEqual(.stderr, capture.streams[2]);
try std.testing.expectEqual(.stdout, capture.streams[3]);
try std.testing.expectEqualStrings("E1E2", capture.stderr[0..capture.stderr_len]);
try std.testing.expectEqualStrings("O1O2", capture.stdout[0..capture.stdout_len]);
}
test "direct executor keeps stderr projector state independent per child" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const producer_argv = [_][]const u8{
"/bin/sh",
"-c",
"printf '\\302' >&2; printf x",
};
const consumer_argv = [_][]const u8{
"/bin/sh",
"-c",
"cat >/dev/null; printf '\\205' >&2",
};
const stages = [_]command_effect.DirectStage{
.{
.executable = "/bin/sh",
.argv = &producer_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/bin/sh",
.argv = &consumer_argv,
.environment_profile = .basic_read_only,
},
};
const result = executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stages)) catch |err| {
std.debug.print("downstream pipe closure failed: {s}\n", .{@errorName(err)});
return err;
};
defer std.testing.allocator.free(result.output);
try std.testing.expect(std.mem.find(u8, result.output, "\\xc2") != null);
try std.testing.expect(std.mem.find(u8, result.output, "\\x85") != null);
try std.testing.expect(std.mem.find(u8, result.output, "\\u{0085}") == null);
}
test "direct executor reports final stage status without pipefail" {
const argv = [_][]const u8{"/usr/bin/false"};
const stages = [_]command_effect.DirectStage{.{
.executable = "/usr/bin/false",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stages));
defer std.testing.allocator.free(result.output);
try std.testing.expectEqual(@as(?i64, 1), result.command_result.?.exit_code);
}
test "direct relay treats a closed downstream pipe as normal completion" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{"/usr/bin/false"};
var child = try std.process.spawn(io_mod.getIo(), .{
.argv = &argv,
.stdin = .pipe,
.stdout = .ignore,
.stderr = .ignore,
});
const destination = child.stdin.?;
child.stdin = null;
defer destination.close(io_mod.getIo());
_ = try child.wait(io_mod.getIo());
try std.testing.expectEqual(
RelayWriteResult.downstream_closed,
try writeRelayChunk(destination, "not consumed"),
);
}
test "direct executor treats downstream pipe closure as normal pipeline completion" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const producer_argv = [_][]const u8{
"/bin/sh",
"-c",
"sleep 0.1; printf upstream",
};
const consumer_argv = [_][]const u8{ "/bin/pwd", "-P" };
const stages = [_]command_effect.DirectStage{
.{
.executable = "/bin/sh",
.argv = &producer_argv,
.environment_profile = .basic_read_only,
},
.{
.executable = "/bin/pwd",
.argv = &consumer_argv,
.environment_profile = .basic_read_only,
},
};
const result = try executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &stages));
defer std.testing.allocator.free(result.output);
try std.testing.expectEqual(@as(?i64, 0), result.command_result.?.exit_code);
const physical_tmp = try io_mod.realpathAlloc(std.testing.allocator, "/tmp");
defer std.testing.allocator.free(physical_tmp);
const expected_output = try std.fmt.allocPrint(
std.testing.allocator,
"\n{s}\n",
.{physical_tmp},
);
defer std.testing.allocator.free(expected_output);
try std.testing.expect(std.mem.find(u8, result.output, expected_output) != null);
}
test "direct executor fails closed for missing executable" {
const missing_argv = [_][]const u8{"/definitely/missing/fx-direct-command"};
const missing_stages = [_]command_effect.DirectStage{.{
.executable = "/definitely/missing/fx-direct-command",
.argv = &missing_argv,
.environment_profile = .basic_read_only,
}};
try std.testing.expectError(
error.DirectExecutableUnavailable,
executeDirectReadOnly(.{
.max_command_output_bytes = 1,
}, std.testing.allocator, injectedPlan("/tmp", &missing_stages)),
);
}
test "direct executor cancellation and timeout terminate and reap the process group" {
const argv = [_][]const u8{ "/bin/sleep", "10" };
const stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sleep",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
var cancel = std.atomic.Value(bool).init(false);
const Flip = struct {
fn run(flag: *std.atomic.Value(bool)) void {
io_mod.sleep(25 * std.time.ns_per_ms);
flag.store(true, .seq_cst);
}
};
const thread = try std.Thread.spawn(.{}, Flip.run, .{&cancel});
defer thread.join();
try std.testing.expectError(
error.Cancelled,
executeDirectReadOnly(.{
.max_command_output_bytes = 1,
.cancel_flag = &cancel,
}, std.testing.allocator, injectedPlan("/tmp", &stages)),
);
try std.testing.expectError(
error.TimeoutExpired,
executeDirectReadOnly(.{
.max_command_output_bytes = 1,
.timeout_ms = 1,
.timeout_started_ms = io_mod.milliTimestamp() - 10,
}, std.testing.allocator, injectedPlan("/tmp", &stages)),
);
}
test "direct executor flushes partial callback output before timeout" {
if (builtin.os.tag != .macos and builtin.os.tag != .linux) return error.SkipZigTest;
const argv = [_][]const u8{
"/bin/sh",
"-c",
"trap 'exit 0' TERM; printf PARTIAL; sleep 10",
};
const stages = [_]command_effect.DirectStage{.{
.executable = "/bin/sh",
.argv = &argv,
.environment_profile = .basic_read_only,
}};
var capture = CallbackCapture{};
try std.testing.expectError(
error.TimeoutExpired,
executeDirectReadOnly(.{
.max_command_output_bytes = 1,
.timeout_ms = 500,
.timeout_started_ms = io_mod.milliTimestamp(),
.output_chunk_ctx = &capture,
.on_output_chunk = CallbackCapture.onChunk,
}, std.testing.allocator, injectedPlan("/tmp", &stages)),
);
try std.testing.expectEqualStrings("PARTIAL", capture.stdout[0..capture.stdout_len]);
}