Skip to content

Commit 21c57d4

Browse files
authored
Merge pull request #1310 from rsturla/1308-fails-to-parse-dir
fix(switch): don't attempt to parse non-oci image ref formats
2 parents 84e7e2e + fcfee2a commit 21c57d4

File tree

1 file changed

+65
-18
lines changed

1 file changed

+65
-18
lines changed

lib/src/spec.rs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use std::fmt::Display;
44

5+
use anyhow::Result;
56
use ostree_ext::oci_spec::image::Digest;
67
use ostree_ext::{container::OstreeImageReference, oci_spec};
78
use schemars::JsonSchema;
@@ -91,20 +92,35 @@ pub struct ImageReference {
9192

9293
impl ImageReference {
9394
/// Returns a canonicalized version of this image reference, preferring the digest over the tag if both are present.
94-
pub fn canonicalize(self) -> Result<Self, anyhow::Error> {
95-
let reference: oci_spec::distribution::Reference = self.image.parse()?;
96-
97-
if reference.digest().is_some() && reference.tag().is_some() {
98-
let registry = reference.registry();
99-
let repository = reference.repository();
100-
let digest = reference.digest().expect("digest is present");
101-
return Ok(ImageReference {
102-
image: format!("{registry}/{repository}@{digest}"),
103-
..self
104-
});
95+
pub fn canonicalize(self) -> Result<Self> {
96+
match self.transport.as_str() {
97+
"containers-storage" | "registry" | "oci" => {
98+
let reference: oci_spec::distribution::Reference = self.image.parse()?;
99+
100+
// No tag? Just pass through.
101+
if reference.tag().is_none() {
102+
return Ok(self);
103+
}
104+
105+
// No digest? Also pass through.
106+
let Some(digest) = reference.digest() else {
107+
return Ok(self);
108+
};
109+
110+
let registry = reference.registry();
111+
let repository = reference.repository();
112+
let r = ImageReference {
113+
image: format!("{registry}/{repository}@{digest}"),
114+
transport: self.transport.clone(),
115+
signature: self.signature.clone(),
116+
};
117+
return Ok(r);
118+
}
119+
_ => {
120+
// For other transports, we don't do any canonicalization
121+
Ok(self)
122+
}
105123
}
106-
107-
Ok(self)
108124
}
109125
}
110126

@@ -276,53 +292,84 @@ mod tests {
276292
fn test_image_reference_canonicalize() {
277293
let sample_digest =
278294
"sha256:5db6d8b5f34d3cbdaa1e82ed0152a5ac980076d19317d4269db149cbde057bb2";
295+
279296
let test_cases = [
280297
// When both a tag and digest are present, the digest should be used
281298
(
282299
format!("quay.io/example/someimage:latest@{}", sample_digest),
283300
format!("quay.io/example/someimage@{}", sample_digest),
301+
"registry",
302+
),
303+
(
304+
format!("quay.io/example/someimage:latest@{}", sample_digest),
305+
format!("quay.io/example/someimage@{}", sample_digest),
306+
"containers-storage",
307+
),
308+
(
309+
format!("quay.io/example/someimage:latest@{}", sample_digest),
310+
format!("quay.io/example/someimage@{}", sample_digest),
311+
"oci",
284312
),
285313
// When only a digest is present, it should be used
286314
(
287315
format!("quay.io/example/someimage@{}", sample_digest),
288316
format!("quay.io/example/someimage@{}", sample_digest),
317+
"registry",
289318
),
290319
// When only a tag is present, it should be preserved
291320
(
292321
"quay.io/example/someimage:latest".to_string(),
293322
"quay.io/example/someimage:latest".to_string(),
323+
"registry",
294324
),
295325
// When no tag or digest is present, preserve the original image name
296326
(
297327
"quay.io/example/someimage".to_string(),
298328
"quay.io/example/someimage".to_string(),
329+
"registry",
299330
),
300331
// When used with a local image (i.e. from containers-storage), the functionality should
301332
// be the same as previous cases
302333
(
303334
"localhost/someimage:latest".to_string(),
304335
"localhost/someimage:latest".to_string(),
336+
"registry",
305337
),
306338
(
307339
format!("localhost/someimage:latest@{sample_digest}"),
308340
format!("localhost/someimage@{sample_digest}"),
341+
"registry",
342+
),
343+
// OCI Archive / Dir should be preserved, and canonicalize should be a no-op
344+
(
345+
"/tmp/repo".to_string(),
346+
"/tmp/repo".to_string(),
347+
"oci-archive",
348+
),
349+
(
350+
"/tmp/image-dir".to_string(),
351+
"/tmp/image-dir".to_string(),
352+
"dir",
309353
),
310354
];
311355

312-
for (initial, expected) in test_cases {
356+
for (initial, expected, transport) in test_cases {
313357
let imgref = ImageReference {
314358
image: initial.to_string(),
315-
transport: "registry".to_string(),
359+
transport: transport.to_string(),
316360
signature: None,
317361
};
318362

319363
let canonicalized = imgref.canonicalize();
320364
if let Err(e) = canonicalized {
321-
panic!("Failed to canonicalize {initial}: {e}");
365+
panic!("Failed to canonicalize {initial} with transport {transport}: {e}");
322366
}
323367
let canonicalized = canonicalized.unwrap();
324-
assert_eq!(canonicalized.image, expected);
325-
assert_eq!(canonicalized.transport, "registry");
368+
assert_eq!(
369+
canonicalized.image, expected,
370+
"Mismatch for transport {transport}"
371+
);
372+
assert_eq!(canonicalized.transport, transport);
326373
assert_eq!(canonicalized.signature, None);
327374
}
328375
}

0 commit comments

Comments
 (0)