The docs App CR + pods pull ghcr.io/hanzoai/docs (public), but deploy-docs.yml
built+pushed+patched ghcr.io/hanzo-docs/docs (private) → every operator deploy
ErrImagePull'd (kept alive only by a manual crane-copy). Converge both on the
canonical public ghcr.io/hanzoai/docs per the Hanzo registry rule: CI push target
now equals the CR pull source. Immutable SHA tag only (drop floating :latest).
Co-authored-by: Hanzo Dev <[email protected]>
hanzoai/static's default CSP is default-src 'none', which blocks all client JS —
the docs' own interactivity and the Scalar OpenAPI reference at /reference. Set a
secure docs CSP (self + inline/eval for the renderer; object-src/frame-ancestors
still locked) via the App CR env. Already applied live; declaring it here for
durability. (k8s/** is outside the deploy-docs trigger paths, so this is
config-only.)
Co-authored-by: Hanzo Dev <[email protected]>
Consolidate to ONE way (native forge): build+deploy lives in .hanzo/workflows/
deploy.yml (Hanzo Git → act_runner → BuildKit → ghcr.io/hanzoai/docs → App/docs
→ hanzocd). Gut .github/workflows/deploy-docs.yml to a sync-notice (GitHub is a
mirror; .github is sync-only per the native-forge convention). Point docs-app.yaml
at the native image repo (ghcr.io/hanzoai/docs, matching the live deploy). Delete
docs-cd-rbac.yaml (the GitHub-Actions-runner App-patch RBAC — dead now that the
build is native). Removes the duplicate/buggy CF-Pages + GitHub-build layers.
Close the loop the docs deploy was missing: push -> build -> TEST -> deploy ->
re-index, no human in it.
- Test gate validates the export (index.html, docs/index.html, docs/services/
index.html, >=50 pages, /docs carries nav) BEFORE anything ships — exactly the
empty-export and trailingSlash failures that reached prod before.
- Deploy is operator-driven: patch App/docs .spec.image.tag to the immutable
built SHA; hanzo-operator reconciles. No floating tag in the cluster, no CI
kubectl on Deployments. In-cluster runner SA scoped by k8s/docs-cd-rbac.yaml
to get+patch ONLY app/docs (patch deploy = denied).
- Re-index posts to /v1/index-docs so search + zen-coder-flash chat answer from
the shipped content (best-effort, never blocks).
- Rips the Cloudflare Pages + docs-router worker path: docs.hanzo.ai serves
from the in-cluster App via the universe file-provider route. One way.
docs.hanzo.ai is now an App CR (like bot-docs/team-docs/analytics) reconciled
by hanzo-operator into Deployment+Service+Ingress. The hand-rolled
docs-landing manifest is superseded: its ingress was never admitted (the
controller routes via the universe file-provider config, not loose ingresses)
and it hard-coded a probe/port the operator derives. Pinned to the built SHA;
CD bumps .spec.image.tag.
The native serve 404'd on every /docs/* route: the trailingSlash:false export
writes docs.html AND a docs/ dir, so hanzoai/static opens the dir, finds no
docs/index.html, redirects /docs -> /docs/, and dead-ends 404. CF Pages
tolerated flat .html via its own router; a plain file server needs the
directory-index convention. trailingSlash:true -> docs/services/index.html,
which static resolves in place. One convention, portable across any file server.
Probe hit /health (no such file -> 404 -> httpGet treats 4xx as failure ->
pod killed every ~90s). Point it at / (200, or 301->200) so it passes.
The cross-org push to ghcr.io/hanzoai/docs failed ('permission_denied: The requested
installation does not exist') — the workflow GITHUB_TOKEN can only write packages in
its OWN org (hanzo-docs), not hanzoai. Push to ghcr.io/hanzo-docs/docs instead (same
org as the repo — conventional, self-contained) and point the docs-landing Deployment
at it. Base pull (hanzoai/static:0.4.1, now public) already works; this clears the push.