Skip to content

feat: build, publish, and deploy the compute workloads plugin bundle - #215

Merged
kevwilliams merged 4 commits into
feat/portal-pluginfrom
feat/workloads-plugin-hosting
Aug 10, 2026
Merged

feat: build, publish, and deploy the compute workloads plugin bundle#215
kevwilliams merged 4 commits into
feat/portal-pluginfrom
feat/workloads-plugin-hosting

Conversation

@kevwilliams

@kevwilliams kevwilliams commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Targets #198 (plugin source, still draft), not main — ui/consumer/workloads lives only there.

No build, publish, or hosting existed for the plugin's static assets. service-catalog's fan-out needs a real HTTPS assets.baseURL to create a ConsumerPortalPlugin. This adds it.

Revised per review:

  • Internal-only. No Gateway/HTTPRoute. The Deployment terminates TLS itself via a cert-manager CSI server cert (key-usages: server auth, datum-control-plane ClusterIssuer) — same pattern milo's own apiserver, ClickHouse, and the OTel collector use for internal TLS. assets.baseURL is the internal Service DNS name; assets.caBundle carries the CA so cloud-portal trusts it without disabling verification.
  • Lives at config/components/consumer-ui-plugin (kind: Component), folded into compute-manager's existing components: list (companion infra PR) — same namespace, same cluster, no new Flux resources.
  • compute-workloads-plugin image stays a floating :latest with imagePullPolicy: Always — a separate bundle to pin its tag would never actually get read once the Deployment moved into compute-manager's own bundle.
  • CI job pin bumped to v1.20.0.

Test plan

  • docker build/run locally with a temporary self-signed cert mounted the same way the CSI volume will be — curl -k and openssl s_client both confirm the TLS server block and cert subject
  • kustomize build config/components/consumer-ui-plugin renders cleanly standalone
  • Full compute-manager composition (base/manager + all its components including this one) renders cleanly, both images present, no cross-contamination
  • After this + infra PR + feat(ui): compute workloads portal plugin #198 merge and CI/Flux reconcile: kubectl get consumerportalplugins shows a compute entry, cloud-portal logs show listed 1 ConsumerPortalPlugin(s)

Nothing built, published, or hosted ui/consumer/workloads's static assets
anywhere — service-catalog's fan-out needs a real HTTPS assets.baseURL
to create a ConsumerPortalPlugin, and there wasn't one.

