Compare commits
2
Commits
e089360ac8
...
a0e6b16abc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0e6b16abc | ||
|
|
3a383aede6 |
@@ -52,6 +52,13 @@ const EXCLUDED_PATHS: &[&str] = &[
|
|||||||
".pytest_cache",
|
".pytest_cache",
|
||||||
".mypy_cache",
|
".mypy_cache",
|
||||||
"vendor",
|
"vendor",
|
||||||
|
// Agent workaround debris. `.gitconfig_temp` appeared on mission 019fc3ba
|
||||||
|
// when an agent hit git's ownership check and wrote its own safe.directory
|
||||||
|
// config into the repository root. The cause is fixed (mission containers
|
||||||
|
// now carry GIT_CONFIG_* env), but excluding the artefact keeps a stray
|
||||||
|
// workaround out of a user's repository if an agent invents another one.
|
||||||
|
".gitconfig_temp",
|
||||||
|
".gitconfig.tmp",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Cap on the captured patch. Past this the diff is truncated with a marker
|
/// Cap on the captured patch. Past this the diff is truncated with a marker
|
||||||
@@ -333,6 +340,17 @@ pub async fn record_uncapturable(
|
|||||||
mission_id: Uuid,
|
mission_id: Uuid,
|
||||||
phase_id: Uuid,
|
phase_id: Uuid,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
// Write a real file behind the artifact. `_outputs` survives teardown, so
|
||||||
|
// it is still writable even though the checkout is gone — and an artifact
|
||||||
|
// row pointing at a path with nothing behind it turns every reader into a
|
||||||
|
// 404 with no explanation.
|
||||||
|
let dir = outputs_root(mission_id).join(phase_id.to_string());
|
||||||
|
if std::fs::create_dir_all(&dir).is_ok() {
|
||||||
|
let _ = std::fs::write(
|
||||||
|
dir.join("diff.patch"),
|
||||||
|
"The mission checkout was removed before this phase's changes could be\n captured. Nothing was lost that had already been captured; this phase\n simply finished after its working tree had been reaped.\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
let rel = format!("_outputs/{mission_id}/{phase_id}/diff.patch");
|
let rel = format!("_outputs/{mission_id}/{phase_id}/diff.patch");
|
||||||
cm_db::repo::missions::register_artifact(
|
cm_db::repo::missions::register_artifact(
|
||||||
pool,
|
pool,
|
||||||
@@ -386,11 +404,20 @@ mod tests {
|
|||||||
assert_eq!(parse_diffstat("\n"), (0, 0, 0));
|
assert_eq!(parse_diffstat("\n"), (0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build output must never reach a patch. A phase that ran `cargo build`
|
/// Build output and agent workaround debris must never reach a patch. A
|
||||||
/// leaves a `target/` bigger than the repository.
|
/// phase that ran `cargo build` leaves a `target/` bigger than the
|
||||||
|
/// repository, and an agent that fought git's ownership check left a
|
||||||
|
/// `.gitconfig_temp` beside the real work.
|
||||||
#[test]
|
#[test]
|
||||||
fn build_output_is_excluded() {
|
fn build_output_is_excluded() {
|
||||||
for p in ["target", "node_modules", ".venv", "dist", "__pycache__"] {
|
for p in [
|
||||||
|
"target",
|
||||||
|
"node_modules",
|
||||||
|
".venv",
|
||||||
|
"dist",
|
||||||
|
"__pycache__",
|
||||||
|
".gitconfig_temp",
|
||||||
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
EXCLUDED_PATHS.contains(&p),
|
EXCLUDED_PATHS.contains(&p),
|
||||||
"{p} must be excluded from capture"
|
"{p} must be excluded from capture"
|
||||||
|
|||||||
@@ -285,6 +285,24 @@ impl MissionRuntimeProvisioner {
|
|||||||
let mut env = vec![
|
let mut env = vec![
|
||||||
format!("ZEROCLAW_GATEWAY_PORT={GATEWAY_PORT}"),
|
format!("ZEROCLAW_GATEWAY_PORT={GATEWAY_PORT}"),
|
||||||
format!("CM_MISSION_ID={mission_id}"),
|
format!("CM_MISSION_ID={mission_id}"),
|
||||||
|
// Let the agents' git read the checkout.
|
||||||
|
//
|
||||||
|
// The server clones as uid 65532; this container runs as root, so
|
||||||
|
// every `git` an agent runs hits "detected dubious ownership" and
|
||||||
|
// refuses the repository. Agents do not report that as a failure —
|
||||||
|
// they improvise. On mission 019fc3ba one wrote a `.gitconfig_temp`
|
||||||
|
// containing `[safe] directory = /mission/repo` into the repository
|
||||||
|
// root, which then showed up in the captured diff and would have
|
||||||
|
// been committed and pushed to the user's repo alongside the real
|
||||||
|
// work.
|
||||||
|
//
|
||||||
|
// `GIT_CONFIG_*` is git's environment form of `-c` and is
|
||||||
|
// inherited by subprocesses, so it covers the agent's own git, any
|
||||||
|
// tool that shells out to git, and the `git_operations` tool alike.
|
||||||
|
// Scoped to the checkout; never `--global`.
|
||||||
|
"GIT_CONFIG_COUNT=1".to_string(),
|
||||||
|
"GIT_CONFIG_KEY_0=safe.directory".to_string(),
|
||||||
|
"GIT_CONFIG_VALUE_0=/mission/repo".to_string(),
|
||||||
];
|
];
|
||||||
// Provider credentials forwarded into the container.
|
// Provider credentials forwarded into the container.
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user