diff --git a/crates/ostree-ext/src/container/store.rs b/crates/ostree-ext/src/container/store.rs index 449d3db2ec..64943c5bdf 100644 --- a/crates/ostree-ext/src/container/store.rs +++ b/crates/ostree-ext/src/container/store.rs @@ -624,6 +624,24 @@ fn cleanup_root(root: &Dir) -> Result<()> { Ok(()) } +/// Copy `/usr` directory metadata to the root, matching the composefs-rs +/// approach since OCI images don't reliably include root dir metadata. +/// +/// See: +/// - +/// - +fn normalize_root_dirmeta(mt: &ostree::MutableTree) -> Result<()> { + let usr = mt.walk(&["usr"], 0).context("looking up /usr in mtree")?; + + let usr_meta_checksum = usr.metadata_checksum(); + if usr_meta_checksum.is_empty() { + anyhow::bail!("/usr has no metadata checksum in mtree"); + } + + mt.set_metadata_checksum(&usr_meta_checksum); + Ok(()) +} + impl ImageImporter { /// The metadata key used in ostree commit metadata to serialize const CACHED_KEY_MANIFEST_DIGEST: &'static str = "ostree-ext.cached.manifest-digest"; @@ -1307,6 +1325,8 @@ impl ImageImporter { ) .context("Writing merged filesystem to mtree")?; + normalize_root_dirmeta(&mt).context("normalizing root dir metadata on mtree")?; + let merged_root = repo .write_mtree(&mt, cancellable) .context("Writing mtree")?; diff --git a/crates/ostree-ext/tests/it/main.rs b/crates/ostree-ext/tests/it/main.rs index e43aab027b..f11fdebd90 100644 --- a/crates/ostree-ext/tests/it/main.rs +++ b/crates/ostree-ext/tests/it/main.rs @@ -58,6 +58,24 @@ fn assert_err_contains(r: Result, s: impl AsRef) { } } +/// Verify that a commit's root directory metadata matches `/usr`. +fn assert_root_dirmeta_matches_usr(repo: &ostree::Repo, commit: &str) { + let root = repo.read_commit(commit, gio::Cancellable::NONE).unwrap().0; + let root = root.downcast::().unwrap(); + root.ensure_resolved().unwrap(); + + let usr = root.resolve_relative_path("usr"); + let usr = usr.downcast::().unwrap(); + usr.ensure_resolved().unwrap(); + + let root_meta_checksum = root.tree_get_metadata_checksum().unwrap(); + let usr_meta_checksum = usr.tree_get_metadata_checksum().unwrap(); + assert_eq!( + root_meta_checksum, usr_meta_checksum, + "root dir metadata checksum should match /usr" + ); +} + static TEST_REGISTRY: LazyLock = LazyLock::new(|| match std::env::var_os("TEST_REGISTRY") { Some(t) => t.to_str().unwrap().to_owned(), @@ -707,6 +725,7 @@ async fn test_export_as_container_nonderived() -> Result<()> { let reimported = fixture.must_import(&dest).await?; let reimport_ls = fixture::ostree_ls(fixture.destrepo(), &reimported.merge_commit).unwrap(); similar_asserts::assert_eq!(initimport_ls, reimport_ls); + assert_root_dirmeta_matches_usr(fixture.destrepo(), &reimported.merge_commit); Ok(()) } @@ -1558,6 +1577,7 @@ async fn test_non_ostree() -> Result<()> { similar_asserts::assert_eq!(&src_manifest, &dest_manifest); } assert_eq!(imp.manifest_digest, src_digest); + assert_root_dirmeta_matches_usr(fixture.destrepo(), &imp.merge_commit); Ok(()) }