Skip to content

Commit ab41675

Browse files
authored
Merge pull request #1474 from jku/document-ngclient
Document ngclient
2 parents 8e9677d + c37d21d commit ab41675

1 file changed

Lines changed: 90 additions & 27 deletions

File tree

tuf/ngclient/updater.py

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,61 @@
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

761
import fnmatch
@@ -22,10 +76,7 @@
2276

2377

2478
class 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

Comments
 (0)