Skip to content

Commit 1d8cf09

Browse files
cgwaltersjeckersb
authored andcommitted
lib: Set user agent header for container image pulls
This allows registries to distinguish "image pulls for bootc client runs" from other skopeo/containers-image users. The user agent will be in the format "bootc/<version> skopeo/<version>". All places in bootc that create ImageProxyConfig now use a new helper function that sets the user_agent_prefix field. Closes: #1686 Assisted-by: OpenCode (Sonnet 4) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 21babe7 commit 1d8cf09

11 files changed

Lines changed: 292 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/lib/src/bootc_composefs/status.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ fn get_sorted_type1_boot_entries_helper(
214214
pub(crate) async fn get_container_manifest_and_config(
215215
imgref: &String,
216216
) -> Result<ImgConfigManifest> {
217-
let config = containers_image_proxy::ImageProxyConfig::default();
217+
let config = crate::deploy::new_proxy_config();
218218
let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?;
219219

220220
let img = proxy

crates/lib/src/boundimage.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ pub(crate) fn query_bound_images(root: &Dir) -> Result<Vec<BoundImage>> {
121121
impl ResolvedBoundImage {
122122
#[context("resolving bound image {}", src.image)]
123123
pub(crate) async fn from_image(src: &BoundImage) -> Result<Self> {
124-
let proxy = containers_image_proxy::ImageProxy::new().await?;
124+
let config = crate::deploy::new_proxy_config();
125+
let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?;
125126
let img = proxy
126127
.open_image(&format!("containers-storage:{}", src.image))
127128
.await?;

crates/lib/src/cli.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use ostree_ext::composefs::fsverity;
2626
use ostree_ext::composefs::fsverity::FsVerityHashValue;
2727
use ostree_ext::composefs::splitstream::SplitStreamWriter;
2828
use ostree_ext::container as ostree_container;
29-
use ostree_ext::containers_image_proxy::ImageProxyConfig;
29+
3030
use ostree_ext::keyfileext::KeyFileExt;
3131
use ostree_ext::ostree;
3232
use ostree_ext::sysroot::SysrootLock;
@@ -1554,7 +1554,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
15541554
} => {
15551555
let (_td_guard, repo) = new_temp_composefs_repo()?;
15561556

1557-
let mut proxycfg = ImageProxyConfig::default();
1557+
let mut proxycfg = crate::deploy::new_proxy_config();
15581558

15591559
let image = if let Some(image) = image {
15601560
image

crates/lib/src/deploy.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,17 @@ use crate::utils::async_task_with_spinner;
3232
// TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a
3333
const BASE_IMAGE_PREFIX: &str = "ostree/container/baseimage/bootc";
3434

35+
/// Create an ImageProxyConfig with bootc's user agent prefix set.
36+
///
37+
/// This allows registries to distinguish "image pulls for bootc client runs"
38+
/// from other skopeo/containers-image users.
39+
pub(crate) fn new_proxy_config() -> ostree_ext::containers_image_proxy::ImageProxyConfig {
40+
ostree_ext::containers_image_proxy::ImageProxyConfig {
41+
user_agent_prefix: Some(format!("bootc/{}", env!("CARGO_PKG_VERSION"))),
42+
..Default::default()
43+
}
44+
}
45+
3546
/// Set on an ostree commit if this is a derived commit
3647
const BOOTC_DERIVED_KEY: &str = "bootc.derived";
3748

@@ -87,7 +98,7 @@ pub(crate) async fn new_importer(
8798
repo: &ostree::Repo,
8899
imgref: &ostree_container::OstreeImageReference,
89100
) -> Result<ostree_container::store::ImageImporter> {
90-
let config = Default::default();
101+
let config = new_proxy_config();
91102
let mut imp = ostree_container::store::ImageImporter::new(repo, imgref, config).await?;
92103
imp.require_bootable();
93104
Ok(imp)
@@ -460,7 +471,7 @@ pub(crate) async fn prepare_for_pull_unified(
460471
let ostree_imgref = OstreeImageReference::from(containers_storage_imgref);
461472

462473
// Configure the importer to use bootc storage as an additional image store
463-
let mut config = ostree_ext::containers_image_proxy::ImageProxyConfig::default();
474+
let mut config = new_proxy_config();
464475
let mut cmd = Command::new("skopeo");
465476
// Use the physical path to bootc storage from the Storage struct
466477
let storage_path = format!(
@@ -1248,6 +1259,23 @@ pub(crate) fn fixup_etc_fstab(root: &Dir) -> Result<()> {
12481259
mod tests {
12491260
use super::*;
12501261

1262+
#[test]
1263+
fn test_new_proxy_config_user_agent() {
1264+
let config = new_proxy_config();
1265+
let prefix = config
1266+
.user_agent_prefix
1267+
.expect("user_agent_prefix should be set");
1268+
assert!(
1269+
prefix.starts_with("bootc/"),
1270+
"User agent should start with bootc/"
1271+
);
1272+
// Verify the version is present (not just "bootc/")
1273+
assert!(
1274+
prefix.len() > "bootc/".len(),
1275+
"Version should be present after bootc/"
1276+
);
1277+
}
1278+
12511279
#[test]
12521280
fn test_switch_inplace() -> Result<()> {
12531281
use cap_std::fs::DirBuilderExt;

crates/lib/src/install.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ async fn install_container(
938938
}
939939
};
940940

941-
let proxy_cfg = ostree_container::store::ImageProxyConfig::default();
941+
let proxy_cfg = crate::deploy::new_proxy_config();
942942
(src_imageref, Some(proxy_cfg))
943943
};
944944
let src_imageref = ostree_container::OstreeImageReference {

crates/ostree-ext/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ xshell = { workspace = true, optional = true }
4141

4242
# Crate-specific dependencies
4343
comfy-table = "7.1.1"
44-
containers-image-proxy = "0.9.0"
44+
containers-image-proxy = "0.9.1"
4545
flate2 = { features = ["zlib"], default-features = false, version = "1.0.20" }
4646
futures-util = "0.3.13"
4747
gvariant = "0.5.0"

crates/xtask/src/tmt.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ pub(crate) fn update_integration() -> Result<()> {
865865
// Define tests in order
866866
let mut tests = vec![];
867867

868-
// Scan for test-*.nu and test-*.sh files in tmt/tests/booted/
868+
// Scan for test-*.nu, test-*.sh, and test-*.py files in tmt/tests/booted/
869869
let booted_dir = Utf8Path::new("tmt/tests/booted");
870870

871871
for entry in std::fs::read_dir(booted_dir)? {
@@ -876,10 +876,11 @@ pub(crate) fn update_integration() -> Result<()> {
876876
};
877877

878878
// Extract stem (filename without "test-" prefix and extension)
879-
let Some(stem) = filename
880-
.strip_prefix("test-")
881-
.and_then(|s| s.strip_suffix(".nu").or_else(|| s.strip_suffix(".sh")))
882-
else {
879+
let Some(stem) = filename.strip_prefix("test-").and_then(|s| {
880+
s.strip_suffix(".nu")
881+
.or_else(|| s.strip_suffix(".sh"))
882+
.or_else(|| s.strip_suffix(".py"))
883+
}) else {
883884
continue;
884885
};
885886

@@ -908,16 +909,16 @@ pub(crate) fn update_integration() -> Result<()> {
908909
.with_context(|| format!("Failed to get relative path for {}", filename))?;
909910

910911
// Determine test command based on file extension
911-
let extension = if filename.ends_with(".nu") {
912-
"nu"
912+
let test_command = if filename.ends_with(".nu") {
913+
format!("nu {}", relative_path.display())
913914
} else if filename.ends_with(".sh") {
914-
"bash"
915+
format!("bash {}", relative_path.display())
916+
} else if filename.ends_with(".py") {
917+
format!("python3 {}", relative_path.display())
915918
} else {
916919
anyhow::bail!("Unsupported test file extension: {}", filename);
917920
};
918921

919-
let test_command = format!("{} {}", extension, relative_path.display());
920-
921922
// Check if test wants bind storage
922923
let try_bind_storage = metadata
923924
.extra

tmt/plans/integration.fmf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,11 @@ execute:
166166
how: fmf
167167
test:
168168
- /tmt/tests/tests/test-33-bib-build
169+
170+
/plan-34-user-agent:
171+
summary: Verify bootc sends correct User-Agent header to registries
172+
discover:
173+
how: fmf
174+
test:
175+
- /tmt/tests/tests/test-34-user-agent
169176
# END GENERATED PLANS

0 commit comments

Comments
 (0)