Skip to content

Commit 1c65051

Browse files
authored
Merge pull request #283 from mitos-run/feat/distribution-registries
feat: distribution to Artifact Hub, krew, OperatorHub, and Red Hat
2 parents 6b02066 + 03f1a4c commit 1c65051

24 files changed

Lines changed: 5239 additions & 18 deletions
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Release Helm chart
2+
3+
# Package the mitos Helm chart and publish it to the gh-pages branch as a
4+
# classic HTTP Helm repository, plus attach the .tgz to a GitHub release. The
5+
# repository is served from https://mitos.run/charts via a Cloudflare rewrite to
6+
# this repo's GitHub Pages site (see docs/distribution.md). Artifact Hub then
7+
# indexes https://mitos.run/charts and the listing backlinks to mitos.run.
8+
#
9+
# chart-releaser only publishes a chart version that does not already have a
10+
# release, so bump deploy/charts/mitos/Chart.yaml `version` for each change.
11+
12+
on:
13+
push:
14+
branches: [main]
15+
paths:
16+
- "deploy/charts/**"
17+
- ".github/workflows/helm-release.yaml"
18+
workflow_dispatch: {}
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
release:
25+
runs-on: ubuntu-latest
26+
permissions:
27+
# chart-releaser pushes to gh-pages and creates the chart release.
28+
contents: write
29+
steps:
30+
- uses: actions/checkout@v6
31+
with:
32+
fetch-depth: 0
33+
34+
- name: Configure git identity
35+
run: |
36+
git config user.name "$GITHUB_ACTOR"
37+
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
38+
39+
- name: Install helm
40+
uses: azure/setup-helm@v4
41+
with:
42+
version: v3.16.3
43+
44+
- name: Run chart-releaser
45+
uses: helm/chart-releaser-action@v1.7.0
46+
with:
47+
charts_dir: deploy/charts
48+
env:
49+
CR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50+
51+
- name: Publish Artifact Hub repository metadata to gh-pages
52+
# The repository ownership file must sit at the repo root next to
53+
# index.yaml so Artifact Hub can fetch it from https://mitos.run/charts.
54+
run: |
55+
set -euo pipefail
56+
# chart-releaser has just pushed to the remote gh-pages, so work from
57+
# origin/gh-pages rather than a stale local ref.
58+
git fetch origin gh-pages
59+
tmp="$(mktemp -d)"
60+
git worktree add --detach "$tmp" origin/gh-pages
61+
cp deploy/charts/artifacthub-repo.yml "$tmp/artifacthub-repo.yml"
62+
git -C "$tmp" add artifacthub-repo.yml
63+
if ! git -C "$tmp" diff --cached --quiet; then
64+
git -C "$tmp" commit -m "chore: publish artifacthub-repo.yml"
65+
git -C "$tmp" push origin HEAD:gh-pages
66+
fi
67+
git worktree remove "$tmp"

