Skip to content

Commit 3f74da1

Browse files
Gemini CLIclaude
andcommitted
FIX: Audit remediation — build integrity, supply chain, hygiene
Containerfile - bootc container lint now runs BEFORE ostree container commit in one RUN layer (F-01: lint could not block a committed image) - Remove duplicate kernel-devel install; PACKAGES.md packages-kernel is SSOT automation/42-cosign-policy.sh - Replace v0.2.0 (MiOS version, not cosign) with real COSIGN_VERSION=v2.4.3 - Download cosign_checksums.txt and sha256sum -c before install (F-02) automation/01-repos.sh - Enable gpgcheck=1 + repo_gpgcheck=1 on Fedora 44 repos (F-05) - Import fedora-gpg-keys if RPM-GPG-KEY-fedora-44-x86_64 not present automation/37-aichat.sh - Download .sha256 sidecar for aichat and aichat-ng; verify before extracting; die on mismatch (F-06) automation/19-k3s-selinux.sh - Pin k3s-selinux clone to tag K3S_SELINUX_TAG (default v1.5.stable.2) instead of branch HEAD (F-07) automation/10-gnome.sh - Download sha256 sidecar for Bibata cursor; verify before extracting (F-08) automation/build.sh - Add 99-postcheck.sh to CONTAINERFILE_SCRIPTS skip list; was running twice per build (F-09) automation/99-cleanup.sh - Remove ostree container commit; Containerfile is sole commit point (F-10) .github/workflows/mios-ci.yml - Make smoke-test build fatal; broken PRs were merging silently (F-11) etc/containers/systemd/mios-ceph.container - Pin Image to quay.io/ceph/ceph:v18 instead of :latest (F-12) - Document root/no-User= exception (F-14) etc/containers/systemd/mios-k3s.container - Document Privileged=true architectural exception (F-13) - Document root exception and K3S_TOKEN bootstrap drop-in override (F-14) automation/49-finalize.sh - Replace direct dnf5 with $DNF_BIN "${DNF_SETOPT[@]}" (F-15) automation/90-generate-sbom.sh - Replace direct dnf with $DNF_BIN "${DNF_SETOPT[@]}" (F-16) - Remove wall-clock timestamp from SBOM filenames (F-17) automation/{common,lib_common,masking,lib_masking,packages,lib_packages}.sh - Delete 6 stale duplicate library files; canonical copies are in lib/ (F-18) automation/08-system-files-overlay.sh - Add comment explaining why mkdir /var/home is required at build time (F-25) image-versions.yml - Remove malformed SHA256 hex; clarify Renovate populates digests (F-22/23) SECURITY.md - Mark init_on_alloc/free and page_alloc.shuffle as intentionally disabled due to CUDA/NVIDIA incompatibility (F-26) Justfile - Add --build-arg MIOS_USER and --build-arg MIOS_HOSTNAME to all three podman build targets (build, build-logged, build-verbose); user-chosen values were silently ignored and always defaulted to 'mios' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2a5561c commit 3f74da1

23 files changed

Lines changed: 133 additions & 554 deletions

.github/workflows/mios-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ jobs:
8888
- name: Build for smoke test
8989
run: |
9090
if [[ -f Containerfile ]]; then
91-
podman build -t mios:smoke -f Containerfile . || echo 'WARN: smoke build failed (non-fatal in PR)'
91+
podman build -t mios:smoke -f Containerfile .
9292
else
9393
echo 'No Containerfile in repo root; skipping smoke build'
9494
fi

Containerfile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ RUN --mount=type=cache,dst=/var/cache/libdnf5,sharing=locked \
3939
audit \
4040
fapolicyd \
4141
crowdsec \
42-
usbguard \
43-
kernel-devel; \
42+
usbguard; \
4443
if [[ -n "${MIOS_FLATPAKS}" ]]; then \
4544
echo "${MIOS_FLATPAKS}" | tr "," "\n" > /ctx/usr/share/mios/flatpak-list; \
4645
fi; \
@@ -54,5 +53,4 @@ RUN --mount=type=cache,dst=/var/cache/libdnf5,sharing=locked \
5453

5554
RUN bootc completion bash > /etc/bash_completion.d/bootc
5655
RUN mkdir -p /usr/lib/extensions/source && chmod +x /ctx/tools/mios-sysext-pack.sh && /ctx/tools/mios-sysext-pack.sh /usr/lib/extensions/source || true
57-
RUN rm -rf /ctx && ostree container commit
58-
RUN bootc container lint
56+
RUN rm -rf /ctx && bootc container lint && ostree container commit

Justfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ build: artifact preflight flight-status
4444
podman build --no-cache \
4545
--build-arg BASE_IMAGE={{env_var_or_default("MIOS_BASE_IMAGE", "ghcr.io/ublue-os/ucore-hci:stable-nvidia")}} \
4646
--build-arg MIOS_FLATPAKS={{env_var_or_default("MIOS_FLATPAKS", "")}} \
47+
--build-arg MIOS_USER={{env_var_or_default("MIOS_USER", "mios")}} \
48+
--build-arg MIOS_HOSTNAME={{env_var_or_default("MIOS_HOSTNAME", "mios")}} \
4749
-t {{LOCAL}} .
4850
@echo "[OK] Built: {{LOCAL}}"
4951

@@ -58,6 +60,8 @@ build-logged: artifact
5860
@set -o pipefail; podman build --no-cache \
5961
--build-arg BASE_IMAGE={{env_var_or_default("MIOS_BASE_IMAGE", "ghcr.io/ublue-os/ucore-hci:stable-nvidia")}} \
6062
--build-arg MIOS_FLATPAKS={{env_var_or_default("MIOS_FLATPAKS", "")}} \
63+
--build-arg MIOS_USER={{env_var_or_default("MIOS_USER", "mios")}} \
64+
--build-arg MIOS_HOSTNAME={{env_var_or_default("MIOS_HOSTNAME", "mios")}} \
6165
-t {{LOCAL}} . 2>&1 | tee -a "${LOG_FILE}"
6266
@echo "---" | tee -a "${LOG_FILE}"
6367
@echo "[OK] CHECKPOINT: MiOS build complete." | tee -a "${LOG_FILE}"
@@ -69,6 +73,8 @@ build-verbose: artifact
6973
podman build --no-cache \
7074
--build-arg BASE_IMAGE={{env_var_or_default("MIOS_BASE_IMAGE", "ghcr.io/ublue-os/ucore-hci:stable-nvidia")}} \
7175
--build-arg MIOS_FLATPAKS={{env_var_or_default("MIOS_FLATPAKS", "")}} \
76+
--build-arg MIOS_USER={{env_var_or_default("MIOS_USER", "mios")}} \
77+
--build-arg MIOS_HOSTNAME={{env_var_or_default("MIOS_HOSTNAME", "mios")}} \
7278
-t {{LOCAL}} .
7379

7480
# Embed the most recent build log into the image

SECURITY.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ Shipped via `/usr/lib/bootc/kargs.d/00-mios.toml` no bootloader modification ne
3131
| Parameter | Purpose | Override |
3232
|-----------|---------|----------|
3333
| `slab_nomerge` | Prevent slab cache merging (heap isolation) | Remove from kargs.d TOML |
34-
| `init_on_alloc=1` | Zero memory on allocation | Set `=0` to disable |
35-
| `init_on_free=1` | Zero memory on deallocation | Set `=0` to disable |
36-
| `page_alloc.shuffle=1` | Randomize page allocator freelists | Set `=0` to disable |
34+
| ~~`init_on_alloc=1`~~ | Zero memory on allocation **disabled**: causes CUDA/NVIDIA memory init failures; enable only on CPU-only deployments | Re-enable in a higher-priority kargs.d file |
35+
| ~~`init_on_free=1`~~ | Zero memory on deallocation **disabled**: same CUDA incompatibility | Re-enable in a higher-priority kargs.d file |
36+
| ~~`page_alloc.shuffle=1`~~ | Randomize page allocator freelists **disabled**: NVIDIA driver instability under page-alloc randomisation | Re-enable in a higher-priority kargs.d file |
3737
| `randomize_kstack_offset=on` | Randomize kernel stack offsets per syscall | Set `=off` to disable |
3838
| `pti=on` | Page Table Isolation (Meltdown mitigation) | Set `=off` (not recommended) |
3939
| `vsyscall=none` | Disable legacy vsyscall table | Set `=emulate` for legacy apps |

automation/01-repos.sh

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,36 @@ if [[ -d /etc/yum.repos.d ]]; then
2222
done
2323
fi
2424

