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
71 changes: 71 additions & 0 deletions .github/workflows/buildenv-diff.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Buildenv Package Diff
on:
# When a PR bumps the kernel-buildenv digest pin (normally dependabot), show
# what actually changed between the two images: each image carries its own
# package manifest at /usr/share/buildenv/packages.tsv, so the diff is just
# two pulls and a compare, posted to the check summary for the reviewer.
pull_request:
paths:
- "Dockerfile"
permissions:
contents: read
packages: read
jobs:
diff:
name: package diff
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v4
- name: docker login ghcr.io
uses: Wandalen/wretry.action@e68c23e6309f2871ca8ae4763e7629b9c258e1ea # v3.8.0
with:
action: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with: |
registry: ghcr.io
username: "${{github.actor}}"
password: "${{secrets.GITHUB_TOKEN}}"
- name: diff package manifests
run: |
extract_ref() {
grep -oE 'ghcr\.io/edera-dev/kernel-buildenv[^[:space:]]*@sha256:[0-9a-f]+' "$1" | head -1 || true
}
git fetch --depth 1 origin "${{ github.base_ref }}"
git show FETCH_HEAD:Dockerfile > Dockerfile.base 2>/dev/null || : > Dockerfile.base
OLD_REF="$(extract_ref Dockerfile.base)"
NEW_REF="$(extract_ref Dockerfile)"
if [ -z "${NEW_REF}" ] || [ "${OLD_REF}" = "${NEW_REF}" ]; then
echo "kernel-buildenv pin unchanged; nothing to diff"
exit 0
fi
MANIFEST=/usr/share/buildenv/packages.tsv
docker run --rm "${NEW_REF}" cat "${MANIFEST}" > packages-new.tsv
{
echo "## kernel-buildenv package changes"
echo ""
} >> "${GITHUB_STEP_SUMMARY}"
if [ -z "${OLD_REF}" ]; then
{
echo "New pin \`${NEW_REF}\` (no previous pin to diff against);"
echo "$(wc -l < packages-new.tsv) packages in the image."
} >> "${GITHUB_STEP_SUMMARY}"
exit 0
fi
docker run --rm "${OLD_REF}" cat "${MANIFEST}" > packages-old.tsv
{
echo "\`${OLD_REF}\`"
echo "→ \`${NEW_REF}\`"
echo ""
if diff -u packages-old.tsv packages-new.tsv > packages.diff; then
echo "No package version changes (image metadata/base layer only)."
else
echo '```diff'
# Skip the +++/--- header noise; keep only the package changes.
grep -E '^[+-][^+-]' packages.diff
echo '```'
fi
} >> "${GITHUB_STEP_SUMMARY}"
124 changes: 124 additions & 0 deletions .github/workflows/buildenv.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Build Environment Image
on:
# Rebuild on a schedule so toolchain updates land as deliberate, dated image
# releases (which dependabot then proposes as digest bumps in the kernel
# Dockerfile) instead of drifting silently into every kernel build. The
# cadence balances cache stability (each new image is a cold sccache build)
# against sitting too long on Debian toolchain fixes.
schedule:
- cron: "0 0 1,15 * *"
workflow_dispatch:
push:
branches:
- main
paths:
- "Dockerfile.buildenv"
- ".github/workflows/buildenv.yml"
permissions:
contents: read
packages: write
id-token: write
concurrency:
group: "buildenv-publish"
env:
IMAGE: ghcr.io/edera-dev/kernel-buildenv
jobs:
build:
name: "build ${{ matrix.arch }}"
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
platform: linux/amd64
runner: ubuntu-latest
- arch: arm64
platform: linux/arm64
runner: ubuntu-24.04-arm
runs-on: "${{ matrix.runner }}"
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v4
- name: docker setup buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: docker login ghcr.io
uses: Wandalen/wretry.action@e68c23e6309f2871ca8ae4763e7629b9c258e1ea # v3.8.0
with:
action: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with: |
registry: ghcr.io
username: "${{github.actor}}"
password: "${{secrets.GITHUB_TOKEN}}"
- name: build and push by digest
run: |
docker buildx build \
-f Dockerfile.buildenv \
--platform "${{ matrix.platform }}" \
--metadata-file metadata.json \
--output "type=image,name=${IMAGE},push-by-digest=true,name-canonical=true,push=true" \
.
jq -r '."containerimage.digest"' metadata.json > "digest-${{ matrix.arch }}"
- name: extract package manifest
run: |
docker run --rm "${IMAGE}@$(cat digest-${{ matrix.arch }})" \
cat /usr/share/buildenv/packages.tsv > "packages-${{ matrix.arch }}.tsv"
- name: upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: "buildenv-digest-${{ matrix.arch }}"
path: "digest-${{ matrix.arch }}"
if-no-files-found: error
compression-level: 0
retention-days: 1
- name: upload package manifest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: "buildenv-packages-${{ matrix.arch }}"
path: "packages-${{ matrix.arch }}.tsv"
if-no-files-found: error
compression-level: 0
merge:
name: merge and publish
needs: build
runs-on: ubuntu-latest
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit
- name: install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: docker setup buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
- name: docker login ghcr.io
uses: Wandalen/wretry.action@e68c23e6309f2871ca8ae4763e7629b9c258e1ea # v3.8.0
with:
action: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
with: |
registry: ghcr.io
username: "${{github.actor}}"
password: "${{secrets.GITHUB_TOKEN}}"
- name: download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "buildenv-digest-*"
merge-multiple: true
- name: assemble and tag manifest list
run: |
TAG="$(date -u +%Y%m%d)"
docker buildx imagetools create \
-t "${IMAGE}:${TAG}" \
-t "${IMAGE}:latest" \
"${IMAGE}@$(cat digest-amd64)" \
"${IMAGE}@$(cat digest-arm64)"
DIGEST="$(docker buildx imagetools inspect "${IMAGE}:${TAG}" --format '{{.Manifest.Digest}}')"
cosign sign --yes "${IMAGE}@${DIGEST}"
{
echo "published \`${IMAGE}:${TAG}\`"
echo ""
echo "pin as: \`${IMAGE}:${TAG}@${DIGEST}\`"
} >> "${GITHUB_STEP_SUMMARY}"
61 changes: 61 additions & 0 deletions Dockerfile.buildenv
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Kernel build environment image, published as ghcr.io/edera-dev/kernel-buildenv.
#
# This exists so the toolchain is a deliberate, reviewed input to kernel builds
# rather than whatever the Debian archive serves on build day: sccache keys
# cache entries on the compiler binary's content hash, so an unplanned gcc
# update silently turns a build into a 100% cache miss. The image is rebuilt on
# a schedule (see .github/workflows/buildenv.yml); the kernel Dockerfile pins
# it by digest and dependabot proposes bumps as reviewable PRs.
FROM debian:bookworm@sha256:ed4fcc40bb1162b6d2d32e7bec15044d13963779abbe63f67f1cd62b06220519

RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && apt-get install -y \
build-essential squashfs-tools python3-yaml \
patch diffutils sed mawk findutils zstd \
python3 python3-packaging curl rsync cpio gpg grep \
flex bison pahole libssl-dev libelf-dev bc kmod && \
rm -rf /var/lib/apt/lists/*
ARG TARGETARCH
RUN if [ "${TARGETARCH}" = "amd64" ]; then \
apt-get update && apt-get install -y linux-headers-amd64 g++-aarch64-linux-gnu gcc-aarch64-linux-gnu && rm -rf /var/lib/apt/lists/*; fi
RUN if [ "${TARGETARCH}" = "arm64" ]; then \
apt-get update && apt-get install -y linux-headers-arm64 g++-x86-64-linux-gnu gcc-x86-64-linux-gnu && rm -rf /var/lib/apt/lists/*; fi

ARG SCCACHE_VERSION=0.16.0
ARG SCCACHE_SHA256_AMD64=aec995a83ad3dff3d14b6314e08858b7b73d35ca85a5bcf3d3a9ec07dee35588
ARG SCCACHE_SHA256_ARM64=f73a5c39f96bb6ebb89cc7915cf182260d4cbf30765322c5e793d0fe8bd80784
# The wrappers must reference the real compiler by absolute path: /usr/lib/sccache
# is first in PATH, so a bare compiler name would resolve back to the wrapper
# itself and recurse.
RUN case "${TARGETARCH}" in \
amd64) SCCACHE_ARCH=x86_64 SCCACHE_SHA256="${SCCACHE_SHA256_AMD64}" ;; \
arm64) SCCACHE_ARCH=aarch64 SCCACHE_SHA256="${SCCACHE_SHA256_ARM64}" ;; \
*) echo "unsupported TARGETARCH ${TARGETARCH}" >&2; exit 1 ;; \
esac && \
SCCACHE_DIST="sccache-v${SCCACHE_VERSION}-${SCCACHE_ARCH}-unknown-linux-musl" && \
curl -Lf -o /tmp/sccache.tar.gz "https://github.com/mozilla/sccache/releases/download/v${SCCACHE_VERSION}/${SCCACHE_DIST}.tar.gz" && \
echo "${SCCACHE_SHA256} /tmp/sccache.tar.gz" | sha256sum -c - && \
tar -xz -C /tmp -f /tmp/sccache.tar.gz && \
install -m 0755 "/tmp/${SCCACHE_DIST}/sccache" /usr/local/bin/sccache && \
rm -rf /tmp/sccache.tar.gz "/tmp/${SCCACHE_DIST}" && \
mkdir -p /usr/lib/sccache && \
for compiler in cc c++ gcc g++ \
x86_64-linux-gnu-gcc x86_64-linux-gnu-g++ \
aarch64-linux-gnu-gcc aarch64-linux-gnu-g++; do \
[ -x "/usr/bin/${compiler}" ] || continue; \
printf '#!/bin/sh\nexec /usr/local/bin/sccache /usr/bin/%s "$@"\n' "${compiler}" >"/usr/lib/sccache/${compiler}"; \
chmod 0755 "/usr/lib/sccache/${compiler}"; \
done
ENV PATH="/usr/lib/sccache:${PATH}"

RUN useradd -ms /bin/sh build

# Self-describing package manifest: lets any two image digests be diffed
# without external records (docker run <image> cat /usr/share/buildenv/packages.tsv).
# The buildenv-diff workflow uses this to summarize dependabot digest bumps.
RUN mkdir -p /usr/share/buildenv && \
{ dpkg-query -W -f '${Package}\t${Version}\t${Architecture}\n' | sort; \
printf 'sccache\t%s\tgithub-release\n' "${SCCACHE_VERSION}"; } \
>/usr/share/buildenv/packages.tsv

LABEL org.opencontainers.image.source="https://github.com/edera-dev/linux-kernel-oci"
LABEL org.opencontainers.image.description="Edera kernel build environment (toolchain + sccache)"
Loading