From 1245c1be5d19ecc3a4a7da5d5cc6d961f7a0bf96 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus <915544+detiber@users.noreply.github.com> Date: Sun, 15 Dec 2024 20:43:49 -0500 Subject: [PATCH] start of generic image build and rechunking --- just/build.just | 189 ++++++++++++++++++++++++++++++++++++++++ just/common.just | 18 ++++ just/cosign.just | 18 ++-- justfile | 1 + variants/ublue/justfile | 24 +++++ 5 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 just/build.just create mode 100644 variants/ublue/justfile diff --git a/just/build.just b/just/build.just new file mode 100644 index 0000000..92865fe --- /dev/null +++ b/just/build.just @@ -0,0 +1,189 @@ +import 'cosign.just' +import 'common.just' + +repo_organization := "detiber" +rechunker_image := "ghcr.io/hhd-dev/rechunk:v1.0.1" + +# Get Fedora Version of an image +_fedora_version base_image tag: + #!/usr/bin/bash + set -eou pipefail + if [[ ! -f /tmp/manifest.json ]]; then + if [[ "{{ tag }}" =~ stable ]]; then + # CoreOS does not uses cosign + skopeo inspect --retry-times 3 docker://quay.io/fedora/fedora-coreos:stable > /tmp/manifest.json + else + skopeo inspect --retry-times 3 docker://"{{ base_image }}:{{ tag }}" > /tmp/manifest.json + fi + fi + fedora_version=$(jq -r '.Labels["ostree.linux"]' < /tmp/manifest.json | grep -oP 'fc\K[0-9]+') + echo "${fedora_version}" + +# Build Image +_build image tag base_image args: _disk-use (_header "Build Image") (verify-image base_image + ":" + `just _fedora_version '{{ base_image }}' '{{ tag }}'`) && (_footer "Build Image") _disk-use + # Build Image + podman build \ + --tag "{{ image }}:{{ tag }}" \ + {{ args }} \ + . + +# Rechunk Image +_rechunk image tag base_image rechunk-dir: (_ensure-directory rechunk-dir) _disk-use (_header "Rechunk") && (_footer "Rechunk") _disk-use + #!/usr/bin/bash + set -eoux pipefail + + # Check if image is already built + ID=$(podman images --filter reference=localhost/"{{ image }}":"{{ tag }}" --format "'{{ '{{.ID}}' }}'") + if [[ -z "$ID" ]]; then + just _build "{{ image }}" "{{ tag }}" "{{ base_image }}" "" + fi + + # Load into Rootful Podman + ID=$(just sudoif podman images --filter reference=localhost/"{{ image }}":"{{ tag }}" --format "'{{ '{{.ID}}' }}'") + if [[ -z "$ID" ]]; then + COPYTMP=$(mktemp -p "{{ rechunk-dir }}" -d -t podman_scp.XXXXXXXXXX) + just sudoif TMPDIR="${COPYTMP}" podman image scp ${UID}@localhost::localhost/"{{ image }}":"{{ tag }}" root@localhost::localhost/"{{ image }}":"{{ tag }}" + rm -rf "${COPYTMP}" + fi + + # Prep Container + CREF=$(just sudoif podman create localhost/"{{ image }}":"{{ tag }}" bash) + OLD_IMAGE=$(just sudoif podman inspect $CREF | jq -r '.[].Image') + OUT_NAME="{{ image }}_build" + MOUNT=$(just sudoif podman mount "${CREF}") + + # Fedora Version + fedora_version=$(just sudoif podman inspect $CREF | jq -r '.[].Config.Labels["ostree.linux"]' | grep -oP 'fc\K[0-9]+') + + # Label Version + if [[ "{{ tag }}" =~ stable ]]; then + VERSION="${fedora_version}.$(date +%Y%m%d)" + else + VERSION="{{ tag }}-${fedora_version}.$(date +%Y%m%d)" + fi + + # # TODO: Cleanup Space during Github Action + + # Run Rechunker's Prune + just sudoif podman run --rm \ + --pull=newer \ + --security-opt label=disable \ + --volume "$MOUNT":/var/tree \ + --env TREE=/var/tree \ + --user 0:0 \ + "{{ rechunker_image }}" \ + /sources/rechunk/1_prune.sh + + # Run Rechunker's Create + just sudoif podman run --rm \ + --security-opt label=disable \ + --volume "$MOUNT":/var/tree \ + --volume "cache_ostree:/var/ostree" \ + --env TREE=/var/tree \ + --env REPO=/var/ostree/repo \ + --env RESET_TIMESTAMP=1 \ + --user 0:0 \ + "{{ rechunker_image }}" \ + /sources/rechunk/2_create.sh + + # Cleanup Temp Container Reference + just sudoif podman unmount "$CREF" + just sudoif podman rm "$CREF" + just sudoif podman rmi "$OLD_IMAGE" + + SHA="dedbeef" + if [[ -z "$(git status -s)" ]]; then + SHA=$(git rev-parse HEAD) + fi + # Run Rechunker + just sudoif podman run --rm \ + --pull=newer \ + --security-opt label=disable \ + --volume "{{ rechunk-dir }}:/workspace" \ + --volume "{{ root-dir }}:/var/git" \ + --volume cache_ostree:/var/ostree \ + --env REPO=/var/ostree/repo \ + --env PREV_REF=ghcr.io/detiber/"{{ image }}":"{{ tag }}" \ + --env OUT_NAME="$OUT_NAME" \ + --env LABELS="org.opencontainers.image.title={{ image }}$'\n''io.artifacthub.package.readme-url=https://raw.githubusercontent.com/detiber/beardy-os/refs/heads/main/README.md'$'\n''io.artifacthub.package.logo-url=https://avatars.githubusercontent.com/u/120078124?s=200&v=4'$'\n'" \ + --env "DESCRIPTION='The preferred bluefin-based OS of bearded developers'" \ + --env "VERSION=${VERSION}" \ + --env VERSION_FN=/workspace/version.txt \ + --env OUT_REF="oci:$OUT_NAME" \ + --env GIT_DIR="/var/git" \ + --env REVISION="$SHA" \ + --user 0:0 \ + "{{ rechunker_image }}" \ + /sources/rechunk/3_chunk.sh + + # Fix Permissions of OCI + if [[ "${UID}" -gt "0" ]]; then + just sudoif chown "${UID}:${GROUPS}" -R "{{ rechunk-dir }}" + elif [[ -n "${SUDO_UID:-}" ]]; then + chown "${SUDO_UID}":"${SUDO_GID}" -R "{{ rechunk-dir }}" + fi + + # Remove cache_ostree + just sudoif podman volume rm cache_ostree + + # Show OCI Labels + just sudoif skopeo inspect oci:"{{ rechunk-dir }}"/"${OUT_NAME}" | jq -r '.Labels' + +# Load OCI into Podman Store +_load-rechunk image tag rechunk-dir: _disk-use (_header "Load Rechunk") && (_footer "Load Rechunk") _disk-use + #!/usr/bin/bash + set -eou pipefail + + # Load Image + OUT_NAME="{{ image }}_build" + IMAGE=$(podman pull oci:"{{ rechunk-dir }}"/"${OUT_NAME}") + podman tag ${IMAGE} localhost/"{{ image }}":{{ tag }} + + # Cleanup + just sudoif "rm -rf ${OUT_NAME}*" + just sudoif "rm -f previous.manifest.json" + +# Secureboot Check +[group('Utility')] +_secureboot image tag: _disk-use (_header "Secureboot") && (_footer "Secureboot") _disk-use + #!/usr/bin/bash + set -eoux pipefail + + # Get the vmlinuz to check + kernel_release=$(podman inspect "{{ image }}":"{{ tag }}" | jq -r '.[].Config.Labels["ostree.linux"]') + TMP=$(podman create "{{ image }}":"{{ tag }}" bash) + podman cp "$TMP":/usr/lib/modules/"${kernel_release}"/vmlinuz /tmp/vmlinuz + podman rm "$TMP" + + # Get the Public Certificates + curl --retry 3 -Lo /tmp/kernel-sign.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key.der + curl --retry 3 -Lo /tmp/akmods.der https://github.com/ublue-os/kernel-cache/raw/main/certs/public_key_2.der + openssl x509 -in /tmp/kernel-sign.der -out /tmp/kernel-sign.crt + openssl x509 -in /tmp/akmods.der -out /tmp/akmods.crt + + # Make sure we have sbverify + CMD="$(command -v sbverify)" + if [[ -z "${CMD:-}" ]]; then + temp_name="sbverify-${RANDOM}" + podman run -dt \ + --entrypoint /bin/sh \ + --volume /tmp/vmlinuz:/tmp/vmlinuz:z \ + --volume /tmp/kernel-sign.crt:/tmp/kernel-sign.crt:z \ + --volume /tmp/akmods.crt:/tmp/akmods.crt:z \ + --name ${temp_name} \ + alpine:edge + podman exec ${temp_name} apk add sbsigntool + CMD="podman exec ${temp_name} /usr/bin/sbverify" + fi + + # Confirm that Signatures Are Good + $CMD --list /tmp/vmlinuz + returncode=0 + if ! $CMD --cert /tmp/kernel-sign.crt /tmp/vmlinuz || ! $CMD --cert /tmp/akmods.crt /tmp/vmlinuz; then + echo "Secureboot Signature Failed...." + returncode=1 + fi + if [[ -n "${temp_name:-}" ]]; then + podman rm -f "${temp_name}" + fi + exit "$returncode" diff --git a/just/common.just b/just/common.just index 7598456..d19e378 100644 --- a/just/common.just +++ b/just/common.just @@ -40,3 +40,21 @@ generate-default-tag tag="latest" ghcr="0": fi echo "${DEFAULT_TAG}" + +_disk-use: (_header "Disk Use") && (_footer "Disk Use") + just sudoif du -hs /var/tmp /tmp + find {{ build-dir }} -type d -exec du -hs {} \; | sort -h + podman system df + just sudoif podman system df + +_header title: + @echo "" + @echo '============================================' + @echo "Start: {{ title }}" + @echo '============================================' + +_footer title: + @echo '============================================' + @echo "End: {{ title }}" + @echo '============================================' + @echo "" diff --git a/just/cosign.just b/just/cosign.just index f98c5f9..bb7df3a 100644 --- a/just/cosign.just +++ b/just/cosign.just @@ -1,6 +1,12 @@ -# Verify Container with Cosign +import 'common.just' + +# Verify Container with Cosign TODO: remove after replacing use in bluefin justfile +[group('Utility')] +verify-container container="" registry="ghcr.io/ublue-os" key="https://raw.githubusercontent.com/ublue-os/main/main/cosign.pub": && (verify-image registry + "/" + container key) + +# Verify Container Image with Cosign [group('Utility')] -verify-container container="" registry="ghcr.io/ublue-os" key="": +verify-image image="ghcr.io/ublue-os/base-main" key="https://raw.githubusercontent.com/ublue-os/main/main/cosign.pub": #!/usr/bin/bash set -eoux pipefail @@ -19,14 +25,8 @@ verify-container container="" registry="ghcr.io/ublue-os" key="": fi fi - # Public Key for Container Verification - key={{ key }} - if [[ -z "${key:-}" ]]; then - key="https://raw.githubusercontent.com/ublue-os/main/main/cosign.pub" - fi - # Verify Container using cosign public key - if ! cosign verify --key "${key}" "{{ registry }}"/"{{ container }}" >/dev/null; then + if ! cosign verify --key "{{ key }}" "{{ image }}" >/dev/null; then echo "NOTICE: Verification failed. Please ensure your public key is correct." exit 1 fi diff --git a/justfile b/justfile index 68b71a9..4ecd16f 100644 --- a/justfile +++ b/justfile @@ -1,5 +1,6 @@ mod bootc 'variants/bootc/justfile' mod bluefin 'variants/bluefin/justfile' +mod ublue 'variants/ublue/justfile' import 'just/common.just' diff --git a/variants/ublue/justfile b/variants/ublue/justfile new file mode 100644 index 0000000..d9740cd --- /dev/null +++ b/variants/ublue/justfile @@ -0,0 +1,24 @@ +import '../../just/common.just' +import '../../just/build.just' + +ublue-build-dir := join(build-dir, 'output', 'variants', 'ublue') +ublue-cache-dir := join(build-dir, 'cache', 'ublue') +rechunk-dir := join(ublue-cache-dir, 'rechunk') + +# Build Image +[group('Image')] +build image="beardy-ublue" tag="latest" base_image="ghcr.io/ublue-os/base-main" args="": && (_build image tag base_image args) + +# Rechunk Image +[group('Utility')] +rechunk image="beardy-ublue" tag="latest" base_image="ghcr.io/ublue-os/base-main": && (_rechunk image tag base_image rechunk-dir) + +# Load OCI into Podman Store +[group('Utility')] +load-rechunk image="beardy-ublue" tag="latest": && (_load-rechunk image tag rechunk-dir) + +# Secureboot Check +[group('Utility')] +secureboot image="beardy-ublue" tag="latest": && (_secureboot image tag) + +try: build rechunk load-rechunk secureboot