- New Dockerfile: bun build stage -> nginx-unprivileged serving dist/.
  Verified locally (docker build + run, plugin-manifest.json and
  remoteEntry.js both serve 200) including under the hardened
  securityContext the Deployment uses (read-only rootfs, non-root,
  dropped capabilities, emptyDir mounts for nginx's writable dirs).
- New ui/consumer/workloads/config/: Deployment+Service+HTTPRoute,
  published as its own kustomize bundle (mirrors datum-storybook's
  pattern — the platform's dominant convention for "app repo publishes
  its own deployable static frontend bundle" — not echo's inline-in-infra
  pattern). HTTPRoute attaches to the shared external-gateway per
  environment, same as cloud-portal/datum-storybook; no dedicated Gateway.
- .github/workflows/publish.yaml: two new jobs (image + kustomize bundle)
  using the same reusable workflows compute's apiserver already calls —
  publish-docker.yaml already supports context/dockerfile-path inputs.
- service-configuration.yaml: sets spec.userInterface.consumer.assets.baseURL
  to the new staging-only hostname, entitlement None for now. Flagged
  inline: this component applies identically to every environment's milo
  control plane today (no per-env patch exists), so this also lands in
  production's control plane — low-risk short-term since production's
  cloud-portal has no platform registry source wired up yet, but real
  per-environment parametrization is still owed.

Companion infra PR wires the environment-side (Gateway listener,
Kustomization, staging-only for the same reason the credential rollout
was staging-only).
Matches the established split (see cloud-portal's config/base, which has
no namespace.yaml either): the app repo's bundle only carries workload
resources; the namespace itself is infra's responsibility
(apps/compute-workloads-plugin/base/namespace.yaml, companion infra PR).
@kevwilliams
kevwilliams requested a review from scotwells August 10, 2026 18:24
Comment thread .github/workflows/publish.yaml Outdated
Comment thread config/components/consumer-ui-plugin/deployment.yaml
Comment thread config/components/service-catalog/service-configuration.yaml Outdated
Per review on #215:
- No reason to expose this plugin publicly — the browser never talks to
  a plugin origin directly (cloud-portal's server fetches the manifest/
  assets and proxies them via /api/plugins/<slug>/...). Drops the
  HTTPRoute entirely; the Deployment now terminates TLS itself via a
  cert-manager CSI server cert (key-usages: server auth, datum-control-plane
  ClusterIssuer) — the same pattern milo's own apiserver, ClickHouse, and
  the OTel collector already use for internal-only TLS. Verified locally:
  docker build/run with a temporary self-signed cert mounted the same way
  the CSI volume will be, curl -k and openssl s_client both confirm the
  server block and cert subject are correct.
- Move config/components/consumer-ui-plugin (was ui/consumer/workloads/config)
  so it lives alongside compute's other kustomize components (matches
  config/components/service-catalog's kind: Component convention) and
  gets folded into compute-manager's own Deployment set via its existing
  components: list (companion infra change) — same cluster, same
  compute-system namespace, no new Flux Kustomization or OCIRepository.
- Bump the reusable workflow pin to v1.20.0 per review (matches
  cloud-portal's own pin). Drop the separate kustomize-bundle publish job
  entirely: once the Deployment is folded into compute-manager, a
  separate bundle publish never actually gets read by anything, so it
  can't pin an image tag that matters. Accept a floating :latest tag with
  imagePullPolicy: Always instead — this is a static asset server, not a
  GitOps-tracked control-plane binary.
- service-configuration.yaml: assets.baseURL is now the internal Service
  DNS name (compute-workloads-plugin.compute-system.svc.cluster.local),
  not a public hostname. Cluster-local DNS resolves correctly in whatever
  environment compute-manager deploys to, so (unlike the previous
  public-hostname draft) this needs no per-environment override. Sets
  assets.caBundle to datum-control-plane-ca's public cert (fetched from
  the live datum-control-plane-trust-bundle ConfigMap, non-sensitive) so
  cloud-portal trusts the CSI-issued cert without disabling verification.

Verified: kustomize build config/components/consumer-ui-plugin standalone,
and the full compute-manager composition (base/manager + all its
components including this new one) — both images present with no
cross-contamination, no build errors.
@kevwilliams
kevwilliams requested a review from scotwells August 10, 2026 21:46
Comment thread .github/workflows/publish.yaml Outdated
Comment thread config/components/consumer-ui-plugin/deployment.yaml Outdated
Comment thread config/components/service-catalog/service-configuration.yaml Outdated
Comment thread ui/consumer/workloads/default.conf Outdated
- Rename compute-workloads-plugin -> compute-consumer-ui-plugin
  throughout (Deployment/Service/labels/image/CSI dns-names/baseURL).
  "Workloads" is one page within compute's consumer plugin, not the
  plugin's identity — and this leaves room for a symmetric
  compute-provider-ui-plugin later.
- Replace nginx with Bun's own static file server (serve.ts): drops an
  entire second runtime/technology for what's a few lines of fetch
  handling, and this project is already Bun-based end to end. Verified
  locally the same way as before — docker build/run with a temporary
  self-signed cert, curl -k for real assets (200), unknown paths (404),
  and a path-traversal attempt (404, confirms the path normalization
  actually blocks it).
- Drop assets.caBundle entirely. Checked plugin-fetch.ts: withCaBundle()
  is a no-op when caBundle is unset, falling through to Bun's default
  TLS trust — and cloud-portal's own Deployment already sets
  NODE_EXTRA_CA_CERTS platform-wide (both staging and production)
  pointing at the same datum-control-plane-trust-bundle the plugin's
  CSI cert chains to. The explicit caBundle was redundant with trust
  cloud-portal already has.
- CI pin: plain `@v1.20.0` instead of the SHA-pinned form.
@kevwilliams
kevwilliams merged commit 5f58f57 into feat/portal-plugin Aug 10, 2026
9 checks passed
@kevwilliams
kevwilliams deleted the feat/workloads-plugin-hosting branch August 10, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants