Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/build-disk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
fail-fast: false
matrix:
variant:
- name: "regular"
- name: "main"
tag: "latest"
- name: "nvidia"
tag: "latest-nvidia"
Expand All @@ -46,10 +46,10 @@ jobs:
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV}

- name: Maximize build space
uses: ublue-os/remove-unwanted-software@695eb75bc387dbcd9685a8e72d23439d8686cba6 # v10
uses: ublue-os/remove-unwanted-software@v9

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
uses: actions/checkout@v4

- name: Build ISO
id: build
Expand All @@ -71,7 +71,7 @@ jobs:
echo "iso-name=$NEW_NAME" >> $GITHUB_OUTPUT

- name: Upload ISO as artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
uses: actions/upload-artifact@v4
with:
name: ${{ env.IMAGE_NAME }}-${{ matrix.variant.name }}-iso
path: output/
Expand All @@ -81,7 +81,7 @@ jobs:

- name: Upload ISO to release
if: inputs.create-release == true && inputs.release-tag != ''
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ inputs.release-tag }}
files: |
Expand Down
117 changes: 48 additions & 69 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ on:
env:
IMAGE_DESC: "Hypercube - A Hyprland-focused bootc image built on Bluefin-DX"
IMAGE_KEYWORDS: "bootc,ublue,universal-blue,hyprland,hypercube,wayland"
IMAGE_LOGO_URL: "https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/main/branding/hypercube-logo.png" # Hypercube logo
IMAGE_NAME: "${{ github.event.repository.name }}" # output image name, usually same as repo name
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit
IMAGE_LOGO_URL: "https://raw.githubusercontent.com/${{ github.repository_owner }}/${{ github.event.repository.name }}/main/branding/hypercube-logo.png"
IMAGE_NAME: "${{ github.event.repository.name }}"
IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}"
DEFAULT_TAG: "latest"

concurrency:
Expand All @@ -28,7 +28,7 @@ concurrency:
jobs:
build_push:
name: Build and push image
runs-on: ubuntu-latest-m
runs-on: ubuntu-24.04

permissions:
contents: read
Expand All @@ -39,9 +39,11 @@ jobs:
fail-fast: false
matrix:
variant:
- base_image: "ghcr.io/ublue-os/bluefin-dx:stable-daily"
- flavor: "main"
base_image: "ghcr.io/ublue-os/bluefin-dx:stable-daily"
tag_suffix: ""
- base_image: "ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily"
- flavor: "nvidia"
base_image: "ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily"
tag_suffix: "-nvidia"

steps:
Expand All @@ -51,22 +53,15 @@ jobs:
echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV}
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV}

# These stage versions are pinned by https://github.com/renovatebot/renovate
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v5
uses: actions/checkout@v4

# This is optional, but if you see that your builds are way too big for the runners, you can enable this by uncommenting the following lines:
# - name: Maximize build space
# uses: ublue-os/remove-unwanted-software@517622d6452028f266b7ba4cc9a123b5f58a6b53 # v7
# with:
# remove-codeql: true
- name: Maximize build space
uses: ublue-os/remove-unwanted-software@v9

- name: Mount BTRFS for podman storage
id: container-storage-action
uses: ublue-os/container-storage-action@911baca08baf30c8654933e9e9723cb399892140

# Fallback to the remove-unwanted-software-action if github doesn't allocate enough space
# See: https://github.com/ublue-os/container-storage-action/pull/11
uses: ublue-os/container-storage-action@main
continue-on-error: true
with:
target-dir: /var/lib/containers
Expand All @@ -75,21 +70,13 @@ jobs:
- name: Get current date
id: date
run: |
# This generates a timestamp like what is defined on the ArtifactHub documentation
# E.G: 2022-02-08T15:38:15Z'
# https://artifacthub.io/docs/topics/repositories/container-images/
# https://linux.die.net/man/1/date
echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT
echo "version=$(date +%Y%m%d)" >> $GITHUB_OUTPUT

