Files
zeekayandHanzo Dev 7eecb75a69 ci: a runner label names the platform, not the org
hanzo-build-linux-amd64, lux-build-linux-amd64, zoo-build-linux-amd64 and
every other org-prefixed spelling all meant the same machine. Which org a
job belongs to does not change which host can build it, so the org bought
one pool name per org per arch and each could go stale on its own -- the
evo host alone answered to fourteen names for one label.

One vocabulary now: linux-amd64, linux-arm64, macos-arm64, win-amd64. The
generic labels every plain workflow uses (ubuntu-latest, self-hosted) are
untouched, so naive CI keeps working.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 12:09:48 -07:00

97 lines
4.1 KiB
YAML

name: deploy
# hanzo.industries is a SITE, not an App: a static export with no compute. It ships on the
# Sites plane. Not GitHub Pages, not Cloudflare Pages, and not an image — baking
# files that never execute into a container so a Go binary can serve them means an
# image, a push, a tag pinned in a CR and running pods, all to hand back bytes.
#
# build -> out
# -> site
#
# The publish mechanics are NOT here. They are bin/site in hanzoai/ci, reached
# through its action, and every static surface in the fleet calls that one
# script — ensure-project, enqueue, presigned per-file upload, complete. A
# contract transcribed per repo is a contract that drifts, and this file used to
# carry its own copy of every call. It also SELF-PROVISIONS: the project is
# created idempotently before the enqueue, so committing this file is enough to
# stand the site up.
#
# The secrets are the KMS machine identity, and the action reads the deploy key
# from KMS with them. They are set ON THE FORGE: this file lives under
# .hanzo/workflows/, which only git.hanzo.ai reads, so GitHub's secret store is
# not in this path at all.
on:
push:
branches: [main]
workflow_dispatch:
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false
jobs:
site:
# NOT ubuntu-latest. This file lives in .hanzo/workflows, which GitHub never
# reads — git.hanzo.ai is the only thing that can run it, and its fleet
# advertises linux-amd64. An unmatched label is not an error here,
# it is silence: the job queues until the 24h timeout and nothing says so.
runs-on: linux-amd64
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: build the static export
env:
NEXT_TELEMETRY_DISABLED: '1'
NEXT_PUBLIC_PUBLISHABLE_KEY: ${{ secrets.PUBLISHABLE_KEY }}
run: |
set -euo pipefail
corepack enable && corepack prepare [email protected] --activate
pnpm install --frozen-lockfile
pnpm build
test -s out/index.html || { echo "::error::next build produced no out/index.html"; exit 1; }
echo "exported $(find out -type f | wc -l) files"
# This gate has caught real breakage, so it runs against the SAME out/ that
# gets synced. No `cp out/index.html out/404.html`: every route here is a
# real exported file, so clobbering the 404 would make a broken link answer
# 404 while rendering the front page.
- name: smoke test the export
run: |
set -euo pipefail
pnpm dlx serve out -l 3333 &
SERVER_PID=$!
for i in $(seq 1 30); do
curl -sf -o /dev/null http://localhost:3333 && { echo "server ready after ${i}s"; break; }
sleep 1
done
BODY=$(curl -s http://localhost:3333)
kill $SERVER_PID 2>/dev/null || true
echo "$BODY" | grep -q "Application error" && { echo "::error::homepage renders 'Application error'"; exit 1; }
FAILED=0
for page in index about research contact careers news ai-models; do
[ -f "out/${page}.html" ] || [ -f "out/${page}/index.html" ] || { echo "::error::missing page ${page}"; FAILED=1; }
done
[ "$FAILED" = "0" ]
echo "all smoke tests passed"
# ONE credential, and the action reads it from KMS: the machine identity is
# what travels, and the deploy key is resealed in one place rather than
# copied into every org's secret store. The 202 carries a prefix-scoped,
# 30-minute presigned POST grant, so nothing here holds a bucket key. Do NOT
# add SITES_S3_* — that is the standing shared-bucket credential the grant
# replaced, and it could overwrite every other org's site.
- name: Publish to the Sites plane
uses: https://git.hanzo.ai/hanzoai/ci/.github/actions/site@v1
with:
slug: hanzo-industries
dir: out
env:
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}