Commit

Reviews, plans and replies are written where the guardrail allows: g1t's answer files are inside it

The outside_workspace guardrail let file tools reach only the project, /tmp and the toolchain caches, but the runner asks the agent to write /work/review.json, /work/plan.json and /work/answer.md. On 2026-10-06 a review on automation-lab#12 was refused that write and its verdict came back as a plain comment. Those three exact files are now allowed; anything else beside the project still is not.

syntaqxcommitted Parentc50c0e3Browse files
4 files+24−50/4 viewed
+21−2
417417 format!("/{}", parts.join("/"))
418418 }
419419
420−/// Where file tools may go: the project, scratch space, and the caches
421−/// where dependencies' sources are.
420+/// The files the runner asks the agent to write its answer to, outside
421+/// the project so they are never committed: a review, a plan, a reply.
422+const ANSWER_FILES: [&str; 3] = [crate::review::REVIEW_FILE, crate::plan::PLAN_FILE, crate::reply::ANSWER_FILE];
423+
424+/// Where file tools may go: the project, scratch space, the caches where
425+/// dependencies' sources are, and the answer files.
422426 fn inside_allowed(path: &str, place: &Place) -> bool {
427+ if ANSWER_FILES.contains(&path) {
428+ return true;
429+ }
423430 let roots = [
424431 crate::WORKDIR.to_owned(),
425432 "/tmp".to_owned(),
814821 }
815822
816823 #[test]
824+ fn the_answer_files_may_be_written_and_nothing_else_beside_the_project() {
825+ let policy = all_on();
826+ let write = |path: &str| decide(&policy, "Write", &json!({ "file_path": path, "content": "{}" }), &place());
827+ for path in ["/work/review.json", "/work/plan.json", "/work/answer.md", "/work/repo/src/lib.rs", "/tmp/x"] {
828+ assert_eq!(write(path), None, "{path}");
829+ }
830+ for path in ["/work/notes.json", "/work/review.json.bak", "/etc/hosts"] {
831+ assert!(write(path).is_some(), "{path}");
832+ }
833+ }
834+
835+ #[test]
817836 fn force_pushes_are_refused_however_written() {
818837 let policy = all_on();
819838 for command in [
+1−1
2323 use crate::report::Reporter;
2424 use crate::{WORKDIR, auth_option, env, harness};
2525
26−const PLAN_FILE: &str = "/work/plan.json";
26+pub(crate) const PLAN_FILE: &str = "/work/plan.json";
2727
2828 const INSTRUCTIONS: &str = "You are planning work for a team of coding agents. The repository is checked out in the current directory. \
2929 Read enough of it to understand how it is built and tested. Do not modify it.
+1−1
2121 use crate::report::Reporter;
2222 use crate::{WORKDIR, auth_option, env, git, harness};
2323
24−const ANSWER_FILE: &str = "/work/answer.md";
24+pub(crate) const ANSWER_FILE: &str = "/work/answer.md";
2525 const MAX_ANSWER_CHARS: usize = 20_000;
2626
2727 const INSTRUCTIONS: &str = "Write your answer to /work/answer.md as Markdown, addressed to whoever asked: \
+1−1
2323 use crate::{WORKDIR, auth_option, env, git, harness};
2424
2525 const DIFF_FILE: &str = "/work/change.diff";
26−const REVIEW_FILE: &str = "/work/review.json";
26+pub(crate) const REVIEW_FILE: &str = "/work/review.json";
2727
2828 const INSTRUCTIONS: &str = "You are reviewing a pull request. The repository is checked out in the current directory at the pull request's head. \
2929 The change under review is in /work/change.diff; read it first, then read the surrounding code as needed. You may run the project's tests. Do not modify the repository.