mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-07-27 04:31:57 +00:00
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: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
2.7 KiB
YAML
66 lines
2.7 KiB
YAML
# docs.hanzo.ai — the ONE canonical serve: a hanzo-operator App CR.
|
|
#
|
|
# WHY AN App CR (not a hand-rolled Deployment/Service/Ingress):
|
|
# The hanzoai/ingress controller only routes ingresses the operator
|
|
# reconciles (analytics, bot-docs, team-docs all work this way). A
|
|
# hand-applied ingress for docs.hanzo.ai was NEVER admitted — the
|
|
# controller fell through to the default *.hanzo.ai cert and 404'd every
|
|
# path. Modeled exactly on the working `bot-docs` App; the only deltas are
|
|
# the image, containerPort (our static server listens on 3000, not 80),
|
|
# and the host.
|
|
#
|
|
# The operator reconciles this into Deployment + Service + Ingress with the
|
|
# correct route registration and a per-host cert via letsencrypt-prod.
|
|
#
|
|
# CD: bump .spec.image.tag to the pushed commit SHA — the operator rolls it.
|
|
# Immutable SHA tags only; never a floating :latest in the cluster.
|
|
apiVersion: hanzo.ai/v1
|
|
kind: App
|
|
metadata:
|
|
name: docs
|
|
namespace: hanzo
|
|
labels:
|
|
app.kubernetes.io/name: docs
|
|
app.kubernetes.io/part-of: platform
|
|
spec:
|
|
component: docs
|
|
partOf: platform
|
|
replicas: 2
|
|
image:
|
|
# ONE registry for docs: ghcr.io/hanzoai/docs (public). This is where the
|
|
# platform-native fabric (POST /v1/runner → buildkit Job, see root Dockerfile)
|
|
# pushes AND where deploy-docs.yml pushes — CR pull source == CI push target,
|
|
# per the "Hanzo → ghcr.io/hanzoai/*" registry rule. NEVER ghcr.io/hanzo-docs/*
|
|
# (a private package the pods' ghcr-secret can't pull → ErrImagePull).
|
|
repository: ghcr.io/hanzoai/docs
|
|
tag: sha-40e315ec0
|
|
pullPolicy: IfNotPresent
|
|
imagePullSecrets:
|
|
- name: ghcr-secret
|
|
# hanzoai/static ships a locked-down default CSP (default-src 'none') that
|
|
# blocks all client JS — including the docs' own interactivity and the Scalar
|
|
# API reference at /reference. HANZO_STATIC_CSP relaxes it to a secure docs
|
|
# policy (self + inline/eval for the OpenAPI renderer) while keeping
|
|
# frame-ancestors/object-src locked. Browsers receive both this and the
|
|
# ingress CSP and enforce the intersection, so this must stay permissive
|
|
# enough for Scalar to execute.
|
|
env:
|
|
- name: HANZO_STATIC_CSP
|
|
value: "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.hanzo.ai https://analytics.hanzo.ai; worker-src 'self' blob:; child-src 'self' blob:; manifest-src 'self'"
|
|
ports:
|
|
- name: http
|
|
containerPort: 3000
|
|
servicePort: 80
|
|
ingress:
|
|
enabled: true
|
|
hosts:
|
|
- docs.hanzo.ai
|
|
tls: true
|
|
resources:
|
|
limits:
|
|
cpu: 200m
|
|
memory: 256Mi
|
|
requests:
|
|
cpu: 50m
|
|
memory: 64Mi
|