🏡 index : quine-global-labs/aurora.git

# Min just version 1.46.0 https://github.com/casey/just/issues/2290
export repo_organization := env("GITHUB_REPOSITORY_OWNER", "ublue-os")
export base_image_org := env("BASE_IMAGE_ORG", "quay.io/fedora-ostree-desktops")
export base_image_name := env("BASE_IMAGE_NAME", "kinoite")

stable_version := "44"
latest_version := "44"
testing_version := "45"

images := '(
    [aurora]=aurora
    [aurora-dx]=aurora-dx
)'

flavors := '(
    [main]=main
    [nvidia-open]=nvidia-open
)'

tags := '(
    [stable]=stable
    [latest]=latest
    [testing]=testing
)'

default_image := "aurora"
default_tag := "testing"
default_flavor := "main"

# Build Containers
chunkah := shell("yq -r \".images[] | select(.name == \\\"chunkah\\\") | \\\"\\\\(.image):\\(.tag)@\\\\(.digest)\\\"\" image-versions.yml")
common := shell("yq -r \".images[] | select(.name == \\\"common\\\") | \\\"\\\\(.image):\\(.tag)@\\\\(.digest)\\\"\" image-versions.yml")
brew := shell("yq -r \".images[] | select(.name == \\\"brew\\\") | \\\"\\\\(.image):\\(.tag)@\\\\(.digest)\\\"\" image-versions.yml")

export SUDO_DISPLAY := if `if [ -n "${DISPLAY:-}" ] || [ -n "${WAYLAND_DISPLAY:-}" ]; then echo true; fi` == "true" { "true" } else { "false" }
export SUDOIF := if `id -u` == "0" { "" } else { "sudo" }
export PODMAN := "podman"
export BUILDAH := "buildah"
just := just_executable()

# Define a retry function for use in recipes
retry_function := '
retry() {
    if [[ "${#}" -lt 3 ]]; then
        echo "retry usage: <number of tries> <time between retries> <command> ..."
        return 1
    fi
    tries="${1}"
    sleep="${2}"
    shift 2
    for i in $(seq 1 ${tries}); do
        if [[ ${i} -gt 1 ]]; then
            # echo "[+] Command failed. Waiting for ${sleep} seconds"
            sleep ${sleep}
        fi
        # echo "[+] Running (try: ${i}): ${@}"
        "${@}" && r=0 && break || r=$?
    done
    return $r
}
'

[private]
default:
    @{{ just }} --list

# Check Just Syntax
[group('Just')]
check:
    #!/usr/bin/env bash
    find . -type f -name "*.just" | while read -r file; do
      echo "Checking syntax: $file"
      {{ just }} --fmt --check -f $file
    done
    echo "Checking syntax: Justfile"
    {{ just }} --fmt --check -f Justfile

# Fix Just Syntax
[group('Just')]
fix:
    #!/usr/bin/env bash
    find . -type f -name "*.just" | while read -r file; do
      echo "Checking syntax: $file"
      {{ just }} --fmt -f $file
    done
    echo "Checking syntax: Justfile"
    {{ just }} --fmt -f Justfile || { exit 1; }

# Clean Repo
[group('Utility')]
clean:
    #!/usr/bin/env bash
    set -eoux pipefail
    rm -f changelog.md
    rm -f output.env
    rm -rf sbom_out
    rm -f /tmp/aurora*-tags.json

# Check if valid combo
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[private]
validate $image $tag $flavor:
    #!/usr/bin/env bash
    set -eou pipefail

    declare -A images={{ images }}
    declare -A tags={{ tags }}
    declare -A flavors={{ flavors }}

    checkimage="${images[${image}]-}"
    checktag="${tags[${tag}]-}"
    checkflavor="${flavors[${flavor}]-}"

    # Validity Checks
    if [[ -z "$checkimage" ]]; then
        echo "Invalid Image..."
        exit 1
    fi
    if [[ -z "$checktag" ]]; then
        echo "Invalid tag..."
        exit 1
    fi
    if [[ -z "$checkflavor" ]]; then
        echo "Invalid flavor..."
        exit 1
    fi

