Initial
This commit is contained in:
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
344
tests/conftest.py
Normal file
344
tests/conftest.py
Normal file
@ -0,0 +1,344 @@
|
||||
from collections import defaultdict
|
||||
from functools import wraps
|
||||
from pathlib import Path
|
||||
from random import choice
|
||||
from random import randint
|
||||
from shutil import copytree
|
||||
from string import ascii_letters
|
||||
from string import digits
|
||||
from string import hexdigits
|
||||
from string import punctuation
|
||||
from subprocess import PIPE
|
||||
from subprocess import Popen
|
||||
from tempfile import NamedTemporaryFile
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Generator
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Set
|
||||
|
||||
from pytest import fixture
|
||||
|
||||
from libkeyringctl.keyring import convert_certificate
|
||||
from libkeyringctl.keyring import export
|
||||
from libkeyringctl.keyring import get_fingerprints_from_keyring_files
|
||||
from libkeyringctl.sequoia import certify
|
||||
from libkeyringctl.sequoia import key_extract_certificate
|
||||
from libkeyringctl.sequoia import key_generate
|
||||
from libkeyringctl.sequoia import keyring_merge
|
||||
from libkeyringctl.sequoia import packet_join
|
||||
from libkeyringctl.types import Fingerprint
|
||||
from libkeyringctl.types import Uid
|
||||
from libkeyringctl.types import Username
|
||||
from libkeyringctl.util import cwd
|
||||
from libkeyringctl.util import simplify_uid
|
||||
from libkeyringctl.util import system
|
||||
|
||||
test_keys: Dict[Username, List[Path]] = defaultdict(list)
|
||||
test_key_revocation: Dict[Username, List[Path]] = defaultdict(list)
|
||||
test_certificates: Dict[Username, List[Path]] = defaultdict(list)
|
||||
test_certificate_uids: Dict[Username, List[List[Uid]]] = defaultdict(list)
|
||||
test_keyring_certificates: Dict[Username, List[Path]] = defaultdict(list)
|
||||
test_main_fingerprints: Set[Fingerprint] = set()
|
||||
test_all_fingerprints: Set[Fingerprint] = set()
|
||||
|
||||
|
||||
@fixture(autouse=True)
|
||||
def reset_storage() -> None:
|
||||
test_keys.clear()
|
||||
test_key_revocation.clear()
|
||||
test_certificates.clear()
|
||||
test_certificate_uids.clear()
|
||||
test_keyring_certificates.clear()
|
||||
test_main_fingerprints.clear()
|
||||
test_all_fingerprints.clear()
|
||||
|
||||
|
||||
def create_certificate(
|
||||
username: Username,
|
||||
uids: List[Uid],
|
||||
keyring_type: str = "packager",
|
||||
func: Optional[Callable[..., Any]] = None,
|
||||
) -> Callable[..., Any]:
|
||||
def decorator(decorated_func: Callable[..., None]) -> Callable[..., Any]:
|
||||
@wraps(decorated_func)
|
||||
def wrapper(working_dir: Path, *args: Any, **kwargs: Any) -> None:
|
||||
key_directory = working_dir / "secret" / f"{username}"
|
||||
key_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
key_file: Path = key_directory / f"{username}.asc"
|
||||
key_generate(uids=uids, outfile=key_file)
|
||||
test_keys[username].append(key_file)
|
||||
|
||||
certificate_directory = working_dir / "certificate" / f"{username}"
|
||||
certificate_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
keyring_root: Path = working_dir / "keyring"
|
||||
keyring_root.mkdir(parents=True, exist_ok=True)
|
||||
certificate_file: Path = certificate_directory / f"{username}.asc"
|
||||
|
||||
key_extract_certificate(key=key_file, output=certificate_file)
|
||||
test_certificates[username].append(certificate_file)
|
||||
test_certificate_uids[username].append(uids)
|
||||
|
||||
key_revocation_packet = key_file.parent / f"{key_file.name}.rev"
|
||||
key_revocation_joined = key_file.parent / f"{key_file.name}.joined.rev"
|
||||
key_revocation_cert = key_file.parent / f"{key_file.name}.cert.rev"
|
||||
packet_join(packets=[certificate_file, key_revocation_packet], output=key_revocation_joined)
|
||||
keyring_merge(certificates=[key_revocation_joined], output=key_revocation_cert)
|
||||
test_key_revocation[username].append(key_revocation_cert)
|
||||
|
||||
target_dir = keyring_root / keyring_type
|
||||
|
||||
for fingerprint in get_fingerprints_from_keyring_files(
|
||||
working_dir=working_dir, source=[certificate_file]
|
||||
).keys():
|
||||
test_all_fingerprints.add(fingerprint)
|
||||
|
||||
decomposed_path: Path = convert_certificate(
|
||||
working_dir=working_dir,
|
||||
certificate=certificate_file,
|
||||
keyring_dir=keyring_root / keyring_type,
|
||||
fingerprint_filter=test_all_fingerprints,
|
||||
)
|
||||
user_dir = decomposed_path.parent
|
||||
(target_dir / user_dir.name).mkdir(parents=True, exist_ok=True)
|
||||
copytree(src=user_dir, dst=(target_dir / user_dir.name), dirs_exist_ok=True)
|
||||
test_keyring_certificates[username].append(target_dir / user_dir.name / decomposed_path.name)
|
||||
|
||||
certificate_fingerprint: Fingerprint = Fingerprint(decomposed_path.name)
|
||||
if "main" == keyring_type:
|
||||
test_main_fingerprints.add(certificate_fingerprint)
|
||||
test_all_fingerprints.add(certificate_fingerprint)
|
||||
|
||||
decorated_func(working_dir=working_dir, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
if not func:
|
||||
return decorator
|
||||
return decorator(func)
|
||||
|
||||
|
||||
def create_uid_certification(
|
||||
issuer: Username, certified: Username, uid: Uid, func: Optional[Callable[[Any], None]] = None
|
||||
) -> Callable[..., Any]:
|
||||
def decorator(decorated_func: Callable[..., None]) -> Callable[..., Any]:
|
||||
@wraps(decorated_func)
|
||||
def wrapper(working_dir: Path, *args: Any, **kwargs: Any) -> None:
|
||||
key: Path = test_keys[issuer][0]
|
||||
certificate: Path = test_certificates[certified][0]
|
||||
fingerprint: Fingerprint = Fingerprint(test_keyring_certificates[certified][0].name)
|
||||
issuer_fingerprint: Fingerprint = Fingerprint(test_keyring_certificates[issuer][0].name)
|
||||
simplified_uid = simplify_uid(Uid(uid))
|
||||
|
||||
output: Path = (
|
||||
working_dir
|
||||
/ "keyring"
|
||||
/ "packager"
|
||||
/ certified
|
||||
/ fingerprint
|
||||
/ "uid"
|
||||
/ simplified_uid
|
||||
/ "certification"
|
||||
/ f"{issuer_fingerprint}.asc"
|
||||
)
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
certify(key, certificate, uid, output)
|
||||
|
||||
decorated_func(working_dir=working_dir, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
if not func:
|
||||
return decorator
|
||||
return decorator(func)
|
||||
|
||||
|
||||
def create_key_revocation(
|
||||
username: Username,
|
||||
keyring_type: str = "packager",
|
||||
func: Optional[Callable[..., Any]] = None,
|
||||
) -> Callable[..., Any]:
|
||||
def decorator(decorated_func: Callable[..., None]) -> Callable[..., Any]:
|
||||
@wraps(decorated_func)
|
||||
def wrapper(working_dir: Path, *args: Any, **kwargs: Any) -> None:
|
||||
revocation = test_key_revocation[username][0]
|
||||
|
||||
keyring_root: Path = working_dir / "keyring"
|
||||
keyring_root.mkdir(parents=True, exist_ok=True)
|
||||
target_dir = keyring_root / keyring_type
|
||||
|
||||
decomposed_path: Path = convert_certificate(
|
||||
working_dir=working_dir,
|
||||
certificate=revocation,
|
||||
keyring_dir=keyring_root / keyring_type,
|
||||
fingerprint_filter=test_all_fingerprints,
|
||||
)
|
||||
user_dir = decomposed_path.parent
|
||||
(target_dir / user_dir.name).mkdir(parents=True, exist_ok=True)
|
||||
copytree(src=user_dir, dst=(target_dir / user_dir.name), dirs_exist_ok=True)
|
||||
|
||||
decorated_func(working_dir=working_dir, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
if not func:
|
||||
return decorator
|
||||
return decorator(func)
|
||||
|
||||
|
||||
def create_signature_revocation(
|
||||
issuer: Username, certified: Username, uid: Uid, func: Optional[Callable[[Any], None]] = None
|
||||
) -> Callable[..., Any]:
|
||||
def decorator(decorated_func: Callable[..., None]) -> Callable[..., Any]:
|
||||
@wraps(decorated_func)
|
||||
def wrapper(working_dir: Path, *args: Any, **kwargs: Any) -> None:
|
||||
issuer_key: Path = test_keys[issuer][0]
|
||||
keyring_root: Path = working_dir / "keyring"
|
||||
|
||||
keyring_certificate: Path = test_keyring_certificates[certified][0]
|
||||
certified_fingerprint = keyring_certificate.name
|
||||
|
||||
with NamedTemporaryFile(dir=str(working_dir), prefix=f"{certified}", suffix=".asc") as certificate:
|
||||
certificate_path: Path = Path(certificate.name)
|
||||
export(
|
||||
working_dir=working_dir,
|
||||
keyring_root=keyring_root,
|
||||
sources=[keyring_certificate],
|
||||
output=certificate_path,
|
||||
)
|
||||
|
||||
with TemporaryDirectory(prefix="gnupg") as gnupg_home:
|
||||
env = {"GNUPGHOME": gnupg_home}
|
||||
|
||||
print(
|
||||
system(
|
||||
[
|
||||
"gpg",
|
||||
"--no-auto-check-trustdb",
|
||||
"--import",
|
||||
f"{str(issuer_key)}",
|
||||
f"{str(certificate_path)}",
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
)
|
||||
|
||||
uid_confirmations = ""
|
||||
for cert_uid in test_certificate_uids[certified][0]:
|
||||
if uid == cert_uid:
|
||||
uid_confirmations += "y\n"
|
||||
else:
|
||||
uid_confirmations += "n\n"
|
||||
|
||||
commands = Popen(["echo", "-e", f"{uid_confirmations}y\n0\ny\n\ny\ny\nsave\n"], stdout=PIPE)
|
||||
system(
|
||||
[
|
||||
"gpg",
|
||||
"--no-auto-check-trustdb",
|
||||
"--command-fd",
|
||||
"0",
|
||||
"--expert",
|
||||
"--yes",
|
||||
"--batch",
|
||||
"--edit-key",
|
||||
f"{certified_fingerprint}",
|
||||
"revsig",
|
||||
"save",
|
||||
],
|
||||
_stdin=commands.stdout,
|
||||
env=env,
|
||||
)
|
||||
|
||||
revoked_certificate = system(["gpg", "--armor", "--export", f"{certified_fingerprint}"], env=env)
|
||||
certificate.truncate(0)
|
||||
certificate.seek(0)
|
||||
certificate.write(revoked_certificate.encode())
|
||||
certificate.flush()
|
||||
|
||||
target_dir = keyring_root / "packager"
|
||||
decomposed_path: Path = convert_certificate(
|
||||
working_dir=working_dir,
|
||||
certificate=certificate_path,
|
||||
keyring_dir=target_dir,
|
||||
fingerprint_filter=test_all_fingerprints,
|
||||
)
|
||||
user_dir = decomposed_path.parent
|
||||
(target_dir / user_dir.name).mkdir(parents=True, exist_ok=True)
|
||||
copytree(src=user_dir, dst=(target_dir / user_dir.name), dirs_exist_ok=True)
|
||||
|
||||
decorated_func(working_dir=working_dir, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
if not func:
|
||||
return decorator
|
||||
return decorator(func)
|
||||
|
||||
|
||||
@fixture(scope="function")
|
||||
def working_dir() -> Generator[Path, None, None]:
|
||||
with TemporaryDirectory(prefix="arch-keyringctl-test-") as tempdir:
|
||||
path: Path = Path(tempdir)
|
||||
with cwd(path):
|
||||
yield path
|
||||
|
||||
|
||||
@fixture(scope="function")
|
||||
def keyring_dir(working_dir: Path) -> Generator[Path, None, None]:
|
||||
yield working_dir / "keyring"
|
||||
|
||||
|
||||
def random_string(length: int, chars: str) -> str:
|
||||
return "".join(choice(chars) for x in range(length))
|
||||
|
||||
|
||||
@fixture(scope="function", params=[16, 40], ids=["short_id", "long_id"])
|
||||
def valid_fingerprint(request: Any) -> Generator[str, None, None]:
|
||||
yield random_string(length=request.param, chars="ABCDEF" + digits)
|
||||
|
||||
|
||||
@fixture(scope="function", params=[16, 40], ids=["short_id", "long_id"])
|
||||
def valid_subkey_fingerprint(request: Any) -> Generator[str, None, None]:
|
||||
yield random_string(length=request.param, chars="ABCDEF" + digits)
|
||||
|
||||
|
||||
@fixture(
|
||||
scope="function",
|
||||
params=[
|
||||
(
|
||||
16,
|
||||
ascii_letters + hexdigits + punctuation,
|
||||
),
|
||||
(
|
||||
40,
|
||||
ascii_letters + hexdigits + punctuation,
|
||||
),
|
||||
(
|
||||
randint(0, 15),
|
||||
"ABCDEF" + digits,
|
||||
),
|
||||
(
|
||||
randint(17, 39),
|
||||
"ABCDEF" + digits,
|
||||
),
|
||||
(
|
||||
randint(41, 100),
|
||||
"ABCDEF" + digits,
|
||||
),
|
||||
],
|
||||
ids=[
|
||||
"short_id_wrong_chars",
|
||||
"long_id_wrong_chars",
|
||||
"right_chars_shorter_than_short_id",
|
||||
"right_chars_shorter_than_long_id_longer_than_short_id",
|
||||
"right_chars_longer_than_long_id",
|
||||
],
|
||||
)
|
||||
def invalid_fingerprint(request: Any) -> Generator[str, None, None]:
|
||||
yield random_string(length=request.param[0], chars=request.param[1])
|
45
tests/test_git.py
Normal file
45
tests/test_git.py
Normal file
@ -0,0 +1,45 @@
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytest import mark
|
||||
|
||||
from libkeyringctl import git
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"git_path, base, paths",
|
||||
[
|
||||
(None, None, None),
|
||||
(Path("git_path"), None, None),
|
||||
(Path("git_path"), "base", None),
|
||||
(Path("git_path"), "base", [Path("foo"), Path("bar")]),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.git.system")
|
||||
def test_git_changed_files(
|
||||
system_mock: Mock,
|
||||
git_path: Optional[Path],
|
||||
base: Optional[str],
|
||||
paths: Optional[List[Path]],
|
||||
) -> None:
|
||||
system_mock.return_value = "create some thing foo\n" "delete some thing bar\n" "some thing baz\n"
|
||||
|
||||
assert git.git_changed_files(git_path=git_path, base=base, paths=paths) == (
|
||||
[Path("foo")],
|
||||
[Path("bar")],
|
||||
[Path("baz")],
|
||||
)
|
||||
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
if git_path:
|
||||
assert "-C" in args[0]
|
||||
assert str(git_path) in args[0]
|
||||
if base:
|
||||
assert base in args[0]
|
||||
if paths:
|
||||
assert "--" in args[0]
|
||||
for path in paths:
|
||||
assert str(path) in args[0]
|
804
tests/test_keyring.py
Normal file
804
tests/test_keyring.py
Normal file
@ -0,0 +1,804 @@
|
||||
from collections import defaultdict
|
||||
from contextlib import nullcontext as does_not_raise
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from random import choice
|
||||
from string import digits
|
||||
from typing import ContextManager
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Set
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytest import mark
|
||||
from pytest import raises
|
||||
|
||||
from libkeyringctl import keyring
|
||||
from libkeyringctl.keyring import PACKET_FILENAME_DATETIME_FORMAT
|
||||
from libkeyringctl.types import Fingerprint
|
||||
from libkeyringctl.types import TrustFilter
|
||||
from libkeyringctl.types import Uid
|
||||
from libkeyringctl.types import Username
|
||||
|
||||
from .conftest import create_certificate
|
||||
from .conftest import create_key_revocation
|
||||
from .conftest import create_signature_revocation
|
||||
from .conftest import create_uid_certification
|
||||
from .conftest import test_all_fingerprints
|
||||
from .conftest import test_certificates
|
||||
from .conftest import test_keyring_certificates
|
||||
from .conftest import test_keys
|
||||
from .conftest import test_main_fingerprints
|
||||
|
||||
|
||||
def test_is_pgp_fingerprint(
|
||||
valid_fingerprint: str,
|
||||
invalid_fingerprint: str,
|
||||
) -> None:
|
||||
assert keyring.is_pgp_fingerprint(string=valid_fingerprint) is True
|
||||
assert keyring.is_pgp_fingerprint(string=invalid_fingerprint) is False
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"create_paths, create_paths_in_keyring_dir",
|
||||
[
|
||||
(True, False),
|
||||
(True, True),
|
||||
(False, True),
|
||||
(False, False),
|
||||
],
|
||||
)
|
||||
def test_transform_username_to_keyring_path(
|
||||
create_paths: bool,
|
||||
create_paths_in_keyring_dir: bool,
|
||||
working_dir: Path,
|
||||
keyring_dir: Path,
|
||||
) -> None:
|
||||
paths = [Path("test")]
|
||||
input_paths = deepcopy(paths)
|
||||
|
||||
for index, path in enumerate(paths):
|
||||
path_in_working_dir = working_dir / path
|
||||
if create_paths:
|
||||
path_in_working_dir.mkdir()
|
||||
|
||||
if create_paths_in_keyring_dir:
|
||||
(keyring_dir / path).mkdir(parents=True)
|
||||
|
||||
paths[index] = path_in_working_dir
|
||||
|
||||
modified_paths = deepcopy(paths)
|
||||
|
||||
keyring.transform_username_to_keyring_path(keyring_dir=keyring_dir, paths=paths)
|
||||
|
||||
for index, path in enumerate(paths):
|
||||
if create_paths or (not create_paths and not create_paths_in_keyring_dir):
|
||||
assert path == modified_paths[index]
|
||||
if not create_paths and create_paths_in_keyring_dir:
|
||||
assert path == keyring_dir / input_paths[index]
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"fingerprint_path, create_paths, create_paths_in_keyring_dir",
|
||||
[
|
||||
(True, True, False),
|
||||
(True, True, True),
|
||||
(True, False, True),
|
||||
(True, False, False),
|
||||
(False, True, False),
|
||||
(False, True, True),
|
||||
(False, False, True),
|
||||
(False, False, False),
|
||||
],
|
||||
)
|
||||
def test_transform_fingerprint_to_keyring_path(
|
||||
fingerprint_path: bool,
|
||||
create_paths: bool,
|
||||
create_paths_in_keyring_dir: bool,
|
||||
working_dir: Path,
|
||||
keyring_dir: Path,
|
||||
valid_fingerprint: str,
|
||||
) -> None:
|
||||
paths = [Path(valid_fingerprint) if fingerprint_path else Path("test")]
|
||||
input_paths = deepcopy(paths)
|
||||
|
||||
keyring_subdir = keyring_dir / "type" / "username"
|
||||
|
||||
for index, path in enumerate(paths):
|
||||
path_in_working_dir = working_dir / path
|
||||
if create_paths:
|
||||
path_in_working_dir.mkdir()
|
||||
|
||||
if create_paths_in_keyring_dir:
|
||||
(keyring_subdir / path).mkdir(parents=True)
|
||||
|
||||
paths[index] = path_in_working_dir
|
||||
|
||||
modified_paths = deepcopy(paths)
|
||||
|
||||
keyring.transform_fingerprint_to_keyring_path(keyring_root=keyring_dir, paths=paths)
|
||||
|
||||
for index, path in enumerate(paths):
|
||||
if create_paths or (not fingerprint_path and not create_paths):
|
||||
assert path == modified_paths[index]
|
||||
if not create_paths and fingerprint_path and create_paths_in_keyring_dir:
|
||||
assert path == keyring_subdir / input_paths[index]
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"valid_current_packet_fingerprint, packet_type, issuer, expectation",
|
||||
[
|
||||
(True, "KeyRevocation", "self", does_not_raise()),
|
||||
(True, "DirectKey", "self", does_not_raise()),
|
||||
(True, "GenericCertification", "self", does_not_raise()),
|
||||
(True, "KeyRevocation", None, does_not_raise()),
|
||||
(True, "CertificationRevocation", None, does_not_raise()),
|
||||
(True, "CertificationRevocation", "self", does_not_raise()),
|
||||
(True, "DirectKey", None, does_not_raise()),
|
||||
(True, "GenericCertification", None, does_not_raise()),
|
||||
(True, "KeyRevocation", "foo", raises(Exception)),
|
||||
(True, "DirectKey", "foo", does_not_raise()),
|
||||
(True, "GenericCertification", "foo", does_not_raise()),
|
||||
(True, "foo", "foo", does_not_raise()),
|
||||
(True, "foo", "self", raises(Exception)),
|
||||
(False, "KeyRevocation", True, raises(Exception)),
|
||||
(False, "DirectKey", True, raises(Exception)),
|
||||
(False, "GenericCertification", True, raises(Exception)),
|
||||
(False, "CertificationRevocation", True, raises(Exception)),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.keyring.get_fingerprint_from_partial")
|
||||
@patch("libkeyringctl.keyring.packet_dump_field")
|
||||
def test_convert_pubkey_signature_packet(
|
||||
packet_dump_field_mock: Mock,
|
||||
get_fingerprint_from_partial_mock: Mock,
|
||||
valid_current_packet_fingerprint: bool,
|
||||
packet_type: str,
|
||||
issuer: Optional[str],
|
||||
expectation: ContextManager[str],
|
||||
working_dir: Path,
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
packet = working_dir / "packet"
|
||||
key_revocations: Dict[Fingerprint, Path] = {}
|
||||
direct_revocations: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
direct_sigs: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
current_packet_fingerprint = None
|
||||
|
||||
if valid_current_packet_fingerprint:
|
||||
current_packet_fingerprint = valid_fingerprint
|
||||
|
||||
packet_dump_field_mock.return_value = packet_type
|
||||
if issuer == "self":
|
||||
get_fingerprint_from_partial_mock.return_value = valid_fingerprint
|
||||
else:
|
||||
get_fingerprint_from_partial_mock.return_value = None if issuer is None else Fingerprint(issuer)
|
||||
|
||||
with expectation:
|
||||
keyring.convert_pubkey_signature_packet(
|
||||
packet=packet,
|
||||
certificate_fingerprint=valid_fingerprint,
|
||||
fingerprint_filter=None,
|
||||
current_packet_fingerprint=current_packet_fingerprint,
|
||||
key_revocations=key_revocations,
|
||||
direct_revocations=direct_revocations,
|
||||
direct_sigs=direct_sigs,
|
||||
)
|
||||
|
||||
if issuer is None or current_packet_fingerprint is None:
|
||||
assert not direct_revocations and not direct_sigs and not key_revocations
|
||||
else:
|
||||
if packet_type == "KeyRevocation":
|
||||
assert key_revocations[valid_fingerprint] == packet
|
||||
elif packet_type in ["CertificationRevocation"]:
|
||||
if issuer != "self":
|
||||
assert not direct_revocations
|
||||
else:
|
||||
assert direct_revocations[valid_fingerprint if issuer == "self" else Fingerprint(issuer)] == [
|
||||
packet
|
||||
]
|
||||
elif packet_type in ["DirectKey", "GenericCertification"]:
|
||||
if issuer != "self":
|
||||
assert not direct_sigs
|
||||
else:
|
||||
assert direct_sigs[valid_fingerprint if issuer == "self" else Fingerprint(issuer)] == [packet]
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"valid_current_packet_uid, packet_type, provide_issuer, issuer_in_filter, expectation",
|
||||
[
|
||||
(True, "CertificationRevocation", "self", True, does_not_raise()),
|
||||
(True, "CertificationRevocation", "self", False, does_not_raise()),
|
||||
(True, "SomeCertification", "self", True, does_not_raise()),
|
||||
(True, "SomeCertification", "self", False, does_not_raise()),
|
||||
(True, "CertificationRevocation", None, True, does_not_raise()),
|
||||
(True, "CertificationRevocation", None, False, does_not_raise()),
|
||||
(True, "SomeCertification", None, True, does_not_raise()),
|
||||
(True, "SomeCertification", None, False, does_not_raise()),
|
||||
(False, "CertificationRevocation", "self", True, raises(Exception)),
|
||||
(False, "CertificationRevocation", "self", False, raises(Exception)),
|
||||
(False, "SomeCertification", "self", True, raises(Exception)),
|
||||
(False, "SomeCertification", "self", False, raises(Exception)),
|
||||
(True, "foo", "self", True, raises(Exception)),
|
||||
(True, "foo", "self", False, raises(Exception)),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.keyring.get_fingerprint_from_partial")
|
||||
@patch("libkeyringctl.keyring.packet_dump_field")
|
||||
def test_convert_uid_signature_packet(
|
||||
packet_dump_field_mock: Mock,
|
||||
get_fingerprint_from_partial_mock: Mock,
|
||||
valid_current_packet_uid: bool,
|
||||
packet_type: str,
|
||||
provide_issuer: Optional[str],
|
||||
issuer_in_filter: bool,
|
||||
expectation: ContextManager[str],
|
||||
working_dir: Path,
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
packet = working_dir / "packet"
|
||||
certifications: Dict[Uid, Dict[Fingerprint, List[Path]]] = defaultdict(lambda: defaultdict(list))
|
||||
revocations: Dict[Uid, Dict[Fingerprint, List[Path]]] = defaultdict(lambda: defaultdict(list))
|
||||
current_packet_uid = None
|
||||
issuer = None
|
||||
fingerprint_filter: Set[Fingerprint] = {Fingerprint("foo")}
|
||||
|
||||
if valid_current_packet_uid:
|
||||
current_packet_uid = Uid("Foobar McFooface <foo@barmcfoofa.ce>")
|
||||
|
||||
packet_dump_field_mock.return_value = packet_type
|
||||
if provide_issuer == "self":
|
||||
issuer = valid_fingerprint
|
||||
else:
|
||||
if provide_issuer is not None:
|
||||
issuer = Fingerprint(provide_issuer)
|
||||
|
||||
get_fingerprint_from_partial_mock.return_value = issuer
|
||||
|
||||
if issuer_in_filter and issuer is not None:
|
||||
fingerprint_filter.add(issuer)
|
||||
|
||||
with expectation:
|
||||
keyring.convert_uid_signature_packet(
|
||||
packet=packet,
|
||||
current_packet_uid=current_packet_uid,
|
||||
fingerprint_filter=fingerprint_filter,
|
||||
certifications=certifications,
|
||||
revocations=revocations,
|
||||
)
|
||||
|
||||
if not valid_current_packet_uid or issuer is None:
|
||||
assert not certifications and not revocations
|
||||
else:
|
||||
if packet_type == "CertificationRevocation" and valid_current_packet_uid and issuer_in_filter:
|
||||
assert revocations[current_packet_uid][issuer] == [packet] # type: ignore
|
||||
elif packet_type.endswith("Certification") and issuer_in_filter:
|
||||
assert certifications[current_packet_uid][issuer] == [packet] # type: ignore
|
||||
elif packet_type.endswith("Certification") and not issuer_in_filter:
|
||||
assert not certifications
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"valid_current_packet_fingerprint, packet_type, issuer, expectation",
|
||||
[
|
||||
(True, "SubkeyBinding", "self", does_not_raise()),
|
||||
(True, "SubkeyRevocation", "self", does_not_raise()),
|
||||
(True, "SubkeyBinding", None, does_not_raise()),
|
||||
(True, "SubkeyRevocation", None, does_not_raise()),
|
||||
(True, "SubkeyBinding", "foo", raises(Exception)),
|
||||
(True, "SubkeyRevocation", "foo", raises(Exception)),
|
||||
(False, "SubkeyBinding", "self", raises(Exception)),
|
||||
(False, "SubkeyRevocation", "self", raises(Exception)),
|
||||
(True, "foo", "self", raises(Exception)),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.keyring.get_fingerprint_from_partial")
|
||||
@patch("libkeyringctl.keyring.packet_dump_field")
|
||||
def test_convert_subkey_signature_packet(
|
||||
packet_dump_field_mock: Mock,
|
||||
get_fingerprint_from_partial_mock: Mock,
|
||||
valid_current_packet_fingerprint: bool,
|
||||
packet_type: str,
|
||||
issuer: Optional[str],
|
||||
expectation: ContextManager[str],
|
||||
working_dir: Path,
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
packet = working_dir / "packet"
|
||||
subkey_bindings: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
subkey_revocations: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
current_packet_fingerprint = None
|
||||
|
||||
if valid_current_packet_fingerprint:
|
||||
current_packet_fingerprint = valid_fingerprint
|
||||
|
||||
packet_dump_field_mock.return_value = packet_type
|
||||
if issuer == "self":
|
||||
get_fingerprint_from_partial_mock.return_value = valid_fingerprint
|
||||
else:
|
||||
get_fingerprint_from_partial_mock.return_value = None if issuer is None else Fingerprint(issuer)
|
||||
|
||||
with expectation:
|
||||
keyring.convert_subkey_signature_packet(
|
||||
packet=packet,
|
||||
certificate_fingerprint=valid_fingerprint,
|
||||
current_packet_fingerprint=current_packet_fingerprint,
|
||||
fingerprint_filter=None,
|
||||
subkey_bindings=subkey_bindings,
|
||||
subkey_revocations=subkey_revocations,
|
||||
)
|
||||
|
||||
if issuer is None or not valid_current_packet_fingerprint:
|
||||
assert not subkey_bindings and not subkey_revocations
|
||||
else:
|
||||
if packet_type == "SubkeyBinding" and issuer == "self":
|
||||
assert subkey_bindings[valid_fingerprint] == [packet]
|
||||
elif packet_type == "SubkeyRevocation" and issuer == "self":
|
||||
assert subkey_revocations[valid_fingerprint] == [packet]
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"valid_certificate_fingerprint, current_packet_mode, expectation",
|
||||
[
|
||||
(True, "pubkey", does_not_raise()),
|
||||
(True, "uid", does_not_raise()),
|
||||
(True, "subkey", does_not_raise()),
|
||||
(True, "uattr", does_not_raise()),
|
||||
(False, "pubkey", raises(Exception)),
|
||||
(False, "uid", raises(Exception)),
|
||||
(False, "subkey", raises(Exception)),
|
||||
(False, "uattr", raises(Exception)),
|
||||
(True, "foo", raises(Exception)),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.keyring.convert_pubkey_signature_packet")
|
||||
@patch("libkeyringctl.keyring.convert_uid_signature_packet")
|
||||
@patch("libkeyringctl.keyring.convert_subkey_signature_packet")
|
||||
def test_convert_signature_packet(
|
||||
convert_subkey_signature_packet_mock: Mock,
|
||||
convert_uid_signature_packet_mock: Mock,
|
||||
convert_pubkey_signature_packet_mock: Mock,
|
||||
valid_certificate_fingerprint: bool,
|
||||
current_packet_mode: str,
|
||||
expectation: ContextManager[str],
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
certificate_fingerprint = None
|
||||
key_revocations: Dict[Fingerprint, Path] = {}
|
||||
direct_revocations: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
direct_sigs: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
certifications: Dict[Uid, Dict[Fingerprint, List[Path]]] = defaultdict(lambda: defaultdict(list))
|
||||
revocations: Dict[Uid, Dict[Fingerprint, List[Path]]] = defaultdict(lambda: defaultdict(list))
|
||||
subkey_bindings: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
subkey_revocations: Dict[Fingerprint, List[Path]] = defaultdict(list)
|
||||
|
||||
if valid_certificate_fingerprint:
|
||||
certificate_fingerprint = valid_fingerprint
|
||||
|
||||
with expectation:
|
||||
keyring.convert_signature_packet(
|
||||
packet=Path("foo"),
|
||||
current_packet_mode=current_packet_mode,
|
||||
certificate_fingerprint=certificate_fingerprint,
|
||||
fingerprint_filter=None,
|
||||
key_revocations=key_revocations,
|
||||
current_packet_fingerprint=None,
|
||||
current_packet_uid=None,
|
||||
direct_revocations=direct_revocations,
|
||||
direct_sigs=direct_sigs,
|
||||
certifications=certifications,
|
||||
revocations=revocations,
|
||||
subkey_bindings=subkey_bindings,
|
||||
subkey_revocations=subkey_revocations,
|
||||
)
|
||||
|
||||
if current_packet_mode == "pubkey":
|
||||
convert_pubkey_signature_packet_mock.assert_called_once()
|
||||
elif current_packet_mode == "uid":
|
||||
convert_uid_signature_packet_mock.assert_called_once()
|
||||
elif current_packet_mode == "subkey":
|
||||
convert_subkey_signature_packet_mock.assert_called_once()
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"packet, packet_split, packet_dump_field, name_override, expectation",
|
||||
[
|
||||
(
|
||||
Path("foo.asc"),
|
||||
[
|
||||
Path("--PublicKey"),
|
||||
Path("--Signature"),
|
||||
Path("--UserID"),
|
||||
Path("--UserAttribute"),
|
||||
Path("--PublicSubkey"),
|
||||
Path("--Signature"),
|
||||
],
|
||||
[
|
||||
"".join(choice("ABCDEF" + digits) for _ in range(40)),
|
||||
"foo <foo@bar.com>",
|
||||
"".join(choice("ABCDEF" + digits) for _ in range(40)),
|
||||
],
|
||||
"bar",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
Path("foo.asc"),
|
||||
[
|
||||
Path("--PublicKey"),
|
||||
Path("--Signature"),
|
||||
Path("--UserID"),
|
||||
Path("--UserID"),
|
||||
],
|
||||
[
|
||||
"".join(choice("ABCDEF" + digits) for _ in range(40)),
|
||||
"foo <foo@bar.com>",
|
||||
"foo <foo@bar.com>",
|
||||
],
|
||||
"bar",
|
||||
raises(Exception),
|
||||
),
|
||||
(
|
||||
Path("foo.asc"),
|
||||
[
|
||||
Path("--SecretKey"),
|
||||
],
|
||||
[],
|
||||
None,
|
||||
raises(Exception),
|
||||
),
|
||||
(
|
||||
Path("foo.asc"),
|
||||
[
|
||||
Path("foo"),
|
||||
],
|
||||
[],
|
||||
None,
|
||||
raises(Exception),
|
||||
),
|
||||
(
|
||||
Path("foo.asc"),
|
||||
[
|
||||
Path("--PublicKey"),
|
||||
],
|
||||
[
|
||||
None,
|
||||
],
|
||||
"bar",
|
||||
raises(Exception),
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.keyring.persist_key_material")
|
||||
@patch("libkeyringctl.keyring.packet_split")
|
||||
@patch("libkeyringctl.keyring.convert_signature_packet")
|
||||
@patch("libkeyringctl.keyring.packet_dump_field")
|
||||
@patch("libkeyringctl.keyring.derive_username_from_fingerprint")
|
||||
def test_convert_certificate(
|
||||
derive_username_from_fingerprint_mock: Mock,
|
||||
packet_dump_field_mock: Mock,
|
||||
convert_signature_packet_mock: Mock,
|
||||
packet_split_mock: Mock,
|
||||
persist_key_material_mock: Mock,
|
||||
packet: Path,
|
||||
packet_split: List[Path],
|
||||
packet_dump_field: List[str],
|
||||
name_override: Optional[Username],
|
||||
expectation: ContextManager[str],
|
||||
working_dir: Path,
|
||||
keyring_dir: Path,
|
||||
) -> None:
|
||||
packet_split_mock.return_value = packet_split
|
||||
packet_dump_field_mock.side_effect = packet_dump_field
|
||||
|
||||
with expectation:
|
||||
keyring.convert_certificate(
|
||||
working_dir=working_dir,
|
||||
certificate=packet,
|
||||
keyring_dir=keyring_dir,
|
||||
name_override=name_override,
|
||||
fingerprint_filter=None,
|
||||
)
|
||||
|
||||
|
||||
@patch("libkeyringctl.keyring.latest_certification")
|
||||
@patch("libkeyringctl.keyring.packet_join")
|
||||
def test_persist_subkey_revocations(
|
||||
packet_join_mock: Mock,
|
||||
latest_certification_mock: Mock,
|
||||
working_dir: Path,
|
||||
keyring_dir: Path,
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
revocation_packet = working_dir / "latest_revocation.asc"
|
||||
latest_certification_mock.return_value = revocation_packet
|
||||
subkey_revocations: Dict[Fingerprint, List[Path]] = {
|
||||
valid_fingerprint: [revocation_packet, working_dir / "earlier_revocation.asc"]
|
||||
}
|
||||
keyring.persist_subkey_revocations(
|
||||
key_dir=keyring_dir,
|
||||
subkey_revocations=subkey_revocations,
|
||||
issuer=valid_fingerprint,
|
||||
)
|
||||
packet_join_mock.assert_called_once_with(
|
||||
packets=[revocation_packet],
|
||||
output=keyring_dir / "subkey" / valid_fingerprint / "revocation" / f"{valid_fingerprint}.asc",
|
||||
force=True,
|
||||
)
|
||||
|
||||
|
||||
@patch("libkeyringctl.keyring.packet_signature_creation_time")
|
||||
@patch("libkeyringctl.keyring.packet_join")
|
||||
def test_persist_directkey_revocations(
|
||||
packet_join_mock: Mock,
|
||||
packet_signature_creation_time_mock: Mock,
|
||||
working_dir: Path,
|
||||
keyring_dir: Path,
|
||||
valid_fingerprint: Fingerprint,
|
||||
) -> None:
|
||||
revocation_packet = working_dir / "latest_revocation.asc"
|
||||
directkey_revocations: Dict[Fingerprint, List[Path]] = {valid_fingerprint: [revocation_packet]}
|
||||
|
||||
dt = datetime(2000, 1, 12, 11, 22, 33)
|
||||
packet_signature_creation_time_mock.return_value = dt
|
||||
keyring.persist_direct_key_revocations(
|
||||
key_dir=keyring_dir,
|
||||
direct_key_revocations=directkey_revocations,
|
||||
)
|
||||
packet_join_mock.assert_called_once_with(
|
||||
packets=[revocation_packet],
|
||||
output=keyring_dir
|
||||
/ "directkey"
|
||||
/ "revocation"
|
||||
/ valid_fingerprint
|
||||
/ f"{dt.strftime(PACKET_FILENAME_DATETIME_FORMAT)}.asc",
|
||||
force=True,
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
def test_convert(working_dir: Path, keyring_dir: Path) -> None:
|
||||
keyring.convert(
|
||||
working_dir=working_dir,
|
||||
keyring_root=keyring_dir,
|
||||
sources=test_certificates[Username("foobar")],
|
||||
target_dir=keyring_dir / "packager",
|
||||
)
|
||||
|
||||
with raises(Exception):
|
||||
keyring.convert(
|
||||
working_dir=working_dir,
|
||||
keyring_root=keyring_dir,
|
||||
sources=test_keys[Username("foobar")],
|
||||
target_dir=keyring_dir / "packager",
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_clean_keyring(working_dir: Path, keyring_dir: Path) -> None:
|
||||
# first pass clean up certification
|
||||
keyring.clean_keyring(keyring=keyring_dir)
|
||||
# second pass skipping clean up because lack of certification
|
||||
keyring.clean_keyring(keyring=keyring_dir)
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("other_main"), uids=[Uid("other main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
def test_export_ownertrust(working_dir: Path, keyring_dir: Path) -> None:
|
||||
output = working_dir / "build"
|
||||
|
||||
keyring.export_ownertrust(
|
||||
certs=[keyring_dir / "main"],
|
||||
keyring_root=keyring_dir,
|
||||
output=output,
|
||||
)
|
||||
|
||||
with open(file=output, mode="r") as output_file:
|
||||
for line in output_file.readlines():
|
||||
assert line.split(":")[0] in test_main_fingerprints
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_key_revocation(username=Username("foobar"))
|
||||
def test_export_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
output = working_dir / "build"
|
||||
|
||||
keyring.export_revoked(
|
||||
certs=[keyring_dir / "packager"],
|
||||
keyring_root=keyring_dir,
|
||||
main_keys=test_main_fingerprints,
|
||||
output=output,
|
||||
)
|
||||
|
||||
revoked_fingerprints = test_all_fingerprints - test_main_fingerprints
|
||||
with open(file=output, mode="r") as output_file:
|
||||
for line in output_file.readlines():
|
||||
assert line.strip() in revoked_fingerprints
|
||||
|
||||
|
||||
@mark.parametrize("path_exists", [(True), (False)])
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_key_revocation(username=Username("foobar"))
|
||||
def test_get_packets_from_path(working_dir: Path, keyring_dir: Path, path_exists: bool) -> None:
|
||||
if not path_exists:
|
||||
assert keyring.get_packets_from_path(path=working_dir / "nope") == []
|
||||
else:
|
||||
for username, paths in test_keyring_certificates.items():
|
||||
for path in paths:
|
||||
keyring.get_packets_from_path(path=path)
|
||||
|
||||
|
||||
@mark.parametrize("path_exists", [(True), (False)])
|
||||
@patch("libkeyringctl.keyring.get_packets_from_path")
|
||||
def test_get_packets_from_listing(get_packets_from_path_mock: Mock, working_dir: Path, path_exists: bool) -> None:
|
||||
path = working_dir / "path"
|
||||
if not path_exists:
|
||||
assert keyring.get_packets_from_listing(path=path) == []
|
||||
else:
|
||||
get_packets_from_path_mock.return_value = []
|
||||
sub_path = path / "sub"
|
||||
sub_path.mkdir(parents=True)
|
||||
assert keyring.get_packets_from_listing(path=path) == []
|
||||
get_packets_from_path_mock.assert_called_once_with(sub_path)
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_key_revocation(username=Username("foobar"))
|
||||
def test_export(working_dir: Path, keyring_dir: Path) -> None:
|
||||
output_file = working_dir / "output"
|
||||
|
||||
empty_dir = working_dir / "empty"
|
||||
empty_dir.mkdir()
|
||||
assert not keyring.export(working_dir=working_dir, keyring_root=empty_dir, sources=None, output=output_file)
|
||||
assert not output_file.exists()
|
||||
|
||||
keyring.export(working_dir=working_dir, keyring_root=keyring_dir, sources=None, output=output_file)
|
||||
assert output_file.exists()
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_key_revocation(username=Username("foobar"))
|
||||
def test_build(working_dir: Path, keyring_dir: Path) -> None:
|
||||
output_dir = working_dir / "output"
|
||||
|
||||
with raises(FileNotFoundError):
|
||||
empty_dir = working_dir / "empty"
|
||||
empty_dir.mkdir()
|
||||
keyring.build(working_dir=working_dir, keyring_root=empty_dir, target_dir=output_dir)
|
||||
|
||||
keyring.build(working_dir=working_dir, keyring_root=keyring_dir, target_dir=output_dir)
|
||||
assert (
|
||||
(output_dir / "archlinux.gpg").exists()
|
||||
and (output_dir / "archlinux-trusted").exists()
|
||||
and (output_dir / "archlinux-revoked").exists()
|
||||
)
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"create_dir, duplicate_fingerprints, expectation",
|
||||
[
|
||||
(True, False, does_not_raise()),
|
||||
(True, True, raises(Exception)),
|
||||
(False, False, does_not_raise()),
|
||||
(False, True, does_not_raise()),
|
||||
],
|
||||
)
|
||||
def test_derive_username_from_fingerprint(
|
||||
create_dir: bool,
|
||||
duplicate_fingerprints: bool,
|
||||
expectation: ContextManager[str],
|
||||
keyring_dir: Path,
|
||||
valid_fingerprint: str,
|
||||
) -> None:
|
||||
username = "username"
|
||||
other_username = "other_user"
|
||||
|
||||
typed_keyring_dir = keyring_dir / "type"
|
||||
|
||||
if create_dir:
|
||||
(typed_keyring_dir / username / valid_fingerprint).mkdir(parents=True)
|
||||
if duplicate_fingerprints:
|
||||
(typed_keyring_dir / other_username / valid_fingerprint).mkdir(parents=True)
|
||||
|
||||
with expectation:
|
||||
returned_username = keyring.derive_username_from_fingerprint(
|
||||
keyring_dir=typed_keyring_dir,
|
||||
certificate_fingerprint=Fingerprint(valid_fingerprint),
|
||||
)
|
||||
if create_dir and not duplicate_fingerprints:
|
||||
assert returned_username == username
|
||||
else:
|
||||
assert returned_username is None
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
def test_list_keyring(working_dir: Path, keyring_dir: Path) -> None:
|
||||
packager_fingerprints = test_all_fingerprints - test_main_fingerprints
|
||||
|
||||
with patch("builtins.print") as print_mock:
|
||||
keyring.list_keyring(keyring_root=keyring_dir, sources=None, main_keys=False)
|
||||
print_args = [mock_call[1][0] for mock_call in print_mock.mock_calls]
|
||||
for fingerprint in packager_fingerprints:
|
||||
assert any([fingerprint in print_arg for print_arg in print_args])
|
||||
|
||||
with patch("builtins.print") as print_mock:
|
||||
keyring.list_keyring(keyring_root=keyring_dir, sources=None, main_keys=True)
|
||||
print_args = [mock_call[1][0] for mock_call in print_mock.mock_calls]
|
||||
for fingerprint in test_main_fingerprints:
|
||||
assert any([fingerprint in print_arg for print_arg in print_args])
|
||||
|
||||
for name, paths in test_keyring_certificates.items():
|
||||
if all(["main" in str(path) for path in paths]):
|
||||
for path in paths:
|
||||
with patch("builtins.print") as print_mock:
|
||||
keyring.list_keyring(keyring_root=keyring_dir, sources=[path], main_keys=True)
|
||||
print_args = [mock_call[1][0] for mock_call in print_mock.mock_calls]
|
||||
assert name in print_args[0] and path.stem in print_args[0]
|
||||
elif all(["packager" in str(path) for path in paths]):
|
||||
for path in paths:
|
||||
with patch("builtins.print") as print_mock:
|
||||
keyring.list_keyring(keyring_root=keyring_dir, sources=[path], main_keys=False)
|
||||
print_args = [mock_call[1][0] for mock_call in print_mock.mock_calls]
|
||||
assert name in print_args[0] and path.stem in print_args[0]
|
||||
with patch("builtins.print") as print_mock:
|
||||
keyring.list_keyring(
|
||||
keyring_root=keyring_dir, sources=paths, main_keys=False, trust_filter=TrustFilter.revoked
|
||||
)
|
||||
print_args = [mock_call[1][0] for mock_call in print_mock.mock_calls]
|
||||
assert not print_args
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
def test_inspect_keyring(working_dir: Path, keyring_dir: Path) -> None:
|
||||
inspect_string = keyring.inspect_keyring(working_dir=working_dir, keyring_root=keyring_dir, sources=None)
|
||||
for fingerprint in test_all_fingerprints:
|
||||
assert fingerprint in inspect_string
|
||||
|
||||
for name, paths in test_keyring_certificates.items():
|
||||
if all(["main" in str(path) for path in paths]):
|
||||
for path in paths:
|
||||
inspect_string = keyring.inspect_keyring(
|
||||
working_dir=working_dir,
|
||||
keyring_root=keyring_dir,
|
||||
sources=[path],
|
||||
)
|
||||
assert path.stem in inspect_string
|
||||
elif all(["packager" in str(path) for path in paths]):
|
||||
for path in paths:
|
||||
inspect_string = keyring.inspect_keyring(
|
||||
working_dir=working_dir,
|
||||
keyring_root=keyring_dir,
|
||||
sources=[path],
|
||||
)
|
||||
assert path.stem in inspect_string
|
||||
|
||||
|
||||
def test_get_fingerprints_from_paths(keyring_dir: Path, valid_fingerprint: str, valid_subkey_fingerprint: str) -> None:
|
||||
fingerprint_dir = keyring_dir / "type" / "username" / valid_fingerprint
|
||||
fingerprint_dir.mkdir(parents=True)
|
||||
(fingerprint_dir / (fingerprint_dir.name + ".asc")).touch()
|
||||
|
||||
fingerprint_subkey_dir = fingerprint_dir / "subkey" / valid_subkey_fingerprint
|
||||
fingerprint_subkey_dir.mkdir(parents=True)
|
||||
fingerprint_subkey_asc = fingerprint_subkey_dir / (fingerprint_subkey_dir.name + ".asc")
|
||||
fingerprint_subkey_asc.touch()
|
||||
|
||||
assert keyring.get_fingerprints_from_paths(sources=[fingerprint_subkey_dir]) == {
|
||||
Fingerprint(valid_subkey_fingerprint)
|
||||
}
|
||||
assert keyring.get_fingerprints_from_paths(sources=[fingerprint_dir]) == {Fingerprint(valid_fingerprint)}
|
368
tests/test_sequoia.py
Normal file
368
tests/test_sequoia.py
Normal file
@ -0,0 +1,368 @@
|
||||
from contextlib import nullcontext as does_not_raise
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from datetime import timezone
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import ContextManager
|
||||
from typing import Dict
|
||||
from typing import Optional
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytest import mark
|
||||
from pytest import raises
|
||||
|
||||
from libkeyringctl import sequoia
|
||||
from libkeyringctl.types import Fingerprint
|
||||
from libkeyringctl.types import PacketKind
|
||||
from libkeyringctl.types import Uid
|
||||
from libkeyringctl.types import Username
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"create_subdir, preserve_filename",
|
||||
[
|
||||
(False, True),
|
||||
(False, False),
|
||||
(True, True),
|
||||
(True, False),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
@patch("libkeyringctl.sequoia.mkdtemp")
|
||||
def test_keyring_split(mkdtemp_mock: Mock, system_mock: Mock, create_subdir: bool, preserve_filename: bool) -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
|
||||
keyring_tmp_dir = tmp_dir / "keyring"
|
||||
keyring_tmp_dir.mkdir()
|
||||
mkdtemp_mock.return_value = keyring_tmp_dir.absolute()
|
||||
|
||||
if create_subdir:
|
||||
keyring_sub_dir = keyring_tmp_dir / "foo"
|
||||
keyring_sub_dir.mkdir()
|
||||
|
||||
returned = sequoia.keyring_split(
|
||||
working_dir=tmp_dir,
|
||||
keyring=Path("foo"),
|
||||
preserve_filename=preserve_filename,
|
||||
)
|
||||
|
||||
if create_subdir:
|
||||
assert returned == [keyring_sub_dir]
|
||||
else:
|
||||
assert returned == []
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"output",
|
||||
[
|
||||
None,
|
||||
Path("output"),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_keyring_merge(system_mock: Mock, output: Optional[Path]) -> None:
|
||||
certificates = [Path("foo"), Path("bar")]
|
||||
system_mock.return_value = "return"
|
||||
|
||||
assert sequoia.keyring_merge(certificates=certificates, output=output) == "return"
|
||||
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
for cert in certificates:
|
||||
assert str(cert) in args[0]
|
||||
if output:
|
||||
assert "--output" in args[0] and str(output) in args[0]
|
||||
|
||||
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
@patch("libkeyringctl.sequoia.mkdtemp")
|
||||
def test_packet_split(mkdtemp_mock: Mock, system_mock: Mock) -> None:
|
||||
certificate = Path("certificate")
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
|
||||
keyring_tmp_dir = tmp_dir / "keyring"
|
||||
keyring_tmp_dir.mkdir()
|
||||
mkdtemp_mock.return_value = keyring_tmp_dir.absolute()
|
||||
keyring_sub_dir = keyring_tmp_dir / "foo"
|
||||
keyring_sub_dir.mkdir()
|
||||
|
||||
assert sequoia.packet_split(working_dir=tmp_dir, certificate=certificate) == [keyring_sub_dir]
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
assert str(certificate) == args[0][-1]
|
||||
|
||||
|
||||
@mark.parametrize("output, force", [(None, True), (None, False), (Path("output"), True), (Path("output"), False)])
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_packet_join(system_mock: Mock, output: Optional[Path], force: bool) -> None:
|
||||
packets = [Path("packet1"), Path("packet2")]
|
||||
system_return = "return"
|
||||
system_mock.return_value = system_return
|
||||
|
||||
assert sequoia.packet_join(packets, output=output, force=force) == system_return
|
||||
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
for packet in packets:
|
||||
assert str(packet) in args[0]
|
||||
if force:
|
||||
assert "--force" == args[0][1]
|
||||
if output:
|
||||
assert "--output" in args[0] and str(output) in args[0]
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"certifications_in_result, certifications, fingerprints",
|
||||
[
|
||||
("something: 0123456789123456789012345678901234567890\n", True, None),
|
||||
("something: 0123456789123456789012345678901234567890\n", False, None),
|
||||
(
|
||||
"something: 0123456789123456789012345678901234567890\n",
|
||||
True,
|
||||
{Fingerprint("0123456789123456789012345678901234567890"): Username("foo")},
|
||||
),
|
||||
(
|
||||
"something: 0123456789123456789012345678901234567890\n",
|
||||
False,
|
||||
{Fingerprint("0123456789123456789012345678901234567890"): Username("foo")},
|
||||
),
|
||||
(
|
||||
"something: 5678901234567890\n",
|
||||
True,
|
||||
{Fingerprint("0123456789123456789012345678901234567890"): Username("foo")},
|
||||
),
|
||||
(
|
||||
"something: 5678901234567890\n",
|
||||
False,
|
||||
{Fingerprint("0123456789123456789012345678901234567890"): Username("foo")},
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_inspect(
|
||||
system_mock: Mock,
|
||||
certifications_in_result: str,
|
||||
certifications: bool,
|
||||
fingerprints: Optional[Dict[Fingerprint, Username]],
|
||||
) -> None:
|
||||
packet = Path("packet")
|
||||
result_header = "result\n"
|
||||
|
||||
if certifications:
|
||||
system_mock.return_value = result_header + "\n" + certifications_in_result
|
||||
else:
|
||||
system_mock.return_value = result_header
|
||||
|
||||
returned = sequoia.inspect(packet=packet, certifications=certifications, fingerprints=fingerprints)
|
||||
|
||||
if fingerprints and certifications:
|
||||
for fingerprint, username in fingerprints.items():
|
||||
assert f"{fingerprint[24:]} {username}" in returned
|
||||
assert result_header in returned
|
||||
|
||||
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_packet_dump(system_mock: Mock) -> None:
|
||||
system_mock.return_value = "return"
|
||||
assert sequoia.packet_dump(packet=Path("packet")) == "return"
|
||||
system_mock.called_once_with(["sq", "packet", "dump", "packet"])
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"packet_dump_return, query, result, expectation",
|
||||
[
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
Version: 4
|
||||
Type: SubkeyBinding
|
||||
Hash algo: SHA512
|
||||
""",
|
||||
"Type",
|
||||
"SubkeyBinding",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
Version: 4
|
||||
Type: SubkeyBinding
|
||||
Hash algo: SHA512
|
||||
Hashed area:
|
||||
Signature creation time: 2022-12-31 15:53:59 UTC
|
||||
Issuer: BBBBBB
|
||||
Unhashed area:
|
||||
Issuer: 42424242
|
||||
""",
|
||||
"Unhashed area.Issuer",
|
||||
"42424242",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
Version: 4
|
||||
Type: SubkeyBinding
|
||||
Hash algo: SHA512
|
||||
Hashed area:
|
||||
Signature creation time: 2022-12-31 15:53:59 UTC
|
||||
Unhashed area:
|
||||
Issuer: 42424242
|
||||
""",
|
||||
"Hashed area|Unhashed area.Issuer",
|
||||
"42424242",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
Version: 4
|
||||
Type: SubkeyBinding
|
||||
Hash algo: SHA1
|
||||
Hashed area:
|
||||
Signature creation time: 2022-12-31
|
||||
""",
|
||||
"*.Signature creation time",
|
||||
"2022-12-31",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
a:
|
||||
b:
|
||||
x: foo
|
||||
b:
|
||||
b:
|
||||
c: bar
|
||||
""",
|
||||
"*.b.c",
|
||||
"bar",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
a:
|
||||
b:
|
||||
x:
|
||||
y:
|
||||
z: foo
|
||||
b:
|
||||
b:
|
||||
x:
|
||||
y:
|
||||
z: foo
|
||||
w:
|
||||
w: foo
|
||||
k:
|
||||
i:
|
||||
c: bar
|
||||
""",
|
||||
"*.b.*.*.c",
|
||||
"bar",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
a:
|
||||
c:
|
||||
b: foo
|
||||
a:
|
||||
b: bar
|
||||
""",
|
||||
"a.b",
|
||||
"bar",
|
||||
does_not_raise(),
|
||||
),
|
||||
(
|
||||
"""
|
||||
Signature Packet
|
||||
Version: 4
|
||||
Type: SubkeyBinding
|
||||
Hash algo: SHA512
|
||||
Hashed area:
|
||||
Signature creation time: 2022-12-31 15:53:59 UTC
|
||||
Unhashed area:
|
||||
Issuer: 42424242
|
||||
Issuer: BBBBBBBB
|
||||
""",
|
||||
"Hashed area.Issuer",
|
||||
None,
|
||||
raises(Exception),
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.sequoia.packet_dump")
|
||||
def test_packet_dump_field(
|
||||
packet_dump_mock: Mock,
|
||||
packet_dump_return: str,
|
||||
query: str,
|
||||
result: str,
|
||||
expectation: ContextManager[str],
|
||||
) -> None:
|
||||
packet_dump_mock.return_value = packet_dump_return
|
||||
|
||||
with expectation:
|
||||
assert sequoia.packet_dump_field(packet=Path("packet"), query=query) == result
|
||||
|
||||
|
||||
@patch("libkeyringctl.sequoia.packet_dump_field")
|
||||
def test_packet_signature_creation_time(packet_dump_field_mock: Mock) -> None:
|
||||
creation_time = "2021-10-31 00:48:09 UTC"
|
||||
packet_dump_field_mock.return_value = creation_time
|
||||
assert sequoia.packet_signature_creation_time(packet=Path("packet")) == datetime.strptime(
|
||||
creation_time, "%Y-%m-%d %H:%M:%S %Z"
|
||||
)
|
||||
|
||||
|
||||
@patch("libkeyringctl.sequoia.packet_dump")
|
||||
def test_packet_kinds(packet_dump_mock: Mock) -> None:
|
||||
lines = [
|
||||
"Type1 something",
|
||||
" foo",
|
||||
"Type2",
|
||||
"WARNING",
|
||||
"Type3 other",
|
||||
" bar",
|
||||
]
|
||||
path = Path("foo")
|
||||
packet_dump_mock.return_value = "\n".join(lines)
|
||||
|
||||
assert sequoia.packet_kinds(packet=path) == [PacketKind("Type1"), PacketKind("Type2"), PacketKind("Type3")]
|
||||
|
||||
|
||||
@patch("libkeyringctl.sequoia.packet_signature_creation_time")
|
||||
def test_latest_certification(packet_signature_creation_time_mock: Mock) -> None:
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
later = now + timedelta(days=1)
|
||||
early_cert = Path("cert1")
|
||||
later_cert = Path("cert2")
|
||||
|
||||
packet_signature_creation_time_mock.side_effect = [now, later]
|
||||
assert sequoia.latest_certification(certifications=[early_cert, later_cert]) == later_cert
|
||||
|
||||
packet_signature_creation_time_mock.side_effect = [later, now]
|
||||
assert sequoia.latest_certification(certifications=[later_cert, early_cert]) == later_cert
|
||||
|
||||
|
||||
@mark.parametrize("output", [(None), (Path("output"))])
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_key_extract_certificate(system_mock: Mock, output: Optional[Path]) -> None:
|
||||
system_mock.return_value = "return"
|
||||
assert sequoia.key_extract_certificate(key=Path("key"), output=output) == "return"
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
if output:
|
||||
assert str(output) == args[0][-1]
|
||||
|
||||
|
||||
@mark.parametrize("output", [(None), (Path("output"))])
|
||||
@patch("libkeyringctl.sequoia.system")
|
||||
def test_certify(system_mock: Mock, output: Optional[Path]) -> None:
|
||||
system_mock.return_value = "return"
|
||||
assert sequoia.certify(key=Path("key"), certificate=Path("cert"), uid=Uid("uid"), output=output) == "return"
|
||||
name, args, kwargs = system_mock.mock_calls[0]
|
||||
if output:
|
||||
assert str(output) == args[0][-1]
|
381
tests/test_trust.py
Normal file
381
tests/test_trust.py
Normal file
@ -0,0 +1,381 @@
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytest import mark
|
||||
from pytest import raises
|
||||
|
||||
from libkeyringctl.trust import certificate_trust
|
||||
from libkeyringctl.trust import certificate_trust_from_paths
|
||||
from libkeyringctl.trust import filter_by_trust
|
||||
from libkeyringctl.trust import format_trust_label
|
||||
from libkeyringctl.trust import trust_color
|
||||
from libkeyringctl.trust import trust_icon
|
||||
from libkeyringctl.types import Color
|
||||
from libkeyringctl.types import Fingerprint
|
||||
from libkeyringctl.types import Trust
|
||||
from libkeyringctl.types import TrustFilter
|
||||
from libkeyringctl.types import Uid
|
||||
from libkeyringctl.types import Username
|
||||
|
||||
from .conftest import create_certificate
|
||||
from .conftest import create_key_revocation
|
||||
from .conftest import create_signature_revocation
|
||||
from .conftest import create_uid_certification
|
||||
from .conftest import test_all_fingerprints
|
||||
from .conftest import test_keyring_certificates
|
||||
from .conftest import test_main_fingerprints
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"sources",
|
||||
[
|
||||
([Path("foobar")]),
|
||||
([Path("foobar"), Path("quxdoo")]),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.trust.certificate_trust")
|
||||
def test_certificate_trust_from_paths(
|
||||
certificate_trust_mock: Mock,
|
||||
sources: List[Path],
|
||||
working_dir: Path,
|
||||
) -> None:
|
||||
certificate_trust_mock.return_value = Trust.full
|
||||
for source in sources:
|
||||
source.mkdir(parents=True, exist_ok=True)
|
||||
cert = source / "foo.asc"
|
||||
cert.touch()
|
||||
|
||||
trusts = certificate_trust_from_paths(
|
||||
sources=sources, main_keys=test_main_fingerprints, all_fingerprints=test_all_fingerprints
|
||||
)
|
||||
for i, source in enumerate(sources):
|
||||
name, args, kwargs = certificate_trust_mock.mock_calls[i]
|
||||
assert kwargs["certificate"] == source
|
||||
assert kwargs["main_keys"] == test_main_fingerprints
|
||||
assert kwargs["all_fingerprints"] == test_all_fingerprints
|
||||
fingerprint = Fingerprint(source.name)
|
||||
assert Trust.full == trusts[fingerprint]
|
||||
assert len(trusts) == len(sources)
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")], keyring_type="main")
|
||||
def test_certificate_trust_main_key_has_full_trust(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.full == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_key_revocation(username=Username("foobar"), keyring_type="main")
|
||||
def test_certificate_trust_main_key_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.revoked == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_key_revocation(username=Username("foobar"), keyring_type="main")
|
||||
def test_certificate_trust_main_key_revoked_unknown_fingerprint_lookup(working_dir: Path, keyring_dir: Path) -> None:
|
||||
fingerprint = Fingerprint(test_keyring_certificates[Username("foobar")][0].name)
|
||||
revocation = list((keyring_dir / "main" / "foobar" / fingerprint / "revocation").iterdir())[0]
|
||||
revocation.rename(revocation.parent / "12341234.asc")
|
||||
with raises(Exception):
|
||||
certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
{Fingerprint("12341234")},
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_key_revocation(username=Username("foobar"), keyring_type="main")
|
||||
def test_certificate_trust_main_key_revoked_unknown_self_revocation(working_dir: Path, keyring_dir: Path) -> None:
|
||||
fingerprint = Fingerprint(test_keyring_certificates[Username("foobar")][0].name)
|
||||
revocation = list((keyring_dir / "main" / "foobar" / fingerprint / "revocation").iterdir())[0]
|
||||
revocation.rename(revocation.parent / "12341234.asc")
|
||||
with raises(Exception):
|
||||
certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
set(),
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")])
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
def test_certificate_trust_no_signature_is_unknown(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.unknown == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_one_signature_is_marginal(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.marginal == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("not_main"), uids=[Uid("main <foo@bar.xyz>")])
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("not_main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_one_none_main_signature_gives_no_trust(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.unknown == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main2"), uids=[Uid("main2 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main3"), uids=[Uid("main3 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main2"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main3"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_three_main_signature_gives_full_trust(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.full == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main2"), uids=[Uid("main2 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main3"), uids=[Uid("main3 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main2"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main3"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_key_revocation(username=Username("main3"), keyring_type="main")
|
||||
def test_certificate_trust_three_main_signature_one_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.marginal == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_key_revocation(username=Username("foobar"))
|
||||
def test_certificate_trust_revoked_key(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.revoked == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main"), uids=[Uid("main <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("main"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_one_signature_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.revoked == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main2"), uids=[Uid("main2 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main3"), uids=[Uid("main3 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main2"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main3"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("main3"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_revoked_if_below_full(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.revoked == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main2"), uids=[Uid("main2 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main3"), uids=[Uid("main3 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main4"), uids=[Uid("main4 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main2"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main3"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main4"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("main4"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_full_remains_if_enough_sigs_present(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.full == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main2"), uids=[Uid("main2 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("main3"), uids=[Uid("main3 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>"), Uid("old <old@old.old>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("main2"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("foobar"), certified=Username("foobar"), uid=Uid("old <old@old.old>"))
|
||||
def test_certificate_trust_not_revoked_if_only_one_uid_is_self_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.marginal == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>"), Uid("old <old@old.old>")])
|
||||
@create_signature_revocation(issuer=Username("foobar"), certified=Username("foobar"), uid=Uid("old <old@old.old>"))
|
||||
def test_certificate_trust_unknown_if_only_contains_self_revoked(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.unknown == trust
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>"), Uid("old <old@old.old>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_missing_signature_fingerprint_lookup(working_dir: Path, keyring_dir: Path) -> None:
|
||||
with raises(Exception):
|
||||
certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
set(),
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("old <old@old.old>")])
|
||||
@create_signature_revocation(issuer=Username("foobar"), certified=Username("foobar"), uid=Uid("old <old@old.old>"))
|
||||
def test_certificate_trust_missing_revocation_fingerprint_lookup(working_dir: Path, keyring_dir: Path) -> None:
|
||||
with raises(Exception):
|
||||
certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
set(),
|
||||
)
|
||||
|
||||
|
||||
@create_certificate(username=Username("main1"), uids=[Uid("main1 <foo@bar.xyz>")], keyring_type="main")
|
||||
@create_certificate(username=Username("foobar"), uids=[Uid("foobar <foo@bar.xyz>")])
|
||||
@create_certificate(username=Username("packager"), uids=[Uid("packager <packager@bar.xyz>")])
|
||||
@create_uid_certification(issuer=Username("main1"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_uid_certification(issuer=Username("packager"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
@create_signature_revocation(issuer=Username("packager"), certified=Username("foobar"), uid=Uid("foobar <foo@bar.xyz>"))
|
||||
def test_certificate_trust_ignore_3rd_party_revocation(working_dir: Path, keyring_dir: Path) -> None:
|
||||
trust = certificate_trust(
|
||||
test_keyring_certificates[Username("foobar")][0],
|
||||
test_main_fingerprints,
|
||||
test_all_fingerprints,
|
||||
)
|
||||
assert Trust.marginal == trust
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"trust, result",
|
||||
[
|
||||
(Trust.revoked, Color.RED),
|
||||
(Trust.full, Color.GREEN),
|
||||
(Trust.marginal, Color.YELLOW),
|
||||
(Trust.unknown, Color.YELLOW),
|
||||
],
|
||||
)
|
||||
def test_trust_color(trust: Trust, result: Color) -> None:
|
||||
assert trust_color(trust) == result
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"trust, result",
|
||||
[
|
||||
(Trust.revoked, "✗"),
|
||||
(Trust.full, "✓"),
|
||||
(Trust.marginal, "~"),
|
||||
(Trust.unknown, "~"),
|
||||
(None, "?"),
|
||||
],
|
||||
)
|
||||
def test_trust_icon(trust: Trust, result: str) -> None:
|
||||
assert trust_icon(trust) == result
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"trust",
|
||||
[
|
||||
Trust.revoked,
|
||||
Trust.full,
|
||||
Trust.marginal,
|
||||
Trust.unknown,
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.trust.trust_icon")
|
||||
@patch("libkeyringctl.trust.trust_color")
|
||||
def test_format_trust_label(trust_color_mock: Mock, trust_icon_mock: Mock, trust: Trust) -> None:
|
||||
trust_icon_mock.return_value = "ICON"
|
||||
trust_color_mock.return_value = Color.GREEN
|
||||
assert f"{Color.GREEN.value}ICON {trust.name}{Color.RST.value}" == format_trust_label(trust)
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"trust, trust_filter, result",
|
||||
[
|
||||
(Trust.revoked, TrustFilter.unknown, False),
|
||||
(Trust.full, TrustFilter.unknown, False),
|
||||
(Trust.marginal, TrustFilter.unknown, False),
|
||||
(Trust.unknown, TrustFilter.unknown, True),
|
||||
(Trust.revoked, TrustFilter.marginal, False),
|
||||
(Trust.full, TrustFilter.marginal, False),
|
||||
(Trust.marginal, TrustFilter.marginal, True),
|
||||
(Trust.unknown, TrustFilter.marginal, False),
|
||||
(Trust.revoked, TrustFilter.full, False),
|
||||
(Trust.full, TrustFilter.full, True),
|
||||
(Trust.marginal, TrustFilter.full, False),
|
||||
(Trust.unknown, TrustFilter.full, False),
|
||||
(Trust.revoked, TrustFilter.revoked, True),
|
||||
(Trust.full, TrustFilter.revoked, False),
|
||||
(Trust.marginal, TrustFilter.revoked, False),
|
||||
(Trust.unknown, TrustFilter.revoked, False),
|
||||
(Trust.revoked, TrustFilter.unrevoked, False),
|
||||
(Trust.full, TrustFilter.unrevoked, True),
|
||||
(Trust.marginal, TrustFilter.unrevoked, True),
|
||||
(Trust.unknown, TrustFilter.unrevoked, True),
|
||||
(Trust.revoked, TrustFilter.all, True),
|
||||
(Trust.full, TrustFilter.all, True),
|
||||
(Trust.marginal, TrustFilter.all, True),
|
||||
(Trust.unknown, TrustFilter.all, True),
|
||||
],
|
||||
)
|
||||
def test_filter_by_trust(trust: Trust, trust_filter: TrustFilter, result: bool) -> None:
|
||||
assert filter_by_trust(trust=trust, trust_filter=trust_filter) == result
|
198
tests/test_util.py
Normal file
198
tests/test_util.py
Normal file
@ -0,0 +1,198 @@
|
||||
from os import chdir
|
||||
from os import getcwd
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
from unittest.mock import Mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from pytest import mark
|
||||
from pytest import raises
|
||||
|
||||
from libkeyringctl import util
|
||||
from libkeyringctl.types import Fingerprint
|
||||
from libkeyringctl.types import Trust
|
||||
|
||||
|
||||
def test_cwd() -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
test_dir = tmp_dir / "test"
|
||||
test_dir.mkdir()
|
||||
chdir(tmp_dir)
|
||||
with util.cwd(new_dir=test_dir):
|
||||
assert getcwd() == str(test_dir)
|
||||
assert getcwd() == str(tmp_dir)
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"input_list, output_list",
|
||||
[
|
||||
([Path("/foo"), Path("/bar/foo"), Path("/foo/20")], [Path("/foo/20"), Path("/foo"), Path("/bar/foo")]),
|
||||
],
|
||||
)
|
||||
def test_natural_sort_path(input_list: List[Path], output_list: List[Path]) -> None:
|
||||
assert util.natural_sort_path(_list=input_list) == output_list
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"raise_on_cmd, exit_on_error",
|
||||
[
|
||||
(False, True),
|
||||
(False, False),
|
||||
(True, True),
|
||||
(True, False),
|
||||
],
|
||||
)
|
||||
@patch("libkeyringctl.util.exit")
|
||||
@patch("libkeyringctl.util.check_output")
|
||||
def test_system(check_output_mock: Mock, exit_mock: Mock, raise_on_cmd: bool, exit_on_error: bool) -> None:
|
||||
if raise_on_cmd:
|
||||
check_output_mock.side_effect = util.CalledProcessError(returncode=1, cmd="foo", output=b"output")
|
||||
|
||||
with raises(util.CalledProcessError):
|
||||
util.system(["foo"], exit_on_error=exit_on_error)
|
||||
if exit_on_error:
|
||||
exit_mock.assert_called_once_with(1)
|
||||
|
||||
else:
|
||||
check_output_mock.return_value = b"output"
|
||||
assert util.system(["foo"], exit_on_error=exit_on_error) == "output"
|
||||
|
||||
|
||||
def test_absolute_path() -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
test_dir = tmp_dir / "test"
|
||||
test_dir.mkdir()
|
||||
chdir(tmp_dir)
|
||||
assert util.absolute_path(path="test") == test_dir
|
||||
|
||||
|
||||
def test_transform_fd_to_tmpfile() -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
with NamedTemporaryFile(dir=tmp_dir) as tmp_file:
|
||||
tmp_file_fd = tmp_file.fileno()
|
||||
util.transform_fd_to_tmpfile(
|
||||
working_dir=tmp_dir,
|
||||
sources=[Path("/foo"), Path(f"/proc/self/fd/{tmp_file_fd}")],
|
||||
)
|
||||
|
||||
|
||||
def test_get_cert_paths() -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
|
||||
cert_dir1 = tmp_dir / "cert1"
|
||||
cert_dir1.mkdir()
|
||||
cert1 = cert_dir1 / "cert1.asc"
|
||||
cert1.touch()
|
||||
cert_dir2 = tmp_dir / "cert2"
|
||||
cert_dir2.mkdir()
|
||||
cert2 = cert_dir2 / "cert2.asc"
|
||||
cert2.touch()
|
||||
|
||||
assert util.get_cert_paths(paths=[tmp_dir]) == {cert_dir1, cert_dir2}
|
||||
|
||||
|
||||
def test_get_parent_cert_paths() -> None:
|
||||
with TemporaryDirectory() as tmp_dir_name:
|
||||
tmp_dir = Path(tmp_dir_name)
|
||||
|
||||
keyring_dir = tmp_dir / "keyring"
|
||||
group_dir = keyring_dir / "parent"
|
||||
user_dir = group_dir / "parent"
|
||||
cert_dir1 = user_dir / "cert1"
|
||||
cert_dir1.mkdir(parents=True)
|
||||
cert1 = cert_dir1 / "cert1.asc"
|
||||
cert1.touch()
|
||||
cert_dir2 = cert_dir1 / "cert2"
|
||||
cert_dir2.mkdir(parents=True)
|
||||
cert2 = cert_dir2 / "cert2.asc"
|
||||
cert2.touch()
|
||||
|
||||
assert util.get_parent_cert_paths(paths=[cert1, cert2]) == {cert_dir1}
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"fingerprints, fingerprint, result",
|
||||
[
|
||||
(
|
||||
[Fingerprint("foo"), Fingerprint("bar")],
|
||||
Fingerprint("foo"),
|
||||
True,
|
||||
),
|
||||
(
|
||||
[Fingerprint("foo"), Fingerprint("bar")],
|
||||
Fingerprint("baz"),
|
||||
False,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_contains_fingerprint(fingerprints: List[Fingerprint], fingerprint: Fingerprint, result: bool) -> None:
|
||||
assert util.contains_fingerprint(fingerprints=fingerprints, fingerprint=fingerprint) is result
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"fingerprints, fingerprint, result",
|
||||
[
|
||||
([Fingerprint("blahfoo"), Fingerprint("blahbar")], Fingerprint("foo"), Fingerprint("blahfoo")),
|
||||
([Fingerprint("blahfoo"), Fingerprint("blahbar")], Fingerprint("blahfoo"), Fingerprint("blahfoo")),
|
||||
(
|
||||
[Fingerprint("bazfoo"), Fingerprint("bazbar")],
|
||||
Fingerprint("baz"),
|
||||
None,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_fingerprint_from_partial(fingerprints: List[Fingerprint], fingerprint: Fingerprint, result: bool) -> None:
|
||||
assert util.get_fingerprint_from_partial(fingerprints=fingerprints, fingerprint=fingerprint) is result
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"trusts, trust, result",
|
||||
[
|
||||
(
|
||||
{Fingerprint("foo"): Trust.full, Fingerprint("bar"): Trust.marginal},
|
||||
Trust.full,
|
||||
[Fingerprint("foo")],
|
||||
),
|
||||
(
|
||||
{Fingerprint("foo"): Trust.full, Fingerprint("bar"): Trust.full},
|
||||
Trust.full,
|
||||
[Fingerprint("foo"), Fingerprint("bar")],
|
||||
),
|
||||
(
|
||||
{Fingerprint("foo"): Trust.full, Fingerprint("bar"): Trust.marginal},
|
||||
Trust.unknown,
|
||||
[],
|
||||
),
|
||||
(
|
||||
{},
|
||||
Trust.unknown,
|
||||
[],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_filter_fingerprints_by_trust(
|
||||
trusts: Dict[Fingerprint, Trust], trust: Trust, result: List[Fingerprint]
|
||||
) -> None:
|
||||
assert util.filter_fingerprints_by_trust(trusts=trusts, trust=trust) == result
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
"_str, result",
|
||||
[
|
||||
("foobar", "foobar"),
|
||||
("", ""),
|
||||
("bbàáâãğț aa", "bbaaaagt_aa"),
|
||||
("<>", ""),
|
||||
("!#$%^&*()_☃", "___________"),
|
||||
("_-.+@", "_-.+@"),
|
||||
],
|
||||
)
|
||||
def test_simplify_ascii(_str: str, result: str) -> None:
|
||||
assert util.simplify_ascii(_str=_str) == result
|
Reference in New Issue
Block a user