fix(#2308): overlay --tmpfs on /knowledge/.git to hide host git credentials

The knowledge repo is cloned with credentials embedded in .git/config;
those credentials survive on disk and the entire LOCAL_DIR (including
.git/) is bind-mounted read-only into every agent container. Any
agent (or prompt-injected PR build) can read the site-admin token via
cat /knowledge/.git/config.

Defense-in-depth layer: in write_nspawn_flags, append
--tmpfs=/knowledge/.git after the --bind-ro=.../knowledge flag whenever
the /knowledge bind mount is present. systemd-nspawn processes the tmpfs
after the bind, overlaying an empty in-memory directory over .git/ inside
the container. Agents see the working-tree documents but not the repo
metadata or stored credentials.

This is independent of the complementary fix in workers/knowledge.rs
(stop embedding credentials in .git/config in the first place). Both
layers together provide defense-in-depth: even if a future credential
accidentally reaches .git/config, it stays off the container floor.

Closes part of issue 2308 (bind-mount isolation layer).
This commit is contained in:
atlas 2026-07-10 13:07:44 +02:00
commit 9451ebfb24

View file

@ -1502,6 +1502,19 @@ fn write_nspawn_flags(
format!("{flag}={}:{}", b.host_path, b.container_path)
})
.collect();
// Defense-in-depth for the knowledge bind-mount: overlay an empty tmpfs
// on /knowledge/.git so the repo metadata (including any credentials the
// host-side git worker embedded in .git/config) is invisible inside agent
// containers. Agents only need the working-tree documents; .git/ has no
// legitimate use in-container. The --tmpfs must come after the --bind-ro
// so nspawn processes it as an overlay on top of the already-mounted tree.
// `crate::knowledge::CONTAINER_MOUNT` is "/knowledge" (hive-c0re const).
if binds
.iter()
.any(|b| b.container_path.as_str() == "/knowledge")
{
flags.push("--tmpfs=/knowledge/.git".to_owned());
}
// Credential forwarding: nspawn loads each host secret into the
// container's credential store under `<name>`; inner units inherit it
// via `LoadCredential=<name>`. Validated (name charset + bind-path