Files
OpenJarvis/tests/sandbox/test_mount_security.py
T
Jon Saad-FalconandClaude Opus 4.6 a4c4081ff4 Add desktop distribution pipeline: rolling releases, auto-updates, code signing
- Rewrite .github/workflows/desktop.yml: 2-job pipeline (validate + build-and-release)
  with rolling desktop-latest pre-release on push to main and stable desktop-v* releases
- Add UpdateChecker component: checks for updates on startup + every 30 min,
  background download with progress bar, one-click relaunch
- Configure Tauri updater: endpoints pointing to desktop-latest release, pubkey placeholder
- Add tauri-plugin-process for relaunch support (Cargo.toml, lib.rs, package.json)
- Add macOS Entitlements.plist for notarization (network + file access, no sandbox)
- Add scripts/bump-desktop-version.sh for atomic version bumps across 3 config files
- Add desktop/README.md with dev setup, auto-update architecture, signing docs
- Update .gitignore for desktop/node_modules, dist, target
- Configure macOS minimumSystemVersion, Windows timestampUrl
- Include all Phase 14-21 work: agent hardening, RBAC, taint tracking, workflows,
  skills, knowledge graph, sessions, A2A, MCP templates, WASM sandbox, TUI dashboard,
  production tools, CLI expansion, API expansion, learning productionization,
  Tauri desktop app, and 10 new channels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 19:14:05 +00:00

171 lines
5.3 KiB
Python

"""Tests for mount_security module."""
from __future__ import annotations
import json
import pytest
from openjarvis.sandbox.mount_security import (
DEFAULT_BLOCKED_PATTERNS,
AllowedRoot,
MountAllowlist,
load_mount_allowlist,
validate_mount,
validate_mounts,
)
class TestDefaultBlockedPatterns:
def test_contains_ssh(self):
assert ".ssh" in DEFAULT_BLOCKED_PATTERNS
def test_contains_env(self):
assert ".env" in DEFAULT_BLOCKED_PATTERNS
def test_contains_pem(self):
assert "*.pem" in DEFAULT_BLOCKED_PATTERNS
def test_contains_key(self):
assert "*.key" in DEFAULT_BLOCKED_PATTERNS
def test_contains_gnupg(self):
assert ".gnupg" in DEFAULT_BLOCKED_PATTERNS
def test_contains_aws(self):
assert ".aws" in DEFAULT_BLOCKED_PATTERNS
def test_contains_credentials(self):
assert "credentials" in DEFAULT_BLOCKED_PATTERNS
class TestValidateMount:
def test_allows_valid_path(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
target = tmp_path / "data"
target.mkdir()
assert validate_mount(str(target), allowlist) is True
def test_blocks_ssh_dir(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
target = tmp_path / ".ssh"
target.mkdir()
assert validate_mount(str(target), allowlist) is False
def test_blocks_env_file(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
target = tmp_path / ".env"
target.touch()
assert validate_mount(str(target), allowlist) is False
def test_blocks_pem_file(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
target = tmp_path / "server.pem"
target.touch()
assert validate_mount(str(target), allowlist) is False
def test_blocks_key_file(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
target = tmp_path / "private.key"
target.touch()
assert validate_mount(str(target), allowlist) is False
def test_rejects_outside_root(self, tmp_path):
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path / "allowed"))],
)
target = tmp_path / "not_allowed" / "data"
target.mkdir(parents=True)
assert validate_mount(str(target), allowlist) is False
def test_no_roots_allows_non_blocked(self, tmp_path):
allowlist = MountAllowlist(roots=[])
target = tmp_path / "safe_dir"
target.mkdir()
assert validate_mount(str(target), allowlist) is True
def test_traversal_prevention(self, tmp_path):
"""Paths with .. are resolved before checking."""
allowed = tmp_path / "allowed"
allowed.mkdir()
# This resolves to tmp_path (outside allowed)
traversal = str(allowed / ".." / "secret")
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(allowed))],
blocked_patterns=["secret"],
)
assert validate_mount(traversal, allowlist) is False
class TestValidateMounts:
def test_returns_valid_mounts(self, tmp_path):
d1 = tmp_path / "data1"
d2 = tmp_path / "data2"
d1.mkdir()
d2.mkdir()
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
result = validate_mounts([str(d1), str(d2)], allowlist)
assert len(result) == 2
def test_raises_for_blocked(self, tmp_path):
target = tmp_path / ".ssh"
target.mkdir()
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path))],
)
with pytest.raises(ValueError, match="blocked"):
validate_mounts([str(target)], allowlist)
def test_raises_for_outside_root(self, tmp_path):
target = tmp_path / "outside"
target.mkdir()
allowlist = MountAllowlist(
roots=[AllowedRoot(path=str(tmp_path / "inside"))],
)
with pytest.raises(ValueError, match="not under"):
validate_mounts([str(target)], allowlist)
def test_empty_list(self):
allowlist = MountAllowlist()
assert validate_mounts([], allowlist) == []
class TestLoadMountAllowlist:
def test_loads_from_json(self, tmp_path):
config = {
"roots": [
{"path": "/home/user/projects", "read_only": False},
{"path": "/data"},
],
"blocked_patterns": [".ssh", "*.pem"],
}
f = tmp_path / "allowlist.json"
f.write_text(json.dumps(config))
al = load_mount_allowlist(str(f))
assert len(al.roots) == 2
assert al.roots[0].path == "/home/user/projects"
assert al.roots[0].read_only is False
assert al.roots[1].read_only is True
assert al.blocked_patterns == [".ssh", "*.pem"]
def test_default_blocked_patterns(self, tmp_path):
config = {"roots": []}
f = tmp_path / "allowlist.json"
f.write_text(json.dumps(config))
al = load_mount_allowlist(str(f))
assert al.blocked_patterns == DEFAULT_BLOCKED_PATTERNS