# Build Image
[arg("flavor", long="flavor", short="f")]
[arg("ghcr", long="ghcr", value="true")]
[arg("image", long="image", short="i")]
[arg("kernel_pin", long="kernel-pin")]
[arg("rechunk", long="rechunk", value="true")]
[arg("retry_pull", long="retry-pull", value="true")]
[arg("tag", long="tag", short="t")]
[group('Image')]
build $image=default_image $tag=default_tag $flavor=default_flavor $rechunk="false" $ghcr="false" $kernel_pin="" $retry_pull="false":
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"

    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")
    akmods_flavor=$({{ just }} akmods_flavor --tag "${tag}")
    fedora_version=$({{ just }} fedora_version --image "${image}" --tag "${tag}" --flavor "${flavor}")

    BASE_IMAGE_REF="${base_image_org}/${base_image_name}:${fedora_version}"
    ALL_IMAGES=()
    ALL_IMAGES+=("${BASE_IMAGE_REF}")

    # Here we pin our kernels to workaround regressions!
    # skopeo list-tags docker://ghcr.io/ublue-os/akmods | jq -r '.Tags | map(select(contains("coreos-stable-44")))'

    ARCH=$(arch)
    if [[ -z "${kernel_pin:-}" ]]; then
      case "${tag}" in
              stable)
                  if [[ "${ARCH}" == "x86_64" ]]; then
                      # <Here is a link why we have it pinned>
                      kernel_pin=""
                  elif [[ "${ARCH}" == "aarch64" ]]; then
                      kernel_pin=""
                  fi
                  ;;
              latest)
                  if [[ "${ARCH}" == "x86_64" ]]; then
                      kernel_pin=""
                  elif [[ "${ARCH}" == "aarch64" ]]; then
                      kernel_pin=""
                  fi
                  ;;
              testing)
                  if [[ "${ARCH}" == "x86_64" ]]; then
                      kernel_pin=""
                  elif [[ "${ARCH}" == "aarch64" ]]; then
                      kernel_pin=""
                  fi
                  ;;
      esac
    fi

    if [[ -z "${kernel_pin:-}" ]]; then
        kernel_release=$(skopeo inspect --no-tags --retry-times 3 docker://ghcr.io/ublue-os/akmods:"${akmods_flavor}"-"${fedora_version}" | jq -r '.Labels["ostree.linux"]')
    else
        kernel_release="${kernel_pin}"
    fi

    BASENAME_AKMODS="ghcr.io/ublue-os/akmods"

    AKMODS="${BASENAME_AKMODS}:${akmods_flavor}-${fedora_version}-${kernel_release}"
    ALL_IMAGES+=("${AKMODS}")

    if [[ "${flavor}" =~ nvidia-open ]]; then
        AKMODS_NVIDIA_OPEN="${BASENAME_AKMODS}-nvidia-open:${akmods_flavor}-${fedora_version}-${kernel_release}"
        ALL_IMAGES+=("${AKMODS_NVIDIA_OPEN}")
    fi

    {{ retry_function }}

    retry 5 60 cosign verify \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      --certificate-identity-regexp="github.com/get-aurora-dev/common/.github/workflows/*" \
      "{{ common }}"

    ALL_IMAGES+=("{{ common }}")

    retry 5 60 cosign verify \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      --certificate-identity-regexp="github.com/coreos/chunkah/.github/workflows/*" \
      "{{ chunkah }}"

    ALL_IMAGES+=("{{ chunkah }}")

    ALL_IMAGES+=("{{ brew }}")

    # I hate this immensely, podman build/pull with --retry does not work for
    # transient network issues
    if [[ "${retry_pull}" == "true" ]]; then
      for fetch_image in "${ALL_IMAGES[@]}"; do
        retry 5 60 ${PODMAN} pull ${fetch_image}
      done
    fi

    # Get Version
    TIMESTAMP="$(date +%Y%m%d)"
    if [[ "${tag}" =~ stable ]]; then
        ver="${fedora_version}.${TIMESTAMP}"
    else
        ver="${tag}-${fedora_version}.${TIMESTAMP}"
    fi

    POINT=$({{ just }} generate-point --image "${image}" --tag "${tag}" --flavor "${flavor}")
    ver="${ver}.$POINT"

    # Build Arguments
    BUILD_ARGS=()
    # Target
    if [[ "${image}" =~ dx ]]; then
           BUILD_ARGS+=("--build-arg" "IMAGE_FLAVOR=dx")
           target="dx"
    fi
    BUILD_ARGS+=("--build-arg" "AKMODS_FLAVOR=${akmods_flavor}")
    BUILD_ARGS+=("--build-arg" "BASE_IMAGE_ORG=${base_image_org}")
    BUILD_ARGS+=("--build-arg" "BASE_IMAGE_NAME=${base_image_name}")
    BUILD_ARGS+=("--build-arg" "FEDORA_MAJOR_VERSION=${fedora_version}")
    BUILD_ARGS+=("--build-arg" "COMMON={{ common }}")
    BUILD_ARGS+=("--build-arg" "BREW={{ brew }}")
    BUILD_ARGS+=("--build-arg" "IMAGE_NAME=${image_name}")
    BUILD_ARGS+=("--build-arg" "IMAGE_VENDOR={{ repo_organization }}")
    BUILD_ARGS+=("--build-arg" "KERNEL=${kernel_release}")
    BUILD_ARGS+=("--build-arg" "VERSION=${ver}")
    if [[ -z "$(git status -s)" ]]; then
        BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=$(git rev-parse --short HEAD)")
    else
        BUILD_ARGS+=("--build-arg" "SHA_HEAD_SHORT=deadbeef")
    fi
    BUILD_ARGS+=("--build-arg" "UBLUE_IMAGE_TAG=${tag}")

    # Labels
    LABELS=()
    LABELS+=("--label" "containers.bootc=1")
    LABELS+=("--label" "io.artifacthub.package.deprecated=false")
    LABELS+=("--label" "io.artifacthub.package.keywords=bootc,fedora,aurora,ublue,universal-blue,kde,linux")
    LABELS+=("--label" "io.artifacthub.package.logo-url=https://avatars.githubusercontent.com/u/120078124?s=200&v=4")
    LABELS+=("--label" "io.artifacthub.package.maintainers=[{\"name\": \"NiHaiden\", \"email\": \"me@nhaiden.io\"}]")
    LABELS+=("--label" "io.artifacthub.package.readme-url=https://raw.githubusercontent.com/ublue-os/aurora/refs/heads/main/README.md")
    LABELS+=("--label" "org.opencontainers.image.created=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)")
    LABELS+=("--label" "org.opencontainers.image.description=The ultimate productivity workstation")
    LABELS+=("--label" "org.opencontainers.image.documentation=https://docs.getaurora.dev")
    LABELS+=("--label" "org.opencontainers.image.source=https://raw.githubusercontent.com/ublue-os/aurora/refs/heads/main/Containerfile.in")
    LABELS+=("--label" "org.opencontainers.image.title=${image_name}")
    LABELS+=("--label" "org.opencontainers.image.url=https://getaurora.dev")
    LABELS+=("--label" "org.opencontainers.image.vendor={{ repo_organization }}")
    LABELS+=("--label" "org.opencontainers.image.version=${ver}")
    if [[ -z "$(git status -s)" ]]; then
        LABELS+=("--label" "org.opencontainers.image.revision=$(git rev-parse HEAD)")
    else
        LABELS+=("--label" "org.opencontainers.image.revision=deadbeef")
    fi
    LABELS+=("--label" "ostree.linux=${kernel_release}")

    if [[ "${image_name}" =~ nvidia ]]; then
        BUILD_ARGS+=("--cpp-flag=-DNVIDIA")
    fi

    PODMAN_BUILD_ARGS=("${BUILD_ARGS[@]}" "${LABELS[@]}" --tag "${image_name}:${tag}" --file Containerfile.in)

    # So we always have the newest images when building locally
    if [[ "${ghcr}" == "false" ]]; then
      PODMAN_BUILD_ARGS+=("--pull=newer")
    fi

    # Add GitHub token secret if available (for CI/CD)
    if [[ -n "${GITHUB_TOKEN:-}" ]]; then
        echo "Adding GitHub token as build secret"
        PODMAN_BUILD_ARGS+=(--secret "id=GITHUB_TOKEN,env=GITHUB_TOKEN")
    else
        echo "No GitHub token found - build may hit rate limit"
    fi

    ${BUILDAH} build "${PODMAN_BUILD_ARGS[@]}" .
    echo "::endgroup::"

# Build Image and Rechunk
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("kernel_pin", long="kernel-pin")]
[arg("retry_pull", long="retry-pull", value="true")]
[arg("tag", long="tag", short="t")]
[group('Image')]
build-rechunk $image=default_image $tag=default_tag $flavor=default_flavor $kernel_pin="" $retry_pull="false": (build image tag flavor kernel_pin retry_pull) (rechunk image tag flavor)