# Image metadata for https://artifacthub.io/ - This is optional but is highly recommended so we all can get a index of all the custom images
# The metadata by itself is not going to do anything, you choose if you want your image to be on ArtifactHub or not.
- name: Image Metadata
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
uses: docker/metadata-action@v5
id: metadata
with:
# This generates all the tags for your image, you can add custom tags here too!
# Default tags are "$DEFAULT_TAG" and "$DEFAULT_TAG.$date".
# Matrix tag_suffix is appended to differentiate variants (e.g., latest vs latest-nvidia)
tags: |
type=raw,value=${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}
type=raw,value=${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}.{{date 'YYYYMMDD'}}
Expand All @@ -105,7 +92,7 @@ jobs:
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
org.opencontainers.image.url=https://github.com/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
org.opencontainers.image.vendor=${{ github.repository_owner }}
org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.{{date 'YYYYMMDD'}}
org.opencontainers.image.version=${{ env.DEFAULT_TAG }}.${{ steps.date.outputs.version }}
io.artifacthub.package.deprecated=false
io.artifacthub.package.keywords=${{ env.IMAGE_KEYWORDS }}
io.artifacthub.package.license=Apache-2.0
Expand All @@ -117,55 +104,50 @@ jobs:

- name: Build Image
id: build_image
uses: redhat-actions/buildah-build@7a95fa7ee0f02d552a32753e7414641a04307056 # v2
uses: redhat-actions/buildah-build@v2
with:
containerfiles: |
./Containerfile
# Postfix image name with -custom to make it a little more descriptive
# Syntax: https://docs.github.com/en/actions/learn-github-actions/expressions#format
image: ${{ env.IMAGE_NAME }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
build-args: |
BASE_IMAGE=${{ matrix.variant.base_image }}
IMAGE_NAME=${{ env.IMAGE_NAME }}
IMAGE_VENDOR=${{ github.repository_owner }}
oci: false

# Rechunk is a script that we use on Universal Blue to make sure there isnt a single huge layer when your image gets published.
# This does not make your image faster to download, just provides better resumability and fixes a few errors.
# Documentation for Rechunk is provided on their github repository at https://github.com/hhd-dev/rechunk
# You can enable it by uncommenting the following lines:
# - name: Run Rechunker
# id: rechunk
# uses: hhd-dev/rechunk@f153348d8100c1f504dec435460a0d7baf11a9d2 # v1.1.1
# with:
# rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.1'
# ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}"
# prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}"
# skip_compression: true
# version: ${{ env.CENTOS_VERSION }}
# labels: ${{ steps.metadata.outputs.labels }} # Rechunk strips out all the labels during build, this needs to be reapplied here with newline separator

# This is necessary so that the podman socket can find the rechunked image on its storage
# - name: Load in podman and tag
# run: |
# IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }})
# sudo rm -rf ${{ steps.rechunk.outputs.output }}
# for tag in ${{ steps.metadata.outputs.tags }}; do
# podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag
# done

# These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing
# They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work
# Rechunk for optimized OCI layers
- name: Run Rechunker
id: rechunk
uses: hhd-dev/rechunk@v1.1.1
if: github.event_name != 'pull_request'
with:
rechunk: 'ghcr.io/hhd-dev/rechunk:v1.0.3'
ref: "localhost/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}"
prev-ref: "${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.DEFAULT_TAG }}${{ matrix.variant.tag_suffix }}"
skip_compression: true
labels: ${{ steps.metadata.outputs.labels }}

- name: Load rechunked image and tag
if: github.event_name != 'pull_request'
run: |
IMAGE=$(podman pull ${{ steps.rechunk.outputs.ref }})
sudo rm -rf ${{ steps.rechunk.outputs.output }}
for tag in ${{ steps.metadata.outputs.tags }}; do
podman tag $IMAGE ${{ env.IMAGE_NAME }}:$tag
done

- name: Login to GitHub Container Registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
uses: docker/login-action@v3
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Push To GHCR
uses: redhat-actions/push-to-registry@5ed88d269cf581ea9ef6dd6806d01562096bee9c # v2
uses: redhat-actions/push-to-registry@v2
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
id: push
env:
Expand All @@ -178,22 +160,19 @@ jobs:
username: ${{ env.REGISTRY_USER }}
password: ${{ env.REGISTRY_PASSWORD }}

# This section is optional and only needs to be enabled if you plan on distributing
# your project for others to consume. You will need to create a public and private key
# using Cosign and save the private key as a repository secret in Github for this workflow
# to consume. For more details, review the image signing section of the README.
- name: Install Cosign
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
uses: sigstore/cosign-installer@v3
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)

