This allows creating new metadata with less boilerplate:
root = Metadata(Root())
targets = Metadata(Targets())
Set reasonable default values for all the arguments -- version to
1, spec_version to current supported version, etc.
Expires does not have a good default value and my original plan was
to require expires argument to be set. That would mean an
incompatible API change though as arguments before expires would be
now optional... So expires now defaults to an arbitrary value of 1
day from moment of creation.
One noteworthy special case is consistent_snapshot where the default
value is True (since that's what we want people to use for new
metadata) but None is also used to imply that metadata does not contain
the field at all.
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
Change to @lukpueh proposal with more clarification on why and how
the `securesystemslib.signer.Signer` interface is used
Co-authored-by: Lukas Pühringer <luk.puehringer@gmail.com>
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
This change updates some parts of the Metadata API docstrings
that did not give enough details and context
Fixes#1600
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
After we have dropped OrderedDict in e3b267e2e0
we are relying on python3.7+ default behavior to preserve the insertion
order, but there is one caveat.
When comparing dictionaries the order is still irrelevant compared to
OrderedDict. For example:
>>> OrderedDict([(1,1), (2,2)]) == OrderedDict([(2,2), (1,1)])
False
>>> dict([(1,1), (2,2)]) == dict([(2,2), (1,1)])
True
There are two special attributes, defined in the specification, where
the order makes a difference when comparing two objects:
- Metadata.signatures
- Targets.delegations.roles.
We want to make sure that the order in those two cases makes a
difference when comparing two objects and that's why those changes
are required inside two __eq__ implementations.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
By adding __eq__ we can compare that two objects are equal.
That will be useful when adding validation API call.
One bug I have found during testing is that I don't check if the type
of "other" in the __eq__ implementations are the expected ones.
I assumed that when comparing "root == obj" if "obj" is None that
automatically the result will be false.
Later after a mypy warning, I realized we should implement the __eq__
methods to accept "Any" type as other and we should check manually
that "other" is the expected type.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
We don't want to error out from the whole verify_delegate() process if
e.g. a single key fails to load but we do want to provide details for
debugging in the unexpected failure cases.
This means "example_client -vv download file1.txt" fails like this:
Found trusted root in /home/jku/.local/share/python-tuf-client-example
INFO:tuf.api.metadata:Key
4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb failed
to verify sig: Failed to load PEM key bogus-key-content-here
INFO:tuf.api.metadata:Key 4e777de0d275f9d28588dd9a1606cc748e548f9e22b6795b7cb3f63f98035fcb failed to verify root
Failed to download target x: root was signed by 0/1 keys
Fixes#1875
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
The Document formats section (chapter 4) of the
specification says the following:
"All of the formats described below include the ability to add more
attribute-value fields to objects for backward-compatible format
changes. Implementers who encounter undefined attribute-value pairs in
the format must include the data when calculating hashes or verifying
signatures and must preserve the data when re-serializing."
I initially thought it's applicable only to the SIGNED fields as
"undefined attribute-value pairs in the format must include the data
when calculating hashes or verifying signatures"
This doesn't mean that the sentence before that excludes "Metadata" as a
possible place for additional fields.
The other maintainers agreed with me and we are going to add support for
'unrecognized_fields" inside "Metadata".
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
If a securesystemslib.FormatError is raised inside
Key.from_securesystemslib_key() then reraise ValueError.
This is done so that our users don't have to import securesystemslib
in order to handle the error and because the securesystemslib error
itself is securesystemslib implementation-specific.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
This change updates some obvious and unnecessary fields docs in the
Metadata API with more despriptive details
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
This change unifies as mush as the context allows and improves the
use of definite vs. indefinite vs. no article across docs in the
Metadata API. It sticks to no article in most cases for simplisity
and readability, but leaves definite article where it's strictly
necessary
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
This change unifies wording across docs in the Metadata API, like
Args vs. Arguments and same repetitive descriptions written
differently in different classes/methods
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
This change unifies quotes to double backtick across docs in the
Metadata API in order to provide better visualisation
Signed-off-by: Ivana Atanasova <iyovcheva@vmware.com>
We should handle the possible SerializationError inside
Key.verify_signature(), because the user of this API is not interested
in SerializationError when he is trying to verify his signature.
Note that the SerializationError can be thrown when calling
signed_serializer.serialize() on the metadata signed part.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Document ValueError, KeyError and TypeError exceptions for __init__ and
from_dict() methods in Metadata API.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
It's not obvious to casual reader that reading metadata and then
writing it might not always produce the same file. It's also not
immediately obvious why this matters.
Document both concepts.
Fixes#1392
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
I looked into all changes between our current version 1.0.19 and the
current version of the specification 1.0.28 and I agree with Jussi that
the only one not fully resolved is:
"8dafd00 (tag: v1.0.24) Clarify optional attributes" and more precisely
the changes from commit:
4dd279bc31
It doesn't make sense to have a target file without "paths" or
"path_hash_prefixes", so our `python-tuf requirement to have at least
one of them set makes sense.
Both with Jussi we agreed that we can easily loosen this requirement if
when solving https://github.com/theupdateframework/specification/issues/200
it's decided that both of them can be omitted,
but for now, we decided it's better to stick to our current requirement
to have one of them set.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
I've not supported many renames but I'm suggesting this one:
FetcherHTTPError was created because we needed to signal 403/404
from the fetcher to updater. At that time the download error hierarchy
in general was not thought out.
Now we have a couple of different errors all derived from
DownloadError. I believe it does not make sense to point out "Fetcher"
in one of their names: DownloadHTTPError makes it clearer this is a
specific type of DownloadError.
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
Catch Metadata.sign() securesystemslib exceptions and instead throw
a more general UnsignedMetadataError exception.
We don't want to expose securesystemslib exceptions and it's better
to replace them with a more general exception that could be easily
handled.
As the signer is an argument implementing securesystemslib.signer.Signer
interface we don't know what exception will it throw.
That's why we need to catch all possible exceptions during signing and
raise UnsignedMetadataError.
That is the same reason why we should move the serialization outside
the "try" block, so a tuf.api.serialization.SerializationError can
propagate and warn the user that 'signed' cannot be serialized.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Reexport securesystemslib StorageError, so that our users can catch
it without importing securesystemslib.
The securesystemslib StorageError makes sense in the context of
metadata API, because it supports different storage interfaces and
this exception is denoting all possible errors that could arrise
from using any kind of storage interface.
Additionally, I changed the places where we mention that StorageError
is thrown, so that our users will know they can directly import it
from tuf/api/exceptions.py instead of importing securesystemslib.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
All TUF implementations used to use "1.0" as the spec version and most
of them have never modified that value since.
Accept two-part spec_version for legacy compatibility: it is strictly
speaking against the current spec (which requires semver) but there
should be no harm in doing this and it allows us to deserialize
metadata generated by e.g. go-tuf.
Fixes#1751
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
The lint warning about argument count is useful in general but in these
two cases we want to break the rule: remove TODOs.
Signed-off-by: Jussi Kukkonen <jkukkonen@vmware.com>
After we drop support for python3.6 we can relly that dictionaries
preserve the insertion order:
https://docs.python.org/3.7/whatsnew/3.7.html
This means we can replace the usage of OrderedDict with a standard
dictionaries.
Something we have to keep in mind is that even thought the insertion
order is preserved the equality comparison for normal dicts is
insensitive for normal dicts compared to OrderedDict
For example:
>>> OrderedDict([(1,1), (2,2)]) == OrderedDict([(2,2), (1,1)])
False
>>> dict([(1,1), (2,2)]) == dict([(2,2), (1,1)])
True
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
SerializationError and DeserializationError are both errors coming
from the repository side looking from the clients point of view.
That's why it makes sense to make them repository errors.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
LengthOrHashMismatchError is a thrown when there are problems with
metadata verification or problems from the repository side when looking
it from the user's perspective.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
UnsupportedAlgorithmError is a detailed securesystemslib exception
and there is no need for TUF to redefine it.
Moreover which hash "algorithms" are allowed is work for
securesystemslib not for TUF.
It's only used once inside "Targetfile.from_data()" and there it's used
to denote that there is a problem with the given argument.
That's why this error can be just replaced with "ValueError".
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
ReplayedMetadataError is a subset of
BadVersionNumberError and in a discussion with
Jussi we realized that ReplayedMetadataError can
be replaced by BadVersionNumberError with a
good message.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
URLParsingError is a specific download error and
is not clear what benefit it provides.
It's used only once in the new code and the
message says everything you need to know about
the exception.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Make FetcherHTTPError a DownloadError as the
error itself denotes an error happening during
the download process.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Stop linting tuf/exceptions.py with mypy as we are going to use
tuf/api/exceptions.py for exceptions in the new code.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
Add tuf/api/exceptions.py for exceptions in the new code.
I copied the exceptions from tuf/exceptions.py with a few important
decisions:
1. I only added the exceptions that are used in the new code
2. I removed the general "Error" class as we can directly inherit
Exceptions
3. I tried grouping the exceptions by relevance
4. I removed the second argument "UnsignedMetadataError" as it's only
kept for backward compatibility and is not used
5. I tried following the new code style guidelines and linted the file
with our linters.
Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
This commit adds to the RTD the links references to source code
examples.
The examples are added to TUF ngclient Updater, Metadata and API
reference.
includes a seed for examples/README.md
Signed-off-by: Kairo de Araujo <kdearaujo@vmware.com>
Just came across two instances where line-continued strings missed
a separating whitespace and fixed them.
Note: I also checked the entire repo for more such cases using the
regex `[^ ]["']\n *f?["'][^ ]` but didn't find any.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>
Remove `bump_version()` method, which is just an alias for "+= 1"
on the version attribute. For a slim low-level API it seems okay to
just directly access/modify the attribute.
The extra level of abstraction of "bumping a version" is more
appropriate for a repository library (see #1136).
This patch also removes a related unit test and updates another one
to directly do `(...).version +=`.
Signed-off-by: Lukas Puehringer <lukas.puehringer@nyu.edu>