Fix issues from review

In addition to multiple smaller review fixes:
* Explain how the proposed library is minimal: more specific
  functionality may be added as we get more experience
* Explain what a concrete Repository implementation must implement
  (details are obviously subject to change but this is what the
  current prototype requires)

Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
This commit is contained in:
Jussi Kukkonen 2021-12-07 12:52:51 +02:00
parent bcab2e96b0
commit f6ede42eae

View file

@ -1,7 +1,7 @@
# Python-tuf repository API proposal: _minimal repository abstraction_
This is an attachment to ADR 10: _Repository library design built on top of
Metadata API_, and documents the design proposal in Dec 2020.
Metadata API_, and documents the design proposal in Dec 2021.
## Design principles
@ -31,22 +31,24 @@ other implementations?
## Design
### Application and library components
![Design: Application and library components](repository-library-design-ownership.jpg)
The design expects a fully functional repository application to contain code at
three levels:
* Repository library (abstract classes that are part of python-tuf)
* The Repository abstract class provides an ergonomic metadata editing API
for all code levels to use. It also implements some core edit actions like
snapshot update
* The Repository abstract class provides an ergonomic abstract metadata
editing API for all code levels to use. It also provides implementations
for some core edit actions like _snapshot update_.
* A small amount of related functionality is also provided (private key
management API, maybe repository validation)
* is a very small library: possibly a few hundred lines of code
management API, maybe repository validation).
* is a very small library: possibly a few hundred lines of code.
* Concrete Repository implementation (typically part of application code,
implements interfaces provided by the repository API in python-tuf)
* Contains the “application level” decisions that the Repository abstraction
requires to operate: examples of application decisions include
* _when should “targets” metadata next expire when it is edited?_
* _When should “targets” metadata next expire when it is edited?_
* _What is the current “targets” metadata version? Where do we load it
from?_
* _Where to store current “targets” after editing? Should the previous
@ -55,7 +57,8 @@ three levels:
* Uses the Repository API to do the repository actions it needs to do
For context heres a trivial example showing what “ergonomic editing” means --
this key-adding code could be in the application or in the python-tuf library:
this key-adding code could be in the application (or later, if common patterns
are found, in the python-tuf library):
```python
with repository.edit(“targets”) as targets:
@ -69,7 +72,8 @@ The reason for the context manager style is that it manages two things
simultaneously:
* Hides the complexity of loading and persisting metadata, and updating expiry
and versions from the editing code (by putting it in the repository
implementation which may still be provided by the application)
implementation that is defined in python-tuf but implemented by the
application)
* Still allows completely arbitrary edits on the metadata in question: now the
library does not need to anticipate what application wants to do and on the
other hand library can still provide e.g. snapshot functionality without
@ -77,6 +81,8 @@ simultaneously:
Other designs do not seem to manage both of these.
### How the components are used
![Design: How components are used](repository-library-design-usage.jpg)
The core idea here is that because editing is ergonomic enough, when new
@ -86,6 +92,12 @@ that adds a bunch of targets into the metadata, but one of the previous layers
could offer that as a helper function as well: code in both cases would look
similar as it would use the common editing interface.
The proposed design is purposefully spartan in that the library provides
very few high-level actions (the prototype only provided _sign_ and
_snapshot_): everything else is left to implementer at this point. As we gain
experience of common usage patterns we can start providing other features as
well.
There are a few additional items worth mentioning:
* Private key management: the Repository API should come with a “keyring
abstraction” -- a way for the application to provide roles private keys for
@ -132,8 +144,28 @@ proposal includes concrete implementations only for the following:
Note that a concrete Repository implementation could provide an easier to use
snapshot that does not require input (see example in git_repo.py)
More concrete implementations (see cli.py for examples) could be added to
Repository itself but none seem essential at this point.
More concrete method implementations (see cli.py for examples) could be added
to Repository itself but none seem essential at this point.
The current prototype API defines five abstract methods that take care of
access to metadata storage, expiry updates, version updates and signing. These
must be implemented in the concrete implementation:
* **keyring()**: A property that returns the private key mapping that should be
used for signing.
* **_load()**: Loads metadata from storage or cache. Is used by edit() and
sign().
* **_save()**: Signs and persists metadata in cache/storage. Is used by edit()
and sign().
* **edit()**: The ContextManager that enables ergonomic metadata
editing by handling expiry and version number management.
* **init_role()**: initializes new metadata handling expiry and version number.
(_init_role is in a way a special case of edit and should potentially be
integrated there_).
The API requires a “Keyring” abstraction that the repository code can use to
lookup a set of signers for a specific role. Specific implementations of
@ -144,7 +176,7 @@ and more could be implemented in applications.
_Prototype status: Prototype Repository and Keyring abstractions exist in
librepo/repo.py._
### Example of Repository implementation
### Example concrete Repository implementation
The design decisions that the included example `GitRepository` makes are not
important but provide an example of what is possible: