11# Copyright 2020, New York University and the TUF contributors
22# SPDX-License-Identifier: MIT OR Apache-2.0
33
4- """TUF client workflow implementation.
4+ """TUF module that implements the client update workflow.
5+
6+ This module contains the Updater class that provides an implementation of the
7+ `TUF client workflow
8+ <https://theupdateframework.github.io/specification/latest/#detailed-client-workflow>`_.
9+ Updater provides an API to query available targets and to download them in a
10+ secure manner: All downloaded files are verified by signed metadata.
11+
12+ High-level description of Updater functionality:
13+ * Initializing an :class:`~tuf.ngclient.updater.Updater` loads and validates
14+ the trusted local root metadata: This root metadata is used as the source
15+ of trust for all other metadata.
16+ * Calling :func:`~tuf.ngclient.updater.Updater.refresh()` will update root
17+ metadata and load all other top-level metadata as described in the
18+ specification, using both locally cached metadata and metadata downloaded
19+ from the remote repository.
20+ * When metadata is up-to-date, targets can be dowloaded. The repository
21+ snapshot is consistent so multiple targets can be downloaded without
22+ fear of repository content changing. For each target:
23+ * :func:`~tuf.ngclient.updater.Updater.get_one_valid_targetinfo()` is
24+ used to find information about a specific target. This will load new
25+ targets metadata as needed (from local cache or remote repository).
26+ * :func:`~tuf.ngclient.updater.Updater.updated_targets()` can be used to
27+ check if target files are already locally cached.
28+ * :func:`~tuf.ngclient.updater.Updater.download_target()` downloads a
29+ target file and ensures it is verified correct by the metadata.
30+
31+ Below is a simple example of using the Updater to download and verify
32+ "file.txt" from a remote repository. The required environment for this example
33+ is:
34+ * A webserver running on http://localhost:8000, serving TUF repository
35+ metadata at "/tuf-repo/" and targets at "/targets/"
36+ * Local metadata directory "~/tufclient/metadata/" is writable and contains
37+ a root metadata version for the remote repository
38+ * Download directory "~/target-downloads/" is writable
39+
40+ Example::
41+
42+ from tuf.ngclient import Updater
43+
44+ # Load trusted local root metadata from client metadata cache. Define the
45+ # remote repository metadata URL prefix and target URL prefix.
46+ updater = Updater(
47+ repository_dir="~/tufclient/metadata/",
48+ metadata_base_url="http://localhost:8000/tuf-repo/",
49+ target_base_url="http://localhost:8000/targets/",
50+ )
51+
52+ # Update top-level metadata from remote
53+ updater.refresh()
54+
55+ # Securely download a target:
56+ # Update target metadata, then download and verify target
57+ targetinfo = updater.get_one_valid_targetinfo("file.txt")
58+ updater.download_target(targetinfo, "~/tufclient/downloads/")
559"""
660
761import fnmatch
2276
2377
2478class Updater :
25- """
26- An implementation of the TUF client workflow.
27- Provides a public API for integration in client applications.
28- """
79+ """Implementation of the TUF client workflow."""
2980
3081 def __init__ (
3182 self ,
@@ -35,10 +86,11 @@ def __init__(
3586 fetcher : Optional [FetcherInterface ] = None ,
3687 config : Optional [UpdaterConfig ] = None ,
3788 ):
38- """
89+ """Creates a new Updater instance and loads trusted root metadata.
90+
3991 Args:
4092 repository_dir: Local metadata directory. Directory must be
41- writable and it must contain at least a root.json file.
93+ writable and it must contain a trusted root.json file.
4294 metadata_base_url: Base URL for all remote metadata downloads
4395 target_base_url: Optional; Default base URL for all remote target
4496 downloads. Can be individually set in download_target()
@@ -68,17 +120,17 @@ def __init__(
68120 self .config = config or UpdaterConfig ()
69121
70122 def refresh (self ) -> None :
71- """
72- This method downloads, verifies, and loads metadata for the top-level
73- roles in the specified order (root -> timestamp -> snapshot -> targets)
74- The expiration time for downloaded metadata is also verified.
123+ """Refreshes top-level metadata.
124+
125+ Downloads, verifies, and loads metadata for the top-level roles in the
126+ specified order (root -> timestamp -> snapshot -> targets) implementing
127+ all the checks required in the TUF client workflow.
75128
76- The metadata for delegated roles are not refreshed by this method, but
77- by the method that returns targetinfo (i.e.,
78- get_one_valid_targetinfo()).
129+ The metadata for delegated roles are not refreshed by this method as
130+ that happens on demand during get_one_valid_targetinfo().
79131
80- The refresh() method should be called by the client before any target
81- requests .
132+ The refresh() method should be called by the client before any other
133+ method calls .
82134
83135 Raises:
84136 OSError: New metadata could not be written to disk
@@ -92,11 +144,20 @@ def refresh(self) -> None:
92144 self ._load_targets ("targets" , "root" )
93145
94146 def get_one_valid_targetinfo (self , target_path : str ) -> Dict :
95- """
96- Returns the target information for a target identified by target_path.
147+ """Returns target information for 'target_path'.
148+
149+ The return value can be used as an argument to
150+ :func:`download_target()` and :func:`updated_targets()`.
151+
152+ :func:`refresh()` must be called before calling
153+ `get_one_valid_targetinfo()`. Subsequent calls to
154+ `get_one_valid_targetinfo()` will use the same consistent repository
155+ state: Changes that happen in the repository between calling
156+ :func:`refresh()` and `get_one_valid_targetinfo()` will not be
157+ seen by the updater.
97158
98159 As a side-effect this method downloads all the additional (delegated
99- targets) metadata required to return the target information.
160+ targets) metadata it needs to return the target information.
100161
101162 Args:
102163 target_path: A target identifier that is a path-relative-URL string
@@ -115,12 +176,15 @@ def get_one_valid_targetinfo(self, target_path: str) -> Dict:
115176 def updated_targets (
116177 targets : List [Dict [str , Any ]], destination_directory : str
117178 ) -> List [Dict [str , Any ]]:
118- """
119- After the client has retrieved the target information for those targets
120- they are interested in updating, they would call this method to
121- determine which targets have changed from those saved locally on disk.
122- All the targets that have changed are returned in a list. From this
123- list, they can request a download by calling 'download_target()'.
179+ """Checks whether local cached target files are up to date
180+
181+ After retrieving the target information for the targets that should be
182+ updated, updated_targets() can be called to determine which targets
183+ have changed compared to locally stored versions.
184+
185+ All the targets that are not up-to-date in destination_directory are
186+ returned in a list. The list items can be downloaded with
187+ 'download_target()'.
124188 """
125189 # Keep track of the target objects and filepaths of updated targets.
126190 # Return 'updated_targets' and use 'updated_targetpaths' to avoid
@@ -159,8 +223,7 @@ def download_target(
159223 destination_directory : str ,
160224 target_base_url : Optional [str ] = None ,
161225 ):
162- """
163- Download target specified by 'targetinfo' into 'destination_directory'.
226+ """Downloads the target file specified by 'targetinfo'.
164227
165228 Args:
166229 targetinfo: data received from get_one_valid_targetinfo() or
0 commit comments