Skip to content

Commit e242a75

Browse files
author
Jussi Kukkonen
authored
Merge pull request #1524 from jku/ngclient-rollback-improvements
ngclient rollback improvements
2 parents f4ffb9d + c8696d9 commit e242a75

File tree

3 files changed

+113
-110
lines changed

3 files changed

+113
-110
lines changed

tests/test_trusted_metadata_set.py

+63-59
Original file line numberDiff line numberDiff line change
@@ -80,21 +80,6 @@ def hashes_length_modifier(timestamp: Timestamp) -> None:
8080
def setUp(self) -> None:
8181
self.trusted_set = TrustedMetadataSet(self.metadata["root"])
8282

83-
def _root_updated_and_update_timestamp(
84-
self, timestamp_bytes: Optional[bytes] = None
85-
) -> None:
86-
"""Finsh root update and update timestamp with passed timestamp_bytes.
87-
88-
Args:
89-
timestamp_bytes:
90-
Bytes used when calling trusted_set.update_timestamp().
91-
Default self.metadata["timestamp"].
92-
93-
"""
94-
timestamp_bytes = timestamp_bytes or self.metadata["timestamp"]
95-
self.trusted_set.root_update_finished()
96-
self.trusted_set.update_timestamp(timestamp_bytes)
97-
9883

