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
Owner

Implements #92.

PR #91's registered-vs-spawned root check is string-equality, so it misses .., symlinks, and roots pointing outside the jails tree. This adds 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.
  • Base defaults to /usr/local/bastille/jails; override with COLIBRI_JAIL_ROOT_BASE for Linux/Docker volume roots.
  • Fail-closed (TargetEscapesRoot); the spawn hook already treats provision errors as fail-soft.

Tests cover child-accepted, base-itself / nonexistent / ..-escape / symlink-escape refused. fmt + clippy --all-targets clean; cargo test --workspace 230 passed / 0 failed.

Closes #92.

🤖 Generated with Claude Code

Implements #92. PR #91's registered-vs-spawned root check is string-equality, so it misses `..`, symlinks, and roots pointing outside the jails tree. This adds 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. - Base defaults to `/usr/local/bastille/jails`; override with `COLIBRI_JAIL_ROOT_BASE` for Linux/Docker volume roots. - Fail-closed (`TargetEscapesRoot`); the spawn hook already treats provision errors as fail-soft. Tests cover child-accepted, base-itself / nonexistent / `..`-escape / symlink-escape refused. fmt + clippy `--all-targets` clean; `cargo test --workspace` 230 passed / 0 failed. Closes #92. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
clawdie added 1 commit 2026-06-20 22:58:40 +02:00
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
8c7051f046
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>
clawdie merged commit b62608247a into main 2026-06-21 06:30:30 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: clawdie/colibri#119
No description provided.