Skip to content

Commit cf3f10f

Browse files
JAORMXclaude
andcommitted
Add pre-built runtime artifacts infrastructure
Add builder container image, release workflow, and Taskfile tasks for building and distributing propolis-runner, libkrun, and libkrunfw as pre-built artifacts. Consumers can fetch via GitHub Releases or OCI registry instead of building from source. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2878b04 commit cf3f10f

9 files changed

Lines changed: 454 additions & 9 deletions

File tree

.github/workflows/builder.yaml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Builder Image
5+
6+
on:
7+
push:
8+
branches:
9+
- main
10+
paths:
11+
- 'images/builder/**'
12+
- 'versions.env'
13+
tags:
14+
- 'v*'
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
packages: write
20+
21+
jobs:
22+
build-push:
23+
runs-on: ubuntu-latest
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/checkout@v4
27+
28+
- name: Source versions.env
29+
run: |
30+
source versions.env
31+
echo "LIBKRUN_VERSION=${LIBKRUN_VERSION}" >> $GITHUB_ENV
32+
echo "LIBKRUNFW_VERSION=${LIBKRUNFW_VERSION}" >> $GITHUB_ENV
33+
34+
- name: Set up Docker Buildx
35+
uses: docker/setup-buildx-action@v3
36+
37+
- name: Set up QEMU
38+
uses: docker/setup-qemu-action@v3
39+
40+
- name: Login to ghcr.io
41+
uses: docker/login-action@v3
42+
with:
43+
registry: ghcr.io
44+
username: ${{ github.actor }}
45+
password: ${{ secrets.GITHUB_TOKEN }}
46+
47+
- name: Build and push
48+
uses: docker/build-push-action@v6
49+
with:
50+
context: images/builder
51+
file: images/builder/Containerfile
52+
platforms: linux/amd64,linux/arm64
53+
push: true
54+
build-args: |
55+
LIBKRUN_VERSION=${{ env.LIBKRUN_VERSION }}
56+
LIBKRUNFW_VERSION=${{ env.LIBKRUNFW_VERSION }}
57+
tags: |
58+
ghcr.io/stacklok/propolis-builder:${{ env.LIBKRUN_VERSION }}
59+
ghcr.io/stacklok/propolis-builder:latest
60+
cache-from: type=gha
61+
cache-to: type=gha,mode=max

.github/workflows/ci.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111

1212
permissions:
1313
contents: read
14+
packages: read
1415

1516
env:
1617
GO_VERSION: "1.25"
@@ -140,3 +141,42 @@ jobs:
140141
- name: Sign runner with entitlements
141142
run: |
142143
codesign --entitlements assets/entitlements.plist --force -s - bin/propolis-runner
144+
145+
build-cgo:
146+
name: Build (Linux CGO)
147+
runs-on: ubuntu-latest
148+
steps:
149+
- name: Checkout repository
150+
uses: actions/checkout@v4
151+
152+
- name: Read builder image version
153+
id: versions
154+
run: |
155+
source versions.env
156+
echo "LIBKRUN_VERSION=${LIBKRUN_VERSION}" >> "$GITHUB_OUTPUT"
157+
158+
- name: Login to ghcr.io
159+
uses: docker/login-action@v3
160+
with:
161+
registry: ghcr.io
162+
username: ${{ github.actor }}
163+
password: ${{ secrets.GITHUB_TOKEN }}
164+
165+
- name: Pull builder image
166+
run: |
167+
docker pull ghcr.io/stacklok/propolis-builder:${{ steps.versions.outputs.LIBKRUN_VERSION }}
168+
169+
- name: Build CGO packages
170+
run: |
171+
docker run --rm -v "${{ github.workspace }}:/src:z" -w /src \
172+
-e CGO_ENABLED=1 \
173+
ghcr.io/stacklok/propolis-builder:${{ steps.versions.outputs.LIBKRUN_VERSION }} \
174+
go build ./krun/...
175+
176+
- name: Build runner binary
177+
run: |
178+
docker run --rm -v "${{ github.workspace }}:/src:z" -w /src \
179+
-e CGO_ENABLED=1 \
180+
ghcr.io/stacklok/propolis-builder:${{ steps.versions.outputs.LIBKRUN_VERSION }} \
181+
go build -ldflags "-X github.com/stacklok/propolis/internal/version.Version=ci" \
182+
-o bin/propolis-runner ./runner/cmd/propolis-runner

