openova/core/controllers
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
..
application fix(chart,api,controllers,ui): qa-loop iter-11 Fix #45 — three-cluster closeout (#1265) 2026-05-10 07:26:05 +04:00
blueprint feat(catalog): catalog-svc HTTP REST service + chart wiring (slice L1+L2, #1097) (#1148) 2026-05-09 04:04:52 +04:00
continuum feat(z): cross-EPIC follow-ups — lastLuaRecord + fleet alerts + edit-pr (#1095/#1096/#1099/#1101) (#1170) 2026-05-09 11:54:06 +04:00
environment fix(controllers): create per-Org/App Gitea repos as PUBLIC (Fix #42 follow-up) (#1260) 2026-05-10 04:44:35 +04:00
internal feat(catalyst-ui): live install flow — useCatalog + InstallForm + /applications + preview (slice I, #1097) (#1152) 2026-05-09 05:19:50 +04:00
organization fix(controllers): COPY core/controllers/pkg into env+org Containerfiles (#1253) 2026-05-10 04:09:34 +04:00
pkg fix(application-controller): HelmRelease targetNamespace = App's namespace, not Org slug (qa-loop iter-10 Fix #44) (#1262) 2026-05-10 05:17:48 +04:00
sandbox feat(sandbox): Wave 1 controller + chart scaffold 2026-05-18 07:05:04 +02:00
useraccess feat(useraccess-controller): tier-aware RoleBinding emission + developer scope auto-injection (slice T3 + C5-followup, #1098) (#1145) 2026-05-09 03:42:32 +04:00
go.mod feat(continuum): K-Cont-2 — reconciler with lease + CNPG status watch + 7-step switchover sequence + audit emit (#1101) (#1155) 2026-05-09 06:45:34 +04:00
go.sum feat(continuum): K-Cont-2 — reconciler with lease + CNPG status watch + 7-step switchover sequence + audit emit (#1101) (#1155) 2026-05-09 06:45:34 +04:00