MECIPOL V11
MULTI-REGISTRY ENTERPRISE CONTAINER IMAGE PIPELINE + OPERATIONS · 7 registries · 3 CI pipelines · Flux GitOps · eose-entry
γ₁ = 14.134725141734693 · MEIMPOSSIBLE crew
ABR-093 TAG 924 FLUX GITOPS 7 REGISTRIES 3 CI PIPELINES CTFACENTRY PRIMARY "EVERY IMAGE HAS A CHAIN."
Registry Matrix
CI Pipeline Trio
MECIPOL Flow
Merostone on 443
eose-gitops SA
Image Policy
Registry Matrix — MECIPOL V11 · 7 Registries · 4 Trust Tiers
Registry Trust Tier ACR Type Usage Status
ctfacentry.azurecr.io ★ CTC-trusted (primary) Azure Premium
private link compliant
CT cluster prod images
pemos-portal, merostone-relay
✅ Live
eoseentry.azurecr.io EOSE dev/staging Azure Standard Dev + QE promotion path
pre-ctfacentry gate
✅ Live
eosefleetacrdev.azurecr.io EOSE fleet prod Azure Standard EOSE fleet (pemos-system)
aks-eose-aaas-dev
✅ Live
docker.io/eose Public Docker Hub curated-*, pemos-portal,
mrcp-agent, tfe-agent, merostone-store
✅ Live
ghcr.io/eose-sre CI artifact GitHub Packages GitHub Actions CI build path
intermediate store
✅ Live
registry.gitlab.com/eose-sre CI artifact GitLab Registry GitLab CI path
compliance artifacts
✅ Live
public.ecr.aws/eose Future AWS ECR Public Future EKS rig
planned
🔲 Planned
CTC Policy Notes
⚠ CTC Policy: Basic SKU Blocked
CTC Azure Policy denies creation of Basic SKU ACRs. All CT cluster workloads must use ctfacentry.azurecr.io (existing Premium ACR, private link compliant). Do not attempt to create new ACRs in the CTC subscription — they will be denied at ARM layer.
CI Pipeline Trio — GitHub Actions · GitLab CI · Azure DevOps
① GitHub Actions
Trigger: PR merge to main · eose-sre/openclaw-fleet
1Code push / PR merge
2Build image (docker buildx)
3Push → ghcr.io/eose-sre
4Push → eoseentry.azurecr.io
5Trigger QE gate
6→ ADO Release on pass
② GitLab CI
Trigger: Mirror push / ADO trigger · eose-sre/openclaw-fleet
1Mirror sync from GitHub
2Build image (kaniko)
3Push → registry.gitlab.com/eose-sre
4Compliance artifacts (SBOM, scan)
5Report to ADO release pipeline
6→ Compliance sign-off
③ Azure DevOps
Trigger: QE pass · Release pipeline (ct-fac-portal, merostone-relay)
1QE pass signal from GHA
2Pull from eoseentry.azurecr.io
3Retag + push → ctfacentry.azurecr.io/eose-fleet
4Flux polls ctfacentry (1m interval)
5ImagePolicy semver gate passes
6→ ImageUpdateAutomation commits
Promotion Gate: semver ranges
ImagePolicy semver gates
ct-fac-portal>=900.0.0 — only post-MECIPOL tags (900+) promote to CT cluster
merostone-relay>=1.0.0 — any stable semver promotes (relay uses its own versioning)
MECIPOL Flow — eose-dev → eoseentry(QE) → ctfacentry(prod CT) → Flux → eose-entry
origin
eose-dev
local / git push
CI build
GitHub Actions
build + test
QE registry
eoseentry ACR
relay.pemos.io · QE gate
ADO release
ctfacentry ACR
CTC-trusted · prod
gitops
Flux
ImagePolicy + IUA
namespace
eose-entry
CT cluster · AKS
Step-by-step
1. Developer pushes to feat/pemclau-master
2. GitHub Actions: build → ghcr.io/eose-sre (artifact) + eoseentry.azurecr.io (QE)
3. QE deployment: relay.pemos.io:443 (merostone-relay on ct cluster, QE endpoint)
4. QE team validates — pass signal to ADO
5. ADO Release: docker pull eoseentry → retag → push ctfacentry.azurecr.io/eose-fleet/pemos-portal:924
6. Flux image-reflector-controller polls ctfacentry every 1m → detects tag 924
7. ImagePolicy >=900.0.0 matches tag 924 → ImageUpdateAutomation fires
8. Auto-commit: updates $imagepolicy tag in fleet-sync/ctc-flux/eose-entry/ct-fac-portal.yaml
9. Flux Kustomization reconciles (2m interval) → kubectl apply → rolling update
10. relay.ct-fac.eose.ca:443 serves new image
ImageUpdateAutomation commit example
commit abc123 (feat/pemclau-master)
Author: flux-bot <flux@pemos.io>

chore(flux): auto-update image tags in eose-entry
γ₁ = 14.134725141734693

