mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 15:45:53 +01:00
Merge pull request #1339 from champtar/repro
ostree-ext: make OCI history reproducible
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -301,6 +301,7 @@ name = "bootc-utils"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"rustix 1.0.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -535,7 +535,7 @@ impl InstallAleph {
|
||||
l.get(oci_spec::image::ANNOTATION_CREATED)
|
||||
.map(|s| s.as_str())
|
||||
})
|
||||
.and_then(crate::status::try_deserialize_timestamp);
|
||||
.and_then(bootc_utils::try_deserialize_timestamp);
|
||||
let r = InstallAleph {
|
||||
image: src_imageref.imgref.name.clone(),
|
||||
version: imgstate.version().as_ref().map(|s| s.to_string()),
|
||||
|
||||
@@ -102,16 +102,6 @@ pub(crate) struct Deployments {
|
||||
pub(crate) other: VecDeque<ostree::Deployment>,
|
||||
}
|
||||
|
||||
pub(crate) fn try_deserialize_timestamp(t: &str) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
match chrono::DateTime::parse_from_rfc3339(t).context("Parsing timestamp") {
|
||||
Ok(t) => Some(t.into()),
|
||||
Err(e) => {
|
||||
tracing::warn!("Invalid timestamp in image: {:#}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn labels_of_config(
|
||||
config: &oci_spec::image::ImageConfiguration,
|
||||
) -> Option<&std::collections::HashMap<String, String>> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::Result;
|
||||
|
||||
use ostree_ext::container as ostree_container;
|
||||
use ostree_ext::oci_spec;
|
||||
@@ -52,7 +52,7 @@ fn create_imagestatus(
|
||||
.map(|s| s.as_str())
|
||||
})
|
||||
.or_else(|| config.created().as_deref())
|
||||
.and_then(try_deserialize_timestamp);
|
||||
.and_then(bootc_utils::try_deserialize_timestamp);
|
||||
|
||||
let version = ostree_container::version_for_config(config).map(ToOwned::to_owned);
|
||||
let architecture = config.architecture().to_string();
|
||||
@@ -70,13 +70,3 @@ fn labels_of_config(
|
||||
) -> Option<&std::collections::HashMap<String, String>> {
|
||||
config.config().as_ref().and_then(|c| c.labels().as_ref())
|
||||
}
|
||||
|
||||
fn try_deserialize_timestamp(t: &str) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
match chrono::DateTime::parse_from_rfc3339(t).context("Parsing timestamp") {
|
||||
Ok(t) => Some(t.into()),
|
||||
Err(e) => {
|
||||
tracing::warn!("Invalid timestamp in image: {:#}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,8 +133,20 @@ pub(crate) fn export_chunked(
|
||||
.uncompressed_sha256
|
||||
.clone();
|
||||
|
||||
let created = imgcfg
|
||||
.created()
|
||||
.as_deref()
|
||||
.and_then(bootc_utils::try_deserialize_timestamp)
|
||||
.unwrap_or_default();
|
||||
// Add the ostree layer
|
||||
ociw.push_layer(manifest, imgcfg, ostree_layer, description, None);
|
||||
ociw.push_layer_full(
|
||||
manifest,
|
||||
imgcfg,
|
||||
ostree_layer,
|
||||
None::<HashMap<String, String>>,
|
||||
description,
|
||||
created,
|
||||
);
|
||||
// Add the component/content layers
|
||||
let mut buf = [0; 8];
|
||||
let sep = COMPONENT_SEPARATOR.encode_utf8(&mut buf);
|
||||
@@ -142,12 +154,13 @@ pub(crate) fn export_chunked(
|
||||
let mut annotation_component_layer = HashMap::new();
|
||||
packages.sort();
|
||||
annotation_component_layer.insert(CONTENT_ANNOTATION.to_string(), packages.join(sep));
|
||||
ociw.push_layer(
|
||||
ociw.push_layer_full(
|
||||
manifest,
|
||||
imgcfg,
|
||||
layer,
|
||||
name.as_str(),
|
||||
Some(annotation_component_layer),
|
||||
name.as_str(),
|
||||
created,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1490,12 +1490,22 @@ pub(crate) fn export_to_oci(
|
||||
.get(i)
|
||||
.and_then(|h| h.comment().as_deref())
|
||||
.unwrap_or_default();
|
||||
dest_oci.push_layer(
|
||||
|
||||
let previous_created = srcinfo
|
||||
.configuration
|
||||
.history()
|
||||
.get(i)
|
||||
.and_then(|h| h.created().as_deref())
|
||||
.and_then(bootc_utils::try_deserialize_timestamp)
|
||||
.unwrap_or_default();
|
||||
|
||||
dest_oci.push_layer_full(
|
||||
&mut new_manifest,
|
||||
&mut new_config,
|
||||
layer,
|
||||
previous_description,
|
||||
previous_annotations,
|
||||
previous_description,
|
||||
previous_created,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ use ocidir::cap_std::fs::{DirBuilder, DirBuilderExt as _};
|
||||
use ocidir::oci_spec::image::ImageConfigurationBuilder;
|
||||
use regex::Regex;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
use std::fmt::Write as _;
|
||||
use std::io::{self, Write};
|
||||
@@ -1014,8 +1015,20 @@ impl NonOstreeFixture {
|
||||
let bw = bw.into_inner()?;
|
||||
let new_layer = bw.complete()?;
|
||||
|
||||
self.src_oci
|
||||
.push_layer(&mut manifest, &mut config, new_layer, "root", None);
|
||||
let created = config
|
||||
.created()
|
||||
.as_deref()
|
||||
.and_then(bootc_utils::try_deserialize_timestamp)
|
||||
.unwrap_or_default();
|
||||
|
||||
self.src_oci.push_layer_full(
|
||||
&mut manifest,
|
||||
&mut config,
|
||||
new_layer,
|
||||
None::<HashMap<String, String>>,
|
||||
"root",
|
||||
created,
|
||||
);
|
||||
let config = self.src_oci.write_config(config)?;
|
||||
|
||||
manifest.set_config(config);
|
||||
|
||||
@@ -8,6 +8,7 @@ repository = "https://github.com/bootc-dev/bootc"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
chrono = { workspace = true, features = ["std"] }
|
||||
rustix = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
@@ -8,5 +8,7 @@ mod path;
|
||||
pub use path::*;
|
||||
mod iterators;
|
||||
pub use iterators::*;
|
||||
mod timestamp;
|
||||
pub use timestamp::*;
|
||||
mod tracing_util;
|
||||
pub use tracing_util::*;
|
||||
|
||||
13
utils/src/timestamp.rs
Normal file
13
utils/src/timestamp.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use anyhow::Context;
|
||||
use chrono;
|
||||
|
||||
/// Try to parse an RFC 3339, warn on error.
|
||||
pub fn try_deserialize_timestamp(t: &str) -> Option<chrono::DateTime<chrono::Utc>> {
|
||||
match chrono::DateTime::parse_from_rfc3339(t).context("Parsing timestamp") {
|
||||
Ok(t) => Some(t.into()),
|
||||
Err(e) => {
|
||||
tracing::warn!("Invalid timestamp in image: {:#}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user