# Rechunk Image
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Image')]
rechunk $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")
    CHUNKAH_OUTPUT_DIR="$(mktemp -d)"
    CHUNKAH_CONFIG_FILE="$(mktemp)"

    trap 'rm -f "${CHUNKAH_CONFIG_FILE}"; rm -rf "${CHUNKAH_OUTPUT_DIR}"' EXIT
    ${PODMAN} inspect "${image_name}:${tag}" > "${CHUNKAH_CONFIG_FILE}"

    ${PODMAN} run --rm --mount=type=image,src="${image_name}:${tag}",target=/chunkah \
    -v "${CHUNKAH_CONFIG_FILE}:/chunkah-config.json:ro,Z" \
    -v "${CHUNKAH_OUTPUT_DIR}:/run/out:Z" \
    "{{ chunkah }}" \
    build \
    --verbose \
    --compressed \
    --max-layers 256 \
    --prune /sysroot/ \
    --label ostree.commit- --label ostree.final-diffid- \
    --config /chunkah-config.json \
    --output oci:/run/out/chunked

    CHUNKED_IMAGE="$(podman pull "oci:${CHUNKAH_OUTPUT_DIR}/chunked")"
    podman tag "${CHUNKED_IMAGE}" "${image_name}:${tag}"

# For Privileged operations
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Image')]
load-rootful $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -oux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    if [[ ! "$(id -u)" == 0 ]]; then
      ID=$(${PODMAN} images --filter reference="${image_name}:${tag}" --format "'{{ '{{.ID}}' }}'")
      if [[ -z "$ID" ]]; then
          {{ just }} build "$image" "$tag" "$flavor"
      fi
      ${PODMAN} image scp "${image_name}:${tag}" root@localhost::
    fi

