KAMOS Gaming OS - initial scaffold with branding
build-image / Build & push (${{ matrix.platform }}) (linux/amd64) (push) Failing after 51s
Details
build-image / Build & push (${{ matrix.platform }}) (linux/amd64) (push) Failing after 51s
Details
This commit is contained in:
commit
b09d43fa87
|
|
@ -0,0 +1,141 @@
|
||||||
|
###############################################################################
|
||||||
|
# Forgejo Actions - build, sign, and push the KAMOS Gaming OS image
|
||||||
|
#
|
||||||
|
# Configured for: cgi.medsys.cloud/mkm1971/kamos
|
||||||
|
# Runner labels: ubuntu-latest / ubuntu-24.04 / ubuntu-22.04 (Forgejo runner v0.4.1)
|
||||||
|
#
|
||||||
|
# Prereqs in your Forgejo repo:
|
||||||
|
# 1. Container Registry feature enabled on cgi.medsys.cloud.
|
||||||
|
# 2. The runner host must be x86_64 (Bazzite NVIDIA is x86_64 only).
|
||||||
|
# 3. Repository secrets at /mkm1971/kamos/settings/actions/secrets:
|
||||||
|
# - SIGNING_SECRET contents of cosign.key (NOT the .pub)
|
||||||
|
# - REGISTRY_USER mkm1971
|
||||||
|
# - REGISTRY_TOKEN Forgejo access token with `package` write scope
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
name: build-image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
schedule:
|
||||||
|
# Rebuild weekly so we pick up base-image security updates.
|
||||||
|
- cron: "0 6 * * 1"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: kamos
|
||||||
|
IMAGE_TAGS: "stable latest"
|
||||||
|
# Override this in your Forgejo repo's variables to point at your instance.
|
||||||
|
REGISTRY: ${{ vars.REGISTRY || 'cgi.medsys.cloud' }}
|
||||||
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
||||||
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build & push (${{ matrix.platform }})
|
||||||
|
# Matches your runner labels: ubuntu-latest / ubuntu-24.04 / ubuntu-22.04
|
||||||
|
# Assumes the runner host is x86_64 - if it's actually Apple Silicon, the
|
||||||
|
# build will hit "exec format error" and we'll need to add binfmt qemu setup.
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform: [linux/amd64]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Compute tags
|
||||||
|
id: tags
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
DATE_TAG="$(date +%Y%m%d)"
|
||||||
|
SHA_TAG="${GITHUB_SHA::7}"
|
||||||
|
{
|
||||||
|
echo "date_tag=${DATE_TAG}"
|
||||||
|
echo "sha_tag=${SHA_TAG}"
|
||||||
|
echo "image_ref=${REGISTRY}/${{ gitea.repository_owner }}/${IMAGE_NAME}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Install build tooling
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get update -y
|
||||||
|
sudo apt-get install -y podman buildah skopeo cosign jq
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
id: build
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
IMAGE_REF: ${{ steps.tags.outputs.image_ref }}
|
||||||
|
DATE_TAG: ${{ steps.tags.outputs.date_tag }}
|
||||||
|
SHA_TAG: ${{ steps.tags.outputs.sha_tag }}
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
podman build \
|
||||||
|
--platform=${{ matrix.platform }} \
|
||||||
|
--pull=newer \
|
||||||
|
--tag "${IMAGE_REF}:${DATE_TAG}" \
|
||||||
|
--tag "${IMAGE_REF}:${SHA_TAG}" \
|
||||||
|
$(for t in $IMAGE_TAGS; do echo --tag "${IMAGE_REF}:${t}"; done) \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Login to Forgejo container registry
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "${REGISTRY_TOKEN}" | podman login \
|
||||||
|
--username "${REGISTRY_USER}" \
|
||||||
|
--password-stdin \
|
||||||
|
"${REGISTRY}"
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
IMAGE_REF: ${{ steps.tags.outputs.image_ref }}
|
||||||
|
DATE_TAG: ${{ steps.tags.outputs.date_tag }}
|
||||||
|
SHA_TAG: ${{ steps.tags.outputs.sha_tag }}
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
for tag in $DATE_TAG $SHA_TAG $IMAGE_TAGS; do
|
||||||
|
podman push "${IMAGE_REF}:${tag}"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Sign image with cosign
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
|
||||||
|
COSIGN_PASSWORD: ""
|
||||||
|
IMAGE_REF: ${{ steps.tags.outputs.image_ref }}
|
||||||
|
run: |
|
||||||
|
set -euxo pipefail
|
||||||
|
for tag in $IMAGE_TAGS; do
|
||||||
|
DIGEST=$(skopeo inspect --format '{{.Digest}}' "docker://${IMAGE_REF}:${tag}")
|
||||||
|
cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE_REF}@${DIGEST}"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
IMAGE_REF: ${{ steps.tags.outputs.image_ref }}
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo "### Built image"
|
||||||
|
echo ""
|
||||||
|
echo "\`${IMAGE_REF}\` with tags: ${IMAGE_TAGS}"
|
||||||
|
echo ""
|
||||||
|
echo "Switch a target machine to this image with:"
|
||||||
|
echo ""
|
||||||
|
echo "\`\`\`"
|
||||||
|
echo "sudo bootc switch ${IMAGE_REF}:stable"
|
||||||
|
echo "\`\`\`"
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
###############################################################################
|
||||||
|
# GitHub Actions equivalent of the Forgejo workflow.
|
||||||
|
# Disabled by default - rename to build.yml or remove the `if:` guard below
|
||||||
|
# if you decide to mirror to GitHub.
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
name: build-image-github
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
# Uncomment when you actually want GitHub to build:
|
||||||
|
# push:
|
||||||
|
# branches: [main]
|
||||||
|
# schedule:
|
||||||
|
# - cron: "0 6 * * 1"
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: kamos
|
||||||
|
IMAGE_TAGS: "stable latest"
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ false }} # remove this line to enable
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Login to GHCR
|
||||||
|
uses: redhat-actions/podman-login@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
IMAGE_REF="${REGISTRY}/${{ github.repository_owner }}/${IMAGE_NAME}"
|
||||||
|
podman build \
|
||||||
|
--pull=newer \
|
||||||
|
$(for t in $IMAGE_TAGS; do echo --tag "${IMAGE_REF}:${t}"; done) \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Push
|
||||||
|
run: |
|
||||||
|
IMAGE_REF="${REGISTRY}/${{ github.repository_owner }}/${IMAGE_NAME}"
|
||||||
|
for t in $IMAGE_TAGS; do podman push "${IMAGE_REF}:${t}"; done
|
||||||
|
|
||||||
|
- name: Sign
|
||||||
|
env:
|
||||||
|
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
|
||||||
|
COSIGN_PASSWORD: ""
|
||||||
|
run: |
|
||||||
|
IMAGE_REF="${REGISTRY}/${{ github.repository_owner }}/${IMAGE_NAME}"
|
||||||
|
for t in $IMAGE_TAGS; do
|
||||||
|
DIGEST=$(skopeo inspect --format '{{.Digest}}' "docker://${IMAGE_REF}:${t}")
|
||||||
|
cosign sign --yes --key env://COSIGN_PRIVATE_KEY "${IMAGE_REF}@${DIGEST}"
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Build output
|
||||||
|
output/
|
||||||
|
*.qcow2
|
||||||
|
*.iso
|
||||||
|
*.raw
|
||||||
|
|
||||||
|
# Cosign - the .key file MUST never be committed
|
||||||
|
cosign.key
|
||||||
|
*.key
|
||||||
|
|
||||||
|
# OS / editor cruft
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
# =============================================================================
|
||||||
|
# KAMOS - Gaming OS - Containerfile
|
||||||
|
# "Play. Perform. Dominate."
|
||||||
|
# Base: Bazzite NVIDIA stable (proprietary NVIDIA driver, gaming-tuned bootc)
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# Why this base:
|
||||||
|
# ghcr.io/ublue-os/bazzite-nvidia:stable ships with the proprietary NVIDIA
|
||||||
|
# driver baked in via akmods. If you want the open-kernel-module variant,
|
||||||
|
# swap to ghcr.io/ublue-os/bazzite-nvidia-open:stable instead.
|
||||||
|
#
|
||||||
|
# Architecture: x86_64 only. This image will NOT boot natively on an Apple
|
||||||
|
# Silicon Mac. Test it inside VMware Fusion (with x86_64 emulation enabled)
|
||||||
|
# or install on a real NVIDIA PC.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ARG BASE_IMAGE="ghcr.io/ublue-os/bazzite-nvidia"
|
||||||
|
ARG BASE_TAG="stable"
|
||||||
|
|
||||||
|
FROM ${BASE_IMAGE}:${BASE_TAG}
|
||||||
|
|
||||||
|
# OCI labels - good practice and surface nicely on registries / artifacthub.
|
||||||
|
LABEL org.opencontainers.image.title="KAMOS"
|
||||||
|
LABEL org.opencontainers.image.description="KAMOS Gaming OS - Bazzite NVIDIA stable bootc image. Play. Perform. Dominate."
|
||||||
|
LABEL org.opencontainers.image.vendor="Khalaf"
|
||||||
|
LABEL org.opencontainers.image.source="https://cgi.medsys.cloud/mkm1971/kamos"
|
||||||
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
||||||
|
LABEL io.artifacthub.package.readme-url="https://cgi.medsys.cloud/mkm1971/kamos/raw/branch/main/README.md"
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage 1: copy our customisations into the build context
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
COPY build_files/ /tmp/build_files/
|
||||||
|
COPY system_files/ /
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Stage 2: run the customisation script
|
||||||
|
# - install / remove packages
|
||||||
|
# - apply branding (wallpaper, plymouth theme, os-release, GRUB logo)
|
||||||
|
# - any other system tweaks
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
RUN --mount=type=cache,dst=/var/cache \
|
||||||
|
--mount=type=cache,dst=/var/log \
|
||||||
|
--mount=type=tmpfs,dst=/tmp \
|
||||||
|
/tmp/build_files/build.sh && \
|
||||||
|
ostree container commit
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Sanity: make sure the image is bootc-compatible after our changes.
|
||||||
|
# `bootc container lint` is run by ostree container commit but we surface a
|
||||||
|
# friendly error via a final no-op so layer caching is clear.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
###############################################################################
|
||||||
|
# Justfile - convenience commands for building and testing the image
|
||||||
|
# Run `just` (no args) to see the list. Requires `just` (brew install just).
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
image_name := "kamos"
|
||||||
|
default_tag := "stable"
|
||||||
|
bib_image := "quay.io/centos-bootc/bootc-image-builder:latest"
|
||||||
|
|
||||||
|
# Show available recipes.
|
||||||
|
default:
|
||||||
|
@just --list
|
||||||
|
|
||||||
|
# Build the OCI image with podman.
|
||||||
|
# On an Apple Silicon Mac you MUST pass --platform=linux/amd64 because the
|
||||||
|
# upstream Bazzite NVIDIA image is x86_64 only. This will use qemu emulation
|
||||||
|
# and will be slow. CI is the much faster path.
|
||||||
|
build target_image=image_name tag=default_tag:
|
||||||
|
podman build \
|
||||||
|
--platform=linux/amd64 \
|
||||||
|
--pull=newer \
|
||||||
|
--tag {{ target_image }}:{{ tag }} \
|
||||||
|
.
|
||||||
|
|
||||||
|
# Build a QCOW2 disk image (good for testing in VMware/UTM/QEMU).
|
||||||
|
build-qcow2 target_image=image_name tag=default_tag:
|
||||||
|
just _build-disk {{ target_image }} {{ tag }} qcow2
|
||||||
|
|
||||||
|
# Build an ISO suitable for installation onto a real NVIDIA PC.
|
||||||
|
build-iso target_image=image_name tag=default_tag:
|
||||||
|
just _build-disk {{ target_image }} {{ tag }} iso
|
||||||
|
|
||||||
|
# Build a raw disk image.
|
||||||
|
build-raw target_image=image_name tag=default_tag:
|
||||||
|
just _build-disk {{ target_image }} {{ tag }} raw
|
||||||
|
|
||||||
|
# Internal: invoke bootc-image-builder.
|
||||||
|
_build-disk target_image tag type:
|
||||||
|
mkdir -p output
|
||||||
|
podman run \
|
||||||
|
--rm \
|
||||||
|
--privileged \
|
||||||
|
--pull=newer \
|
||||||
|
--security-opt label=type:unconfined_t \
|
||||||
|
-v $(pwd)/output:/output \
|
||||||
|
-v $(pwd)/disk_config:/config:ro \
|
||||||
|
-v /var/lib/containers/storage:/var/lib/containers/storage \
|
||||||
|
{{ bib_image }} \
|
||||||
|
--type {{ type }} \
|
||||||
|
--use-librepo=True \
|
||||||
|
--local \
|
||||||
|
localhost/{{ target_image }}:{{ tag }}
|
||||||
|
|
||||||
|
# Run the QCOW2 image in QEMU directly (fast, headless-friendly).
|
||||||
|
run-vm-qcow2:
|
||||||
|
qemu-system-x86_64 \
|
||||||
|
-enable-kvm \
|
||||||
|
-M q35 \
|
||||||
|
-cpu host \
|
||||||
|
-smp 4 \
|
||||||
|
-m 6G \
|
||||||
|
-drive file=output/qcow2/disk.qcow2,if=virtio \
|
||||||
|
-nic user,model=virtio-net-pci
|
||||||
|
|
||||||
|
# Lint shell scripts.
|
||||||
|
lint:
|
||||||
|
shellcheck build_files/*.sh
|
||||||
|
|
||||||
|
# Format shell scripts.
|
||||||
|
format:
|
||||||
|
shfmt -w build_files/*.sh
|
||||||
|
|
||||||
|
# Validate the Justfile itself.
|
||||||
|
check:
|
||||||
|
just --fmt --check --unstable
|
||||||
|
|
||||||
|
# Remove build artifacts.
|
||||||
|
clean:
|
||||||
|
rm -rf output
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
# KAMOS - Gaming OS
|
||||||
|
|
||||||
|
> Play. Perform. Dominate.
|
||||||
|
|
||||||
|
KAMOS is a personal Bazzite-based bootc image with custom logo, wallpaper, boot splash, and OS branding. Built on top of `ghcr.io/ublue-os/bazzite-nvidia:stable` so the proprietary NVIDIA driver and Bazzite's gaming/desktop tuning come for free.
|
||||||
|
|
||||||
|
## Architecture note (important if you're on a Mac)
|
||||||
|
|
||||||
|
KAMOS is `linux/amd64` only. Bazzite NVIDIA has no ARM64 build and NVIDIA's proprietary driver doesn't run on Apple Silicon anyway. The MacBook M2 is fine as a *build host* (CI does the heavy lifting) and as a *test host* via VMware Fusion's x86_64 emulation, but KAMOS is meant to run on a real NVIDIA PC.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
kamos/
|
||||||
|
├── Containerfile # FROM bazzite-nvidia:stable + COPY + RUN build.sh
|
||||||
|
├── Justfile # build / build-iso / build-qcow2 / lint
|
||||||
|
├── build_files/
|
||||||
|
│ └── build.sh # all KAMOS customisation lives here
|
||||||
|
├── disk_config/
|
||||||
|
│ └── iso.toml # bootc-image-builder ISO config
|
||||||
|
├── system_files/ # COPY'd into / inside the image
|
||||||
|
│ └── usr/share/
|
||||||
|
│ ├── backgrounds/kamos/ # drop kamos-wallpaper.jpg here
|
||||||
|
│ ├── plymouth/themes/kamos/ # boot splash (kamos.plymouth + kamos.script + logo)
|
||||||
|
│ └── pixmaps/ # drop kamos-logo.png here (GRUB logo)
|
||||||
|
├── .forgejo/workflows/build.yml # primary CI - builds & pushes to Forgejo
|
||||||
|
└── .github/workflows/build.yml # disabled GitHub equivalent (mirror if needed)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 1 — Drop in your KAMOS branding assets
|
||||||
|
|
||||||
|
The repo has placeholder `DROP_*_HERE.txt` files in the right folders. Replace them with:
|
||||||
|
|
||||||
|
| Path | What goes here | Recommended size |
|
||||||
|
| --------------------------------------------------------------------- | ------------------------------------------- | --------------------- |
|
||||||
|
| `system_files/usr/share/backgrounds/kamos/kamos-wallpaper.jpg` | Your "Play. Perform. Dominate." wallpaper | 3840x2160 or 1920x1080 |
|
||||||
|
| `system_files/usr/share/plymouth/themes/kamos/kamos-logo.png` | KAMOS logo (raven crest) for boot splash | 256x256 or 512x512, transparent PNG |
|
||||||
|
| `system_files/usr/share/pixmaps/kamos-logo.png` | Same logo, used by GRUB boot menu | 256x256 or 512x512, transparent PNG |
|
||||||
|
|
||||||
|
You can drop additional files anywhere under `system_files/`; they'll all be COPY'd into `/`. Delete the `DROP_*_HERE.txt` files once you've added the real assets.
|
||||||
|
|
||||||
|
## Step 2 — Configure your Forgejo registry
|
||||||
|
|
||||||
|
The repo is already wired for `cgi.medsys.cloud/mkm1971/kamos` and the runner label `ubuntu-latest`. You only need to add three secrets so CI can push and sign images.
|
||||||
|
|
||||||
|
Go to **https://cgi.medsys.cloud/mkm1971/kamos/settings/actions/secrets** and add:
|
||||||
|
|
||||||
|
| Secret name | Value |
|
||||||
|
| ---------------- | -------------------------------------------------------------- |
|
||||||
|
| `SIGNING_SECRET` | The full contents of `cosign.key` (created in Step 3 below) |
|
||||||
|
| `REGISTRY_USER` | `mkm1971` |
|
||||||
|
| `REGISTRY_TOKEN` | A Forgejo access token with `package` write scope |
|
||||||
|
|
||||||
|
To create `REGISTRY_TOKEN`: in Forgejo, click your avatar (top-right) → **Settings → Applications → Generate New Token**. Name it `kamos-ci`, tick the **package: write** scope, click Generate, and copy the token immediately (it's shown only once).
|
||||||
|
|
||||||
|
## Step 3 — Generate a cosign signing key
|
||||||
|
|
||||||
|
On your M2:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install cosign
|
||||||
|
cd /path/to/kamos
|
||||||
|
COSIGN_PASSWORD="" cosign generate-key-pair
|
||||||
|
```
|
||||||
|
|
||||||
|
Creates `cosign.key` (private — **never commit**) and `cosign.pub` (commit this). Paste the contents of `cosign.key` into the `SIGNING_SECRET` repository secret.
|
||||||
|
|
||||||
|
## Step 4 — Push to Forgejo and let CI build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git init
|
||||||
|
git add .
|
||||||
|
git commit -m "KAMOS initial scaffold"
|
||||||
|
git remote add origin https://cgi.medsys.cloud/mkm1971/kamos.git
|
||||||
|
git push -u origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
Forgejo Actions needs an `linux-amd64` runner. Register one on any x86_64 Linux machine (the NVIDIA PC works perfectly).
|
||||||
|
|
||||||
|
## Step 5 — (Optional) Iterate locally on the M2
|
||||||
|
|
||||||
|
The base image is x86_64, so Podman has to emulate. Slow but works for quick checks.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install podman just
|
||||||
|
podman machine init --cpus 6 --memory 8192 --disk-size 60
|
||||||
|
podman machine start
|
||||||
|
just build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step 6 — Generate a bootable ISO for VMware Fusion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
just build # builds the OCI image
|
||||||
|
just build-iso # wraps it with bootc-image-builder into output/bootiso/install.iso
|
||||||
|
```
|
||||||
|
|
||||||
|
VMware Fusion 13+ on Apple Silicon supports x86_64 emulation. New VM → install from ISO → choose `output/bootiso/install.iso` → guest type "Other Linux 5.x kernel 64-bit". Expect single-digit FPS in the GUI, but the boot splash and branding will render fine. This is the path you mentioned for your VMware testing setup.
|
||||||
|
|
||||||
|
## Step 7 — Install on the real NVIDIA PC
|
||||||
|
|
||||||
|
If the PC is already on a bootc image (Bazzite, Bluefin, Aurora, etc.):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo bootc switch cgi.medsys.cloud/mkm1971/kamos:stable
|
||||||
|
sudo systemctl reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
If it's running something else, install Bazzite from its normal ISO first, then `bootc switch` to KAMOS. Or burn the ISO from step 6 to a USB stick and install fresh.
|
||||||
|
|
||||||
|
## Updating
|
||||||
|
|
||||||
|
CI rebuilds weekly so you pick up upstream Bazzite security fixes. Push any commit to `main` or run the workflow manually to bump immediately.
|
||||||
|
|
||||||
|
## What gets branded
|
||||||
|
|
||||||
|
`build.sh` applies KAMOS branding in seven places:
|
||||||
|
|
||||||
|
1. `/etc/os-release` → `NAME`, `PRETTY_NAME`, `VARIANT`, `HOME_URL` (so `neofetch`/`fastfetch` show "KAMOS Gaming OS - Play. Perform. Dominate.")
|
||||||
|
2. GNOME default wallpaper (system-wide via dconf override, applies to all new users)
|
||||||
|
3. GNOME lock-screen / screensaver background (same wallpaper)
|
||||||
|
4. Plymouth boot splash (custom `kamos` theme with pulsing logo on black)
|
||||||
|
5. Initramfs is regenerated with `dracut --force --regenerate-all` so the splash shows on first boot
|
||||||
|
6. GRUB boot-menu logo (logo PNG dropped into Bazzite's GRUB theme)
|
||||||
|
7. Container image labels (visible in registries / artifacthub)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**`podman build` fails with "exec format error"**: forgot `--platform=linux/amd64` on Apple Silicon, or QEMU user-static isn't enabled in your Podman machine.
|
||||||
|
|
||||||
|
**Boot splash doesn't show**: confirm the kernel cmdline has `rhgb quiet splash` (it does, via iso.toml). On a `bootc switch` upgrade you may need to re-run `dracut --force --regenerate-all` and reboot once.
|
||||||
|
|
||||||
|
**Wallpaper doesn't apply for existing user**: the dconf override is `system-db:local`, which only affects new users. Existing accounts have their own user dconf — set it manually once with `gsettings set org.gnome.desktop.background picture-uri 'file:///usr/share/backgrounds/kamos/kamos-wallpaper.jpg'`.
|
||||||
|
|
||||||
|
**Image builds but boot loops on real hardware**: usually SecureBoot rejecting unsigned NVIDIA modules. Disable SecureBoot in BIOS or enroll Bazzite's MOK key (Bazzite docs cover this).
|
||||||
|
|
||||||
|
**Cosign signing step fails**: `SIGNING_SECRET` must be the *contents* of `cosign.key`, not a path. The key must be generated with an empty password.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache-2.0 — same as the upstream `ublue-os/image-template`.
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# =============================================================================
|
||||||
|
# build.sh - runs INSIDE the container during `podman build`
|
||||||
|
#
|
||||||
|
# Anything you'd normally `dnf install`, `systemctl enable`, or drop in
|
||||||
|
# /etc or /usr goes here. Run as root, on Fedora bootc.
|
||||||
|
# =============================================================================
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 1. Install extra packages
|
||||||
|
# Bazzite already ships a LOT - check `rpm -qa` on the base before adding.
|
||||||
|
# Anything you uncomment below will be layered on top.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
EXTRA_PACKAGES=(
|
||||||
|
# CLI niceties
|
||||||
|
# htop
|
||||||
|
# bat
|
||||||
|
# ripgrep
|
||||||
|
# fastfetch
|
||||||
|
|
||||||
|
# Dev tooling
|
||||||
|
# gh
|
||||||
|
# tmux
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ ${#EXTRA_PACKAGES[@]} -gt 0 ]; then
|
||||||
|
dnf -y install "${EXTRA_PACKAGES[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 2. Remove packages you don't want
|
||||||
|
# Use `dnf -y remove --no-autoremove` so you don't accidentally pull
|
||||||
|
# half the desktop with you.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
REMOVE_PACKAGES=(
|
||||||
|
# firefox
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ ${#REMOVE_PACKAGES[@]} -gt 0 ]; then
|
||||||
|
dnf -y remove --no-autoremove "${REMOVE_PACKAGES[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 3. Enable systemd units (system-wide)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
SERVICES_ENABLE=(
|
||||||
|
# podman.socket
|
||||||
|
)
|
||||||
|
|
||||||
|
for svc in "${SERVICES_ENABLE[@]}"; do
|
||||||
|
systemctl enable "$svc"
|
||||||
|
done
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 4. KAMOS branding - OS release name shown in `neofetch`, login screen, etc.
|
||||||
|
# The base bazzite-nvidia overrides /etc/os-release; we patch the
|
||||||
|
# customisable fields without breaking version detection.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
KAMOS_OS_NAME="KAMOS Gaming OS"
|
||||||
|
KAMOS_TAGLINE="Play. Perform. Dominate."
|
||||||
|
KAMOS_HOME_URL="https://cgi.medsys.cloud/mkm1971/kamos"
|
||||||
|
|
||||||
|
if [ -f /usr/lib/os-release ]; then
|
||||||
|
sed -i \
|
||||||
|
-e "s|^NAME=.*|NAME=\"${KAMOS_OS_NAME}\"|" \
|
||||||
|
-e "s|^PRETTY_NAME=.*|PRETTY_NAME=\"${KAMOS_OS_NAME} - ${KAMOS_TAGLINE}\"|" \
|
||||||
|
-e "s|^HOME_URL=.*|HOME_URL=\"${KAMOS_HOME_URL}\"|" \
|
||||||
|
-e "s|^VARIANT=.*|VARIANT=\"KAMOS\"|" \
|
||||||
|
-e "s|^VARIANT_ID=.*|VARIANT_ID=kamos|" \
|
||||||
|
/usr/lib/os-release
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 5. KAMOS wallpaper
|
||||||
|
# File: system_files/usr/share/backgrounds/kamos/kamos-wallpaper.jpg
|
||||||
|
# Sets a system-wide default for all new users via a dconf override.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
KAMOS_WALLPAPER="/usr/share/backgrounds/kamos/kamos-wallpaper.jpg"
|
||||||
|
|
||||||
|
if [ -f "${KAMOS_WALLPAPER}" ]; then
|
||||||
|
echo "==> Applying KAMOS wallpaper"
|
||||||
|
mkdir -p /etc/dconf/db/local.d /etc/dconf/profile
|
||||||
|
cat > /etc/dconf/profile/user <<'EOF'
|
||||||
|
user-db:user
|
||||||
|
system-db:local
|
||||||
|
EOF
|
||||||
|
cat > /etc/dconf/db/local.d/01-kamos-wallpaper <<EOF
|
||||||
|
[org/gnome/desktop/background]
|
||||||
|
picture-uri='file://${KAMOS_WALLPAPER}'
|
||||||
|
picture-uri-dark='file://${KAMOS_WALLPAPER}'
|
||||||
|
picture-options='zoom'
|
||||||
|
primary-color='#000000'
|
||||||
|
|
||||||
|
[org/gnome/desktop/screensaver]
|
||||||
|
picture-uri='file://${KAMOS_WALLPAPER}'
|
||||||
|
picture-options='zoom'
|
||||||
|
primary-color='#000000'
|
||||||
|
EOF
|
||||||
|
dconf update || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 6. KAMOS Plymouth boot splash
|
||||||
|
# Files (provided by us in system_files/):
|
||||||
|
# /usr/share/plymouth/themes/kamos/kamos.plymouth
|
||||||
|
# /usr/share/plymouth/themes/kamos/kamos.script
|
||||||
|
# /usr/share/plymouth/themes/kamos/kamos-logo.png (drop your PNG here)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
if [ -f /usr/share/plymouth/themes/kamos/kamos.plymouth ]; then
|
||||||
|
echo "==> Setting KAMOS as default plymouth theme"
|
||||||
|
plymouth-set-default-theme kamos
|
||||||
|
# Rebuild the initramfs so the splash is actually used at next boot.
|
||||||
|
# Bazzite uses dracut.
|
||||||
|
if command -v dracut >/dev/null 2>&1; then
|
||||||
|
dracut --force --regenerate-all || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 7. KAMOS GRUB logo
|
||||||
|
# Bazzite ships its own GRUB theme; we replace the logo asset only.
|
||||||
|
# File: system_files/usr/share/pixmaps/kamos-logo.png (24-bit, ~256x256)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
KAMOS_LOGO="/usr/share/pixmaps/kamos-logo.png"
|
||||||
|
if [ -f "${KAMOS_LOGO}" ]; then
|
||||||
|
echo "==> KAMOS logo present at ${KAMOS_LOGO}"
|
||||||
|
# If a Bazzite GRUB theme exists, drop the logo into it for the boot menu.
|
||||||
|
for theme_dir in /usr/share/grub/themes/*/; do
|
||||||
|
if [ -d "${theme_dir}" ]; then
|
||||||
|
cp -f "${KAMOS_LOGO}" "${theme_dir}/logo.png" || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 8. Cleanup
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
dnf clean all
|
||||||
|
rm -rf /tmp/* /var/* || true
|
||||||
|
mkdir -p /var/log /var/cache /var/tmp
|
||||||
|
|
||||||
|
echo "==> build.sh finished cleanly"
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEes1gKNIutrZ1lvZDyo7GXBsJh0Xo
|
||||||
|
k1Pdq+dfBYlpZFHHzZISMSxpBbIeB6XB5xSnhTe8IREfdBmVqYunmwsd+A==
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
# KAMOS Gaming OS - bootc-image-builder ISO config
|
||||||
|
# Used by `just build-iso` and the build-disk workflow.
|
||||||
|
# Reference: https://osbuild.org/docs/bootc/
|
||||||
|
|
||||||
|
[customizations]
|
||||||
|
hostname = "kamos"
|
||||||
|
|
||||||
|
[[customizations.user]]
|
||||||
|
name = "khalaf"
|
||||||
|
password = "changeme"
|
||||||
|
groups = ["wheel"]
|
||||||
|
|
||||||
|
[customizations.kernel]
|
||||||
|
# NVIDIA proprietary driver works best with the modules baked into Bazzite's
|
||||||
|
# kernel. `splash` enables Plymouth so the KAMOS boot splash actually shows.
|
||||||
|
# Don't add nomodeset unless you've fallen back to a recovery scenario.
|
||||||
|
append = "rhgb quiet splash"
|
||||||
|
|
||||||
|
[customizations.locale]
|
||||||
|
languages = ["en_US.UTF-8"]
|
||||||
|
keyboard = "us"
|
||||||
|
|
||||||
|
[customizations.timezone]
|
||||||
|
timezone = "UTC"
|
||||||
|
|
||||||
|
[[customizations.filesystem]]
|
||||||
|
mountpoint = "/"
|
||||||
|
minsize = "10 GiB"
|
||||||
|
|
||||||
|
[[customizations.filesystem]]
|
||||||
|
mountpoint = "/var"
|
||||||
|
minsize = "20 GiB"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 523 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 523 KiB |
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Plymouth Theme]
|
||||||
|
Name=KAMOS
|
||||||
|
Description=KAMOS Gaming OS boot splash - Play. Perform. Dominate.
|
||||||
|
ModuleName=script
|
||||||
|
|
||||||
|
[script]
|
||||||
|
ImageDir=/usr/share/plymouth/themes/kamos
|
||||||
|
ScriptFile=/usr/share/plymouth/themes/kamos/kamos.script
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// =============================================================================
|
||||||
|
// KAMOS Gaming OS - Plymouth boot splash
|
||||||
|
// Pure black background (matches the wallpaper aesthetic) with the KAMOS logo
|
||||||
|
// centered, plus a subtle pulsing alpha so it feels alive on long boots.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// 1. Pure black background
|
||||||
|
Window.SetBackgroundTopColor(0.0, 0.0, 0.0);
|
||||||
|
Window.SetBackgroundBottomColor(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
// 2. Logo - expects kamos-logo.png in the same theme directory
|
||||||
|
logo.image = Image("kamos-logo.png");
|
||||||
|
logo.sprite = Sprite(logo.image);
|
||||||
|
logo.x = Window.GetX() + Window.GetWidth() / 2 - logo.image.GetWidth() / 2;
|
||||||
|
logo.y = Window.GetY() + Window.GetHeight() / 2 - logo.image.GetHeight() / 2;
|
||||||
|
logo.sprite.SetPosition(logo.x, logo.y, 0);
|
||||||
|
|
||||||
|
// 3. Gentle pulse - alpha bobs between 0.65 and 1.0 over ~2 seconds
|
||||||
|
progress = 0;
|
||||||
|
fun refresh_callback () {
|
||||||
|
progress += 0.02;
|
||||||
|
alpha = 0.825 + 0.175 * Math.Sin(progress);
|
||||||
|
logo.sprite.SetOpacity(alpha);
|
||||||
|
}
|
||||||
|
Plymouth.SetRefreshFunction(refresh_callback);
|
||||||
|
|
||||||
|
// 4. Show password prompts (LUKS unlock) below the logo if needed
|
||||||
|
fun display_password_callback (prompt, bullets) {
|
||||||
|
if (!global.prompt_box) {
|
||||||
|
global.prompt_box.image = Image.Text(prompt, 1, 1, 1);
|
||||||
|
global.prompt_box.sprite = Sprite(global.prompt_box.image);
|
||||||
|
global.prompt_box.sprite.SetPosition(
|
||||||
|
Window.GetWidth() / 2 - global.prompt_box.image.GetWidth() / 2,
|
||||||
|
logo.y + logo.image.GetHeight() + 40,
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Plymouth.SetDisplayPasswordFunction(display_password_callback);
|
||||||
Loading…
Reference in New Issue