.github/workflows/release.yaml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Release
5+
6+
on:
7+
push:
8+
tags:
9+
- "v*"
10+
11+
permissions:
12+
contents: write
13+
packages: write
14+
15+
env:
16+
GO_VERSION: "1.25"
17+
18+
jobs:
19+
build-artifacts:
20+
name: Build (${{ matrix.arch }})
21+
runs-on: ${{ matrix.runner }}
22+
strategy:
23+
matrix:
24+
include:
25+
- arch: amd64
26+
runner: ubuntu-latest
27+
- arch: arm64
28+
runner: ubuntu-24.04-arm
29+
steps:
30+
- name: Checkout repository
31+
uses: actions/checkout@v4
32+
33+
- name: Source versions.env
34+
run: |
35+
set -euo pipefail
36+
source versions.env
37+
echo "LIBKRUN_VERSION=${LIBKRUN_VERSION}" >> "$GITHUB_ENV"
38+
39+
- name: Pull builder image
40+
run: |
41+
docker pull ghcr.io/stacklok/propolis-builder:${LIBKRUN_VERSION}
42+
43+
- name: Extract libraries from builder image
44+
run: |
45+
id=$(docker create ghcr.io/stacklok/propolis-builder:${LIBKRUN_VERSION})
46+
docker cp $id:/opt/libkrun-built/libkrun.so.1 .
47+
docker cp $id:/opt/libkrun-built/libkrunfw.so.5 .
48+
docker rm $id
49+
50+
- name: Build propolis-runner
51+
run: |
52+
docker run --rm -v $(pwd):/src:z -w /src \
53+
-e CGO_ENABLED=1 \
54+
ghcr.io/stacklok/propolis-builder:${LIBKRUN_VERSION} \
55+
go build -ldflags "-X github.com/stacklok/propolis/internal/version.Version=${{ github.ref_name }} -X github.com/stacklok/propolis/internal/version.Commit=${GITHUB_SHA::8} -X github.com/stacklok/propolis/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
56+
-o bin/propolis-runner ./runner/cmd/propolis-runner
57+
58+
- name: Package runtime tarball
59+
run: |
60+
staging="propolis-runtime-linux-${{ matrix.arch }}"
61+
mkdir -p "${staging}"
62+
cp bin/propolis-runner libkrun.so.1 "${staging}/"
63+
echo "${{ github.ref_name }}" > "${staging}/VERSION"
64+
tar czf "${staging}.tar.gz" "${staging}"
65+
66+
- name: Package firmware tarball
67+
run: |
68+
staging="propolis-firmware-linux-${{ matrix.arch }}"
69+
mkdir -p "${staging}"
70+
cp libkrunfw.so.5 "${staging}/"
71+
echo "${{ github.ref_name }}" > "${staging}/VERSION"
72+
cat > "${staging}/LICENSE-GPL" <<'EOF'
73+
libkrunfw is licensed under the GNU General Public License v2.0 (GPL-2.0).
74+
See https://github.com/containers/libkrunfw for full license text.
75+
EOF
76+
tar czf "${staging}.tar.gz" "${staging}"
77+
78+
- name: Upload runtime artifact
79+
uses: actions/upload-artifact@v4
80+
with:
81+
name: propolis-runtime-linux-${{ matrix.arch }}
82+
path: propolis-runtime-linux-${{ matrix.arch }}.tar.gz
83+
84+
- name: Upload firmware artifact
85+
uses: actions/upload-artifact@v4
86+
with:
87+
name: propolis-firmware-linux-${{ matrix.arch }}
88+
path: propolis-firmware-linux-${{ matrix.arch }}.tar.gz
89+
90+
create-release:
91+
name: Create Release
92+
runs-on: ubuntu-latest
93+
needs: build-artifacts
94+
steps:
95+
- name: Download all artifacts
96+
uses: actions/download-artifact@v4
97+
with:
98+
merge-multiple: true
99+
100+
- name: Generate checksums
101+
run: |
102+
sha256sum propolis-*.tar.gz > sha256sums.txt
103+
104+
- name: Create GitHub Release
105+
uses: softprops/action-gh-release@v2
106+
with:
107+
generate_release_notes: true
108+
files: |
109+
propolis-runtime-linux-amd64.tar.gz
110+
propolis-runtime-linux-arm64.tar.gz
111+
propolis-firmware-linux-amd64.tar.gz
112+
propolis-firmware-linux-arm64.tar.gz
113+
sha256sums.txt
114+
115+
push-oci:
116+
name: Push OCI (${{ matrix.arch }})
117+
runs-on: ubuntu-latest
118+
needs: build-artifacts
119+
strategy:
120+
matrix:
121+
include:
122+
- arch: amd64
123+
- arch: arm64
124+
steps:
125+
- name: Download runtime artifact
126+
uses: actions/download-artifact@v4
127+
with:
128+
name: propolis-runtime-linux-${{ matrix.arch }}
129+
130+
- name: Download firmware artifact
131+
uses: actions/download-artifact@v4
132+
with:
133+
name: propolis-firmware-linux-${{ matrix.arch }}
134+
135+
- name: Install oras
136+
uses: oras-project/setup-oras@v1
137+
138+
- name: Login to ghcr.io
139+
run: |
140+
echo "${{ secrets.GITHUB_TOKEN }}" | oras login ghcr.io -u ${{ github.actor }} --password-stdin
141+
142+
- name: Push runtime OCI artifact
143+
run: |
144+
oras push ghcr.io/stacklok/propolis/runtime:${{ github.ref_name }}-linux-${{ matrix.arch }} \
145+
--artifact-type application/vnd.stacklok.propolis.runtime \
146+
propolis-runtime-linux-${{ matrix.arch }}.tar.gz:application/gzip
147+
148+
- name: Push firmware OCI artifact
149+
run: |
150+
oras push ghcr.io/stacklok/propolis/firmware:${{ github.ref_name }}-linux-${{ matrix.arch }} \
151+
--artifact-type application/vnd.stacklok.propolis.firmware \
152+
propolis-firmware-linux-${{ matrix.arch }}.tar.gz:application/gzip

