Repository navigation
feat(helm): the fleet's own container registry (cr.meshweaver.cloud) as a separate service - #3697
Conversation
…as a separate service Two off-the-shelf images, zero registry code of ours: CNCF distribution 3.0.0 (storage driver azure as the namespace's workload identity, token auth) and cesanta/docker_auth 1.14.0 (one static publisher account by bcrypt hash; every other password validated as a MeshWeaver instance key against the portal via ext_auth). One Ingress on the host: /auth → docker_auth, / → distribution. Off by default; with registry.enabled every required key must be set or the render fails naming it. A complete example overlay is a 4th combination of the chart gate, so the registry renders on every PR. Measured before shipping (real docker login/push/pull against the rendered configs): docker_auth 1.13.0 cannot pair with distribution 3 (libtrust kid vs RFC 7638 lookup) — 1.14.0 with disable_legacy_key_id is the pin; the endpoint headers env override needs YAML-list form; OTLP export is on by default. Part of #3353. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new SecretProviderClass syncs memex-registry-secrets using alias names as secretObjects.data[].objectName, which is inconsistent with the chart’s established Key Vault sync pattern and risks leaving required env-backed secrets (e.g. REGISTRY_HTTP_SECRET) empty at runtime.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds an opt-in, chart-managed OCI registry service (cr.meshweaver.cloud) deployed alongside the portal, built entirely from off-the-shelf images (CNCF distribution + cesanta/docker_auth) and wired with Key Vault + workload identity. This change lives in the Helm chart + docs only (no src/ runtime code changes), and is accompanied by a rendered example overlay and chart-gate coverage to keep registry templates exercised on every PR.
Changes:
- Introduces
registry.*values plus a gatedtemplates/registry/suite (SecretProviderClass, ConfigMaps, Deployments, Services, Ingress) to run the registry + token service whenregistry.enabled: true. - Adds a complete
values.registry.example.yamland extendscheck-chart-invariants.shso the registry templates are rendered/validated in CI. - Updates architecture + What’s New documentation to reflect the “separate service” decision and measured verification.
File summaries
| File | Description |
|---|---|
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-09-08-the-fleet-has-its-own-container-registry.md | Adds a What’s New entry describing the new registry option and behavior. |
| src/MeshWeaver.Documentation/Data/Architecture/ContainerRegistryInMemex.md | Updates the design page with the “separate service” decision + measured validation notes. |
| deploy/helm/values.yaml | Adds the registry: configuration block (disabled by default) and explanatory comments. |
| deploy/helm/values.registry.example.yaml | Provides a complete example overlay for CI/template validation. |
| deploy/helm/templates/registry/_registry.tpl | Centralizes required-value gating and defaults for all registry templates. |
| deploy/helm/templates/registry/configmap.yaml | Defines distribution + docker_auth configuration, including ext_auth validator script. |
| deploy/helm/templates/registry/deployment-registry.yaml | Deploys the distribution registry with Key Vault CSI + env wiring and probes. |
| deploy/helm/templates/registry/deployment-auth.yaml | Deploys docker_auth with Key Vault CSI + validator script and probes. |
| deploy/helm/templates/registry/ingress.yaml | Adds a single host ingress routing /auth to docker_auth and / to distribution. |
| deploy/helm/templates/registry/secretproviderclass.yaml | Adds Key Vault SecretProviderClass and synced Secret for cert/key/http-secret (+ optional notification secret). |
| deploy/aks/scripts/check-chart-invariants.sh | Ensures CI renders the registry templates via an added values-file combination. |
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| - objectName: cert.pem | ||
| key: cert.pem | ||
| - objectName: key.pem | ||
| key: key.pem | ||
| - objectName: http-secret | ||
| key: http-secret | ||
| {{- if $r.notificationSecretObject }} | ||
| - objectName: notification-authorization | ||
| key: notification-authorization | ||
| {{- end }} |
…art-invariant combinations and both status paragraphs (registry service + the #3696 consumer record)
The fleet's own container registry,
cr.meshweaver.cloud, as a SEPARATE service in the chart — two off-the-shelf images, zero registry code of ours. Part of MeshWeaver#3353; design page updated (Doc/Architecture/ContainerRegistryInMemex→ new status block + "The registry as a separate service").What is in the chart (
deploy/helm/templates/registry/, all NEW files;registry.enabled: falseby default)SecretProviderClass memex-registry-keyvaultcertObject/keyObject/httpSecretObject(+notificationSecretObjectwhen notifications are on) under aliasescert.pem/key.pem/http-secret/notification-authorization, synced into Secretmemex-registry-secretsConfigMap memex-registry-configconfig.yml: storageazurewithcredentials.type: default_credentials(workload identity),delete.enabled: true,redirect.disable: false,auth.token→https://<host>/auth,rootcertbundle: /etc/registry/token/cert.pem, storage-driver health check,notifications:rendered only whennotifications.urlis setConfigMap memex-registry-auth-configauth_config.yml(:5001, token issuer/expiration 900/cert/key,disable_legacy_key_id: true, ONE staticusers:entry = the publisher's bcrypt hash,ext_auth: validate.sh, ACL: publisherpush,pull,deleteon everything,account: "/.+/"pullon everything, anonymous nothing) +validate.sh(busyboxwget -S→ 200 exit 0 / 401,403 exit 1 / anything else exit 3 = docker_auth ERROR)Deployment memex-registry-deployment+ Service:5000azure.workload.identity/use: "true",serviceAccountName: registry.serviceAccount, CSI mount at/etc/registry/token,REGISTRY_HTTP_SECRETfrom the synced Secret,OTEL_TRACES_EXPORTER=none, readinesshttpGet /, liveness TCP, config checksum annotationDeployment memex-registry-auth-deployment+ Service:5001validate.shmounted0555Ingress memex-registryregistry.host:/auth→ auth:5001,/→ registry:5000;cert-manager.io/cluster-issuerwhen set,proxy-body-size: "0", request buffering off, read/send timeouts 3600helm templateFAILS naming the key whenenabled: trueand any ofhost,image,authImage,storage.accountName,keyVault.name,keyVault.certObject,keyVault.keyObject,keyVault.httpSecretObject,publisher.passwordBcryptis empty (all reads go through thememex.registryhelper in_registry.tpl), and whennotifications.urlis set withoutkeyVault.notificationSecretObject.keyVault.tenantId/identityClientIdfall back tokeyVaultSecrets.*.Additive elsewhere: a
registry:block invalues.yaml(inserted beforesecrets:, away from the sectionsfeat/3353-mirror-consumers-coreedits),deploy/helm/values.registry.example.yaml(complete, credential-free), and that example added as a 4th combination tocheck-chart-invariants.shso the chart gate renders the registry on every PR.Values shape
🚨 Deviations from the brief, each measured
1.14.0, not1.13.cesanta/docker_auth:1.13does not exist on Docker Hub (1.13.0does), and 1.13.0 CANNOT pair with distribution 3.0: distribution 3 keysrootcertbundleby RFC 7638 JWK thumbprint, docker_auth's defaultkidis the libtrust id (KF26:LQHR:…) and nox5cis sent, so every token — the publisher's included — was refused withtoken signed by untrusted key with IDwhile the token exchange answered 200. 1.14.0 addstoken.disable_legacy_key_id: truefor this exact case; the config sets it. Verified the failure with 1.13.0 AND with 1.14.0-without-the-flag before the fix.docker buildx imagetools inspect(nocraneon this host;docker manifest inspectgives the same index).keyVault.httpSecretObjectis also required (the brief's list did not name it): without a sharedhttp.secret, a chunked upload cannot continue on another replica.validate.shexits 3, not 2, on a non-definite answer — docker_auth's contract is0 allow / 1 deny / 2 no-match (try next authenticator) / 3 error; the brief asked for "error, never silently pass", and 3 is what docker_auth logs as an error (bad return code from command: 3).endpoints[0].headersunmarshals the value as YAML into[]string(cannot unmarshal !!str into []string, measured), so the plain vault value is wrapped into list form by the container command at start (MEMEX_REGISTRY_NOTIFICATION_AUTHORIZATION→REGISTRY_NOTIFICATIONS_ENDPOINTS_0_HEADERS_AUTHORIZATION); the config file stays the rendered one.OTEL_TRACES_EXPORTER=none: distribution 3.0 ships an OTLP exporter on by default and logstraces export … connection refusedevery 10 s otherwise.httpGet /on both (both answer 200; distribution's health wrapper turns that into 503 when the storage driver check fails); liveness is TCP.Verification
Chart (helm v4.2.4 locally; CI uses v3.16.3):
helm lintclean;helm templatewithvalues.yaml + values.registry.example.yamlrenders all 8 registry objects; default values render ZEROmemex-registry*objects; blankinghost,publisher.passwordBcrypt, ornotificationSecretObject-with-url each fails naming the key. Gates as CI runs them:check-chart-invariants.shexit 0 (4 combinations, the new one included),check-values-are-read.shexit 0,test-chart-drift-compare.shexit 0.Docker (Colima 29.5.2 linux/aarch64, 2026-09-08 08:10Z) — the two pinned images run with the RENDERED ConfigMaps extracted from
helm template(only the storage driver swapped tofilesystem, the host to the published localhost ports — 5555/5556, because 5000 is macOS AirPlay on this Mac — and the validation/notification URLs pointed at a python stub answering 200 for one known bearer and 401 otherwise, recording every notification), a self-signed RSA-2048 cert fromopenssl req -x509, docker_auth's password =htpasswd -nbB publisher example-publisher-password(a$2y$hash):Docs:
DocumentationLinkIntegrityTest,WhatsNewEntryIntegrityTest,DocumentationEmbedIntegrityTestrun after a-c Release -warnaserrorbuild ofMeshWeaver.Documentation.Test(31 projects, 0 warnings, 0 errors).What's New:
2026-09-08-the-fleet-has-its-own-container-registry.md(Category: Feature).Pairs-with: none — no public type or member leaves
src/; this change is chart, scripts and docs only.🤖 Generated with Claude Code