From f0f30d950732acdc39811505d01e9784fad572e0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 23 Sep 2022 04:49:05 +0000 Subject: [PATCH] Treat spec_version `1.0.0` as valid In #377, @lukesteensen noticed that we created metadata with the wrong spec version. We used `1.0`, but the proper form is `1.0.0`. Unfortunately landing this fix will be non-trivial, since old versions of rust-tuf will error out if the spec version is not `1.0`. As a stopgap, this patch changes rust-tuf to allow either a spec version of `1.0` or `1.0.0` so that we can switch to the proper schem once all the old clients have upgraded, or we come up with another way to gracefully perform this migration. --- tuf/src/interchange/cjson/shims.rs | 40 +++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/tuf/src/interchange/cjson/shims.rs b/tuf/src/interchange/cjson/shims.rs index 9b125e9..db7a4ff 100644 --- a/tuf/src/interchange/cjson/shims.rs +++ b/tuf/src/interchange/cjson/shims.rs @@ -10,6 +10,14 @@ use crate::Result; const SPEC_VERSION: &str = "1.0"; +// Ensure the given spec version matches our spec version. +// +// We also need to handle the literal "1.0" here, despite that fact that it is not a valid version +// according to the SemVer spec, because it is already baked into some of the old roots. +fn valid_spec_version(other: &str) -> bool { + matches!(other, "1.0" | "1.0.0") +} + fn parse_datetime(ts: &str) -> Result> { Utc.datetime_from_str(ts, "%FT%TZ") .map_err(|e| Error::Encoding(format!("Can't parse DateTime: {:?}", e))) @@ -70,7 +78,7 @@ impl RootMetadata { ))); } - if self.spec_version != SPEC_VERSION { + if !valid_spec_version(&self.spec_version) { return Err(Error::Encoding(format!( "Unknown spec version {}", self.spec_version @@ -184,7 +192,7 @@ impl TimestampMetadata { ))); } - if self.spec_version != SPEC_VERSION { + if !valid_spec_version(&self.spec_version) { return Err(Error::Encoding(format!( "Unknown spec version {}", self.spec_version @@ -233,7 +241,7 @@ impl SnapshotMetadata { ))); } - if self.spec_version != SPEC_VERSION { + if !valid_spec_version(&self.spec_version) { return Err(Error::Encoding(format!( "Unknown spec version {}", self.spec_version @@ -299,7 +307,7 @@ impl TargetsMetadata { ))); } - if self.spec_version != SPEC_VERSION { + if !valid_spec_version(&self.spec_version) { return Err(Error::Encoding(format!( "Unknown spec version {}", self.spec_version @@ -570,3 +578,27 @@ mod deserialize_reject_duplicates { }) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn spec_version_validation() { + let valid_spec_versions = ["1.0.0", "1.0"]; + + for version in valid_spec_versions { + assert!(valid_spec_version(version), "{:?} should be valid", version); + } + + let invalid_spec_versions = ["1.0.1", "1.1.0", "2.0.0", "3.0"]; + + for version in invalid_spec_versions { + assert!( + !valid_spec_version(version), + "{:?} should be invalid", + version + ); + } + } +}