Hmbown/CodeWhale · critical
the envelope must independently refuse the write-capable…
Error message
the envelope must independently refuse the write-capable filter
What it means
In the read-only-role enforcement test (crates/tui/src/tools/subagent/tests.rs:8255), `registry.envelope_refusal("bash", &call).expect("the envelope must independently refuse the write-capable filter")` asserts that the execution envelope returns a refusal (an `Option`/`Result` that is `Some`/`Ok`) for `sort -o filter-output.txt input.txt`, a command that writes via an output flag. A panic means the envelope failed to flag the write-capable filter — a security-relevant regression, not an environmental fault.
Solutions
- Run the test and check which deny rules evaluate for `sort -o filter-output.txt input.txt`.
- Restore/extend the write-detection rule so output-flag usage of text filters is refused.
- If the rule identifier changed, update both the rule and the assertion string together.
- Verify `envelope_refusal` returns a refusal rather than `None` for postures where posture permits but envelope denies.
Example fix
// before
let envelope_refusal = registry.envelope_refusal("bash", &call).expect("the envelope must independently refuse the write-capable filter");
// after (test diagnostics)
let envelope_refusal = registry.envelope_refusal("bash", &call)
.unwrap_or_else(|| panic!("envelope did not refuse write-capable filter: {call}")); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check the command against write-capable patterns before dispatch
fn writes_output_file(cmd: &str) -> bool {
// e.g. sort -o <file>, tee, redirect targets
cmd.contains(" -o ") || cmd.contains(">") || cmd.contains("tee ")
} Try / catch
// In tests, assert refusal presence with a diagnostic message
let refusal = registry.envelope_refusal("bash", &call)
.unwrap_or_else(|| panic!("envelope failed to refuse write-capable command: {call}"));
assert!(refusal.contains("[execution_envelope.executes.write_denied]")); Prevention
- Treat any test asserting sandbox refusal as security-critical; never weaken it to go green.
- Keep denial-rule identifiers and their test assertions in sync in one change.
- Extend write-detection rules whenever a new output-flag pattern (like sort -o) is added to the carve-out.
- Run the read-only-role enforcement tests on every envelope rule change.
When it happens
Trigger: Modifying the envelope's deny rules (e.g. the `[execution_envelope.executes.write_denied]` rule) so `sort -o <file>` no longer matches write-capable filter usage, or changing how `envelope_refusal` signals refusal (returning `None` on allowed commands).
Common situations: Relaxing the bash carve-out for text filters, renaming the refusal rule marker so the assertion string no longer matches, or refactoring rule evaluation order so the write rule is skipped.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- fleet task ' ' path ' ' cannot contain parent traversal
- reviewed plugin MCP argument path escaped its staged root
- scrub backup
- shell commands are restricted by
- agent action=claim widens an enforced write scope, and the…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/3d89b384a990cf33.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/tests.rs:8255
std::fs::write(&input_path, "b\na\n").expect("input fixture");
let output_path = tmp.path().join("filter-output.txt");
let mut runtime =
stub_runtime().with_agent_tool_surface_options(enabled_agent_surface_options());
runtime.context = ToolContext::new(tmp.path().to_path_buf());
runtime.worker_profile = WorkerRuntimeProfile::for_role(role.clone());
seed_read_only_role_deny_list(&mut runtime);
let registry = SubAgentToolRegistry::new(
runtime,
role.clone(),
None,
crate::tools::todo::new_shared_todo_list(),
crate::tools::plan::new_shared_plan_state(),
);
let call = json!({"command": "sort -o filter-output.txt input.txt"});
let envelope_refusal = registry
.envelope_refusal("bash", &call)
.expect("the envelope must independently refuse the write-capable filter");
assert!(
envelope_refusal.contains("[execution_envelope.executes.write_denied]"),
"{role:?} envelope refusal did not identify its failed rule: {envelope_refusal}"
);
let posture_refusal = registry
.execute("agent_read_only_filter", "bash", call)
.await
.expect_err("a read-only inspection role must not write through sort")
.to_string();
assert!(
posture_refusal.contains("[shell.readonly.command]"),
"{role:?} posture refusal did not identify its failed rule: {posture_refusal}"
);
assert!(
!output_path.exists(),
"{role:?} read-only filter created {} from {}",
output_path.display(),View on GitHub (pinned to 433685b202)