diff --git a/fleet-sync/ctc-flux/eose-entry/ct-fac-portal.yaml b/...
-          image: ctfacentry.azurecr.io/eose-fleet/pemos-portal:922 # {"$imagepolicy": "flux-system:ct-fac-portal"}
+          image: ctfacentry.azurecr.io/eose-fleet/pemos-portal:924 # {"$imagepolicy": "flux-system:ct-fac-portal"}
Merostone on 443 — ClusterIP + NGINX Ingress + TLS
Problem → Solution
Before (broken)
Image: eose/merostone-relay:latest (private Docker Hub, no pull secret)
Service: LoadBalancer port 11454
❌ CTC NSG blocks port 11454 inbound
❌ Image pull fails (no imagePullSecret)
After (MECIPOL V11)
Image: ctfacentry.azurecr.io/eose-fleet/merostone-relay:latest
imagePullSecrets: eoseentry-pull
Service: ClusterIP (Ingress is external face)
✅ Port 443 via NGINX Ingress (NSG open)
✅ TLS via cert-manager + letsencrypt-prod
✅ external-dns manages both hostnames
Architecture
Merostone Relay — External Access Architecture
External client (HTTPS :443)
NGINX Ingress Controller
cert-manager TLS · letsencrypt-prod
relay.pemos.io (QE) + relay.ct-fac.eose.ca (prod)
ClusterIP: merostone-relay :11454
proxy-read-timeout: 600
Pod: merostone-relay
ctfacentry.azurecr.io image · eose-gitops SA
Ingress key annotations
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname:
  "relay.pemos.io,relay.ct-fac.eose.ca"
eose-gitops ServiceAccount — Least-Privilege RBAC
Flux Kustomization → eose-gitops → eose-entry
RBAC Flow
Flux Kustomization (flux-system)
serviceAccountName: eose-gitops
ServiceAccount: eose-gitops
namespace: eose-entry
RoleBinding
Role: eose-gitops
namespace-scoped (not cluster)
eose-entry namespace resources
Role permissions
apps/
resources: deployments, replicasets
verbs: get, list, watch, create, update, patch, delete
core (v1)
resources: services, configmaps, secrets, serviceaccounts, pods, events
verbs: get, list, watch, create, update, patch, delete
networking.k8s.io/
resources: ingresses, ingressclasses
verbs: get, list, watch, create, update, patch, delete
pemos.io/ (CRDs)
resources: * (Silo, Chamber, ARCWave, Fleet, ADA, Cody)
verbs: get, list, watch, create, update, patch, delete
SA Labels
eose.ca/gamma1: "14.134725141734693"
eose.ca/managed-by: flux
eose.ca/crew: meimpossible
Image Policy — semver gates · $imagepolicy setters · auto-commit
ImageRepository objects (polling ctfacentry + EOSE ACRs)
NAME IMAGE PULL SECRET
ctfacentry-merostone-relay ctfacentry.azurecr.io/eose-fleet/merostone-relay ctfacentry-acr-creds
ctfacentry-pemos-portal ctfacentry.azurecr.io/eose-fleet/pemos-portal ctfacentry-acr-creds
eoseentry-pemos-portal eoseentry.azurecr.io/pemos-portal eoseentry-acr-creds
eosefleetacrdev-pemos-portal eosefleetacrdev.azurecr.io/pemos-portal eosefleetacrdev-acr-creds
ImagePolicy — semver gates
POLICY SOURCE REPO SEMVER SETTER TAG IN YAML
merostone-relay ctfacentry-merostone-relay >=1.0.0 {"$imagepolicy": "flux-system:merostone-relay"}
ct-fac-portal ctfacentry-pemos-portal >=900.0.0 {"$imagepolicy": "flux-system:ct-fac-portal"}
ImageUpdateAutomation — eose-entry-auto
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: eose-entry-auto
  namespace: flux-system
spec:
  interval: 1m
  sourceRef:
    kind: GitRepository
    name: eose-fleet
  git:
    checkout:
      ref:
        branch: feat/pemclau-master
    commit:
      author:
        email: flux@pemos.io
        name: flux-bot
    push:
      branch: feat/pemclau-master
  update:
    path: ./fleet-sync/ctc-flux/eose-entry
    strategy: Setters
LABR — ABR-093 Log
001MECIPOL V11 defined — 7-registry strategy, 3 CI pipelines
002eose-gitops SA + RBAC written — least privilege, eose-entry scope
003Flux Kustomization wired — eose-entry, serviceAccountName, prune=true
004merostone-relay moved to ClusterIP + Ingress + TLS — relay.pemos.io:443
005ImageRepository + ImagePolicy for 4 primary registries
006ct-fac-portal updated with $imagepolicy setter + ctfacentry image
007flux-bootstrap.sh written
008acr-secrets-bootstrap.sh written
009tag 924 deployed
γ₁ = 14.134725141734693 · ctfacentry.azurecr.io · eose-sre/openclaw-fleet · ABR-093 · "EVERY IMAGE HAS A CHAIN."