Merge pull request #10 from bootnode/chore/platform-ci

ci: migrate bootnode build to platform.hanzo.ai
This commit is contained in:
2026-06-19 11:22:32 -07:00
committed by GitHub
3 changed files with 164 additions and 45 deletions
+49 -45
View File
@@ -1,63 +1,67 @@
# Deployment managed by hanzoai/universe — this workflow only builds and pushes images
# Self-contained image build on the self-hosted arcd pools.
#
# Previously this delegated to hanzoai/.github's reusable docker-build.yml, but
# bootnode is in a separate GitHub org and that workflow's access is org-scoped,
# so every run failed "workflow was not found" (broken since ~2026-05-19). The
# build steps are inlined here — same self-hosted runners, no cross-org
# reusable dependency. (platform.hanzo.ai via .platform.yml is the canonical
# path; this is the retained GHA fallback. No GitHub-hosted runners.)
name: Docker Release
on:
# Only build after CI passes on main
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
# Tags build directly (release cuts)
push:
branches: [main]
tags: ["v*"]
# Manual override
workflow_dispatch:
concurrency:
group: docker-${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.ref }}
group: docker-release-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
packages: write
id-token: write
jobs:
# Gate: only proceed if CI passed (skip check for tags/manual)
gate:
runs-on: ubuntu-latest
if: >-
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success'
build:
runs-on: [self-hosted, linux, amd64]
strategy:
fail-fast: false
matrix:
include:
- { app: api, context: ./api }
- { app: web, context: ./web }
steps:
- run: echo "CI passed — proceeding with Docker build"
- uses: actions/checkout@v4
# Build API image via standard Hanzo reusable workflow
# NOTE: pushed under the `bootnode` package with `-api` tag suffix so it
# doesn't collide with web's tags in the same package.
api:
needs: gate
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
with:
image: ghcr.io/hanzoai/bootnode
context: ./api
dockerfile: Dockerfile
platforms: "linux/amd64"
tag-suffix: -api
secrets: inherit
- uses: docker/setup-buildx-action@v3
# Build Web image via standard Hanzo reusable workflow
# NOTE: pushed under the `bootnode` package (not `bootnode-web`) with `web-`
# tag prefix because GHCR auto-creation of `bootnode-web` package fails 403
# when the GH org has no policy allowing first-push package creation.
# Deployment image: ghcr.io/hanzoai/bootnode:web-<sha>|web-latest
web:
needs: gate
uses: hanzoai/.github/.github/workflows/docker-build.yml@main
with:
image: ghcr.io/hanzoai/bootnode
context: ./web
dockerfile: Dockerfile
platforms: "linux/amd64"
tag-suffix: -web
secrets: inherit
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Compute tags
id: tags
run: |
BASE=ghcr.io/hanzoai/bootnode
SHORT=$(echo "${{ github.sha }}" | cut -c1-7)
# *-latest is what hanzo/universe pins; sha tag is for traceability.
TAGS="$BASE:${{ matrix.app }}-latest,$BASE:sha-${SHORT}-amd64-${{ matrix.app }}"
if [ "${{ github.ref_type }}" = "tag" ]; then
V="${{ github.ref_name }}"; V="${V#v}"
TAGS="$TAGS,$BASE:${V}-amd64-${{ matrix.app }}"
fi
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
- name: Build and push ${{ matrix.app }}
uses: docker/build-push-action@v6
with:
context: ${{ matrix.context }}
file: ${{ matrix.context }}/Dockerfile
push: true
tags: ${{ steps.tags.outputs.tags }}
platforms: linux/amd64
provenance: false
+94
View File
@@ -0,0 +1,94 @@
name: Platform Build (arcd executor)
# Dispatched by platform.hanzo.ai (NOT by GitHub on push). Platform receives
# the repo webhook, schedules the build, and triggers this workflow via
# workflow_dispatch with the inputs below — pinning the arcd runner pool per
# build target. On completion this workflow calls back into platform, which
# records the outcome and (on success) rolls the image out via the operator.
#
# This is the per-repo half of the platform-native CI/CD escape from GHA as a
# single point of failure. The build muscle still runs on self-hosted arcd.
on:
workflow_dispatch:
inputs:
build-job-id:
description: Platform buildJob id (echoed back on completion)
required: true
target:
description: "Build target, e.g. linux/amd64"
required: true
runner-pool:
description: "arcd pool label, e.g. hanzoai-linux-amd64"
required: true
image:
description: "Fully-resolved image ref, e.g. ghcr.io/hanzoai/zip:<sha>"
required: true
dockerfile:
description: Path to the Dockerfile
required: true
default: ./Dockerfile
context:
description: Build context
required: true
default: .
push:
description: Whether to push the built image
required: true
default: "true"
jobs:
build:
runs-on: ${{ inputs.runner-pool }}
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to GHCR
if: ${{ inputs.push == 'true' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile }}
push: ${{ inputs.push }}
tags: ${{ inputs.image }}
provenance: false
- name: Report success to platform
if: success()
env:
TOKEN: ${{ secrets.PLATFORM_BUILD_CALLBACK_TOKEN }}
run: |
curl -fsS -X POST "https://platform.hanzo.ai/v1/build-callback" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -nc \
--arg id '${{ inputs.build-job-id }}' \
--arg inst '${{ github.event.installation.id }}' \
--arg img '${{ inputs.image }}' \
'{buildJobId:$id, outcome:"success", installationId:$inst, log:("built "+$img)}')"
- name: Report failure to platform
if: failure()
env:
TOKEN: ${{ secrets.PLATFORM_BUILD_CALLBACK_TOKEN }}
run: |
curl -fsS -X POST "https://platform.hanzo.ai/v1/build-callback" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -nc \
--arg id '${{ inputs.build-job-id }}' \
--arg inst '${{ github.event.installation.id }}' \
'{buildJobId:$id, outcome:"failure", installationId:$inst, error:"build step failed"}')"
+21
View File
@@ -0,0 +1,21 @@
# Platform-native CI/CD — platform.hanzo.ai owns the build, escaping the
# cross-org GitHub Actions reusable workflow (hanzoai/.github docker-build.yml),
# which bootnode (a separate GitHub org) cannot access. Platform receives the
# repo webhook, schedules the build onto the self-hosted arcd pool, and pushes
# the image. See hanzoai/platform docs/PLATFORM_CI.md.
#
# Scope: the API image — the v1.0.0 backend (Lux/Hanzo/Zoo node deploy,
# contracts, subgraphs, mpc, launch). bootnode also ships a `web` image; the
# .platform.yml schema is single-build per repo, so web needs a follow-up
# (a multi-build schema extension, or its own config). Deploy is intentionally
# omitted: bootnode-k8s rolls via universe, not a hanzo-operator Service CR
# (the deploy block's target), so this is build-only until that's wired.
build:
matrix:
- { os: linux, arch: amd64 }
dockerfile: ./Dockerfile
context: ./api
image: ghcr.io/hanzoai/bootnode
tag-pattern: "{{git.sha}}-amd64-api"
push: true
dispatch: native