mirror of
https://github.com/hanzoai/store.git
synced 2026-10-30 14:54:46 +00:00
98 lines
4.5 KiB
YAML
98 lines
4.5 KiB
YAML
name: deploy
|
|
|
|
# store.hanzo.ai 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 only credentials are KMS_CLIENT_ID / KMS_CLIENT_SECRET, which identify us
|
|
# to kms.hanzo.ai; the action fetches the deploy grant there, so no storage key
|
|
# is held in a repo. 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 hanzo-build-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: hanzo-build-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_WALLETCONNECT_PROJECT_ID: ${{ secrets.WALLETCONNECT_PROJECT_ID }}
|
|
NEXT_PUBLIC_PUBLISHABLE_KEY: ${{ secrets.PUBLISHABLE_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
# package-lock.json is lockfileVersion 3 and the tree needs the peer-dep
|
|
# escape; without --legacy-peer-deps the install fails outright.
|
|
npm ci --legacy-peer-deps
|
|
# The catalog pages are GENERATED from data/agents/*.json and
|
|
# data/tools/*.json before the export; skip this and next build exports
|
|
# an empty store.
|
|
npm run generate-store
|
|
npm run build
|
|
test -s out/index.html || { echo "::error::next build produced no out/index.html"; exit 1; }
|
|
# Clean URLs. next.config.js does not set trailingSlash, so the export is
|
|
# FLAT (out/agents.html, …) while the edge serves a DIRECTORY's
|
|
# index.html — write every top-level page as <name>/index.html too.
|
|
for f in out/*.html; do
|
|
case "$f" in out/index.html|out/404.html) continue ;; esac
|
|
d="${f%.html}"; mkdir -p "$d"; cp "$f" "$d/index.html"
|
|
done
|
|
echo "exported $(find out -type f | wc -l) files"
|
|
|
|
# ONE credential. 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.
|
|
#
|
|
# THE SLUG IS `hanzo-store`, NOT `store`, and it cannot be `store`. That label
|
|
# is in cloud's baked-in reserved set (apps/sites/reserved.go — brand terms an
|
|
# impersonator would want, beside `hanzo`, `docs` and `blog`), which create
|
|
# time rejects outright: POST /v1/projects answers 400 "slug is a reserved
|
|
# subdomain and cannot be used". The set is additive-only by design, so no
|
|
# operator config can free it. That 400 is why every run of this workflow
|
|
# since the Sites plane landed here has failed — four in a row, on four
|
|
# different commits, before the enqueue ever ran.
|
|
#
|
|
# The HOSTNAME is unaffected: store.hanzo.ai is a domain binding, a separate
|
|
# record from the slug, and a build never decides which site owns a host.
|
|
- name: Publish to the Sites plane
|
|
uses: https://git.hanzo.ai/hanzoai/ci/.github/actions/site@v1
|
|
with:
|
|
slug: hanzo-store
|
|
dir: out
|
|
env:
|
|
KMS_CLIENT_ID: ${{ secrets.KMS_CLIENT_ID }}
|
|
KMS_CLIENT_SECRET: ${{ secrets.KMS_CLIENT_SECRET }}
|