diff --git a/Dockerfile b/Dockerfile index 499c7199b..48232c761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -83,18 +83,9 @@ ARG rootfs="" RUN --mount=type=bind,from=packaging,target=/run/packaging /run/packaging/configure-rootfs "${variant}" "${rootfs}" COPY --from=packaging /usr-extras/ /usr/ -# Default target for source builds (just build) -# Installs packages from the internal build stage +# Final target: installs pre-built packages from /run/packages volume mount. +# Use with: podman build --target=final -v path/to/packages:/run/packages:ro FROM final-common as final -RUN --mount=type=bind,from=packaging,target=/run/packaging \ - --mount=type=bind,from=build,target=/build-output \ - --network=none \ - /run/packaging/install-rpm-and-setup /build-output/out -RUN bootc container lint --fatal-warnings - -# Alternative target for pre-built packages (CI workflow) -# Use with: podman build --target=final-from-packages -v path/to/packages:/run/packages:ro -FROM final-common as final-from-packages RUN --mount=type=bind,from=packaging,target=/run/packaging \ --network=none \ /run/packaging/install-rpm-and-setup /run/packages diff --git a/Justfile b/Justfile index 16a98be19..8b29ed594 100644 --- a/Justfile +++ b/Justfile @@ -47,6 +47,15 @@ buildargs := base_buildargs + " --secret=id=secureboot_key,src=target/test-secur # Args for build-sealed (no base arg, it sets that itself) sealed_buildargs := "--build-arg=variant=" + variant + " --secret=id=secureboot_key,src=target/test-secureboot/db.key --secret=id=secureboot_cert,src=target/test-secureboot/db.crt" +# The default target: build the container image from current sources. +# Note commonly you might want to override the base image via e.g. +# `just build --build-arg=base=quay.io/fedora/fedora-bootc:42` +# +# This first builds RPMs via the `package` target, then injects them +# into the container image. +build: package _keygen + @just _build-from-package target/packages + # Compute SOURCE_DATE_EPOCH and VERSION from git for reproducible builds. # Outputs shell variable assignments that can be eval'd. _git-build-vars: @@ -66,26 +75,20 @@ _git-build-vars: echo "SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}" echo "VERSION=${VERSION}" -# The default target: build the container image from current sources. -# Note commonly you might want to override the base image via e.g. -# `just build --build-arg=base=quay.io/fedora/fedora-bootc:42` -# -# The Dockerfile builds RPMs internally in its 'build' stage, so we don't need -# to call 'package' first. This avoids cache invalidation from external files. -build: _keygen - #!/bin/bash - set -xeuo pipefail - eval $(just _git-build-vars) - podman build {{base_buildargs}} --target=final \ - --build-arg=SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH} \ - --build-arg=pkgversion=${VERSION} \ - -t {{base_img}}-bin {{buildargs}} . - ./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}} - # Generate Secure Boot keys (only for our own CI/testing) _keygen: ./hack/generate-secureboot-keys +# Internal helper: build container image from packages at PATH +_build-from-package PATH: + #!/bin/bash + set -xeuo pipefail + # Resolve to absolute path for podman volume mount + # Use :z for SELinux relabeling + pkg_path=$(realpath "{{PATH}}") + podman build --target=final -v "${pkg_path}":/run/packages:ro,z -t {{base_img}}-bin {{buildargs}} . + ./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}} + # Build a sealed image from current sources. build-sealed: @just --justfile {{justfile()}} variant=composefs-sealeduki-sdboot build @@ -108,34 +111,6 @@ package: _packagecontainer chmod a+r target/packages/*.rpm podman rmi localhost/bootc-pkg -# Copy pre-existing packages from PATH into target/packages/ -# Note: This is mainly for CI artifact extraction; build-from-package -# now uses volume mounts directly instead of copying to target/packages/. -copy-packages-from PATH: - #!/bin/bash - set -xeuo pipefail - if ! compgen -G "{{PATH}}/*.rpm" > /dev/null; then - echo "Error: No packages found in {{PATH}}" >&2 - exit 1 - fi - mkdir -p target/packages - rm -vf target/packages/*.rpm - cp -v {{PATH}}/*.rpm target/packages/ - chmod a+rx target target/packages - chmod a+r target/packages/*.rpm - -# Build the container image using pre-existing packages from PATH -# Uses the 'final-from-packages' target with a volume mount to inject packages, -# avoiding Docker context cache invalidation issues. -build-from-package PATH: _keygen - #!/bin/bash - set -xeuo pipefail - # Resolve to absolute path for podman volume mount - # Use :z for SELinux relabeling - pkg_path=$(realpath "{{PATH}}") - podman build {{base_buildargs}} --target=final-from-packages -v "${pkg_path}":/run/packages:ro,z -t {{base_img}}-bin {{buildargs}} . - ./hack/build-sealed {{variant}} {{base_img}}-bin {{base_img}} {{sealed_buildargs}} - # Pull images used by hack/lbi _pull-lbi-images: podman pull -q --retry 5 --retry-delay 5s {{lbi_images}} @@ -146,8 +121,8 @@ build-integration-test-image: build _pull-lbi-images ./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}} # Build integration test image using pre-existing packages from PATH -build-integration-test-image-from-package PATH: _pull-lbi-images - @just build-from-package {{PATH}} +build-integration-test-image-from-package PATH: _keygen _pull-lbi-images + @just _build-from-package {{PATH}} cd hack && podman build {{base_buildargs}} -t {{integration_img}}-bin -f Containerfile . ./hack/build-sealed {{variant}} {{integration_img}}-bin {{integration_img}} {{sealed_buildargs}} diff --git a/crates/ostree-ext/src/container/store.rs b/crates/ostree-ext/src/container/store.rs index 3e9991faa..2a480b2e7 100644 --- a/crates/ostree-ext/src/container/store.rs +++ b/crates/ostree-ext/src/container/store.rs @@ -1508,13 +1508,7 @@ pub(crate) fn export_to_oci( let srcinfo = query_image(repo, imgref)?.ok_or_else(|| anyhow!("No such image"))?; let (commit_layer, component_layers, remaining_layers) = parse_manifest_layout(&srcinfo.manifest, &srcinfo.configuration)?; - let commit_layer = commit_layer.ok_or_else(|| anyhow!("Missing {DIFFID_LABEL}"))?; - let commit_chunk_ref = ref_for_layer(commit_layer)?; - let commit_chunk_rev = repo.require_rev(&commit_chunk_ref)?; - let mut chunking = chunking::Chunking::new(repo, &commit_chunk_rev)?; - for layer in component_layers { - chunking_from_layer_committed(repo, layer, &mut chunking)?; - } + // Unfortunately today we can't guarantee we reserialize the same tar stream // or compression, so we'll need to generate a new copy of the manifest and config // with the layers reset. @@ -1526,8 +1520,6 @@ pub(crate) fn export_to_oci( } new_config.rootfs_mut().diff_ids_mut().clear(); - let mut dest_oci = ocidir::OciDir::ensure(dest_oci.try_clone()?)?; - let opts = ExportOpts { skip_compression: opts.skip_compression, authfile: opts.authfile, @@ -1536,19 +1528,36 @@ pub(crate) fn export_to_oci( let mut labels = HashMap::new(); - // Given the object chunking information we recomputed from what - // we found on disk, re-serialize to layers (tarballs). - export_chunked( - repo, - &srcinfo.base_commit, - &mut dest_oci, - &mut new_manifest, - &mut new_config, - &mut labels, - chunking, - &opts, - "", - )?; + let mut dest_oci = ocidir::OciDir::ensure(dest_oci.try_clone()?)?; + + let commit_chunk_ref = commit_layer + .as_ref() + .map(|l| ref_for_layer(l)) + .transpose()?; + let commit_chunk_rev = commit_chunk_ref + .as_ref() + .map(|r| repo.require_rev(&r)) + .transpose()?; + if let Some(commit_chunk_rev) = commit_chunk_rev { + let mut chunking = chunking::Chunking::new(repo, &commit_chunk_rev)?; + for layer in component_layers { + chunking_from_layer_committed(repo, layer, &mut chunking)?; + } + + // Given the object chunking information we recomputed from what + // we found on disk, re-serialize to layers (tarballs). + export_chunked( + repo, + &srcinfo.base_commit, + &mut dest_oci, + &mut new_manifest, + &mut new_config, + &mut labels, + chunking, + &opts, + "", + )?; + } // Now, handle the non-ostree layers; this is a simple conversion of //