.github/workflows/krew.yaml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: krew
2+
3+
# On a published GitHub Release, cross-compile the kubectl-sandbox plugin for
4+
# the five krew-supported platforms, package each archive to match the URLs in
5+
# .krew.yaml, upload them as release assets, then run krew-release-bot to open
6+
# (or update) the PR against kubernetes-sigs/krew-index. Also runnable manually
7+
# via workflow_dispatch against an existing release tag.
8+
on:
9+
release:
10+
types: [published]
11+
workflow_dispatch:
12+
inputs:
13+
tag:
14+
description: "Existing release tag to (re)build assets for (for example v0.4.0)"
15+
required: true
16+
17+
permissions:
18+
contents: read
19+
20+
jobs:
21+
release-assets:
22+
# Build and attach the per-platform archives to the release. Needs
23+
# contents: write to upload assets onto the GitHub Release. Only runs for
24+
# plugin releases tagged v*, so chart releases (mitos-*) are ignored.
25+
if: ${{ github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'v') }}
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: write
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
include:
33+
- goos: linux
34+
goarch: amd64
35+
ext: tar.gz
36+
- goos: linux
37+
goarch: arm64
38+
ext: tar.gz
39+
- goos: darwin
40+
goarch: amd64
41+
ext: tar.gz
42+
- goos: darwin
43+
goarch: arm64
44+
ext: tar.gz
45+
- goos: windows
46+
goarch: amd64
47+
ext: zip
48+
env:
49+
# The tag this run targets: the release tag on a release event, or the
50+
# workflow_dispatch input on a manual run.
51+
TAG: ${{ github.event.release.tag_name || github.event.inputs.tag }}
52+
steps:
53+
- uses: actions/checkout@v6
54+
with:
55+
ref: ${{ github.event.release.tag_name || github.event.inputs.tag }}
56+
- uses: actions/setup-go@v6
57+
with:
58+
go-version: "1.26"
59+
- name: Build and package
60+
run: |
61+
set -euo pipefail
62+
os="${{ matrix.goos }}"
63+
arch="${{ matrix.goarch }}"
64+
ext="${{ matrix.ext }}"
65+
bin="kubectl-sandbox"
66+
if [ "$os" = "windows" ]; then
67+
bin="kubectl-sandbox.exe"
68+
fi
69+
stage="$(mktemp -d)"
70+
GOOS="$os" GOARCH="$arch" CGO_ENABLED=0 \
71+
go build -ldflags "-s -w" -o "$stage/$bin" ./cmd/kubectl-sandbox/
72+
cp LICENSE "$stage/LICENSE"
73+
archive="kubectl-sandbox_${TAG}_${os}_${arch}.${ext}"
74+
if [ "$ext" = "zip" ]; then
75+
(cd "$stage" && zip -q -X "$OLDPWD/$archive" "$bin" LICENSE)
76+
else
77+
tar -C "$stage" -czf "$archive" "$bin" LICENSE
78+
fi
79+
echo "ARCHIVE=$archive" >> "$GITHUB_ENV"
80+
- name: Upload archive to the release
81+
env:
82+
GH_TOKEN: ${{ github.token }}
83+
run: gh release upload "$TAG" "$ARCHIVE" --clobber --repo "$GITHUB_REPOSITORY"
84+
85+
krew-release-bot:
86+
# After the assets exist on the release, open/update the krew-index PR from
87+
# .krew.yaml. The bot computes per-platform sha256 from the uploaded
88+
# archives, so it must run after release-assets.
89+
needs: release-assets
90+
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@v6
93+
- name: Update the krew-index PR
94+
uses: rajatjindal/krew-release-bot@v0.0.46
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: Release operator bundle
2+
3+
# Build and publish the OLM operator bundle for a release, and (optionally) open
4+
# the version PR to k8s-operatorhub/community-operators. The committed bundle
5+
# under deploy/olm/bundle is the 0.4.0 base; this workflow rewrites it to the
6+
# release version in a throwaway workspace, validates it, pushes the bundle
7+
# image, and prepares the community-operators contribution.
8+
#
9+
# Prerequisites and notes:
10+
# * Images must already be published to ghcr.io/mitos-run for the version.
11+
# * The first community-operators listing is still a manual PR; this automates
12+
# subsequent versions once a fork and token exist.
13+
# * To open the PR automatically, set the COMMUNITY_OPERATORS_TOKEN secret to a
14+
# PAT (repo scope) whose account has a fork of k8s-operatorhub/community-
15+
# operators. Without it, the versioned bundle is uploaded as an artifact.
16+
# * Pass `previous` so the bundle gets a spec.replaces upgrade edge.
17+
18+
on:
19+
release:
20+
types: [published]
21+
workflow_dispatch:
22+
inputs:
23+
version:
24+
description: "Bundle version without leading v, for example 0.4.1"
25+
required: true
26+
previous:
27+
description: "Previous bundle version for spec.replaces, for example 0.4.0"
28+
required: false
29+
30+
permissions:
31+
contents: read
32+
33+
jobs:
34+
bundle:
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: read
38+
packages: write
39+
id-token: write
40+
env:
41+
BUNDLE_IMAGE: ghcr.io/mitos-run/mitos-operator-bundle
42+
steps:
43+
- uses: actions/checkout@v6
44+
45+
- name: Derive version
46+
id: ver
47+
run: |
48+
set -euo pipefail
49+
if [ "${{ github.event_name }}" = "release" ]; then
50+
v="${GITHUB_REF_NAME#v}"
51+
else
52+
v="${{ inputs.version }}"
53+
fi
54+
[ -n "$v" ] || { echo "no version resolved"; exit 1; }
55+
echo "version=$v" >> "$GITHUB_OUTPUT"
56+
echo "previous=${{ inputs.previous }}" >> "$GITHUB_OUTPUT"
57+
58+
- name: Install yq and operator-sdk
59+
run: |
60+
set -euo pipefail
61+
sudo curl -fsSL -o /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
62+
sudo chmod +x /usr/local/bin/yq
63+
sudo curl -fsSL -o /usr/local/bin/operator-sdk \
64+
https://github.com/operator-framework/operator-sdk/releases/latest/download/operator-sdk_linux_amd64
65+
sudo chmod +x /usr/local/bin/operator-sdk
66+
67+
- name: Rewrite the bundle to the release version
68+
env:
69+
VERSION: ${{ steps.ver.outputs.version }}
70+
PREVIOUS: ${{ steps.ver.outputs.previous }}
71+
run: |
72+
set -euo pipefail
73+
csv=deploy/olm/bundle/manifests/mitos.clusterserviceversion.yaml
74+
BASE="$(yq '.spec.version' "$csv")"
75+
export BASE
76+
echo "rewriting bundle ${BASE} -> ${VERSION}"
77+
yq -i '.metadata.name = "mitos.v" + strenv(VERSION)' "$csv"
78+
yq -i '.spec.version = strenv(VERSION)' "$csv"
79+
yq -i '.metadata.annotations.createdAt = (now | format_datetime("2006-01-02T15:04:05Z"))' "$csv"
80+
# rewrite the controller image tag, the containerImage annotation, and
81+
# the husk-stub image arg from :v$BASE to :v$VERSION.
82+
yq -i '.metadata.annotations.containerImage |= sub(":v" + strenv(BASE), ":v" + strenv(VERSION))' "$csv"
83+
yq -i '(.spec.install.spec.deployments[].spec.template.spec.containers[].image) |= sub(":v" + strenv(BASE), ":v" + strenv(VERSION))' "$csv"
84+
yq -i '(.spec.install.spec.deployments[].spec.template.spec.containers[].args[]) |= sub(":v" + strenv(BASE), ":v" + strenv(VERSION))' "$csv"
85+
if [ -n "${PREVIOUS}" ]; then
86+
yq -i '.spec.replaces = "mitos.v" + strenv(PREVIOUS)' "$csv"
87+
fi
88+
89+
- name: Validate the bundle
90+
run: |
91+
set -euo pipefail
92+
operator-sdk bundle validate ./deploy/olm/bundle
93+
operator-sdk bundle validate ./deploy/olm/bundle --select-optional suite=operatorframework
94+
95+
- name: Log in to GHCR
96+
uses: docker/login-action@v4
97+
with:
98+
registry: ghcr.io
99+
username: ${{ secrets.GHCR_WRITE_USER || github.actor }}
100+
password: ${{ secrets.GHCR_WRITE_TOKEN || secrets.GITHUB_TOKEN }}
101+
102+
- name: Build and push the bundle image
103+
id: push
104+
env:
105+
VERSION: ${{ steps.ver.outputs.version }}
106+
run: |
107+
set -euo pipefail
108+
docker build -f deploy/olm/bundle/bundle.Dockerfile -t "${BUNDLE_IMAGE}:${VERSION}" deploy/olm/bundle
109+
docker push "${BUNDLE_IMAGE}:${VERSION}"
110+
digest="$(docker inspect --format='{{index .RepoDigests 0}}' "${BUNDLE_IMAGE}:${VERSION}" | cut -d@ -f2)"
111+
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
112+
113+
- name: Install cosign
114+
uses: sigstore/cosign-installer@v3
115+
116+
- name: Cosign keyless sign the bundle image
117+
env:
118+
DIGEST: ${{ steps.push.outputs.digest }}
119+
run: cosign sign --yes "${BUNDLE_IMAGE}@${DIGEST}"
120+
121+
- name: Stage the community-operators contribution
122+
env:
123+
VERSION: ${{ steps.ver.outputs.version }}
124+
run: |
125+
set -euo pipefail
126+
dst="contribution/operators/mitos/${VERSION}"
127+
mkdir -p "$dst"
128+
cp -r deploy/olm/bundle/manifests "$dst/manifests"
129+
cp -r deploy/olm/bundle/metadata "$dst/metadata"
130+
echo "staged $dst"
131+
132+
- name: Upload the versioned bundle artifact
133+
uses: actions/upload-artifact@v7
134+
with:
135+
name: community-operators-mitos-${{ steps.ver.outputs.version }}
136+
path: contribution/
137+
138+
- name: Open the community-operators PR
139+
env:
140+
VERSION: ${{ steps.ver.outputs.version }}
141+
CO_TOKEN: ${{ secrets.COMMUNITY_OPERATORS_TOKEN }}
142+
run: |
143+
set -euo pipefail
144+
if [ -z "${CO_TOKEN}" ]; then
145+
echo "COMMUNITY_OPERATORS_TOKEN not set; skipping PR. The bundle is in the uploaded artifact."
146+
exit 0
147+
fi
148+
export GH_TOKEN="${CO_TOKEN}"
149+
owner="$(gh api user -q .login)"
150+
# ensure the fork exists under the token owner.
151+
gh repo fork k8s-operatorhub/community-operators --clone=false || true
152+
git clone "https://x-access-token:${CO_TOKEN}@github.com/${owner}/community-operators" co
153+
cd co
154+
git remote add upstream https://github.com/k8s-operatorhub/community-operators
155+
git fetch -q upstream
156+
branch="mitos-${VERSION}"
157+
git checkout -q -b "$branch" upstream/main
158+
mkdir -p "operators/mitos/${VERSION}"
159+
cp -r "../contribution/operators/mitos/${VERSION}/." "operators/mitos/${VERSION}/"
160+
git config user.name "mitos-run"
161+
git config user.email "maintainers@mitos.run"
162+
git add "operators/mitos/${VERSION}"
163+
# community-operators requires a DCO sign-off.
164+
git commit -s -q -m "operator mitos (${VERSION})"
165+
git push -q origin "$branch"
166+
gh pr create --repo k8s-operatorhub/community-operators \
167+
--base main --head "${owner}:${branch}" \
168+
--title "operator mitos (${VERSION})" \
169+
--body "Adds mitos ${VERSION}. Snapshot-fork sandboxes for AI agents on Kubernetes. https://mitos.run"

