11
11
import sys
12
12
import tempfile
13
13
import unittest
14
+ from datetime import datetime , timedelta
14
15
from typing import Optional , Tuple
15
- from unittest .mock import MagicMock , patch
16
+ from unittest .mock import MagicMock , call , patch
16
17
17
18
from tests import utils
18
19
from tests .repository_simulator import RepositorySimulator
19
20
from tuf .api .metadata import SPECIFICATION_VERSION , Targets
20
- from tuf .exceptions import BadVersionNumberError , UnsignedMetadataError
21
+ from tuf .exceptions import (
22
+ BadVersionNumberError ,
23
+ ExpiredMetadataError ,
24
+ UnsignedMetadataError ,
25
+ )
21
26
from tuf .ngclient import Updater
22
27
23
28
@@ -241,6 +246,7 @@ def test_not_loading_targets_twice(self, wrapped_open: MagicMock) -> None:
241
246
242
247
# Run refresh, top-level roles are loaded
243
248
updater = self ._run_refresh ()
249
+
244
250
# Clean up calls to open during refresh()
245
251
wrapped_open .reset_mock ()
246
252
@@ -254,6 +260,54 @@ def test_not_loading_targets_twice(self, wrapped_open: MagicMock) -> None:
254
260
updater .get_targetinfo ("somepath" )
255
261
wrapped_open .assert_not_called ()
256
262
263
+ @patch .object (builtins , "open" , wraps = builtins .open )
264
+ def test_expired_metadata (self , wrapped_open : MagicMock ) -> None :
265
+ updater = self ._run_refresh ()
266
+
267
+ past_datetime = datetime .utcnow ().replace (microsecond = 0 ) - timedelta (
268
+ days = 5
269
+ )
270
+
271
+ self .sim .timestamp .expires = past_datetime
272
+ self .sim .snapshot .expires = past_datetime
273
+ self .sim .targets .expires = past_datetime
274
+
275
+ # Add targets to repository
276
+ self .sim .targets .version += 1
277
+ self .sim .add_target ("targets" , b"some content" , self .targets_dir )
278
+ self .sim .update_snapshot ()
279
+
280
+ # Clean up calls to open during refresh()
281
+ wrapped_open .reset_mock ()
282
+
283
+ # Make a successful update of valid metadata which stores it in cache
284
+ updater .get_targetinfo (self .targets_dir )
285
+
286
+ # Create a new updater and perform a second update while
287
+ # the metadata is already stored in cache (metadata dir)
288
+ updater = Updater (
289
+ self .metadata_dir ,
290
+ "https://example.com/metadata/" ,
291
+ self .targets_dir ,
292
+ "https://example.com/targets/" ,
293
+ self .sim ,
294
+ )
295
+
296
+ with self .assertRaises (ExpiredMetadataError ):
297
+ updater .get_targetinfo (self .targets_dir )
298
+
299
+ # Test that an expired timestamp/snapshot/targets
300
+ # when loaded from cache is not stored as final
301
+ # but is used to verify the new timestamp
302
+ wrapped_open .assert_has_calls (
303
+ [
304
+ call (os .path .join (self .metadata_dir , "root.json" ), "rb" ),
305
+ call (os .path .join (self .metadata_dir , "timestamp.json" ), "rb" ),
306
+ ]
307
+ )
308
+
309
+ wrapped_open .reset_mock ()
310
+
257
311
258
312
if __name__ == "__main__" :
259
313
if "--dump" in sys .argv :
0 commit comments