mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-09 09:59:45 -10:00
fix(tools): validate_data, review and verify go through the read guard
resolve_guarded_read_path is the single entry for in-process readers that hand file content, or something derived from it, to a model. It applies the deny-list to the path as written, resolves it, refuses Codewhale credential and config files, and applies the deny-list again to the resolved path.d87f4c33camoved pandoc_convert and image_ocr onto it; three readers were missed: - validate_data (load_input_source) read the file with only resolve_path. Its TOML error prints the source line, so `validate_data {path: ".env", format: "toml"}` could return a dotenv line to the model. The tool is read-only and auto-approved, so it ran without a prompt even in Plan mode and for read-only workers, where no shell exists. - review (resolve_file_target) and verify (gather_files) embedded the whole file in a provider request as a Text block. Model-bound redaction masks only ToolResult blocks, so nothing redacted it. Each now calls crate::tools::file::resolve_guarded_read_path with its tool name. A denied path fails with the same error `read` gives; verify reports it per file through its existing error branch. Found by the 2026-10-17 fail-open hunt (verifier confidence high for both). Receipts: CW/artifacts/failopen-hunt-20261017/round2.json. Verification: the scripts/dev-test.sh tui tools:: ... run described in92f900edf0covers these modules (4819 passed; the failures there are unrelated to these files). clippy with the CI flags and fmt: clean. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01NBKbhx19BRbZtvWK8rVKjz
This commit is contained in:
1 parent
5d1c8adf30
commit
4fa8fdda02
5 files changed
+14
-3
No files matched your search
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- `validate_data`, `review` and `verify` honor the read deny-list, as `read`
|
||||
does. They read files such as a workspace `.env`, or in trust mode
|
||||
`~/.aws/credentials`, without the check. `validate_data`'s TOML parse
|
||||
error could quote a line of such a file back to the model, and `review`
|
||||
and `verify` sent the whole file to the provider.
|
||||
- Commands that start outside the shell tool now get the same sandbox as
|
||||
shell commands:
|
||||
- `terminal_*` PTY sessions used a default sandbox with no credential
|
||||
|
||||
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- `validate_data`, `review` and `verify` honor the read deny-list, as `read`
|
||||
does. They read files such as a workspace `.env`, or in trust mode
|
||||
`~/.aws/credentials`, without the check. `validate_data`'s TOML parse
|
||||
error could quote a line of such a file back to the model, and `review`
|
||||
and `verify` sent the whole file to the provider.
|
||||
- Commands that start outside the shell tool now get the same sandbox as
|
||||
shell commands:
|
||||
- `terminal_*` PTY sessions used a default sandbox with no credential
|
||||
|
||||
@@ -1721,7 +1721,7 @@ async fn resolve_review_source(
|
||||
}
|
||||
|
||||
fn resolve_file_target(target: &str, context: &ToolContext) -> Result<ReviewSource, ToolError> {
|
||||
let path = context.resolve_path(target)?;
|
||||
let path = crate::tools::file::resolve_guarded_read_path(context, target, "review")?;
|
||||
if !path.is_file() {
|
||||
return Err(ToolError::invalid_input(format!(
|
||||
"Target is not a file: {}",
|
||||
|
||||
@@ -124,7 +124,8 @@ fn load_input_source(
|
||||
)),
|
||||
(None, None) => Err(ToolError::missing_field("path or content")),
|
||||
(Some(path), None) => {
|
||||
let resolved = context.resolve_path(path)?;
|
||||
let resolved =
|
||||
crate::tools::file::resolve_guarded_read_path(context, path, "validate_data")?;
|
||||
let raw_content = if context.features.enabled(crate::features::Feature::DataHost) {
|
||||
use std::io::Read;
|
||||
let mut content = String::new();
|
||||
|
||||
@@ -720,7 +720,7 @@ fn gather_files(files: &[String], context: &ToolContext) -> Vec<EvidenceBlock> {
|
||||
if raw.is_empty() {
|
||||
continue;
|
||||
}
|
||||
match context.resolve_path(raw) {
|
||||
match crate::tools::file::resolve_guarded_read_path(context, raw, "verify") {
|
||||
Ok(path) => match std::fs::read_to_string(&path) {
|
||||
Ok(content) => {
|
||||
let display = path
|
||||
|
||||
Reference in new issue
Block a user