# Generate OCI Archive for PR Testing
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
export-oci $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -oux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    ARCHIVE_NAME="${image_name}"-"$(arch)".oci

    ${PODMAN} push --compression-format=zstd --compression-level=3 "${image_name}:${tag}" oci-archive:"${ARCHIVE_NAME}"

# Run Container
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Image')]
run $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")
    # Check if image exists
    ID=$(${PODMAN} images --filter reference="${image_name}:${tag}" --format "'{{ '{{.ID}}' }}'")
    if [[ -z "$ID" ]]; then
        {{ just }} build "$image" "$tag" "$flavor"
    fi

    # Run Container
    ${PODMAN} run -it --rm "${image_name}:${tag}" bash -l

# Test Changelogs
[group('Changelogs')]
changelogs branch="stable" handwritten="":
    #!/usr/bin/env bash
    set -eou pipefail
    python3 ./.github/changelogs.py "{{ branch }}" ./output.env ./changelog.md --workdir . --handwritten "{{ handwritten }}"

# Secureboot Check
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
secureboot $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -eou pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    # Get the vmlinuz to check
    kernel_release=$(${PODMAN} inspect "${image_name}":"${tag}" | jq -r '.[].Config.Labels["ostree.linux"]')
    TMP=$(${PODMAN} create "${image_name}":"${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/akmods/raw/main/certs/public_key.der
    curl --retry 3 -Lo /tmp/akmods.der https://github.com/ublue-os/akmods/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 || true)"
    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} \
            docker.io/library/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"

# Get Fedora Version of an image
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[private]
fedora_version image=default_image tag=default_tag flavor=default_flavor:
    #!/usr/bin/env bash
    set -eou pipefail

    {{ just }} validate --image {{ image }} --tag {{ tag }} --flavor {{ flavor }}

    # Determine Version
    if [[ "{{ tag }}" =~ stable ]]; then
        VERSION="{{ stable_version }}"
    elif [[ "{{ tag }}" =~ testing ]]; then
        VERSION="{{ testing_version }}"
    else
        VERSION="{{ latest_version }}"
    fi

    echo "${VERSION}"

[arg("tag", long="tag", short="t")]
[private]
akmods_flavor tag=default_tag:
    #!/usr/bin/env bash
    set -eou pipefail

    if [[ "{{ tag }}" =~ stable ]]; then
        akmods_flavor="coreos-stable"
    elif [[ "{{ tag }}" =~ testing ]]; then
        akmods_flavor="main"
    else
        akmods_flavor="main"
    fi

    echo "${akmods_flavor}"

