Commit Graph

3 Commits

Author SHA1 Message Date
e3mrah
61c8d77b58
feat(bp-openclaw): per-tenant Keycloak SSO + NewAPI as OpenAI-compatible LLM gateway (#915) (#917)
Wire bp-openclaw to the per-tenant Keycloak realm (OIDC SSO) and the
per-tenant NewAPI (OpenAI-compatible LLM endpoint, NOT direct OpenAI),
delivering C3 of umbrella epic #915.

Chart changes (bp-openclaw 0.1.0 → 0.2.0):
- Add canonical `oidc.{issuerURL,clientId,clientSecret.{name,key}}` block.
- Add canonical `llm.{baseURL,apiKey.{name,key},defaultModel}` block.
- Controller Deployment now emits OIDC_*, LLM_*, OPENAI_API_{BASE,KEY},
  LLM_DEFAULT_MODEL envs (legacy KEYCLOAK_*/NEWAPI_BASE_URL_DEFAULT
  retained for back-compat with current controller image).
- Per-user pods carry OPENAI_API_BASE / OPENAI_API_KEY / LLM_DEFAULT_MODEL
  alongside the identity-blind NEWAPI_BASE_URL / NEWAPI_KEY (ADR-0003
  §3.3 unchanged).
- Legacy `keycloak.*` / `newapi.*` keys remain accepted as fallbacks;
  helpers prefer canonical blocks but fall back to the legacy alias when
  the canonical block is unset (or still at placeholder).
- assertNoPlaceholders guard updated to check resolved canonical values.
- render-toggles.sh smoke test extended: asserts both canonical and
  legacy code-paths render and that all expected envs reach the
  rendered Deployment.

Orchestrator changes (catalyst-api smeTenantBPOpenClaw template):
- Emit per-tenant `oidc.issuerURL` = https://keycloak.<sub>.<parent>/realms/sme-<sub>
- Emit per-tenant `oidc.clientId` = openclaw, secret from
  openclaw-oidc-client-secret/OIDC_CLIENT_SECRET (rendered by
  bp-keycloak's post-install hook).
- Emit per-tenant `llm.baseURL` = https://api.<sub>.<parent>/v1 (alice's
  own NewAPI ingress, NOT the otech-wide newapi.<otech-fqdn>); apiKey
  from openclaw-newapi-controller-token/NEWAPI_KEY.
- Emit `llm.defaultModel: qwen3.6` — NewAPI uses this to select the
  backing channel; C4 of #915 wires Qwen3.6@BankDhofar at tenant-create.
- Legacy keycloak/newapi blocks still emitted for back-compat with
  bp-openclaw < 0.2.0.

Tests:
- New TestRenderSMETenantOverlay_OpenClawOIDCAndLLMBlocks asserts the
  rendered HelmRelease contains the canonical oidc + llm blocks with
  per-tenant values, and that llm.baseURL is the per-tenant
  api.<sub>.<parent>/v1 (NOT the otech-wide newapi).
- bp-openclaw render-toggles.sh extended (Case 2b/2c).

Co-authored-by: alierenbaysal <alierenbaysal@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 13:26:59 +04:00
e3mrah
d6dedb1ecd
fix(bp-openclaw): use placeholder defaults so blueprint-release smoke render passes (#803) (#813)
The blueprint-release CI workflow runs `helm template <chart>` with
default values as a smoke gate (.github/workflows/blueprint-release.yaml
SMOKE step). The original chart shipped empty-string defaults for every
required value (keycloak.realmURL, tenant.namespace, etc.) and used
`required` / `fail` to abort render — which is correct fail-fast
behaviour for real installs but wrongly fails CI's default-values
smoke step. Result: bp-openclaw 0.1.0 never published to GHCR (run
25335221500 fail).

Match the bp-self-sovereign-cutover pattern (PR #791): provide
placeholder defaults that let smoke render produce valid YAML, gated
behind a new `assertNoPlaceholders` toggle that per-cluster Flux
overlays MUST set to `true`. With the toggle ON, _helpers.tpl ::
assertNoPlaceholders fails render with a clear message identifying any
placeholder still in place.

Changes:
- values.yaml: add placeholder defaults for keycloak.realmURL,
  keycloak.clientSecretName, newapi.baseURL, tenant.namespace,
  ingress.host, controller.image.tag, perUserPod.image.tag.
  Add `assertNoPlaceholders: false` flag (overlays set true).
- _helpers.tpl: replace assertRequired with assertNoPlaceholders —
  same intent, runs only when the toggle is on, so smoke render passes
  while real installs still get fail-fast on bad overlays.
- serviceaccount.yaml: invoke assertNoPlaceholders instead of assertRequired.
- controller-deployment.yaml + controller-ingress.yaml: drop the
  `required` calls (defaults are now valid bytes; the
  assertNoPlaceholders helper enforces real values at install time).
- tests/render-toggles.sh: rewrite Case 1 (now expects success) and
  Case 2 (asserts assertNoPlaceholders=true fails on placeholders) +
  Case 2b (assertNoPlaceholders=true with real values succeeds).
  All 7 gates pass locally.

Output (post-merge): chart published to
oci://ghcr.io/openova-io/bp-openclaw:0.1.0.

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 22:17:43 +04:00
e3mrah
93bd3ace5b
feat(bp-openclaw): workspace controller + per-user pod chart (#803) (#810)
Implements locked decision [A] of epic #795: per-SME-tenant workspace
controller deployment + per-user runtime pod, identity-blind by
construction. Consumes the per-user newapi-key-{uuid} Secrets rendered
by the unified-rbac user-create hook (ADR-0003 §3.3).

What this delivers:
- platform/openclaw/chart/        bp-openclaw v0.1.0 (no-upstream)
- platform/openclaw/runtime/      Go reference runtime (NEWAPI_BASE_URL
                                  + NEWAPI_KEY env contract only)
- .github/workflows/openclaw-runtime.yaml
                                  Event-driven build for the runtime
                                  image (paths-on-push + manual rerun;
                                  NO schedule:cron per CLAUDE.md).
- platform/openclaw/blueprint.yaml
                                  Catalyst registration + configSchema.

Chart highlights:
- Required values guarded by _helpers.tpl :: assertRequired so missing
  realmURL/clientSecretName/tenant.namespace/baseURL/host fail render
  with helpful messages.
- RBAC: namespaced Role in tenant ns; create verbs split into separate
  rules WITHOUT resourceNames per feedback_rbac_create_no_resourcenames.md.
  Label-based ownership (catalyst.openova.io/openclaw-user) enforced at
  the controller, not in RBAC.
- ingress: cert-manager.io/cluster-issuer annotation triggers ACME
  auto-issuance for openclaw.<sme-domain>.
- per-user pod template ConfigMap holds the pod-spec the controller
  renders per session, with ${USER_UUID}/${SECRET_NAME} placeholders
  filled at session-start.
- networkPolicy covers controller pod only; per-user pod NetworkPolicy
  is rendered by the controller at session-start (target hostname is
  read from the per-user Secret which doesn't exist at chart-render
  time — documented in README.md).

Tests: chart/tests/render-toggles.sh (7 cases) covers required-value
enforcement, RBAC create+resourceNames violation guard, ServiceMonitor
default-off, networkPolicy toggle, pod-template placeholder presence,
cert-manager annotation. All seven gates pass locally.

Closes part of #795 (epic still open).

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 22:10:24 +04:00