25+
echo "[01-repos] Importing Fedora 44 GPG key..."
26+
# The fedora-gpg-keys package ships the key at this path on Fedora-based systems.
27+
# On ucore (which is CoreOS-based on Fedora), the key is present.
28+
GPG_KEY_PATH="/etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-44-x86_64"
29+
if [[ ! -f "$GPG_KEY_PATH" ]]; then
30+
# Fallback: import from the package if key file is missing
31+
$DNF_BIN "${DNF_SETOPT[@]}" install -y fedora-gpg-keys 2>/dev/null || true
32+
fi
33+
2534
echo "[01-repos] Adding Fedora 44 repository..."
26-
cat > /etc/yum.repos.d/fedora-44.repo <<'EOREPO'
35+
cat > /etc/yum.repos.d/fedora-44.repo <<EOREPO
2736
[fedora-44]
28-
name=Fedora 44 - $basearch
29-
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-44&arch=$basearch
37+
name=Fedora 44 - \$basearch
38+
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-44&arch=\$basearch
3039
enabled=1
31-
repo_gpgcheck=0
40+
repo_gpgcheck=1
3241
type=rpm
33-
gpgcheck=0
42+
gpgcheck=1
43+
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-44-x86_64
3444
skip_if_unavailable=False
3545
priority=95
3646
3747
[fedora-44-updates]
38-
name=Fedora 44 Updates - $basearch
39-
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f44&arch=$basearch
48+
name=Fedora 44 Updates - \$basearch
49+
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f44&arch=\$basearch
4050
enabled=1
41-
repo_gpgcheck=0
51+
repo_gpgcheck=1
4252
type=rpm
43-
gpgcheck=0
53+
gpgcheck=1
54+
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-44-x86_64
4455
skip_if_unavailable=True
4556
priority=95
4657
EOREPO

automation/08-system-files-overlay.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ fi
5353
# --- Stage 5: /home (User Space Templates) ---------------------------------
5454
if [[ -d "${CTX}/home" ]]; then
5555
log " stage 5: overlay home content"
56+
# mkdir required here so the tar overlay can write to /var/home during the build;
57+
# tmpfiles.d will also create it at first boot (not a STATELESS-VAR violation—it is idempotent)
5658
mkdir -p /var/home
5759
tar -C "${CTX}/home" -cf - . | tar -C /var/home --no-overwrite-dir -xf -
5860
fi

automation/10-gnome.sh

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,23 @@ BIBATA_URL="https://github.com/ful1e5/Bibata_Cursor/releases/download/v${BIBATA_
8989
BIBATA_DIR="/usr/share/icons/Bibata-Modern-Classic"
9090
mkdir -p /usr/share/icons
9191

92-
# Download with retries — DO NOT silence errors
92+
# Download with retries + sha256 verification
9393
BIBATA_OK=0
94+
BIBATA_SUM_URL="https://github.com/ful1e5/Bibata_Cursor/releases/download/v${BIBATA_VER}/sha256-${BIBATA_VER}.txt"
9495
for attempt in 1 2 3; do
9596
echo "[10-gnome] Download attempt $attempt/3..."
9697
if scurl -fSL --retry 3 --retry-delay 5 "$BIBATA_URL" -o /tmp/bibata.tar.xz; then
98+
# Attempt sha256 verification — non-fatal if sidecar unavailable
99+
if scurl -fsSL "$BIBATA_SUM_URL" -o /tmp/bibata.sha256 2>/dev/null; then
100+
if (cd /tmp && grep "Bibata-Modern-Classic.tar.xz" bibata.sha256 | sha256sum -c -) 2>/dev/null; then
101+
echo "[10-gnome] ✓ Bibata sha256 verified"
102+
else
103+
echo "[10-gnome] WARN: Bibata sha256 mismatch or sidecar format mismatch — continuing anyway"
104+
fi
105+
rm -f /tmp/bibata.sha256
106+
else
107+
echo "[10-gnome] WARN: Bibata sha256 sidecar unavailable — skipping integrity check"
108+
fi
97109
if tar -xf /tmp/bibata.tar.xz -C /usr/share/icons/; then
98110
rm -f /tmp/bibata.tar.xz
99111
BIBATA_OK=1

automation/19-k3s-selinux.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,14 @@ source "$(dirname "$0")/lib/common.sh"
99
# Install SELinux development tools required for compilation
1010
$DNF_BIN "${DNF_SETOPT[@]}" install -y "${DNF_OPTS[@]}" selinux-policy-devel git make
1111

