Public Access
Post-merge / detect-type (push) Successful in 13s
Post-merge / validate-commit-msg (push) Successful in 10s
Post-merge / configure-repo (push) Successful in 28s
Post-merge / vikunja (push) Successful in 44s
Post-merge / sync-wiki (push) Successful in 58s
Post-merge / release (push) Successful in 1m7s
Post-merge / publish (push) Successful in 44s
Post-merge / badges (push) Successful in 1m6s
135 lines
4.4 KiB
Python
135 lines
4.4 KiB
Python
"""Unit tests for devx.utils.vault."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from devx.utils.vault import (
|
|
decrypt_file,
|
|
encrypt_file,
|
|
is_encrypted,
|
|
load_vault_yaml,
|
|
save_vault_yaml,
|
|
)
|
|
|
|
|
|
class TestIsEncrypted:
|
|
def test_encrypted_file(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "secret.yml"
|
|
f.write_text("$ANSIBLE_VAULT;1.1;AES256\n9382928...\n")
|
|
assert is_encrypted(f) is True
|
|
|
|
def test_plain_file(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "plain.yml"
|
|
f.write_text("key: value\n")
|
|
assert is_encrypted(f) is False
|
|
|
|
|
|
class TestLoadVaultYaml:
|
|
def test_plain_yaml_no_vault_pass(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "data.yml"
|
|
f.write_text("key: value\nlist:\n - a\n - b\n")
|
|
data = load_vault_yaml(f)
|
|
assert data == {"key": "value", "list": ["a", "b"]}
|
|
|
|
def test_empty_file(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "empty.yml"
|
|
f.write_text("")
|
|
data = load_vault_yaml(f)
|
|
assert data == {}
|
|
|
|
def test_vault_pass_not_exists(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "data.yml"
|
|
f.write_text("key: value\n")
|
|
data = load_vault_yaml(f, vault_pass=tmp_path / "nonexistent")
|
|
assert data == {"key": "value"}
|
|
|
|
@patch("devx.utils.vault.subprocess.run")
|
|
def test_encrypted_file_success(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
f = tmp_path / "secret.yml"
|
|
f.write_text("$ANSIBLE_VAULT\n...")
|
|
vp = tmp_path / "vault-password"
|
|
vp.write_text("secret")
|
|
|
|
mock_run.return_value = MagicMock(returncode=0, stdout="key: decrypted\n", stderr="")
|
|
data = load_vault_yaml(f, vault_pass=vp)
|
|
assert data == {"key": "decrypted"}
|
|
|
|
@patch("devx.utils.vault.subprocess.run")
|
|
def test_not_vault_encrypted_fallback(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
f = tmp_path / "plain.yml"
|
|
f.write_text("key: value\n")
|
|
vp = tmp_path / "vault-password"
|
|
vp.write_text("secret")
|
|
|
|
mock_run.return_value = MagicMock(returncode=1, stdout="", stderr="is not vault encrypted")
|
|
data = load_vault_yaml(f, vault_pass=vp)
|
|
assert data == {"key": "value"}
|
|
|
|
|
|
class TestSaveVaultYaml:
|
|
def test_save_plain(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "output.yml"
|
|
save_vault_yaml(f, {"key": "value"})
|
|
content = f.read_text()
|
|
assert "key: value" in content
|
|
|
|
def test_save_with_vault_pass_not_exists(self, tmp_path: Path) -> None:
|
|
f = tmp_path / "output.yml"
|
|
vp = tmp_path / "nonexistent"
|
|
save_vault_yaml(f, {"key": "value"}, vault_pass=vp)
|
|
# Should save as plain YAML
|
|
content = f.read_text()
|
|
assert "key: value" in content
|
|
assert "$ANSIBLE_VAULT" not in content
|
|
|
|
@patch("devx.utils.vault.subprocess.run")
|
|
def test_save_and_encrypt(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
f = tmp_path / "output.yml"
|
|
vp = tmp_path / "vault-password"
|
|
vp.write_text("secret")
|
|
|
|
save_vault_yaml(f, {"key": "value"}, vault_pass=vp)
|
|
# File should be written
|
|
assert f.exists()
|
|
# ansible-vault encrypt should be called
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
assert "ansible-vault" in cmd
|
|
assert "encrypt" in cmd
|
|
|
|
|
|
class TestEncryptFile:
|
|
@patch("devx.utils.vault.subprocess.run")
|
|
def test_calls_ansible_vault(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
f = tmp_path / "file.yml"
|
|
f.write_text("key: value")
|
|
vp = tmp_path / "vault-password"
|
|
vp.write_text("secret")
|
|
|
|
encrypt_file(f, vp)
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
assert "ansible-vault" in cmd
|
|
assert "encrypt" in cmd
|
|
assert str(f) in cmd
|
|
assert str(vp) in cmd
|
|
|
|
|
|
class TestDecryptFile:
|
|
@patch("devx.utils.vault.subprocess.run")
|
|
def test_calls_ansible_vault(self, mock_run: MagicMock, tmp_path: Path) -> None:
|
|
f = tmp_path / "file.yml"
|
|
f.write_text("$ANSIBLE_VAULT\n...")
|
|
vp = tmp_path / "vault-password"
|
|
vp.write_text("secret")
|
|
|
|
decrypt_file(f, vp)
|
|
mock_run.assert_called_once()
|
|
cmd = mock_run.call_args[0][0]
|
|
assert "ansible-vault" in cmd
|
|
assert "decrypt" in cmd
|
|
assert str(f) in cmd
|
|
assert str(vp) in cmd
|