fix(vault): canonicalize + allowed-root containment on provision target (#92) #119

Merged
clawdie merged 1 commit from fix/vault-provision-containment into main 2026-06-21 06:30:30 +02:00

1 commit

Author SHA1 Message Date
Sam & Claude
8c7051f046 fix(vault): canonicalize + allowed-root containment on provision target (#92)
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / markdown (pull_request) Has been cancelled
CI / port (pull_request) Has been cancelled
CI / agent-jail-pkgs (pull_request) Has been cancelled
PR #91 added a string-equality registered-vs-spawned root check, which doesn't
catch `..`, symlinks, or a root pointing outside the jails tree. Add a real
containment guard in colibri-vault::provision, the layer that writes the .env:

- Before create_dir_all, canonicalize the target (resolving `..`/symlinks) and
  assert it is STRICTLY under the allowed jail-root base; refuse otherwise.
  Running before create_dir_all means a traversal/symlink target can't even
  create a directory outside the tree, let alone an .env.
- Allowed base defaults to /usr/local/bastille/jails (FreeBSD/Bastille),
  overridable via COLIBRI_JAIL_ROOT_BASE for Linux/Docker volume roots.
- Fail-closed: returns VaultError::TargetEscapesRoot; the daemon spawn hook
  already treats provision errors as fail-soft (no .env written).
- Tests: child accepted; base-itself / nonexistent / `..`-escape / symlink-escape
  all refused (no tempfile dep — uses std temp_dir).

Acceptance (#92): a target with `..`, a symlink, or resolving outside the jail
root is refused, no .env written. fmt + clippy --all-targets clean;
cargo test --workspace 230 passed / 0 failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:58:30 +02:00