claire/tests/test_vault.py
Natalie 70b09d5a9b feat(@projects/@claire): vault secret management
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-31 21:01:11 -06:00

57 lines
2.3 KiB
Python

"""Vault secret resolver + file IO + rsync command build."""
from __future__ import annotations
import stat
from pathlib import Path
from claire import vault
def test_write_read_roundtrip_and_0600(tmp_path: Path) -> None:
p = vault.write_vault_file("s.txt", "hunter2", vault_dir=tmp_path)
assert vault.read_vault_file("s.txt", vault_dir=tmp_path) == "hunter2"
assert stat.S_IMODE(p.stat().st_mode) == 0o600
assert stat.S_IMODE(tmp_path.stat().st_mode) == 0o700
def test_read_missing_returns_none(tmp_path: Path) -> None:
assert vault.read_vault_file("nope.txt", vault_dir=tmp_path) is None
def test_resolve_prefers_vault_over_fallback(tmp_path: Path) -> None:
vault.write_vault_file("claire-sync-secret.txt", "VAULTSECRET", vault_dir=tmp_path)
assert vault.resolve_sync_secrets("CONFIGSECRET", vault_dir=tmp_path) == ["VAULTSECRET"]
def test_resolve_falls_back_to_config_when_no_vault(tmp_path: Path) -> None:
assert vault.resolve_sync_secrets("CONFIGSECRET", vault_dir=tmp_path) == ["CONFIGSECRET"]
def test_resolve_empty_when_nothing(tmp_path: Path) -> None:
assert vault.resolve_sync_secrets(None, vault_dir=tmp_path) == []
def test_resolve_includes_prev_during_rotation(tmp_path: Path) -> None:
vault.write_vault_file("claire-sync-secret.txt", "NEW", vault_dir=tmp_path)
vault.write_vault_file("claire-sync-secret.prev.txt", "OLD", vault_dir=tmp_path)
assert vault.resolve_sync_secrets(None, vault_dir=tmp_path) == ["NEW", "OLD"]
def test_resolve_dedupes_prev_equal_current(tmp_path: Path) -> None:
vault.write_vault_file("claire-sync-secret.txt", "SAME", vault_dir=tmp_path)
vault.write_vault_file("claire-sync-secret.prev.txt", "SAME", vault_dir=tmp_path)
assert vault.resolve_sync_secrets(None, vault_dir=tmp_path) == ["SAME"]
def test_rsync_cmd_flags(tmp_path: Path) -> None:
cmd = vault._rsync_cmd(tmp_path, "apricot:.vault/", delete=False, ts="T")
assert "--no-inplace" in cmd
assert "--exclude=*.prev.txt" in cmd # rotation prev stays plum-local
assert "--backup-dir=../.vault-backups/T/" in cmd
assert "--delete" not in cmd
assert cmd[-2:] == [f"{tmp_path}/", "apricot:.vault/"]
def test_rsync_cmd_delete_opt_in(tmp_path: Path) -> None:
assert "--delete" in vault._rsync_cmd(tmp_path, "h:.vault/", delete=True, ts="T")