.github/workflows/publish.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ on:
99
tag:
1010
description: "Image tag to build and publish (for example v0.1.0)"
1111
required: true
12+
ref:
13+
description: "Git ref to build from. Defaults to the tag. Set to main to build current code when a tag predates a component Dockerfile."
14+
required: false
1215

1316
permissions:
1417
contents: read
1518

1619
jobs:
1720
publish:
18-
# Build, push, cosign keyless-sign, and SBOM-attest the three mitos images
21+
# Build, push, cosign keyless-sign, and SBOM-attest the seven mitos images
1922
# under ghcr.io/mitos-run (supply chain, issue #35). Keyless signing
2023
# uses the workflow GitHub OIDC identity (id-token: write); there is NO
2124
# private key in the repo or in secrets. Each image is pushed by digest and
@@ -37,6 +40,12 @@ jobs:
3740
dockerfile: Dockerfile.husk-stub
3841
- name: mitos-kvm-device-plugin
3942
dockerfile: Dockerfile.kvm-device-plugin
43+
- name: mitos-facade
44+
dockerfile: Dockerfile.facade
45+
- name: mitos-console
46+
dockerfile: Dockerfile.console
47+
- name: mitos-gateway
48+
dockerfile: Dockerfile.gateway
4049
env:
4150
REGISTRY: ghcr.io
4251
IMAGE: ghcr.io/mitos-run/${{ matrix.name }}
@@ -48,7 +57,7 @@ jobs:
4857
# the release tag with GITHUB_TOKEN, which does NOT auto-trigger
4958
# on: push: tags, so a release is published by dispatching this workflow
5059
# with the tag input.
51-
ref: ${{ github.event.inputs.tag || github.ref }}
60+
ref: ${{ github.event.inputs.ref || github.event.inputs.tag || github.ref }}
5261
- name: Log in to GHCR
5362
uses: docker/login-action@v4
5463
with:

0 commit comments

Comments
 (0)