CLAUDE.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@ Two-process model: pure-Go library spawns a CGO runner subprocess. Module: `gith
66
## Commands
77

88
```bash
9-
task build-dev # Build runner (requires libkrun-devel, Linux)
10-
task build-dev-darwin # Build runner (macOS, requires Homebrew libkrun, signs entitlements)
11-
task test # go test -v -race ./...
12-
task lint # golangci-lint run ./...
13-
task lint-fix # Auto-fix lint issues
14-
task fmt # go fmt + goimports
15-
task verify # fmt + lint + test (CI pipeline)
16-
task tidy # go mod tidy
17-
task clean # Remove bin/ and coverage files
9+
task build-dev # Build runner (requires libkrun-devel, Linux)
10+
task build-dev-darwin # Build runner (macOS, requires Homebrew libkrun, signs entitlements)
11+
task build-runner # Build runner + libs using builder container (no system libkrun needed)
12+
task fetch-runtime # Download pre-built runtime from GitHub Release
13+
task fetch-firmware # Download pre-built firmware from GitHub Release
14+
task builder-image-build # Build the builder container image locally
15+
task test # go test -v -race ./...
16+
task lint # golangci-lint run ./...
17+
task lint-fix # Auto-fix lint issues
18+
task fmt # go fmt + goimports
19+
task verify # fmt + lint + test (CI pipeline)
20+
task tidy # go mod tidy
21+
task clean # Remove bin/ and coverage files
1822
```
1923

2024
Run a single test: `go test -v -race -run TestName ./path/to/package`

0 commit comments

Comments
 (0)