In the securesystemslib pr https://github.com/secure-systems-lab/securesystemslib/pull/319
I added a new Signer interface with the purpose of supporting multiple
signing implementations.
Additionally, I added the SSlibSigner implementation of that interface
which implements the signing operation for rsa, ed25519 and ecdsa
schemes.
With this commit, I integrate the SSlibSigner into the new API in tuf.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Revert an earlier commit that moved to/from_dict metadata class
model methods to a util module of the serialization sub-package.
We keep to/from_dict methods on the metadata classes because:
- It seems **idiomatic** (see e.g. 3rd-party libaries such as attrs,
pydantic, marshmallow, or built-ins that provide default or
customizable dict representation for higher-level objects).
The idiomatic choice should make usage more intuitive.
- It feels better **structured** when each method is encapsulated
within the corresponding class, which in turn should make
maintaining/modifying/extending the class model easier.
- It allows us to remove function-scope imports (see subsequent
commit).
Caveat:
Now that "the meat" of the sub-packaged JSON serializer is
implemented on the class, it might make it harder to create a
non-dict based serializer by copy-paste-amending the JSON
serializer.
However, the benefits from above seem to outweigh the disadvantage.
See option 5 of ADR0006 for further details (#1270).
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Add tuf.api.serialization.util module with functions to
convert between TUF metadata class model and the corresponding
dictionary representation. These functions replace the
corresponding to/from_dict classmethods.
Configure api/pylintrc to exempt '_type' from protected member
access warning, because the underscore prefix here is only used to
avoid name shadowing.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Re-raise all errors that happen during de/serialization as custom
De/SerializationError.
Whilelist 'e', which is idiomatic for error, in api/pylintrc, and
inline exempt broad-except, which are okay if re-raised.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Ensure that the newly added files' docstrings adhere to the
recently adopted code style guideline (#1232).
Small code style improvements in comments and imports.
Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
Use a common test level constant for defining
the host address forming the download URL on
the client side.
Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
* Move FetcherInterface to tuf/client/ directory: This way everything
inside that directory is clearly part of client API, and everything
outside _may_ be more of an implementation detail (settings is still
an unfortunate exception)
* Keep RequestsFetcher in tuf/ for same reasons: it's just the default
implementation, not explicitly part of client API
An even clearer division would be if we moved all the client specific
implementation details (download.py, mirrors.py, requests_fetcher.py)
to tuf/client/_internal/ but that's a larger change...
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
A custom error is required so that updater is able to special case
403 & 404 status codes.
Rewrite the test case a bit to be more readable.
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
Add test cases to test_fetcher and test_download that
decrease default chunk size and download data in more
than one chunk.
Small code-style improvements.
Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
On Windows (Github Actions) the lookup for 'localhost' takes 1 second.
This is because:
- Windows retries connect() with a timeout
- the machine has IPv6 and IPv4 but Testserver only binds the port on IPv4
- the test clients connect to 'localhost'
Since socketserver.TCPServer does not seem to support IPv6 before 3.8,
just replace 'localhost' with '127.0.0.1' in client-side URLs.
See #1257
Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
The GitHub action windows runners (added in a subsequent commit)
choke on a test that runs os.makedirs with a too long directory
name, and expects an OSError with error numbers ENAMETOOLONG or
ENOENT. However, this particular runner returns EINVAL in Python 3,
which according to bugs.python.org/msg295851 is not unlikely.
This commit simply adds EINVAL to the expected error numbers.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Add a test to ensure that metadata expires at the expiration time, not
after it.
This tests the change to the updater introduced in 4bcd703
Signed-off-by: Joshua Lock <jlock@vmware.com>
When the updater is verifying that the new root metadata is signed by a
threshold of keys defined by the new root metadata itself, multiple
signatures with the same keyid should not be counted more than once
towards the threshold.
Implement a test for this, which currently fails.
Reported-by: Trishank Karthik Kuppusamy <trishank.kuppusamy@datadoghq.com>
Signed-off-by: Joshua Lock <jlock@vmware.com>
Currently, we are importing the "utils" module in tests/utils
with "import utils".
This could become a problem when there is another module with
the same general name "utils" and could lead to import mistakes.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
This quote from the Google Python style guide made me realize
why empty list as a default value for an argument could be
dangerous:
"Default arguments are evaluated once at module load time.
This may cause problems if the argument is a mutable object
such as a list or a dictionary. If the function modifies the object
(e.g., by appending an item to a list), the default value is modified."
Read more here:
https://google.github.io/styleguide/pyguide.html#2123-cons
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
In 'repository_lib._generate_and_write_metadata' sort the set of
signing key keyids alphabetically before passing them on to signing
functions, to make the order in which signatures are added
deterministic.
This is above all beneficial for testing.
This commit also adds an exemplary test for signatures on root
metadata using the repository_tool interface to setup all the state
that required to test _generate_and_write_metadata.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Update the comments to not mention the usage of temp file
for logging regarding the instances of the TestServerProcess class.
Also, remove one unused import.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
The current implementation for server startup in TestServerProcess
relies on the fact that "bind successful..." is the first message
sent by the server process.
Make sure that this is true and leave a comment about this.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
We want to make sure that server are successfully started in
the common use cases and that the new port generation works.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Now, after we can use wait_for_server and the retry mechanism
of TestServerProcess in utils.py we no longer need to use
sleep in this test file.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
These changes can be summarized with the following bullets:
- Delegate generation of ports used for the tests to the OS
- Use thread-safe Queue for processes communication
instead of temporary files
- Remove all instances of port generation or hardcoded ports
- Make test_slow_retrieval.py fully conform with TestServerProcess
Delegate generation of ports used for the tests to the OS is much
better than if we manually generate them, because there is always
a chance that the port we have randomly pick turns out to be taken.
By giving 0 to the port argument we ask the OS to give us
an arbitrary unused port.
Use thread-safe Queue for processes communication instead of temporary
files became a necessity because of findings made by Jussi Kukkonen.
With the latest changes made in pr 1192 we were rapidly reading
from the temporary files and Jussi found that it happened rarely
the successful message "bind succeded..." to be corrupted.
It seems, this is a thread issue related to the thread redirecting
the subprocess stdout to the temp file and our thread rapidly
reading from the file.
By using a thread-safe Queue we eliminate this possibility.
For reference read:
https://github.com/theupdateframework/tuf/issues/1196
Lastly, test_slow_retrieval.py and slow_retrieval.py were refactored.
Until now, slow_retrieval.py couldn't use the TestServerProcess class
from utils.py for a port generation because of a bug related to
httpd.handle_request().
Now, when we use httpd.serve_forever() we can refactor both of those
files and fully conform with TestServerProcess.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Remove the test with mode 2 ('mode_2': During the download process,
the server blocks the download by sending just several characters
every few seconds.) from test_slow_retrieval.
This test is marked as "expected failure" with the purpose of
rewriting it one day, but slow retrievals have been removed from
the specification and soon it will be removed from the tuf
reference implementation as a whole.
That means that the chances of making this test useful are close
to 0 if not none.
The other test (with mode 1) in test_slow_retrieval is not removed.
For reference:
- https://github.com/theupdateframework/specification/pull/111
- https://github.com/theupdateframework/tuf/pull/1156
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
secure-systems-lab/securesystemslib#288 changes the key generation
interface functions in such a way that it is clear if a call opens
a blocking prompt, or writes the key unencrypted. To do this two
functions are added per key type:
- `generate_and_write_*_keypair_with_prompt`
- `generate_and_write_unencrypted_*_keypair`
The default `generate_and_write_*_keypair` function now only allows
encrypted keys and only using a passed password. This respects the
principle of secure defaults and least surprise.
sslib#288 furthermore adds a protected
`_generate_and_write_*_keypair`, which is not exposed publicly
because it does not encrypt by default, but is more flexible and
thus convenient e.g. to consume all arguments from a key generation
command line tool such as 'repo.py'.
This commit adds the new public functions to the tuf namespace and
adopts their usage accordingly.
NOTE regarding repo.py:
This commit does not fix any problematic password behavior of
'repo.py' like default passwords, etc. (see #881). It only adopts
the sslib#288 changes to maintain the current behvior, plus
removing one glaringly obsolete password prompt.
NOTE regarding key import:
The securesystemslib private key import functions were also changed
to no longer auto-prompt for decryption passwords , TUF, however,
only exposes custom wrappers (see repository_lib) that do
auto-prompt. sslib#288 changes to the prompt texts are nevertheless
propagated to tuf and reflected in this commit.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
The call stack and code for download_target() is more complex than
required:
* download_target() : builds target destination filepath, gets length
and hashes
* _get_target_file() : fixes filenames if consistent snapshots enabled,
defines verification callback
* _get_file() : iterates mirrors, tries to download files, verifies them
Remove the verification callback and collapse the call stack by a single
level to make the code easier to follow.
Signed-off-by: Joshua Lock <jlock@vmware.com>
Use deepcopy to ensure that the dictionaries with expected data
are not referencing the same memory as the tested ones.
Add a check asserting that metadata is not equal prior to its
update.
Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
There is a simpler way to skip modules or particular tests
built-in into the unittest module.
That's why it doesn't make sense for us to manually filter
modules based on the python version we are running.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Even though we don't want to promote the usage of [''] as a value
for confined_target_dirs, it's good to test against because we
don't want to introduce a breaking change for our users.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
The field confined_target_dirs from the MIRROR_SCHEMA is
a list of strings. Those strings define the accessible target
paths for that mirror. For one target to be available for that mirror,
its path should have as a prefix at least one of the strings defined
in confined_target_dirs.
That's why when confined_target_dirs is a list with one element empty
string (e.g. ['']) this means all targets files on that mirror are
available and if confined_target_dirs is empty list (e.g. []) this
would be interpreted as none of the target files is available.
This is a confusing API that could easily lead to mistakes.
That's why it's better we promote to not set confined_target_dirs
at all if a user wants targets to be available.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>