234 lines
6.4 KiB
Python
234 lines
6.4 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from pathlib import Path
|
|
from enroll.sopsutil import SopsError, _pgp_arg, find_sops_cmd, require_sops_cmd
|
|
|
|
|
|
def test_find_sops_cmd():
|
|
result = find_sops_cmd()
|
|
if result is None:
|
|
pytest.skip("sops not installed")
|
|
assert result.endswith("sops")
|
|
|
|
|
|
def test_require_sops_cmd():
|
|
exe = require_sops_cmd()
|
|
assert exe is not None
|
|
assert "sops" in exe
|
|
|
|
|
|
def test_require_sops_cmd_raises_when_not_found(monkeypatch):
|
|
import enroll.sopsutil as s
|
|
|
|
def fake_find():
|
|
return None
|
|
|
|
monkeypatch.setattr(s, "find_sops_cmd", fake_find)
|
|
|
|
with pytest.raises(SopsError) as exc_info:
|
|
require_sops_cmd()
|
|
|
|
assert "sops" in str(exc_info.value).lower()
|
|
assert "not found" in str(exc_info.value).lower()
|
|
|
|
|
|
def test_pgp_arg_with_empty_fingerprints():
|
|
with pytest.raises(SopsError) as exc_info:
|
|
_pgp_arg([])
|
|
assert "No GPG fingerprints" in str(exc_info.value)
|
|
|
|
|
|
def test_pgp_arg_with_whitespace_fingerprints():
|
|
result = _pgp_arg([" ", "ABC123", " DEF456 "])
|
|
assert result == "ABC123,DEF456"
|
|
|
|
|
|
def test_pgp_arg_with_single_fingerprint():
|
|
result = _pgp_arg(["ABC123DEF456"])
|
|
assert result == "ABC123DEF456"
|
|
|
|
|
|
def test_pgp_arg_with_multiple_fingerprints():
|
|
result = _pgp_arg(["ABC123", "DEF456", "GHI789"])
|
|
assert result == "ABC123,DEF456,GHI789"
|
|
|
|
|
|
def test_encrypt_file_binary_success(monkeypatch, tmp_path: Path):
|
|
"""Test successful encryption path."""
|
|
# Create source file
|
|
src = tmp_path / "secret.txt"
|
|
src.write_text("secret data", encoding="utf-8")
|
|
dst = tmp_path / "encrypted.sops"
|
|
|
|
# Mock subprocess.run to succeed
|
|
class Result:
|
|
returncode = 0
|
|
stdout = b"encrypted data"
|
|
stderr = b""
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
# Mock require_sops_cmd to return a fake path
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
|
|
from enroll.sopsutil import encrypt_file_binary
|
|
|
|
encrypt_file_binary(src, dst, pgp_fingerprints=["ABC123"])
|
|
|
|
assert dst.exists()
|
|
assert dst.read_bytes() == b"encrypted data"
|
|
|
|
|
|
def test_encrypt_file_binary_fails(monkeypatch, tmp_path: Path):
|
|
"""Test encryption failure path."""
|
|
src = tmp_path / "secret.txt"
|
|
src.write_text("secret data", encoding="utf-8")
|
|
dst = tmp_path / "encrypted.sops"
|
|
|
|
class Result:
|
|
returncode = 1
|
|
stdout = b""
|
|
stderr = b"sops: gpg error"
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
|
|
from enroll.sopsutil import encrypt_file_binary, SopsError
|
|
|
|
with pytest.raises(SopsError) as exc_info:
|
|
encrypt_file_binary(src, dst, pgp_fingerprints=["ABC123"])
|
|
|
|
assert "encryption failed" in str(exc_info.value).lower()
|
|
|
|
|
|
def test_encrypt_file_binary_chmod_fails(monkeypatch, tmp_path: Path):
|
|
"""Test when chmod fails but file is still written."""
|
|
src = tmp_path / "secret.txt"
|
|
src.write_text("secret data", encoding="utf-8")
|
|
dst = tmp_path / "encrypted.sops"
|
|
|
|
class Result:
|
|
returncode = 0
|
|
stdout = b"encrypted data"
|
|
stderr = b""
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
def fake_chmod(path, mode):
|
|
raise OSError("Permission denied")
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
monkeypatch.setattr("enroll.sopsutil.os.chmod", fake_chmod)
|
|
|
|
from enroll.sopsutil import encrypt_file_binary
|
|
|
|
# Should not raise even though chmod fails
|
|
encrypt_file_binary(src, dst, pgp_fingerprints=["ABC123"])
|
|
|
|
assert dst.exists()
|
|
|
|
|
|
def test_decrypt_file_binary_to_success(monkeypatch, tmp_path: Path):
|
|
"""Test successful decryption path."""
|
|
src = tmp_path / "encrypted.sops"
|
|
src.write_bytes(b"encrypted data")
|
|
dst = tmp_path / "decrypted.txt"
|
|
|
|
class Result:
|
|
returncode = 0
|
|
stdout = b"decrypted data"
|
|
stderr = b""
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
|
|
from enroll.sopsutil import decrypt_file_binary_to
|
|
|
|
decrypt_file_binary_to(src, dst)
|
|
|
|
assert dst.exists()
|
|
assert dst.read_bytes() == b"decrypted data"
|
|
|
|
|
|
def test_decrypt_file_binary_to_fails(monkeypatch, tmp_path: Path):
|
|
"""Test decryption failure path."""
|
|
src = tmp_path / "encrypted.sops"
|
|
src.write_bytes(b"encrypted data")
|
|
dst = tmp_path / "decrypted.txt"
|
|
|
|
class Result:
|
|
returncode = 1
|
|
stdout = b""
|
|
stderr = b"sops: decryption failed"
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
|
|
from enroll.sopsutil import decrypt_file_binary_to, SopsError
|
|
|
|
with pytest.raises(SopsError) as exc_info:
|
|
decrypt_file_binary_to(src, dst)
|
|
|
|
assert "decryption failed" in str(exc_info.value).lower()
|
|
|
|
|
|
def test_decrypt_file_binary_to_chmod_fails(monkeypatch, tmp_path: Path):
|
|
"""Test when chmod fails during decryption but file is still written."""
|
|
src = tmp_path / "encrypted.sops"
|
|
src.write_bytes(b"encrypted data")
|
|
dst = tmp_path / "decrypted.txt"
|
|
|
|
class Result:
|
|
returncode = 0
|
|
stdout = b"decrypted data"
|
|
stderr = b""
|
|
|
|
def fake_run(cmd, capture_output, check):
|
|
return Result()
|
|
|
|
def fake_require():
|
|
return "/fake/sops"
|
|
|
|
def fake_chmod(path, mode):
|
|
raise OSError("Permission denied")
|
|
|
|
monkeypatch.setattr("enroll.sopsutil.subprocess.run", fake_run)
|
|
monkeypatch.setattr("enroll.sopsutil.require_sops_cmd", fake_require)
|
|
monkeypatch.setattr("enroll.sopsutil.os.chmod", fake_chmod)
|
|
|
|
from enroll.sopsutil import decrypt_file_binary_to
|
|
|
|
# Should not raise even though chmod fails
|
|
decrypt_file_binary_to(src, dst)
|
|
|
|
assert dst.exists()
|