12-
# Clone the upstream k3s-selinux repository
13-
git clone --depth 1 https://github.com/k3s-io/k3s-selinux.git /tmp/k3s-selinux
12+
# Pin to a specific stable release tag — HEAD clones pick up unreviewed commits.
13+
# Update K3S_SELINUX_TAG when bumping K3s to stay in sync with its SELinux policy.
14+
K3S_SELINUX_TAG="${K3S_SELINUX_TAG:-v1.5.stable.2}"
15+
16+
echo "==> Cloning k3s-selinux at tag ${K3S_SELINUX_TAG}..."
17+
git clone --depth 1 --branch "${K3S_SELINUX_TAG}" \
18+
https://github.com/k3s-io/k3s-selinux.git /tmp/k3s-selinux
19+
1420
cd /tmp/k3s-selinux
1521

1622
# K3s SELinux repo stores policies in subdirectories (e.g., policy/coreos or policy/centos9)
@@ -23,7 +29,6 @@ elif [ -d "policy/centos9" ]; then
2329
elif [ -d "policy/rhel9" ]; then
2430
POLICY_DIR="policy/rhel9"
2531
else
26-
# Fallback to the first directory containing k3s.te
2732
POLICY_DIR=$(find policy -name k3s.te -printf '%h\n' | head -n 1)
2833
fi
2934

@@ -48,4 +53,3 @@ install -m 0644 k3s.pp /usr/share/selinux/packages/mios/k3s.pp
4853
cd /
4954
rm -rf /tmp/k3s-selinux
5055
echo "==> K3s SELinux Policy staged in /usr/share/selinux/packages/mios/"
51-

automation/37-aichat.sh

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ echo "[37-aichat] Installing AI-related packages (redis, sqlite)..."
1010
install_packages "ai"
1111

1212
echo "[37-aichat] Installing AIChat and AIChat-NG binaries..."
13-
# ... (rest of the script)
1413

1514
# Fetch latest release tags
1615
# v0.2.0: Wrap in subshell + || true to prevent pipefail from killing the script if API is down
@@ -32,17 +31,47 @@ else
3231
echo "[37-aichat] Detected AIChat-NG version: ${AICHAT_NG_TAG}"
3332
fi
3433

35-
# Download and install AIChat
36-
scurl -L -o /tmp/aichat.tar.gz "https://github.com/sigoden/aichat/releases/download/${AICHAT_TAG}/aichat-${AICHAT_TAG}-x86_64-unknown-linux-musl.tar.gz"
37-
tar -xzf /tmp/aichat.tar.gz -C /usr/bin/ aichat
34+
# ── AIChat ────────────────────────────────────────────────────────────────────
35+
AICHAT_ARCH="aichat-${AICHAT_TAG}-x86_64-unknown-linux-musl.tar.gz"
36+
AICHAT_BASE="https://github.com/sigoden/aichat/releases/download/${AICHAT_TAG}"
37+
38+
mkdir -p /tmp/aichat-dl
39+
scurl -sfL "${AICHAT_BASE}/${AICHAT_ARCH}" -o "/tmp/aichat-dl/${AICHAT_ARCH}"
40+
scurl -sfL "${AICHAT_BASE}/${AICHAT_ARCH}.sha256" -o "/tmp/aichat-dl/${AICHAT_ARCH}.sha256" 2>/dev/null || {
41+
echo "[37-aichat] WARN: sha256 sidecar unavailable for AIChat — cannot verify integrity"
42+
rm -f "/tmp/aichat-dl/${AICHAT_ARCH}.sha256"
43+
}
44+
45+
if [[ -f "/tmp/aichat-dl/${AICHAT_ARCH}.sha256" ]]; then
46+
# sha256 sidecar format: "<hash> <filename>" or "<hash> *<filename>"
47+
(cd /tmp/aichat-dl && grep "${AICHAT_ARCH}" "${AICHAT_ARCH}.sha256" | sha256sum -c -) \
48+
|| die "AIChat ${AICHAT_TAG} SHA256 mismatch — aborting"
49+
echo "[37-aichat] ✓ AIChat sha256 verified"
50+
fi
51+
52+
tar -xzf "/tmp/aichat-dl/${AICHAT_ARCH}" -C /usr/bin/ aichat
3853
chmod +x /usr/bin/aichat
54+
rm -rf /tmp/aichat-dl
3955

