diff --git a/tests/repository_simulator.py b/tests/repository_simulator.py index 67329bde72..81a3e60adb 100644 --- a/tests/repository_simulator.py +++ b/tests/repository_simulator.py @@ -100,8 +100,8 @@ def _initialize(self): snapshot = Snapshot(1, SPEC_VER, expiry, meta) self.md_snapshot = Metadata(snapshot, OrderedDict()) - meta = {"snapshot.json": MetaFile(snapshot.version)} - timestamp = Timestamp(1, SPEC_VER, expiry, meta) + snapshot_meta = MetaFile(snapshot.version) + timestamp = Timestamp(1, SPEC_VER, expiry, snapshot_meta) self.md_timestamp = Metadata(timestamp, OrderedDict()) root = Root(1, SPEC_VER, expiry, {}, {}, True) @@ -175,7 +175,7 @@ def _fetch_metadata(self, role: str, version: Optional[int] = None) -> bytes: return md.to_bytes(JSONSerializer()) def update_timestamp(self): - self.timestamp.meta["snapshot.json"].version = self.snapshot.version + self.timestamp.snapshot.version = self.snapshot.version self.timestamp.version += 1 diff --git a/tests/test_api.py b/tests/test_api.py index 76b8ba45fe..758dedc811 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -350,11 +350,11 @@ def test_metadata_timestamp(self): fileinfo = MetaFile(2, 520, hashes) self.assertNotEqual( - timestamp.signed.meta['snapshot.json'].to_dict(), fileinfo.to_dict() + timestamp.signed.snapshot.to_dict(), fileinfo.to_dict() ) timestamp.signed.update(fileinfo) self.assertEqual( - timestamp.signed.meta['snapshot.json'].to_dict(), fileinfo.to_dict() + timestamp.signed.snapshot.to_dict(), fileinfo.to_dict() ) @@ -563,7 +563,7 @@ def test_length_and_hash_validation(self): timestamp_path = os.path.join( self.repo_dir, 'metadata', 'timestamp.json') timestamp = Metadata[Timestamp].from_file(timestamp_path) - snapshot_metafile = timestamp.signed.meta["snapshot.json"] + snapshot_metafile = timestamp.signed.snapshot snapshot_path = os.path.join( self.repo_dir, 'metadata', 'snapshot.json') diff --git a/tests/test_trusted_metadata_set.py b/tests/test_trusted_metadata_set.py index b097e350a1..f0fbf85304 100644 --- a/tests/test_trusted_metadata_set.py +++ b/tests/test_trusted_metadata_set.py @@ -70,8 +70,8 @@ def setUpClass(cls): cls.keystore[role] = SSlibSigner(key_dict) def hashes_length_modifier(timestamp: Timestamp) -> None: - timestamp.meta["snapshot.json"].hashes = None - timestamp.meta["snapshot.json"].length = None + timestamp.snapshot.hashes = None + timestamp.snapshot.length = None cls.metadata["timestamp"] = cls.modify_metadata( cls, "timestamp", hashes_length_modifier @@ -245,13 +245,13 @@ def version_modifier(timestamp: Timestamp) -> None: def test_update_timestamp_snapshot_ver_below_current(self): def bump_snapshot_version(timestamp: Timestamp) -> None: - timestamp.meta["snapshot.json"].version = 2 + timestamp.snapshot.version = 2 # set current known snapshot.json version to 2 timestamp = self.modify_metadata("timestamp", bump_snapshot_version) self.trusted_set.update_timestamp(timestamp) - # newtimestamp.meta["snapshot.json"].version < trusted_timestamp.meta["snapshot.json"].version + # newtimestamp.meta.version < trusted_timestamp.meta.version with self.assertRaises(exceptions.ReplayedMetadataError): self.trusted_set.update_timestamp(self.metadata["timestamp"]) @@ -271,7 +271,7 @@ def timestamp_expired_modifier(timestamp: Timestamp) -> None: def test_update_snapshot_length_or_hash_mismatch(self): def modify_snapshot_length(timestamp: Timestamp) -> None: - timestamp.meta["snapshot.json"].length = 1 + timestamp.snapshot.length = 1 # set known snapshot.json length to 1 timestamp = self.modify_metadata("timestamp", modify_snapshot_length) @@ -289,7 +289,7 @@ def test_update_snapshot_cannot_verify_snapshot_with_threshold(self): def test_update_snapshot_version_different_timestamp_snapshot_version(self): def timestamp_version_modifier(timestamp: Timestamp) -> None: - timestamp.meta["snapshot.json"].version = 2 + timestamp.snapshot.version = 2 timestamp = self.modify_metadata("timestamp", timestamp_version_modifier) self.trusted_set.update_timestamp(timestamp) @@ -341,7 +341,7 @@ def snapshot_expired_modifier(snapshot: Snapshot) -> None: def test_update_snapshot_successful_rollback_checks(self): def meta_version_bump(timestamp: Timestamp) -> None: - timestamp.meta["snapshot.json"].version += 1 + timestamp.snapshot.version += 1 def version_bump(snapshot: Snapshot) -> None: snapshot.version += 1 diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index cca8247147..ff3704d87a 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -904,11 +904,11 @@ def verify_length_and_hashes(self, data: Union[bytes, IO[bytes]]) -> None: class Timestamp(Signed): """A container for the signed part of timestamp metadata. - Timestamp contains information about the snapshot Metadata file. + TUF file format uses a dictionary to contain the snapshot information: + this is not the case with Timestamp.snapshot which is a MetaFile. Attributes: - meta: A dictionary of filenames to MetaFiles. The only valid key value - is the snapshot filename, as defined by the specification. + snapshot: MetaFile instance with the snapshot meta information. """ _signed_type = "timestamp" @@ -918,33 +918,31 @@ def __init__( version: int, spec_version: str, expires: datetime, - meta: Dict[str, MetaFile], + snapshot: MetaFile, unrecognized_fields: Optional[Mapping[str, Any]] = None, ) -> None: super().__init__(version, spec_version, expires, unrecognized_fields) - self.meta = meta + self.snapshot = snapshot @classmethod def from_dict(cls, signed_dict: Dict[str, Any]) -> "Timestamp": """Creates Timestamp object from its dict representation.""" common_args = cls._common_fields_from_dict(signed_dict) meta_dict = signed_dict.pop("meta") - meta = {"snapshot.json": MetaFile.from_dict(meta_dict["snapshot.json"])} + snapshot_meta = MetaFile.from_dict(meta_dict["snapshot.json"]) # All fields left in the timestamp_dict are unrecognized. - return cls(*common_args, meta, signed_dict) + return cls(*common_args, snapshot_meta, signed_dict) def to_dict(self) -> Dict[str, Any]: """Returns the dict representation of self.""" res_dict = self._common_fields_to_dict() - res_dict["meta"] = { - "snapshot.json": self.meta["snapshot.json"].to_dict() - } + res_dict["meta"] = {"snapshot.json": self.snapshot.to_dict()} return res_dict # Modification. def update(self, snapshot_meta: MetaFile) -> None: - """Assigns passed info about snapshot metadata to meta dict.""" - self.meta["snapshot.json"] = snapshot_meta + """Assigns passed info about snapshot metadata.""" + self.snapshot = snapshot_meta class Snapshot(Signed): diff --git a/tuf/ngclient/_internal/trusted_metadata_set.py b/tuf/ngclient/_internal/trusted_metadata_set.py index cef3d6fa1e..bef7254285 100644 --- a/tuf/ngclient/_internal/trusted_metadata_set.py +++ b/tuf/ngclient/_internal/trusted_metadata_set.py @@ -233,13 +233,13 @@ def update_timestamp(self, data: bytes) -> None: ) # Prevent rolling back snapshot version if ( - new_timestamp.signed.meta["snapshot.json"].version - < self.timestamp.signed.meta["snapshot.json"].version + new_timestamp.signed.snapshot.version + < self.timestamp.signed.snapshot.version ): raise exceptions.ReplayedMetadataError( "snapshot", - new_timestamp.signed.meta["snapshot.json"].version, - self.timestamp.signed.meta["snapshot.json"].version, + new_timestamp.signed.snapshot.version, + self.timestamp.signed.snapshot.version, ) # expiry not checked to allow old timestamp to be used for rollback @@ -286,11 +286,11 @@ def update_snapshot(self, data: bytes) -> None: # Snapshot cannot be loaded if final timestamp is expired self._check_final_timestamp() - meta = self.timestamp.signed.meta["snapshot.json"] + snapshot_meta = self.timestamp.signed.snapshot # Verify against the hashes in timestamp, if any try: - meta.verify_length_and_hashes(data) + snapshot_meta.verify_length_and_hashes(data) except exceptions.LengthOrHashMismatchError as e: raise exceptions.RepositoryError( "Snapshot length or hashes do not match" @@ -345,14 +345,10 @@ def _check_final_snapshot(self) -> None: assert self.timestamp is not None # nosec if self.snapshot.signed.is_expired(self.reference_time): raise exceptions.ExpiredMetadataError("snapshot.json is expired") - - if ( - self.snapshot.signed.version - != self.timestamp.signed.meta["snapshot.json"].version - ): + snapshot_meta = self.timestamp.signed.snapshot + if self.snapshot.signed.version != snapshot_meta.version: raise exceptions.BadVersionNumberError( - f"Expected snapshot version " - f"{self.timestamp.signed.meta['snapshot.json'].version}, " + f"Expected snapshot version {snapshot_meta.version}, " f"got {self.snapshot.signed.version}" ) diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 68db18874a..4ea7fdb838 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -352,11 +352,11 @@ def _load_snapshot(self) -> None: logger.debug("Local snapshot not valid as final: %s", e) assert self._trusted_set.timestamp is not None # nosec - metainfo = self._trusted_set.timestamp.signed.meta["snapshot.json"] - length = metainfo.length or self.config.snapshot_max_length + snapshot_meta = self._trusted_set.timestamp.signed.snapshot + length = snapshot_meta.length or self.config.snapshot_max_length version = None if self._trusted_set.root.signed.consistent_snapshot: - version = metainfo.version + version = snapshot_meta.version data = self._download_metadata("snapshot", length, version) self._trusted_set.update_snapshot(data)