mirror of
https://github.com/bdbrown4/peltier.io.git
synced 2026-11-07 10:58:28 +00:00
agent: patch-surface fixes from the comrak-005 transcript
- propose_patch allows the /dev/null headers git emits for new/deleted files (previously every new-file diff was refused as an absolute path). - read_target_source serves HEAD (pristine) content instead of the working tree, matching propose_patch's standalone-vs-pristine base so post-proposal reads can't drift a later diff's context lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EcKPWQ3MQD4NdEHwar96u2
This commit is contained in:
@@ -189,8 +189,22 @@ fn handle(root: &Path, line: &str) -> Result<Value> {
|
||||
let p = field(&req, "path")?;
|
||||
check_target(t)?;
|
||||
check_rel_path(p)?;
|
||||
let full = root.join(format!("targets/{t}/workspace")).join(p);
|
||||
let text = std::fs::read_to_string(full)?;
|
||||
// Serve the PRISTINE (HEAD) content, not the working tree:
|
||||
// propose_patch applies each proposal against a reset
|
||||
// workspace, so reads must show the same base the diff needs
|
||||
// — otherwise reads after a proposal show the patched tree
|
||||
// and the next diff's context lines drift (phase2-comrak-005
|
||||
// burned turns rediscovering this).
|
||||
let ws = root.join(format!("targets/{t}/workspace"));
|
||||
let shown = Command::new("git")
|
||||
.args(["-C", ws.to_str().unwrap(), "show", &format!("HEAD:{p}")])
|
||||
.output()?;
|
||||
ensure!(
|
||||
shown.status.success(),
|
||||
"cannot read {p} at HEAD: {}",
|
||||
String::from_utf8_lossy(&shown.stderr).trim()
|
||||
);
|
||||
let text = String::from_utf8_lossy(&shown.stdout).into_owned();
|
||||
// Optional line window so large source files (100KB+) can be read in
|
||||
// chunks instead of overflowing one response — otherwise the agent
|
||||
// is tempted to reach for a shell it must not have.
|
||||
@@ -231,7 +245,9 @@ fn handle(root: &Path, line: &str) -> Result<Value> {
|
||||
);
|
||||
// Allowlist: every path named by the diff must be a safe
|
||||
// relative path (the git -C below roots them in the target
|
||||
// workspace; nothing outside it is reachable).
|
||||
// workspace; nothing outside it is reachable). `/dev/null`
|
||||
// is the one absolute path git legitimately emits, for
|
||||
// new/deleted files.
|
||||
for l in diff.lines() {
|
||||
if let Some(p) = l
|
||||
.strip_prefix("--- a/")
|
||||
@@ -240,8 +256,10 @@ fn handle(root: &Path, line: &str) -> Result<Value> {
|
||||
check_rel_path(p.trim())?;
|
||||
}
|
||||
ensure!(
|
||||
!l.starts_with("--- /") && !l.starts_with("+++ /"),
|
||||
"absolute diff paths forbidden"
|
||||
(!l.starts_with("--- /") && !l.starts_with("+++ /"))
|
||||
|| l == "--- /dev/null"
|
||||
|| l == "+++ /dev/null",
|
||||
"absolute diff paths forbidden (only /dev/null is allowed, for new/deleted files)"
|
||||
);
|
||||
}
|
||||
let ws = root.join(format!("targets/{t}/workspace"));
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user