9984
def _update_all_besides_targets(
10085
self,
@@ -112,13 +97,14 @@ def _update_all_besides_targets(
11297
Default self.metadata["snapshot"].
11398
11499
"""
115-
self._root_updated_and_update_timestamp(timestamp_bytes)
100+
101+
timestamp_bytes = timestamp_bytes or self.metadata["timestamp"]
102+
self.trusted_set.update_timestamp(timestamp_bytes)
116103
snapshot_bytes = snapshot_bytes or self.metadata["snapshot"]
117104
self.trusted_set.update_snapshot(snapshot_bytes)
118105

119106

120107
def test_update(self):
121-
self.trusted_set.root_update_finished()
122108
self.trusted_set.update_timestamp(self.metadata["timestamp"])
123109
self.trusted_set.update_snapshot(self.metadata["snapshot"])
124110
self.trusted_set.update_targets(self.metadata["targets"])
@@ -139,24 +125,16 @@ def test_update(self):
139125
self.assertTrue(count, 6)
140126

141127
def test_out_of_order_ops(self):
142-
# Update timestamp before root is finished
143-
with self.assertRaises(RuntimeError):
144-
self.trusted_set.update_timestamp(self.metadata["timestamp"])
145-
146-
self.trusted_set.root_update_finished()
147-
with self.assertRaises(RuntimeError):
148-
self.trusted_set.root_update_finished()
149-
150-
# Update root after a previous successful root update
151-
with self.assertRaises(RuntimeError):
152-
self.trusted_set.update_root(self.metadata["root"])
153-
154128
# Update snapshot before timestamp
155129
with self.assertRaises(RuntimeError):
156130
self.trusted_set.update_snapshot(self.metadata["snapshot"])
157131

158132
self.trusted_set.update_timestamp(self.metadata["timestamp"])
159133

134+
# Update root after timestamp
135+
with self.assertRaises(RuntimeError):
136+
self.trusted_set.update_root(self.metadata["root"])
137+
160138
# Update targets before snapshot
161139
with self.assertRaises(RuntimeError):
162140
self.trusted_set.update_targets(self.metadata["targets"])
@@ -198,8 +176,6 @@ def test_update_with_invalid_json(self):
198176
with self.assertRaises(exceptions.RepositoryError):
199177
self.trusted_set.update_root(self.metadata["snapshot"])
200178

201-
self.trusted_set.root_update_finished()
202-
203179
top_level_md = [
204180
(self.metadata["timestamp"], self.trusted_set.update_timestamp),
205181
(self.metadata["snapshot"], self.trusted_set.update_snapshot),
@@ -241,15 +217,16 @@ def test_update_root_new_root_ver_same_as_trusted_root_ver(self):
241217
with self.assertRaises(exceptions.ReplayedMetadataError):
242218
self.trusted_set.update_root(self.metadata["root"])
243219

244-
def test_root_update_finished_expired(self):
220+
def test_root_expired_final_root(self):
245221
def root_expired_modifier(root: Root) -> None:
246222
root.expires = datetime(1970, 1, 1)
247223

224+
# intermediate root can be expired
248225
root = self.modify_metadata("root", root_expired_modifier)
249226
tmp_trusted_set = TrustedMetadataSet(root)
250-
# call root_update_finished when trusted root has expired
227+
# update timestamp to trigger final root expiry check
251228
with self.assertRaises(exceptions.ExpiredMetadataError):
252-
tmp_trusted_set.root_update_finished()
229+
tmp_trusted_set.update_timestamp(self.metadata["timestamp"])
253230

254231

255232
def test_update_timestamp_new_timestamp_ver_below_trusted_ver(self):
@@ -258,7 +235,7 @@ def version_modifier(timestamp: Timestamp) -> None:
258235
timestamp.version = 3
259236

260237
timestamp = self.modify_metadata("timestamp", version_modifier)
261-
self._root_updated_and_update_timestamp(timestamp)
238+
self.trusted_set.update_timestamp(timestamp)
262239
with self.assertRaises(exceptions.ReplayedMetadataError):
263240
self.trusted_set.update_timestamp(self.metadata["timestamp"])
264241

@@ -268,35 +245,38 @@ def bump_snapshot_version(timestamp: Timestamp) -> None:
268245

269246
# set current known snapshot.json version to 2
270247
timestamp = self.modify_metadata("timestamp", bump_snapshot_version)
271-
self._root_updated_and_update_timestamp(timestamp)
248+
self.trusted_set.update_timestamp(timestamp)
272249

273250
# newtimestamp.meta["snapshot.json"].version < trusted_timestamp.meta["snapshot.json"].version
274251
with self.assertRaises(exceptions.ReplayedMetadataError):
275252
self.trusted_set.update_timestamp(self.metadata["timestamp"])
276253

277254
def test_update_timestamp_expired(self):
278-
self.trusted_set.root_update_finished()
279255
# new_timestamp has expired
280256
def timestamp_expired_modifier(timestamp: Timestamp) -> None:
281257
timestamp.expires = datetime(1970, 1, 1)
282258

259+
# intermediate timestamp is allowed to be expired
283260
timestamp = self.modify_metadata("timestamp", timestamp_expired_modifier)
261+
self.trusted_set.update_timestamp(timestamp)
262+
263+
# update snapshot to trigger final timestamp expiry check
284264
with self.assertRaises(exceptions.ExpiredMetadataError):
285-
self.trusted_set.update_timestamp(timestamp)
265+
self.trusted_set.update_snapshot(self.metadata["snapshot"])
286266

287267
def test_update_snapshot_length_or_hash_mismatch(self):
288268
def modify_snapshot_length(timestamp: Timestamp) -> None:
289269
timestamp.meta["snapshot.json"].length = 1
290270

291271
# set known snapshot.json length to 1
292272
timestamp = self.modify_metadata("timestamp", modify_snapshot_length)
293-
self._root_updated_and_update_timestamp(timestamp)
273+
self.trusted_set.update_timestamp(timestamp)
294274

295275
with self.assertRaises(exceptions.RepositoryError):
296276
self.trusted_set.update_snapshot(self.metadata["snapshot"])
297277

298278
def test_update_snapshot_cannot_verify_snapshot_with_threshold(self):
299-
self._root_updated_and_update_timestamp(self.metadata["timestamp"])
279+
self.trusted_set.update_timestamp(self.metadata["timestamp"])
300280
snapshot = Metadata.from_bytes(self.metadata["snapshot"])
301281
snapshot.signatures.clear()
302282
with self.assertRaises(exceptions.UnsignedMetadataError):
@@ -307,46 +287,70 @@ def timestamp_version_modifier(timestamp: Timestamp) -> None:
307287
timestamp.meta["snapshot.json"].version = 2
308288

309289
timestamp = self.modify_metadata("timestamp", timestamp_version_modifier)
310-
self._root_updated_and_update_timestamp(timestamp)
311-
# new_snapshot.version != trusted timestamp.meta["snapshot"].version
312-
def snapshot_version_modifier(snapshot: Snapshot) -> None:
313-
snapshot.version = 3
290+
self.trusted_set.update_timestamp(timestamp)
291+
292+
#intermediate snapshot is allowed to not match meta version
293+
self.trusted_set.update_snapshot(self.metadata["snapshot"])
314294

315-
snapshot = self.modify_metadata("snapshot", snapshot_version_modifier)
295+
# final snapshot must match meta version
316296
with self.assertRaises(exceptions.BadVersionNumberError):
317-
self.trusted_set.update_snapshot(snapshot)
297+
self.trusted_set.update_targets(self.metadata["targets"])
298+
318299

319-
def test_update_snapshot_after_successful_update_new_snapshot_no_meta(self):
300+
def test_update_snapshot_file_removed_from_meta(self):
320301
self._update_all_besides_targets(self.metadata["timestamp"])
321-
# Test removing a meta_file in new_snapshot compared to the old snapshot
322-
def no_meta_modifier(snapshot: Snapshot) -> None:
323-
snapshot.meta = {}
302+
def remove_file_from_meta(snapshot: Snapshot) -> None:
303+
del snapshot.meta["targets.json"]
324304

325-
snapshot = self.modify_metadata("snapshot", no_meta_modifier)
305+
# Test removing a meta_file in new_snapshot compared to the old snapshot
306+
snapshot = self.modify_metadata("snapshot", remove_file_from_meta)
326307
with self.assertRaises(exceptions.RepositoryError):
327308
self.trusted_set.update_snapshot(snapshot)
328309

329-
def test_update_snapshot_after_succesfull_update_new_snapshot_meta_version_different(self):
330-
self._root_updated_and_update_timestamp(self.metadata["timestamp"])
331-
# snapshot.meta["project1"].version != new_snapshot.meta["project1"].version
310+
def test_update_snapshot_meta_version_decreases(self):
311+
self.trusted_set.update_timestamp(self.metadata["timestamp"])
312+
332313
def version_meta_modifier(snapshot: Snapshot) -> None:
333-
for metafile_path in snapshot.meta.keys():
334-
snapshot.meta[metafile_path].version += 1
314+
snapshot.meta["targets.json"].version += 1
335315

336316
snapshot = self.modify_metadata("snapshot", version_meta_modifier)
337317
self.trusted_set.update_snapshot(snapshot)
318+
338319
with self.assertRaises(exceptions.BadVersionNumberError):
339320
self.trusted_set.update_snapshot(self.metadata["snapshot"])
340321

341322
def test_update_snapshot_expired_new_snapshot(self):
342-
self._root_updated_and_update_timestamp(self.metadata["timestamp"])
343-
# new_snapshot has expired
323+
self.trusted_set.update_timestamp(self.metadata["timestamp"])
344324
def snapshot_expired_modifier(snapshot: Snapshot) -> None:
345325
snapshot.expires = datetime(1970, 1, 1)
346326

327+
# intermediate snapshot is allowed to be expired
347328
snapshot = self.modify_metadata("snapshot", snapshot_expired_modifier)
329+
self.trusted_set.update_snapshot(snapshot)
330+
331+
# update targets to trigger final snapshot expiry check
348332
with self.assertRaises(exceptions.ExpiredMetadataError):
349-
self.trusted_set.update_snapshot(snapshot)
333+
self.trusted_set.update_targets(self.metadata["targets"])
334+
335+
def test_update_snapshot_successful_rollback_checks(self):
336+
def meta_version_bump(timestamp: Timestamp) -> None:
337+
timestamp.meta["snapshot.json"].version += 1
338+
339+
def version_bump(snapshot: Snapshot) -> None:
340+
snapshot.version += 1
341+
342+
# load a "local" timestamp, then update to newer one:
343+
self.trusted_set.update_timestamp(self.metadata["timestamp"])
344+
new_timestamp = self.modify_metadata("timestamp", meta_version_bump)
345+
self.trusted_set.update_timestamp(new_timestamp)
346+
347+
# load a "local" snapshot, then update to newer one:
348+
self.trusted_set.update_snapshot(self.metadata["snapshot"])
349+
new_snapshot = self.modify_metadata("snapshot", version_bump)
350+
self.trusted_set.update_snapshot(new_snapshot)
351+
352+
# update targets to trigger final snapshot meta version check
353+
self.trusted_set.update_targets(self.metadata["targets"])
350354

351355
def test_update_targets_no_meta_in_snapshot(self):
352356
def no_meta_modifier(snapshot: Snapshot) -> None:

0 commit comments

Comments
 (0)