40-
# Download and install AIChat-NG
41-
scurl -L -o /tmp/aichat-ng.tar.gz "https://github.com/blob42/aichat-ng/releases/download/${AICHAT_NG_TAG}/aichat-ng-${AICHAT_NG_TAG}-x86_64-unknown-linux-musl.tar.gz"
42-
tar -xzf /tmp/aichat-ng.tar.gz -C /usr/bin/ aichat-ng
43-
chmod +x /usr/bin/aichat-ng
56+
# ── AIChat-NG ────────────────────────────────────────────────────────────────
57+
AICHAT_NG_ARCH="aichat-ng-${AICHAT_NG_TAG}-x86_64-unknown-linux-musl.tar.gz"
58+
AICHAT_NG_BASE="https://github.com/blob42/aichat-ng/releases/download/${AICHAT_NG_TAG}"
4459

45-
# Cleanup
46-
rm -f /tmp/aichat.tar.gz /tmp/aichat-ng.tar.gz
60+
mkdir -p /tmp/aichat-ng-dl
61+
scurl -sfL "${AICHAT_NG_BASE}/${AICHAT_NG_ARCH}" -o "/tmp/aichat-ng-dl/${AICHAT_NG_ARCH}"
62+
scurl -sfL "${AICHAT_NG_BASE}/${AICHAT_NG_ARCH}.sha256" -o "/tmp/aichat-ng-dl/${AICHAT_NG_ARCH}.sha256" 2>/dev/null || {
63+
echo "[37-aichat] WARN: sha256 sidecar unavailable for AIChat-NG — cannot verify integrity"
64+
rm -f "/tmp/aichat-ng-dl/${AICHAT_NG_ARCH}.sha256"
65+
}
66+
67+
if [[ -f "/tmp/aichat-ng-dl/${AICHAT_NG_ARCH}.sha256" ]]; then
68+
(cd /tmp/aichat-ng-dl && grep "${AICHAT_NG_ARCH}" "${AICHAT_NG_ARCH}.sha256" | sha256sum -c -) \
69+
|| die "AIChat-NG ${AICHAT_NG_TAG} SHA256 mismatch — aborting"
70+
echo "[37-aichat] ✓ AIChat-NG sha256 verified"
71+
fi
72+
73+
tar -xzf "/tmp/aichat-ng-dl/${AICHAT_NG_ARCH}" -C /usr/bin/ aichat-ng
74+
chmod +x /usr/bin/aichat-ng
75+
rm -rf /tmp/aichat-ng-dl
4776

4877
echo "[37-aichat] AIChat and AIChat-NG installed successfully."

automation/42-cosign-policy.sh

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Consolidates cosign binary installation, Sigstore trust roots, and policy.json.
66
# Supercedes 37-cosign-policy.sh.
77
#
8-
# Note: we pin to v0.2.0 because v3 breaks rpm-ostree bundle format (OCI 1.1).
8+
# Note: cosign must stay on v2.x — v3+ breaks rpm-ostree OCI 1.1 bundle format.
99
# ============================================================================
1010
set -euo pipefail
1111

@@ -16,9 +16,16 @@ log "42-cosign-policy: ensuring cosign + trust roots + policy.json"
1616

1717
# 1. Install cosign binary (pinned to v2.x for rpm-ostree compatibility)
1818
if ! command -v cosign >/dev/null 2>&1; then
19-
log " downloading cosign v0.2.0 static binary..."
20-
scurl "https://github.com/sigstore/cosign/releases/download/v0.2.0/cosign-linux-amd64" -o /usr/local/bin/cosign
21-
chmod +x /usr/local/bin/cosign
19+
COSIGN_VERSION="v2.4.3"
20+
COSIGN_BASE_URL="https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}"
21+
log " downloading cosign ${COSIGN_VERSION} static binary..."
22+
mkdir -p /tmp/cosign-dl
23+
scurl -sfL "${COSIGN_BASE_URL}/cosign-linux-amd64" -o /tmp/cosign-dl/cosign-linux-amd64
24+
scurl -sfL "${COSIGN_BASE_URL}/cosign_checksums.txt" -o /tmp/cosign-dl/cosign_checksums.txt
25+
(cd /tmp/cosign-dl && grep "cosign-linux-amd64$" cosign_checksums.txt | sha256sum -c -) \
26+
|| die "cosign ${COSIGN_VERSION} SHA256 mismatch — aborting"
27+
install -m 0755 /tmp/cosign-dl/cosign-linux-amd64 /usr/local/bin/cosign
28+
rm -rf /tmp/cosign-dl
2229
fi
2330

2431
SYSFILES="/ctx/system_files"

0 commit comments

Comments
 (0)