condorcore-keyring/tests/test_trust.py
Levente Polyak f908838822
fix(trust): do not count revoked main keys for packager trust
If a main key is revoked we do not want to use those keys to count
the required trust threshold.
2022-02-25 21:36:35 +01:00

382 lines
18 KiB
Python

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