openova/core
hatiyildiz a1314048a8 feat(sandbox): Wave 1 controller + chart scaffold
Wires the sandbox-controller binary + standalone Helm chart for the
Wave 1 slice of the Sandbox product (architecture spec:
products/sandbox/docs/architecture.md §7). Companion to the CRD
shipped in PR #1615.

Controller (core/controllers/sandbox/):
  - cmd/sandbox-controller/main.go — controller-runtime entry point,
    env-driven config, leader election on by default. Mirrors
    core/controllers/organization/cmd/main.go shape.
  - internal/controller/sandbox_controller.go — Reconciler that
    Get's the Sandbox CR, renders Wave 1 manifests, and writes them
    into the per-Org `catalyst-tenant` Gitea repo under
    `sandbox/<owner-uid>/`. Same idiom organization-controller uses
    for vcluster manifests (organization_controller.go:188-225).
  - internal/gitops/manifests.go — text/template renderer for the
    Wave 1 set: Namespace + ResourceQuota + ServiceAccount + Role +
    RoleBinding + placeholder Secret + 1 PVC per spec.repos[] +
    kustomization. Sorted iteration + no time.Now() = deterministic
    output (byte-equal PutFile short-circuit on steady state).
  - internal/controller/sandbox_controller_test.go — 5 cases:
    happy-path + idempotency + 2 drift paths (missing orgRef /
    missing email) + missing-CR. Cloned from
    organization_controller_test.go.
  - Dockerfile — two-stage build, alpine:3.20 runtime, non-root
    UID 65534. Mirrors organization/Containerfile (same CC1 shared
    go.mod + pkg layout).

Chart (platform/sandbox/chart/):
  - Chart.yaml / values.yaml — opt-in via .enabled=false default.
  - templates/{serviceaccount,clusterrole,clusterrolebinding,deployment}.yaml
    + _helpers.tpl — modelled on
    products/catalyst/chart/templates/controllers/organization-controller-*.yaml.
  - ClusterRole grants are least-privilege (sandboxes +
    sandboxes/status + sandboxes/finalizers + leases + events).
    No secrets:get yet (deferred to Wave 2 when the long-lived
    org-scoped token issuance flow lands).
  - Image tag is required at render time (fail-fast on empty per
    Inviolable Principle #4a — no :latest).

Wave 1 does NOT ship: pty-server / openova-sandbox-mcp Deployments,
HTTPRoutes for preview subdomains, long-lived token issuance, per-repo
git-clone initContainer. Those land in Wave 2.

Hard rules respected: READ-ONLY clusters, no chart 1.4.156 bump, no
UI touched, no npm/tsc.

Verified locally:
  - `go build ./sandbox/...` clean (go 1.23.4)
  - `go test -count=1 ./sandbox/...` ok (5/5 pass)
  - `go vet ./sandbox/...` clean
  - `helm lint platform/sandbox/chart` clean
  - `helm template ... --set enabled=true --set image.tag=abc123 ...`
    renders 4 resources (SA + ClusterRole + CRB + Deployment).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 07:05:04 +02:00
..
admin fix(admin,billing): drop unsafe state-write in snippet — spinner stays forever (#1000) (#1001) 2026-05-05 23:36:50 +04:00
cmd feat(epic-4): K+P+X1+G — k8s-ws-proxy + projector + WebSocket logs + Guacamole chart (#1099) (#1164) 2026-05-09 09:27:39 +04:00
console feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00
controllers feat(sandbox): Wave 1 controller + chart scaffold 2026-05-18 07:05:04 +02:00
marketplace fix(marketplace,checkout): drop Google sign-in, port Sovereign-style PinInput6 (#1010) (#1011) 2026-05-06 00:08:42 +04:00
marketplace-api feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00
pkg/dynadot-client fix(pdm/dynadot): remove fictional ResponseHeader wrapper from api3.json adapter (#939) (#948) 2026-05-05 15:11:39 +04:00
pool-domain-manager fix(pdm/dynadot): auto-register NS glue records before set_ns (#1496) 2026-05-15 13:32:49 +04:00
services fix(catalog): D27 — fresh-seed apps default Published+Deployable (#1584) 2026-05-17 09:28:35 +04:00
README.md feat(consolidation): Phase 1 — move Catalyst-Zero apps + CI + manifests into public monorepo 2026-04-28 12:08:09 +02:00

Catalyst Control Plane (core/)

The user-facing Catalyst control plane modules. Status: Consolidated and deployed on Catalyst-Zero (Contabo k3s) as of Pass 105 (2026-04-28).

Read first: docs/PROVISIONING-PLAN.md, docs/GLOSSARY.md, docs/ARCHITECTURE.md, docs/IMPLEMENTATION-STATUS.md.


What this is

The four modules that constitute the Catalyst control plane's user-facing surface, plus the Go backend they share. Each is its own Containerfile-built workload, deployed on every Catalyst Sovereign (starting with Catalyst-Zero on Contabo, and on every franchised Sovereign provisioned thereafter).

Module Stack Purpose Deployed image
console/ Astro + Svelte Primary user-facing UI. Form / Advanced / IaC editor depths. The Sovereign-provisioning wizard at /sovereign (Phase 3) lives here. ghcr.io/openova-io/openova/console:<sha>
admin/ Astro + Svelte Sovereign-admin operations UI. Includes the canonical voucher / billing / catalog / orders / tenants admin surface that sovereign-admin uses to issue vouchers to franchised tenants. ghcr.io/openova-io/openova/admin:<sha>
marketplace/ Astro + Svelte Public-facing Blueprint card grid (the "App Store"). 5-step Plan → Apps → Addons → Checkout → Review flow. ghcr.io/openova-io/openova/marketplace:<sha>
marketplace-api/ Go Backend API for marketplace and console. Handlers (handlers/), provisioner (provisioner/), store (store/). Phase 4 extends this with full Hetzner provisioning. ghcr.io/openova-io/openova/marketplace-api:<sha>

The Helm chart that deploys all four (plus catalyst-ui, catalyst-api, and the legacy SME backend services) lives at products/catalyst/chart/.


CI / Build

Each module has a corresponding GitHub Actions workflow:

Each workflow watches its module path, builds the Containerfile, pushes to GHCR with a SHA tag, and pins the SHA into the corresponding manifest in products/catalyst/chart/templates/ (so Flux on Catalyst-Zero picks up the new image on the next reconciliation).


Migration history

  • Pass 105 (2026-04-28): console/, admin/, marketplace/ consolidated from openova-private/apps/{console,admin,marketplace}/ into this directory. marketplace-api/ consolidated from openova-private/website/marketplace-api/. Six CI workflows migrated to .github/workflows/ of the public repo. Catalyst-Zero K8s manifests migrated from openova-private/clusters/contabo-mkt/apps/{catalyst,sme/services,marketplace-api}/ into products/catalyst/chart/templates/. Image references updated from ghcr.io/openova-io/openova-private/sme-{admin,console,marketplace} to ghcr.io/openova-io/openova/{admin,console,marketplace}. The 8 legacy SME backend services (auth, billing, catalog, domain, gateway, notification, provisioning, tenant) keep their openova-private/sme-* image refs until their source code migrates in a follow-up phase.

Part of OpenOva