Repository navigation
Conversation
sigstore-tuf now follows the workspace version and goes to 1.0 with the other crates. - Rename the HTTP transport feature from fetch to client, matching rekor and tsa. - Error: drop the unused InvalidSignatureEncoding and InvalidTimestamp variants (no more hex or jiff error types in the API), give Transport an optional source, and add Io, NotRefreshed and TargetNotFound in place of stringly Malformed/Transport uses. - Role expiry is a jiff::Timestamp parsed with the metadata; Role is sealed and is_expired no longer returns a Result. - Mark the metadata, key and UpdaterConfig structs #[non_exhaustive]; max_root_rotations is a u32 like max_delegations. - MetadataStore::load returns Result<Option<_>> so stores can report I/O errors; the Updater logs them and treats them as cache misses. - Rename Updater::get_targetinfo to get_target_info; download_target takes &self. - Share one length/hash check between metadata and targets, and guard the root version increment against overflow. - trust-root keeps the tuf error's source chain in its messages. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Wolf Vollprecht <w.vollprecht@gmail.com>
jku
left a comment
There was a problem hiding this comment.
Couple of things that maybe could be changed (or I could be mistaken), otherwise lgtm
| } | ||
| } | ||
|
|
||
| pub(crate) fn io(context: impl Into<String>, source: std::io::Error) -> Self { |
There was a problem hiding this comment.
I assume from transport() that this should be pub as well:
| pub(crate) fn io(context: impl Into<String>, source: std::io::Error) -> Self { | |
| pub fn io(context: impl Into<String>, source: std::io::Error) -> Self { |
There was a problem hiding this comment.
Yes, MetadataStore is public, so outside implementations need it. Made pub in 4c5a223.
| fn error_chain(error: &sigstore_tuf::Error) -> String { | ||
| let mut message = error.to_string(); | ||
| let mut source = std::error::Error::source(error); | ||
| while let Some(cause) = source { | ||
| message.push_str(": "); | ||
| message.push_str(&cause.to_string()); | ||
| source = cause.source(); | ||
| } | ||
| message | ||
| } |
There was a problem hiding this comment.
gemini tells me this combined with Io and Transport in errors.rs leads to inconsistent Display vs. Error::source():
- When error_chain walks .source(), it appends : {cause} onto error.to_string(). For Error::Io, Error::Json, and Error::Crypto, the cause is rendered twice (e.g., "reading /path/timestamp.json: permission denied: permission denied")
- Callers like conformance_client.rs:234 that format sigstore_tuf::Error with {e} or %e lose the underlying reqwest::Error / url::ParseError on Error::Transport.
I did not confirm this myself but maybe you can tell your ai what my ai said?
There was a problem hiding this comment.
Your AI was right on both counts. Io, Json and Crypto put the cause in Display and returned it from source(), while Transport only did the latter. Fixed in 4c5a223 with one rule for every variant: Display describes only the error itself, and the cause is reached through source(). The warn! logs in client.rs and conformance_client now print the full chain, so nothing is lost or duplicated. I also added a regression test.
|
I also noticed some related nits in our feature checking ... but I think that could maybe use a general refactor so I'll look into that in a separate PR |
Error::Io, Json and Crypto repeated their cause in Display while also returning it from source(), so chain renderers printed it twice. Display now describes only the error itself; causes come through source(). Internal warn! logs and the conformance example render the full chain. Error::io is now public so MetadataStore implementations can build Error::Io values.
sigstore-tufwas going to stay on 0.x. This PR reviews and finishes its API instead, so it can go to 1.0 with the rest of the workspace. The verification logic is unchanged. The changes are to the public surface and error reporting, plus two small hardening fixes.Versioning
sigstore-tufusesversion.workspace, and the release-plz note about keeping it on 0.x is removed.API changes
fetchis renamed toclient, matchingsigstore-rekorandsigstore-tsa.rustlsandnative-tlsenable it, as in those crates.Error:InvalidSignatureEncoding, which was never constructed, andInvalidTimestamp. The public API no longer exposeshex::FromHexErrororjiff::Error.Transportis now{ message, source }, so the reqwest error is kept as a source instead of being formatted into the message.Error::transport()andError::transport_with_source()are for customRepositoryimplementations.Io { context, source }for store I/O, which was reported asTransportbefore.NotRefreshedandTargetNotFound(path), both reported asMalformedbefore.Expired.expiresis ajiff::Timestamp.expiresonRoot,Timestamp,SnapshotandTargetsis ajiff::Timestamp, parsed with the metadata.Roleis sealed,Role::expires()returns the timestamp, andis_expired()returns abool.Key,KeyValandSignatureare now#[non_exhaustive], so fields from future spec versions can be added.UpdaterConfig: now#[non_exhaustive]. Start fromdefault()and set fields.max_root_rotationsis au32, likemax_delegations.MetadataStore::load: returnsResult<Option<Vec<u8>>>, so a store can report I/O errors and not only misses.FileStorereturnsOk(None)only forNotFound. TheUpdaterlogs read errors and treats them as cache misses. Everything it loads is re-verified anyway.StoreRepositorypasses the errors through.Updater:get_targetinfois renamed toget_target_info, anddownload_targettakes&self.Fixes
update_rootuseschecked_addfortrusted + 1. Before, a pinned root at versionu64::MAXwould panic in debug builds.max_delegationsdocs said it bounds tree depth. It actually bounds the number of roles visited, as in python-tuf.Downstream
sigstore-trust-rootflattens tuf errors intoError::Tuf(String). It now renders the whole source chain, so HTTP and I/O causes still show up in its messages.Testing
clippy --workspace --all-targets --all-features -D warningsand rustdoc with-D warningsare clean.sigstore-tufbuilds with--no-default-features, andsigstore-trust-rootbuilds with onlytuf.Expirederror,NotRefreshedandTargetNotFound.expiresparsing against the reference vectors.Signed-off-by: Wolf Vollprecht w.vollprecht@gmail.com
🤖 Generated with Claude Code