- name: Sign container image
if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
run: |
IMAGE_FULL="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}"
for tag in ${{ steps.metadata.outputs.tags }}; do
cosign sign -y --key env://COSIGN_PRIVATE_KEY $IMAGE_FULL:$tag
done
# Sign by digest for better security
IMAGE_DIGEST="${{ steps.push.outputs.digest }}"
IMAGE_REF="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}@${IMAGE_DIGEST}"

echo "Signing image: ${IMAGE_REF}"
cosign sign -y --key env://COSIGN_PRIVATE_KEY "${IMAGE_REF}"
env:
TAGS: ${{ steps.push.outputs.digest }}
COSIGN_EXPERIMENTAL: false
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
19 changes: 16 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
# Secrets
cosign.key
_build_*
output
_build-*/**

# Build artifacts
_build*
_rechunk_output/
output/
output.env
previous.manifest.json
changelog.md

# Titanoboa ISO builder
_titanoboa/

# VM testing
_vm_build/

# ISO files
*.iso
result-iso/
68 changes: 40 additions & 28 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,40 +1,52 @@
# This build argument allows building different variants (regular vs NVIDIA)
ARG BASE_IMAGE=ghcr.io/ublue-os/bluefin-dx:stable-daily
# Hypercube Container Build
# Aligned with Bluefin patterns

# Allow build scripts to be referenced without being copied into the final image
# ============================================
# Build Arguments
# ============================================
ARG BASE_IMAGE=ghcr.io/ublue-os/bluefin-dx:stable-daily
ARG IMAGE_NAME=hypercube
ARG IMAGE_VENDOR=binarypie-dev
ARG SHA_HEAD_SHORT=""

# ============================================
# Stage 1: Context Aggregation
# ============================================
# Aggregate all build context into a single layer for mounting
FROM scratch AS ctx
COPY build_files /
COPY branding /branding
COPY system_files /system_files
COPY build_files /build_files

# Base Image
# ============================================
# Stage 2: Main Build
# ============================================
FROM ${BASE_IMAGE}

# Copy dot_files into the image at /usr/share/hypercube/config
# Re-declare ARGs after FROM (they don't persist across stages)
ARG IMAGE_NAME
ARG IMAGE_VENDOR
ARG SHA_HEAD_SHORT

# Export build-time environment variables
ENV IMAGE_NAME=${IMAGE_NAME}
ENV IMAGE_VENDOR=${IMAGE_VENDOR}

# Copy dot_files (config templates) into the image
COPY dot_files /usr/share/hypercube/config

# Ensure all config files are readable by everyone
RUN chmod -R a+rX /usr/share/hypercube/config

## Other possible base images include:
# FROM ghcr.io/ublue-os/bazzite:latest
# FROM ghcr.io/ublue-os/bluefin-dx-nvidia:stable-daily
#
# ... and so on, here are more base images
# Universal Blue Images: https://github.com/orgs/ublue-os/packages
# Fedora base image: quay.io/fedora/fedora-bootc:41
# CentOS base images: quay.io/centos-bootc/centos-bootc:stream10

### MODIFICATIONS
## make modifications desired in your image and install packages by modifying the build.sh script
## the following RUN directive does all the things required to run "build.sh" as recommended.

# Build with mounted context and caches
# - Bind mount from ctx stage for build scripts and system files
# - Cache mounts for DNF and rpm-ostree to speed up rebuilds
# - Tmpfs for /tmp to avoid polluting the image
RUN --mount=type=bind,from=ctx,source=/,target=/ctx \
--mount=type=cache,dst=/var/cache \
--mount=type=cache,dst=/var/log \
--mount=type=tmpfs,dst=/tmp \
/ctx/build.sh && \
ostree container commit

### LINTING
## Verify final image and contents are correct.
--mount=type=cache,dst=/var/cache/libdnf5 \
--mount=type=cache,dst=/var/cache/rpm-ostree \
--mount=type=tmpfs,dst=/tmp \
/ctx/build_files/shared/build.sh && \
ostree container commit

# Final validation
RUN bootc container lint
Loading