Skip to content

Commit 2ef07ec

Browse files
authored
Merge pull request #687 from ckyrouac/bound-parse-fix
boundimage: Replace %% with % in bound image spec
2 parents 604dd9c + d4fe356 commit 2ef07ec

File tree

1 file changed

+72
-27
lines changed

1 file changed

+72
-27
lines changed

lib/src/boundimage.rs

Lines changed: 72 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -139,29 +139,37 @@ struct BoundImage {
139139

140140
impl BoundImage {
141141
fn new(image: String, auth_file: Option<String>) -> Result<BoundImage> {
142-
validate_spec_value(&image).context("Invalid image value")?;
142+
let image = parse_spec_value(&image).context("Invalid image value")?;
143143

144-
if let Some(auth_file) = &auth_file {
145-
validate_spec_value(auth_file).context("Invalid auth_file value")?;
146-
}
144+
let auth_file = if let Some(auth_file) = &auth_file {
145+
Some(parse_spec_value(auth_file).context("Invalid auth_file value")?)
146+
} else {
147+
None
148+
};
147149

148150
Ok(BoundImage { image, auth_file })
149151
}
150152
}
151153

152-
fn validate_spec_value(value: &String) -> Result<()> {
153-
let mut number_of_percents = 0;
154-
for char in value.chars() {
155-
if char == '%' {
156-
number_of_percents += 1;
157-
} else if number_of_percents % 2 != 0 {
158-
anyhow::bail!("Systemd specifiers are not supported by bound bootc images: {value}");
159-
} else {
160-
number_of_percents = 0;
154+
fn parse_spec_value(value: &str) -> Result<String> {
155+
let mut it = value.chars();
156+
let mut ret = String::new();
157+
while let Some(c) = it.next() {
158+
if c != '%' {
159+
ret.push(c);
160+
continue;
161+
}
162+
let c = it.next().ok_or_else(|| anyhow::anyhow!("Unterminated %"))?;
163+
match c {
164+
'%' => {
165+
ret.push('%');
166+
}
167+
_ => {
168+
anyhow::bail!("Systemd specifiers are not supported by bound bootc images: {value}")
169+
}
161170
}
162171
}
163-
164-
Ok(())
172+
Ok(ret)
165173
}
166174

167175
#[cfg(test)]
@@ -229,22 +237,59 @@ mod tests {
229237
}
230238

231239
#[test]
232-
fn test_validate_spec_value() -> Result<()> {
233-
//should not return an error with no % characters
234-
let value = String::from("[Image]\nImage=quay.io/foo/foo:latest");
235-
validate_spec_value(&value).unwrap();
240+
fn test_parse_spec_value() -> Result<()> {
241+
//should parse string with no % characters
242+
let value = String::from("quay.io/foo/foo:latest");
243+
assert_eq!(parse_spec_value(&value).unwrap(), value);
244+
245+
//should parse string with % followed by another %
246+
let value = String::from("quay.io/foo/%%foo:latest");
247+
assert_eq!(parse_spec_value(&value).unwrap(), "quay.io/foo/%foo:latest");
248+
249+
//should parse string with multiple separate %%
250+
let value = String::from("quay.io/foo/%%foo:%%latest");
251+
assert_eq!(
252+
parse_spec_value(&value).unwrap(),
253+
"quay.io/foo/%foo:%latest"
254+
);
255+
256+
//should parse the string with %% at the start or end
257+
let value = String::from("%%quay.io/foo/foo:latest%%");
258+
assert_eq!(
259+
parse_spec_value(&value).unwrap(),
260+
"%quay.io/foo/foo:latest%"
261+
);
262+
263+
//should not return an error with multiple %% in a row
264+
let value = String::from("quay.io/foo/%%%%foo:latest");
265+
assert_eq!(
266+
parse_spec_value(&value).unwrap(),
267+
"quay.io/foo/%%foo:latest"
268+
);
236269

237270
//should return error when % is NOT followed by another %
238-
let value = String::from("[Image]\nImage=quay.io/foo/%foo:latest");
239-
assert!(validate_spec_value(&value).is_err());
271+
let value = String::from("quay.io/foo/%foo:latest");
272+
assert!(parse_spec_value(&value).is_err());
273+
274+
//should return an error when %% is followed by a specifier
275+
let value = String::from("quay.io/foo/%%%foo:latest");
276+
assert!(parse_spec_value(&value).is_err());
277+
278+
//should return an error when there are two specifiers
279+
let value = String::from("quay.io/foo/%f%ooo:latest");
280+
assert!(parse_spec_value(&value).is_err());
281+
282+
//should return an error with a specifier at the start
283+
let value = String::from("%fquay.io/foo/foo:latest");
284+
assert!(parse_spec_value(&value).is_err());
240285

241-
//should not return an error when % is followed by another %
242-
let value = String::from("[Image]\nImage=quay.io/foo/%%foo:latest");
243-
validate_spec_value(&value).unwrap();
286+
//should return an error with a specifier at the end
287+
let value = String::from("quay.io/foo/foo:latest%f");
288+
assert!(parse_spec_value(&value).is_err());
244289

245-
//should not return an error when %% is followed by a specifier
246-
let value = String::from("[Image]\nImage=quay.io/foo/%%%foo:latest");
247-
assert!(validate_spec_value(&value).is_err());
290+
//should return an error with a single % at the end
291+
let value = String::from("quay.io/foo/foo:latest%");
292+
assert!(parse_spec_value(&value).is_err());
248293

249294
Ok(())
250295
}

0 commit comments

Comments
 (0)