mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
tests: add basic tests for dsse support
* Add API tests for SimpleEnvelope This is not as comprehensive as Metadata API. The latter also includes tests for all payload classes, which should cover the same scenarios as if used with SimpleEnvelope. * Add unit test for newly added simple envelope load helper function in trusted metadata set. Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
This commit is contained in:
parent
8eb6f08a5c
commit
0f64cf4c91
2 changed files with 142 additions and 1 deletions
|
|
@ -15,6 +15,7 @@
|
|||
import unittest
|
||||
from copy import copy, deepcopy
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from typing import Any, ClassVar, Dict, Optional
|
||||
|
||||
from securesystemslib import exceptions as sslib_exceptions
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
|
||||
from tests import utils
|
||||
from tuf.api import exceptions
|
||||
from tuf.api.dsse import SimpleEnvelope
|
||||
from tuf.api.metadata import (
|
||||
TOP_LEVEL_ROLE_NAMES,
|
||||
DelegatedRole,
|
||||
|
|
@ -1144,6 +1146,95 @@ def test_delegations_get_delegated_role(self) -> None:
|
|||
)
|
||||
|
||||
|
||||
class TestSimpleEnvelope(unittest.TestCase):
|
||||
"""Tests for public API in 'tuf/api/dsse.py'."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
repo_data_dir = Path(utils.TESTS_DIR) / "repository_data"
|
||||
cls.metadata_dir = repo_data_dir / "repository" / "metadata"
|
||||
cls.signer_store = {}
|
||||
for role in [Snapshot, Targets, Timestamp]:
|
||||
key_path = repo_data_dir / "keystore" / f"{role.type}_key"
|
||||
key = import_ed25519_privatekey_from_file(
|
||||
str(key_path),
|
||||
password="password",
|
||||
)
|
||||
cls.signer_store[role.type] = SSlibSigner(key)
|
||||
|
||||
def test_serialization(self) -> None:
|
||||
"""Basic de/serialization test.
|
||||
|
||||
1. Load test metadata for each role
|
||||
2. Wrap metadata payloads in envelope serializing the payload
|
||||
3. Serialize envelope
|
||||
4. De-serialize envelope
|
||||
5. De-serialize payload
|
||||
|
||||
"""
|
||||
for role in [Root, Timestamp, Snapshot, Targets]:
|
||||
metadata_path = self.metadata_dir / f"{role.type}.json"
|
||||
metadata = Metadata.from_file(str(metadata_path))
|
||||
self.assertIsInstance(metadata.signed, role)
|
||||
|
||||
envelope = SimpleEnvelope.from_signed(metadata.signed)
|
||||
envelope_bytes = envelope.to_bytes()
|
||||
|
||||
envelope2 = SimpleEnvelope.from_bytes(envelope_bytes)
|
||||
payload = envelope2.get_signed()
|
||||
self.assertEqual(metadata.signed, payload)
|
||||
|
||||
def test_fail_envelope_serialization(self) -> None:
|
||||
envelope = SimpleEnvelope(b"foo", "bar", ["baz"])
|
||||
with self.assertRaises(SerializationError):
|
||||
envelope.to_bytes()
|
||||
|
||||
def test_fail_envelope_deserialization(self) -> None:
|
||||
with self.assertRaises(DeserializationError):
|
||||
SimpleEnvelope.from_bytes(b"[")
|
||||
|
||||
def test_fail_payload_serialization(self) -> None:
|
||||
with self.assertRaises(SerializationError):
|
||||
SimpleEnvelope.from_signed("foo") # type: ignore
|
||||
|
||||
def test_fail_payload_deserialization(self) -> None:
|
||||
payloads = [b"[", b'{"_type": "foo"}']
|
||||
for payload in payloads:
|
||||
envelope = SimpleEnvelope(payload, "bar", [])
|
||||
with self.assertRaises(DeserializationError):
|
||||
envelope.get_signed()
|
||||
|
||||
def test_verify_delegate(self) -> None:
|
||||
"""Basic verification test.
|
||||
|
||||
1. Load test metadata for each role
|
||||
2. Wrap non-root payloads in envelope serializing the payload
|
||||
3. Sign with correct delegated key
|
||||
4. Verify delegate with root
|
||||
|
||||
"""
|
||||
root_path = self.metadata_dir / "root.json"
|
||||
root = Metadata[Root].from_file(str(root_path)).signed
|
||||
|
||||
for role in [Timestamp, Snapshot, Targets]:
|
||||
metadata_path = self.metadata_dir / f"{role.type}.json"
|
||||
metadata = Metadata.from_file(str(metadata_path))
|
||||
self.assertIsInstance(metadata.signed, role)
|
||||
|
||||
signer = self.signer_store[role.type]
|
||||
self.assertIn(
|
||||
signer.key_dict["keyid"], root.roles[role.type].keyids
|
||||
)
|
||||
|
||||
envelope = SimpleEnvelope.from_signed(metadata.signed)
|
||||
envelope.sign(signer)
|
||||
self.assertTrue(len(envelope.signatures) == 1)
|
||||
|
||||
root.verify_delegate(
|
||||
role.type, envelope.pae(), envelope.signatures_dict
|
||||
)
|
||||
|
||||
|
||||
# Run unit test.
|
||||
if __name__ == "__main__":
|
||||
utils.configure_test_logging(sys.argv)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
from tests import utils
|
||||
from tuf.api import exceptions
|
||||
from tuf.api.dsse import SimpleEnvelope
|
||||
from tuf.api.metadata import (
|
||||
Metadata,
|
||||
MetaFile,
|
||||
|
|
@ -25,7 +26,10 @@
|
|||
Timestamp,
|
||||
)
|
||||
from tuf.api.serialization.json import JSONSerializer
|
||||
from tuf.ngclient._internal.trusted_metadata_set import TrustedMetadataSet
|
||||
from tuf.ngclient._internal.trusted_metadata_set import (
|
||||
TrustedMetadataSet,
|
||||
_load_from_simple_envelope,
|
||||
)
|
||||
from tuf.ngclient.config import EnvelopeType
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -490,6 +494,52 @@ def target_expired_modifier(target: Targets) -> None:
|
|||
|
||||
# TODO test updating over initial metadata (new keys, newer timestamp, etc)
|
||||
|
||||
def test_load_from_simple_envelope(self) -> None:
|
||||
"""Basic unit test for ``_load_from_simple_envelope`` helper.
|
||||
|
||||
TODO: Test via trusted metadata set tests like for traditional metadata
|
||||
"""
|
||||
metadata = Metadata.from_bytes(self.metadata[Root.type])
|
||||
root = metadata.signed
|
||||
envelope = SimpleEnvelope.from_signed(root)
|
||||
|
||||
# Unwrap unsigned envelope without verification
|
||||
envelope_bytes = envelope.to_bytes()
|
||||
payload_obj, signed_bytes, signatures = _load_from_simple_envelope(
|
||||
Root, envelope_bytes
|
||||
)
|
||||
|
||||
self.assertEqual(payload_obj, root)
|
||||
self.assertEqual(signed_bytes, envelope.pae())
|
||||
self.assertDictEqual(signatures, {})
|
||||
|
||||
# Unwrap correctly signed envelope (use default role name)
|
||||
sig = envelope.sign(self.keystore[Root.type])
|
||||
envelope_bytes = envelope.to_bytes()
|
||||
_, _, signatures = _load_from_simple_envelope(
|
||||
Root, envelope_bytes, root
|
||||
)
|
||||
self.assertDictEqual(signatures, {sig.keyid: sig})
|
||||
|
||||
# Load correctly signed envelope (with explicit role name)
|
||||
_, _, signatures = _load_from_simple_envelope(
|
||||
Root, envelope.to_bytes(), root, Root.type
|
||||
)
|
||||
self.assertDictEqual(signatures, {sig.keyid: sig})
|
||||
|
||||
# Fail load envelope with unexpected 'payload_type'
|
||||
envelope_bad_type = SimpleEnvelope.from_signed(root)
|
||||
envelope_bad_type.payload_type = "foo"
|
||||
envelope_bad_type_bytes = envelope_bad_type.to_bytes()
|
||||
with self.assertRaises(exceptions.RepositoryError):
|
||||
_load_from_simple_envelope(Root, envelope_bad_type_bytes)
|
||||
|
||||
# Fail load envelope with unexpected payload type
|
||||
envelope_bad_signed = SimpleEnvelope.from_signed(root)
|
||||
envelope_bad_signed_bytes = envelope_bad_signed.to_bytes()
|
||||
with self.assertRaises(exceptions.RepositoryError):
|
||||
_load_from_simple_envelope(Targets, envelope_bad_signed_bytes)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
utils.configure_test_logging(sys.argv)
|
||||
|
|
|
|||
Loading…
Reference in a new issue