# Image Name
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[private]
image_name image=default_image tag=default_tag flavor=default_flavor:
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image {{ image }} --tag {{ tag }} --flavor {{ flavor }}
    if [[ "{{ flavor }}" =~ main ]]; then
        image_name={{ image }}
    else
        image_name="{{ image }}-{{ flavor }}"
    fi

    echo "${image_name}"

# Generate Tags
[arg("flavor", long="flavor", short="f")]
[arg("ghcr", long="ghcr", value="true")]
[arg("github_event", long="github-event")]
[arg("github_number", long="github-number")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[arg("version", long="version")]
[group('Utility')]
generate-build-tags $image=default_image $tag=default_tag $flavor=default_flavor $ghcr="false" $version="" $github_event="" $github_number="":
    #!/usr/bin/env bash
    set -eoux pipefail

    FEDORA_VERSION=$({{ just }} fedora_version --image "${image}" --tag "${tag}" --flavor "${flavor}")
    IMAGE_NAME=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    TIMESTAMP="$(date +%Y%m%d)"
    version="${FEDORA_VERSION}.${TIMESTAMP}"

    BUILD_TAGS=()
    COMMIT_TAGS=()

    # Commit Tags
    github_number="${github_number}"
    SHA_SHORT="$(git rev-parse --short HEAD)"
    if [[ "${ghcr}" == "true" ]]; then
        COMMIT_TAGS+=(pr-${github_number:-}-${tag}-${version})
        COMMIT_TAGS+=(${SHA_SHORT}-${tag}-${version})
    fi

    POINT=$({{ just }} generate-point --image "${image}" --tag "${tag}" --flavor "${flavor}")

    # These are always used regardless of the stream
    COMMON_TAGS=()
    COMMON_TAGS+=("${tag}")
    COMMON_TAGS+=("${tag}-${version}")
    COMMON_TAGS+=("${tag}-${version:3}")
    COMMON_TAGS+=("${tag}-${version}.${POINT}")
    COMMON_TAGS+=("${tag}-${version:3}.${POINT}")

    BUILD_TAGS=("${COMMON_TAGS[@]}" "${BUILD_TAGS[@]}")

    # No special handling here for testing for now
    if [[ "{{ tag }}" == stable ]]; then
      # Legacy Compatibility Tag so stable-daily points to stable, do not remove this
      BUILD_TAGS+=("{{ tag }}-daily")
      BUILD_TAGS+=("${version}")
      BUILD_TAGS+=("{{ tag }}-daily-${version}")
      BUILD_TAGS+=("{{ tag }}-daily-${version:3}")
      BUILD_TAGS+=("{{ tag }}-daily-${version}.${POINT}")
      BUILD_TAGS+=("{{ tag }}-daily-${version:3}.${POINT}")
    elif [[ "{{ tag }}" == latest ]]; then
      # We only want :$FEDORA_VERSION to point to :latest
      BUILD_TAGS+=("{{ tag }}-${FEDORA_VERSION}")
      BUILD_TAGS+=("${FEDORA_VERSION}-${version}")
      BUILD_TAGS+=("${FEDORA_VERSION}-${version:3}")
      BUILD_TAGS+=("${FEDORA_VERSION}-${version}.${POINT}")
      BUILD_TAGS+=("${FEDORA_VERSION}-${version:3}.${POINT}")
    fi

    github_event="${github_event}"

    if [[ "${github_event}" == "pull_request" ]]; then
        alias_tags=("${COMMIT_TAGS[@]}")
    else
        alias_tags=("${BUILD_TAGS[@]}")
    fi

    echo "${alias_tags[*]}"

# Get Index Point for multiple daily images
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[private]
generate-point $image=default_image $tag=default_tag $flavor=default_flavor:
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    IMAGE_NAME=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")
    TIMESTAMP="$(date +%Y%m%d)"

    tags="/tmp/${IMAGE_NAME}-tags.json"

    if [[ ! -f ${tags} ]]; then
      skopeo list-tags docker://ghcr.io/{{ repo_organization }}/${IMAGE_NAME} > "${tags}"
    fi

    if [[ $(jq --arg tag "${tag}" --arg timestamp "${TIMESTAMP}" 'any(.Tags[]; contains($tag + "-" + $timestamp))' < "${tags}") == "true" ]]; then

      # our image already exists, so find the highest POINT
      POINT=$(jq -r --arg tag "${tag}" --arg timestamp "${TIMESTAMP}" \
        '($tag + "-" + $timestamp) as $base | [ .Tags[] | select(startswith($base + ".")) ] | sort_by(split(".")[-1]
        | tonumber)
        |.[-1] | if . == null then "1" else split(".")[-1] end' < "${tags}")

      ((POINT++))

    else
      # there is no image that exists for that day yet
      POINT=1
    fi

    echo "${POINT}"

# Tag Images
[arg("default_tag", long="default-tag")]
[arg("image", long="image", short="i")]
[arg("tags", long="tags")]
[group('Utility')]
tag-images $image="" $default_tag="" $tags="":
    #!/usr/bin/env bash
    set -eoux pipefail

    # Get Image, and untag
    IMAGE=$(${PODMAN} inspect "${image}:${default_tag}" | jq -r .[].Id)
    ${PODMAN} untag localhost/"${image}:${default_tag}"

    # Tag Image
    # Do not quote this, we want word splitting here
    for tag in ${tags}; do
        ${PODMAN} tag $IMAGE ${image}:${tag}
    done

    # Show Images
    ${PODMAN} images

# Extract Container and generate SBOM
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
gen-sbom $image=default_image $tag=default_tag $flavor=default_flavor $syft_cmd="syft":
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    OUT_DIR="sbom_out/${image_name}"
    mkdir -p "${OUT_DIR}"

    # We have to do it this stupid way because we are OOMing on github runners
    # https://github.com/anchore/syft/issues/3800
    ${PODMAN} container create --replace --name ${image_name} "${image_name}:${tag}"

    ROOTFS="${OUT_DIR}/rootfs"
    mkdir -p "${ROOTFS}"

    ${PODMAN} export ${image_name} | tar -C "${ROOTFS}" -xf -
    ${PODMAN} container rm ${image_name}

    SBOM="${OUT_DIR}/sbom.json"

    ${syft_cmd} --verbose --source-name "${image_name}:${tag}" "${OUT_DIR}" -o syft-json=${SBOM}
    du -sh "${SBOM}"

    rm -rf "${ROOTFS}"

# Attach sbom to exisitng image
[arg("digest", long="digest")]
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("registry", long="registry")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
attach-sbom $image=default_image $tag=default_tag $flavor=default_flavor $registry="" $digest="":
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    OUT_DIR="sbom_out/${image_name}"
    SBOM="sbom.json"
    FULL_SBOM_PATH="${OUT_DIR}/${SBOM}"
    IMAGE="${registry}/${image_name}:${tag}@${digest}"

    # we need to be in the directory of the sbom json file or else we end up having the directories in the oci artifact
    pushd "${OUT_DIR}"

    oras attach \
      --artifact-type application/vnd.spdx+json \
      --annotation filename="${SBOM}" \
      "${IMAGE}" \
      "${SBOM}"

    popd

    SBOM_DIGEST="$(oras discover --format json "${IMAGE}" | jq -r '.referrers[] | select(.artifactType == "application/vnd.spdx+json") | .digest')"

    echo "${SBOM_DIGEST}" > /tmp/sbom-digestfile

    # debugging
    echo "oras pull ${registry}/${image_name}:${tag}@${SBOM_DIGEST}"

# We are not using https://github.com/actions/cache because of:
# https://github.com/ublue-os/aurora/issues/2351
# https://github.com/actions/cache/issues/1537

# DNF CI package cache
[arg("flavor", long="flavor", short="f")]
[arg("ghcr", long="ghcr", value="true")]
[arg("github_event", long="github-event")]
[arg("image", long="image", short="i")]
[arg("pull", long="pull", value="true")]
[arg("push", long="push", value="true")]
[arg("registry", long="registry")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
[private]
setup-cache $image=default_image $tag=default_tag $flavor=default_flavor $ghcr="false" $pull="false" $push="false" $registry="" $github_event="":
    #!/usr/bin/env bash
    set -eoux pipefail

    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    fedora_version=$({{ just }} fedora_version --image "${image}" --tag "${tag}" --flavor "${flavor}")

    # compromise between most shared packages
    BLESSED_IMAGE=aurora-dx

    CACHE_NAME="aurora/cache/dnf"
    CACHE_IMAGE="${registry}/${CACHE_NAME}:${fedora_version}-$(arch)"

    # directory where buildah-cache-UID is
    BUILDAH_CACHE_DIR="/var/tmp"
    BUILDAH_CACHE="buildah-cache-${UID}"

    POINT=$({{ just }} generate-point --image "${image}" --tag "${tag}" --flavor "${flavor}")
    CURRENT_DAY="$(LC_TIME=C date +%A)"
    BLESSED_DAY="Sunday"

    # Always attempt to pull cache, but don't on the first run that will publish the build on Sundays
    if [[ "${CURRENT_DAY}" == "${BLESSED_DAY}" && "$POINT" == "1" && "${ghcr}" == "true" && ( "${github_event}" == "workflow_dispatch" || "${github_event}" == "merge_group" ) ]]; then
      echo "Not pulling build cache. Uploading fresh cache later."
    elif [[ "${pull}" == "true" ]]; then
      # We want to avoid using --allow-path-traversal
      pushd "${BUILDAH_CACHE_DIR}"
      oras pull "${CACHE_IMAGE}" || exit 0
      popd
    fi

    if [[ "${image_name}" == "${BLESSED_IMAGE}" ]] && \
       [[ "${pull:-false}" == "false" ]] && \
       [[ "${push}" == "true" ]] && \
       [[ "${ghcr}" == "true" ]] && \
       [[ "${CURRENT_DAY}" == "${BLESSED_DAY}" ]] && \
       [[ "${POINT}" == "1" ]] && \
       [[ ( "${github_event}" == "workflow_dispatch" || "${github_event}" == "merge_group" ) ]]; then

      {{ just }} login-registry oras ghcr.io
      pushd "${BUILDAH_CACHE_DIR}"
      oras push "${CACHE_IMAGE}" "${BUILDAH_CACHE}"
      popd
    fi

# Example: just bootc -t testing -- --help
[arg("flavor", long="flavor", short="f")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[private]
bootc $image=default_image $tag=default_tag $flavor=default_flavor *ARGS:
    #!/usr/bin/env bash
    set -eoux pipefail

    {{ just }} validate --image "${image}" --tag "${tag}" --flavor "${flavor}"
    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    BOOTC_INSTALL_OPTIONS=()
    BOOTC_INSTALL_OPTIONS+=("-v" "/var/lib/containers:/var/lib/containers" "-v" "/etc/containers:/etc/containers")

    if [[ -d /sys/fs/selinux ]]; then
      BOOTC_INSTALL_OPTIONS+=("-v" "/sys/fs/selinux:/sys/fs/selinux" "--security-opt" "label=type:unconfined_t")
    fi

    ${PODMAN} run \
        --rm --privileged --pid=host \
        -it \
        "${BOOTC_INSTALL_OPTIONS[@]}" \
        -v /dev:/dev \
        -v "${BUILD_BASE_DIR:-.}:/data" \
        "${image_name}:${tag}" bootc {{ ARGS }}

# Example: sudo just disk-image -t testing --backend composefs
# Create bootable image
[arg("backend", long="backend")]
[arg("flavor", long="flavor", short="f")]
[arg("ghcr", long="ghcr", value="true")]
[arg("image", long="image", short="i")]
[arg("tag", long="tag", short="t")]
[group('Utility')]
disk-image $image=default_image $tag=default_tag $flavor=default_flavor $ghcr="false" $backend="ostree":
    #!/usr/bin/env bash
    set -eoux pipefail

    # this is enough for base aurora to make it more likely to run in CI
    if [[ "${ghcr}" == "true" ]]; then
      # absurd size so it will always be enough for the image
      IMG_SIZE=35G
    else
      # Should at least be enough to rebase and install couple applications
      IMG_SIZE=40G
    fi

    BYTES_IMAGE_SIZE=$(numfmt --from=iec ${IMG_SIZE})

    if [ ! -e "${BUILD_BASE_DIR:-.}/bootable.img" ]; then
      FREE_SPACE=$(findmnt -bno AVAIL -T "${BUILD_BASE_DIR:-.}")
      if [ "${FREE_SPACE}" -gt "${BYTES_IMAGE_SIZE}" ]; then
        fallocate -l "${BYTES_IMAGE_SIZE}" "${BUILD_BASE_DIR:-.}/bootable.img"
      else
        echo "not enough disk space available"
        exit 1
      fi
    fi

    BOOTC_INSTALL_ARGS=()
    BOOTC_INSTALL_ARGS+=("--generic-image"  "--via-loopback" "/data/bootable.img" "--wipe")

    if [[ "${backend}" == "ostree" ]]; then
      BOOTC_INSTALL_ARGS+=("--bootloader grub")
    else
      BOOTC_INSTALL_ARGS+=("--bootloader grub" "--composefs-backend")
    fi

    {{ just }} bootc --image "${image}" --tag "${tag}" --flavor "${flavor}" install to-disk -- "${BOOTC_INSTALL_ARGS[@]}"

# FIXME: Please consider using podman push in the future for signing as well instead of temporary tag + cosign
# See: https://github.com/ublue-os/aurora/pull/2199
# Once https://github.com/containers/podman/issues/27796 is resolved

# Push Image to Registry
[arg("flavor", long="flavor", short="f")]
[arg("ghcr", long="ghcr", value="true")]
[arg("image", long="image", short="i")]
[arg("registry", long="registry")]
[arg("tag", long="tag", short="t")]
[arg("temp_push", long="temp-push", value="true")]
[arg("temp_push_tag", long="temp-push-tag")]
[group('Utility')]
push-image $image=default_image $tag=default_tag $flavor=default_flavor $ghcr="false" $registry="" $temp_push="false" $temp_push_tag="":
    #!/usr/bin/env bash
    set -eoux pipefail

    PUSH_CMD_ARGS=()
    PUSH_CMD_ARGS+=("--digestfile=/tmp/digestfile")
    PUSH_CMD_ARGS+=("--compression-format=zstd")
    PUSH_CMD_ARGS+=("--compression-level=3")
    # TODO; This has failed already once, investigate if this actually does something and we need to use the retry function
    PUSH_CMD_ARGS+=("--retry-delay=60s")
    PUSH_CMD_ARGS+=("--retry=10")

    PUSH_CMD=""${PODMAN}" push "${PUSH_CMD_ARGS[@]}""

    image_name=$({{ just }} image_name --image "${image}" --tag "${tag}" --flavor "${flavor}")

    alias_tags=$({{ just }} generate-build-tags --image "${image}" --tag "${tag}" --flavor "${flavor}")

    if [[ "${ghcr}" == "true" && -n "${registry}" ]]; then

      if [[ "${temp_push}" == "false" ]]; then
        for tag in ${alias_tags}; do
          ${PUSH_CMD} ${image_name}:${tag} ${registry}/${image_name}:${tag}
          # We need to push twice to workaround https://github.com/containers/podman/issues/27796
          ${PUSH_CMD} ${image_name}:${tag} ${registry}/${image_name}:${tag}
          cat /tmp/digestfile
        done

      elif [[ "${temp_push}" == "true" ]]; then
        ${PUSH_CMD} ${image_name}:${tag} ${registry}/${image_name}:${temp_push_tag}-${tag}
        # We need to push twice to workaround https://github.com/containers/podman/issues/27796
        # If we don't do this then the digest changes and we are only signing this specific tag
        ${PUSH_CMD} ${image_name}:${tag} ${registry}/${image_name}:${temp_push_tag}-${tag}
      fi

    else
      echo "This is intended to be run in ghcr only."
      exit 1
    fi

# Login to Container Registry
[group('Utility')]
login-registry bin="" registry="":
    #!/usr/bin/env bash
    set -euxo pipefail

    {{ retry_function }}

    retry 5 60 echo "${GITHUB_TOKEN}" | "{{ bin }}" login "{{ registry }}" -u "${GITHUB_ACTOR}" --password-stdin

# # Examples:
#   > just retag-nvidia-on-ghcr stable stable-41.20250126.3 0
#   > just retag-nvidia-on-ghcr latest latest-41.20250228.1 0
#
# working_tag: The tag of the most recent known good image (e.g., latest.20250126.3)
# stream:      One of latest, stable or testing
# dry_run:     Only print the skopeo commands instead of running them
#
# First generate a PAT with package write access (https://github.com/settings/tokens)
# and set $GITHUB_USERNAME and $GITHUB_PAT environment variables

# Retag images on GHCR
[group('Admin')]
retag-nvidia-on-ghcr working_tag="" stream="" dry_run="1":
    #!/usr/bin/env bash
    set -euxo pipefail
    skopeo="echo === skopeo"
    if [[ "{{ dry_run }}" -ne 1 ]]; then
        echo "$GITHUB_PAT" | podman login -u $GITHUB_USERNAME --password-stdin ghcr.io
        skopeo="skopeo"
    fi
    for image in aurora-nvidia-open aurora-dx-nvidia-open; do
      $skopeo copy docker://ghcr.io/ublue-os/${image}:{{ working_tag }} docker://ghcr.io/ublue-os/${image}:{{ stream }}
    done