Skip to content

Commit 8534350

Browse files
authored
Merge pull request #1595 from jvanz/issue1547
fix(kwctl): normalize registry:// URIs to include explicit tag
2 parents 2dda15b + 0ca0172 commit 8534350

2 files changed

Lines changed: 51 additions & 11 deletions

File tree

crates/kwctl/src/main.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::{
2222
},
2323
load::load,
2424
save::save,
25-
utils::{LookupError, find_file_matching_file},
25+
utils::{LookupError, find_file_matching_file, normalize_uri},
2626
};
2727

2828
mod annotate;
@@ -119,7 +119,8 @@ async fn main() -> Result<()> {
119119
Some("info") => info::info(),
120120
Some("pull") => {
121121
if let Some(matches) = matches.subcommand_matches("pull") {
122-
let uri = matches.get_one::<String>("uri").unwrap();
122+
let uri = normalize_uri(matches.get_one::<String>("uri").unwrap());
123+
let uri = &uri;
123124
let destination = matches
124125
.get_one::<String>("output-path")
125126
.map(|output| PathBuf::from_str(output).unwrap());
@@ -133,7 +134,8 @@ async fn main() -> Result<()> {
133134
}
134135
Some("verify") => {
135136
if let Some(matches) = matches.subcommand_matches("verify") {
136-
let uri = matches.get_one::<String>("uri").unwrap();
137+
let uri = normalize_uri(matches.get_one::<String>("uri").unwrap());
138+
let uri = uri.as_str();
137139
let sources = remote_server_options(matches)?;
138140
let verification_options = build_verification_options(matches)?
139141
.ok_or_else(|| anyhow!("could not retrieve sigstore options"))?;
@@ -193,8 +195,9 @@ async fn main() -> Result<()> {
193195
}
194196
Some("rm") => {
195197
if let Some(matches) = matches.subcommand_matches("rm") {
196-
let uri_or_sha_prefix = matches.get_one::<String>("uri_or_sha_prefix").unwrap();
197-
rm::rm(uri_or_sha_prefix)?;
198+
let uri_or_sha_prefix =
199+
normalize_uri(matches.get_one::<String>("uri_or_sha_prefix").unwrap());
200+
rm::rm(&uri_or_sha_prefix)?;
198201
}
199202
Ok(())
200203
}
@@ -233,7 +236,8 @@ async fn main() -> Result<()> {
233236
}
234237
Some("inspect") => {
235238
if let Some(matches) = matches.subcommand_matches("inspect") {
236-
let uri_or_sha_prefix = matches.get_one::<String>("uri_or_sha_prefix").unwrap();
239+
let uri_or_sha_prefix =
240+
normalize_uri(matches.get_one::<String>("uri_or_sha_prefix").unwrap());
237241
let output = inspect::OutputType::try_from(
238242
matches.get_one::<String>("output").map(|s| s.as_str()),
239243
)?;
@@ -242,7 +246,7 @@ async fn main() -> Result<()> {
242246
.get_one::<bool>("show-signatures")
243247
.unwrap_or(&false)
244248
.to_owned();
245-
inspect::inspect(uri_or_sha_prefix, output, sources, no_color, no_signatures)
249+
inspect::inspect(&uri_or_sha_prefix, output, sources, no_color, no_signatures)
246250
.await?;
247251
};
248252
Ok(())
@@ -446,7 +450,8 @@ async fn pull_command(
446450
* This function will pull the policy if it is not already present in the local store.
447451
*/
448452
async fn scaffold_manifest_command(matches: &ArgMatches) -> Result<()> {
449-
let uri_or_sha_prefix = matches.get_one::<String>("uri_or_sha_prefix").unwrap();
453+
let uri_or_sha_prefix = normalize_uri(matches.get_one::<String>("uri_or_sha_prefix").unwrap());
454+
let uri_or_sha_prefix = uri_or_sha_prefix.as_str();
450455

451456
pull_if_needed(uri_or_sha_prefix, matches).await?;
452457

crates/kwctl/src/utils.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,23 @@ pub(crate) enum LookupError {
2424
IoError(#[from] std::io::Error),
2525
}
2626

27+
/// Normalizes a `registry://` URI to include an explicit tag.
28+
/// If no tag is specified, defaults to `:latest`, making the URI consistent
29+
/// with how the local store paths are keyed.
30+
/// Non-registry URIs (e.g. `file://`, `http://`) are returned unchanged.
31+
pub(crate) fn normalize_uri(uri: &str) -> String {
32+
if let Some(image) = uri.strip_prefix("registry://")
33+
&& let Ok(reference) = Reference::from_str(image)
34+
{
35+
return format!("registry://{}", reference.whole());
36+
}
37+
uri.to_string()
38+
}
39+
2740
pub(crate) fn map_path_to_uri(uri_or_sha_prefix: &str) -> std::result::Result<String, LookupError> {
2841
let uri_has_schema = Regex::new(r"^\w+://").unwrap();
2942
if uri_has_schema.is_match(uri_or_sha_prefix) {
30-
return Ok(String::from(uri_or_sha_prefix));
43+
return Ok(normalize_uri(uri_or_sha_prefix));
3144
}
3245

3346
let path = PathBuf::from(uri_or_sha_prefix);
@@ -46,8 +59,9 @@ pub(crate) fn map_path_to_uri(uri_or_sha_prefix: &str) -> std::result::Result<St
4659
}
4760

4861
pub(crate) fn get_uri(uri_or_sha_prefix: &String) -> std::result::Result<String, LookupError> {
49-
map_path_to_uri(uri_or_sha_prefix).or_else(|_| {
50-
Reference::from_str(uri_or_sha_prefix)
62+
let normalized = normalize_uri(uri_or_sha_prefix);
63+
map_path_to_uri(&normalized).or_else(|_| {
64+
Reference::from_str(&normalized)
5165
.map(|oci_reference| format!("registry://{}", oci_reference.whole()))
5266
.map_err(|_| LookupError::PolicyMissing(uri_or_sha_prefix.to_string()))
5367
})
@@ -103,8 +117,29 @@ pub(crate) fn find_file_matching_file(possible_names: &[&str]) -> Option<PathBuf
103117
mod tests {
104118
use std::collections::HashMap;
105119

120+
use rstest::rstest;
121+
106122
use super::*;
107123

124+
#[rstest]
125+
#[case(
126+
"registry://ghcr.io/kubewarden/policies/pod-privileged",
127+
"registry://ghcr.io/kubewarden/policies/pod-privileged:latest"
128+
)]
129+
#[case(
130+
"registry://ghcr.io/kubewarden/policies/pod-privileged:v0.2.2",
131+
"registry://ghcr.io/kubewarden/policies/pod-privileged:v0.2.2"
132+
)]
133+
#[case(
134+
"registry://ghcr.io/kubewarden/policies/pod-privileged@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
135+
"registry://ghcr.io/kubewarden/policies/pod-privileged@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
136+
)]
137+
#[case("file:///some/path/policy.wasm", "file:///some/path/policy.wasm")]
138+
#[case("https://example.com/policy.wasm", "https://example.com/policy.wasm")]
139+
fn test_normalize_uri(#[case] input: &str, #[case] expected: &str) {
140+
assert_eq!(normalize_uri(input), expected);
141+
}
142+
108143
#[test]
109144
fn test_map_path_to_uri_remote_scheme() -> Result<()> {
110145
assert_eq!(

0 commit comments

Comments
 (0)