Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata API: change meta type in Timestamp #1446

Merged
merged 1 commit into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/repository_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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_meta.version = self.snapshot.version

self.timestamp.version += 1

Expand Down
6 changes: 3 additions & 3 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_meta.to_dict(), fileinfo.to_dict()
)
timestamp.signed.update(fileinfo)
self.assertEqual(
timestamp.signed.meta['snapshot.json'].to_dict(), fileinfo.to_dict()
timestamp.signed.snapshot_meta.to_dict(), fileinfo.to_dict()
)


Expand Down Expand Up @@ -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_meta

snapshot_path = os.path.join(
self.repo_dir, 'metadata', 'snapshot.json')
Expand Down
14 changes: 7 additions & 7 deletions tests/test_trusted_metadata_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_meta.hashes = None
timestamp.snapshot_meta.length = None

cls.metadata["timestamp"] = cls.modify_metadata(
cls, "timestamp", hashes_length_modifier
Expand Down Expand Up @@ -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_meta.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"])

Expand All @@ -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_meta.length = 1

# set known snapshot.json length to 1
timestamp = self.modify_metadata("timestamp", modify_snapshot_length)
Expand All @@ -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_meta.version = 2

timestamp = self.modify_metadata("timestamp", timestamp_version_modifier)
self.trusted_set.update_timestamp(timestamp)
Expand Down Expand Up @@ -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_meta.version += 1

def version_bump(snapshot: Snapshot) -> None:
snapshot.version += 1
Expand Down
22 changes: 10 additions & 12 deletions tuf/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,11 +923,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_meta 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_meta: MetaFile instance with the snapshot meta information.
"""

_signed_type = "timestamp"
Expand All @@ -937,33 +937,31 @@ def __init__(
version: int,
spec_version: str,
expires: datetime,
meta: Dict[str, MetaFile],
snapshot_meta: MetaFile,
unrecognized_fields: Optional[Mapping[str, Any]] = None,
) -> None:
super().__init__(version, spec_version, expires, unrecognized_fields)
self.meta = meta
self.snapshot_meta = snapshot_meta

@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_meta.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_meta = snapshot_meta
MVrachev marked this conversation as resolved.
Show resolved Hide resolved


class Snapshot(Signed):
Expand Down
22 changes: 9 additions & 13 deletions tuf/ngclient/_internal/trusted_metadata_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_meta.version
< self.timestamp.signed.snapshot_meta.version
):
raise exceptions.ReplayedMetadataError(
"snapshot",
new_timestamp.signed.meta["snapshot.json"].version,
self.timestamp.signed.meta["snapshot.json"].version,
new_timestamp.signed.snapshot_meta.version,
self.timestamp.signed.snapshot_meta.version,
)

# expiry not checked to allow old timestamp to be used for rollback
Expand Down Expand Up @@ -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_meta

# 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"
Expand Down Expand Up @@ -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_meta
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}"
)

Expand Down
6 changes: 3 additions & 3 deletions tuf/ngclient/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -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_meta
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)
Expand Down