From ecc242d1e1dce46ec4ce919822aea71feba04aeb Mon Sep 17 00:00:00 2001 From: Brandon Squizzato Date: Thu, 3 Sep 2026 15:00:50 -0400 Subject: [PATCH 1/4] feat(ci): auto-update OpenShell gateway and supervisor images via Renovate Add a Renovate customManager (regex) that detects the OpenShell gateway and supervisor image references pinned as env var values in deploy/base/ manifests. A regex versioningTemplate filters the 3000+ noisy tags (commit SHAs, arch-specific, build artifacts) down to the official release convention (v{major}.{minor}.{patch}-rhaiv.{build}). Both images are grouped into a single "OpenShell images" PR with automerge on green CI. Includes the auto-update spec under specs/platform/. [HYPERSHELL-46] Co-Authored-By: Claude Opus 4.6 --- renovate.json | 23 +++ specs/index.spec.md | 1 + .../openshell-image-auto-update.spec.md | 131 ++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 specs/platform/openshell-image-auto-update.spec.md diff --git a/renovate.json b/renovate.json index 6dcfdd12..742a11a0 100644 --- a/renovate.json +++ b/renovate.json @@ -5,6 +5,18 @@ "minimumReleaseAge": "14 days", "internalChecksFilter": "strict", "prConcurrentLimit": 6, + "customManagers": [ + { + "customType": "regex", + "description": "OpenShell gateway and supervisor images pinned as env var values in deployment manifests", + "fileMatch": ["^deploy/base/.*\\.yaml$"], + "matchStrings": [ + "-\\s*name:\\s*GATEWAY(?:_SUPERVISOR)?_IMAGE\\n\\s+value:\\s*(?[^:\\s]+):(?[^@\\s]+)@(?sha256:[a-f0-9]+)" + ], + "datasourceTemplate": "docker", + "versioningTemplate": "regex:^v(?\\d+)\\.(?\\d+)\\.(?\\d+)-rhaiv\\.(?\\d+)$" + } + ], "packageRules": [ { "description": "Group non-major Go indirect dependencies", @@ -38,6 +50,17 @@ "matchManagers": ["github-actions"], "matchUpdateTypes": ["digest", "minor", "patch", "pinDigest"], "groupName": "GitHub Actions" + }, + { + "description": "Group OpenShell gateway and supervisor image updates into a single PR", + "matchManagers": ["custom.regex"], + "matchPackageNames": [ + "quay.io/opendatahub/odh-openshell-gateway", + "quay.io/opendatahub/odh-openshell-supervisor" + ], + "groupName": "OpenShell images", + "automerge": true, + "automergeType": "pr" } ] } diff --git a/specs/index.spec.md b/specs/index.spec.md index 05bbd639..667aec20 100644 --- a/specs/index.spec.md +++ b/specs/index.spec.md @@ -52,6 +52,7 @@ Machine-readable index for autonomous reconciliation (`/reconcile` skill). | `platform/local-development.spec.md` | platform | Kind cluster, images, Make targets | ALL | cross-cutting, security | | `platform/oidc-integration.spec.md` | platform | API JWT validation, BFF OIDC session, IdP client config, Kind opt-in | API, WEB, CP | local-development, openshell-gateway-oidc, web-console/architecture | | `platform/e2e-testing.spec.md` | platform | Infra drivers, e2e test suite, CI workflow, deploy overlays | ALL | local-development, control-plane, openshell-gateway-routing | +| `platform/openshell-image-auto-update.spec.md` | platform | Renovate customManager, OpenShell image bumps, merge policy | CI | e2e-testing, control-plane | | `platform/api-server-observability.spec.md` | platform | API OTel SDK bootstrap, HTTP/gRPC server spans, W3C trace continuation, request metrics | API | web-console/tracing, security, local-development, e2e-testing | | `platform/control-plane-observability.spec.md` | platform | CP OTel SDK bootstrap, reconcile spans, gRPC client spans, watch lifecycle, K8s API spans, reconcile metrics | CP | api-server-observability, control-plane, security, local-development | | `standards/ui/foundations.spec.md` | standards | UI foundations | WEB | - | diff --git a/specs/platform/openshell-image-auto-update.spec.md b/specs/platform/openshell-image-auto-update.spec.md new file mode 100644 index 00000000..3f1c9048 --- /dev/null +++ b/specs/platform/openshell-image-auto-update.spec.md @@ -0,0 +1,131 @@ +# OpenShell Image Auto-Update + +**Date:** 2026-09-03 +**Status:** Active +**JIRA:** HYPERSHELL-46 + +## Purpose + +This spec defines the desired state for continuously updating the downstream +OpenShell gateway and supervisor container images consumed by the HyperShell +control plane. The mechanism must detect new upstream image tags/digests, propose +a bump via pull request, gate that bump on the platform's full PR test suite, and +merge only on green — preventing both silent drift and unvalidated upgrades. + +## Scope + +**In scope:** + +- OpenShell gateway image (`quay.io/opendatahub/odh-openshell-gateway`) +- OpenShell supervisor image (`quay.io/opendatahub/odh-openshell-supervisor`) +- Pinned references in `deploy/base/` deployment manifests + +**Out of scope:** + +- Internal registry mirrors (e.g. `deploy/ibm/kustomization.yaml`) — these are + cluster-local copies updated by the mirror process, not by Renovate. +- Go source constants for non-OpenShell images (`defaultConsoleImage`, + `defaultOAuth2ProxyImage`, etc.) — separate concern. +- Database-backed image defaults (future; tracked by existing TODO in + `config.go`). + +## Image Pinning Strategy + +All OpenShell image references are pinned using the `tag@digest` format: + +``` +quay.io/opendatahub/odh-openshell-gateway:v0.0.109-rhaiv.0@sha256: +``` + +- **Tag** provides human readability and version ordering. +- **Digest** provides immutable, content-addressed reproducibility. +- Both must be updated together on every bump. + +## Watched Sources + +| Image | Registry | Pinned In | +|-------|----------|-----------| +| `odh-openshell-gateway` | `quay.io/opendatahub` | `deploy/base/controller.yaml`, `deploy/base/control-plane/deployment.yaml` | +| `odh-openshell-supervisor` | `quay.io/opendatahub` | `deploy/base/controller.yaml`, `deploy/base/control-plane/deployment.yaml` | + +The images are set as environment variable values (`GATEWAY_IMAGE`, +`GATEWAY_SUPERVISOR_IMAGE`) on the control-plane Deployment, which the +`StaticImageDefaults` reads at runtime via `os.Getenv`. + +## Update Mechanism + +### Renovate Custom Manager + +Renovate's built-in managers do not detect container image references inside YAML +`env` `value:` fields. A `customManagers` entry with `customType: "regex"` scans +the deployment manifests for the `GATEWAY_IMAGE` / `GATEWAY_SUPERVISOR_IMAGE` env +var pattern and extracts `depName`, `currentValue`, and `currentDigest` for the +Docker datasource. + +The regex matches the two-line YAML pattern: + +```yaml +- name: GATEWAY_IMAGE + value: //:@sha256: +``` + +### Version Filtering + +The upstream quay.io repositories contain thousands of tags — commit SHAs, +architecture-specific manifests (`-linux-m2xlarge-amd64`), and build artifacts +(`.git`, `.prefetch`). A `regex` versioning template restricts Renovate to tags +matching the release convention: + +``` +v{major}.{minor}.{patch}-rhaiv.{build} +``` + +The `build` component (the `-rhaiv.N` suffix) represents the downstream rebuild +number. Higher values are newer. Renovate's regex versioning compares `build` +after `patch`, so `v0.0.113-rhaiv.2` correctly supersedes `v0.0.113-rhaiv.1`. + +### Schedule and Constraints + +The auto-update follows the repository's existing Renovate conventions: + +- **Schedule:** Monday 00:00–07:00 ET (inherited from top-level `schedule`) +- **Minimum release age:** 14 days (inherited from top-level `minimumReleaseAge`) +- **Concurrent PR limit:** shared with other Renovate PRs (top-level + `prConcurrentLimit`) +- **Grouping:** both images are grouped into a single "OpenShell images" PR so + gateway and supervisor stay in lockstep. + +### Validation Gate + +Every bump PR must pass the full platform PR test suite before merge: + +- GitHub Actions `e2e.yml` workflow +- Tekton PR pipelines (`.tekton/*-pull-request.yaml`) + +A red check blocks the PR. Renovate will not merge a failing PR regardless of +automerge configuration. + +### Merge Policy + +Automerge is enabled (`automerge: true`, `automergeType: "pr"`). Renovate merges +the PR only after all required status checks pass. If any check fails: + +- The PR stays open and blocked. +- The failure is visible in the PR checks — not swallowed. +- A platform maintainer must investigate before the image is adopted. + +## Cross-Stack Consistency + +After a bump, every `GATEWAY_IMAGE` and `GATEWAY_SUPERVISOR_IMAGE` reference in +`deploy/base/` must carry the same tag and digest. Renovate's regex manager +updates all matches in all files within a single PR, maintaining consistency. + +Internal registry mirrors in environment-specific overlays (IBM, etc.) are +updated separately through their own mirror+redeploy process, not by Renovate. + +## Verification + +- `renovate-config-validator` passes on the updated `renovate.json` in CI. +- A Renovate dry-run detects the current pinned images and proposes the expected + version. +- A representative bump PR exercises the e2e pipeline and is correctly gated. From ca2e3b9ca25ac702f281174f4fa84276c1dd8fb7 Mon Sep 17 00:00:00 2001 From: Brandon Squizzato Date: Thu, 3 Sep 2026 15:08:20 -0400 Subject: [PATCH 2/4] fix: replace em dashes with hyphens and document the convention Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 1 + specs/platform/openshell-image-auto-update.spec.md | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0aad3909..dacfd740 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -122,6 +122,7 @@ Cross-cutting rules that apply across ALL components. - **PatternFly 6 for web UI**: Reuse PatternFly and canonical shared components; do not create duplicate UI components - **Narrow hexagonal UI boundary**: Put application workflows and external effects behind application-owned ports; keep React, TanStack Query, Fastify, generated SDKs, and infrastructure outside - **Domain probes for UI observability**: Publish typed workflow and dependency facts through a fan-out port; no raw console or direct telemetry calls in production browser/BFF code +- **No em dashes**: Use hyphens (`-`) instead of em dashes (`—` U+2014) in all text files; the pre-commit hook rejects them Component-specific conventions: - Control Plane: [conventions](specs/standards/control-plane/conventions.spec.md) diff --git a/specs/platform/openshell-image-auto-update.spec.md b/specs/platform/openshell-image-auto-update.spec.md index 3f1c9048..46a6ef89 100644 --- a/specs/platform/openshell-image-auto-update.spec.md +++ b/specs/platform/openshell-image-auto-update.spec.md @@ -10,7 +10,7 @@ This spec defines the desired state for continuously updating the downstream OpenShell gateway and supervisor container images consumed by the HyperShell control plane. The mechanism must detect new upstream image tags/digests, propose a bump via pull request, gate that bump on the platform's full PR test suite, and -merge only on green — preventing both silent drift and unvalidated upgrades. +merge only on green - preventing both silent drift and unvalidated upgrades. ## Scope @@ -22,10 +22,10 @@ merge only on green — preventing both silent drift and unvalidated upgrades. **Out of scope:** -- Internal registry mirrors (e.g. `deploy/ibm/kustomization.yaml`) — these are +- Internal registry mirrors (e.g. `deploy/ibm/kustomization.yaml`) - these are cluster-local copies updated by the mirror process, not by Renovate. - Go source constants for non-OpenShell images (`defaultConsoleImage`, - `defaultOAuth2ProxyImage`, etc.) — separate concern. + `defaultOAuth2ProxyImage`, etc.) - separate concern. - Database-backed image defaults (future; tracked by existing TODO in `config.go`). @@ -71,7 +71,7 @@ The regex matches the two-line YAML pattern: ### Version Filtering -The upstream quay.io repositories contain thousands of tags — commit SHAs, +The upstream quay.io repositories contain thousands of tags - commit SHAs, architecture-specific manifests (`-linux-m2xlarge-amd64`), and build artifacts (`.git`, `.prefetch`). A `regex` versioning template restricts Renovate to tags matching the release convention: @@ -111,7 +111,7 @@ Automerge is enabled (`automerge: true`, `automergeType: "pr"`). Renovate merges the PR only after all required status checks pass. If any check fails: - The PR stays open and blocked. -- The failure is visible in the PR checks — not swallowed. +- The failure is visible in the PR checks - not swallowed. - A platform maintainer must investigate before the image is adopted. ## Cross-Stack Consistency From 6e005bb96e12d6d7f5573b82579076245e40d2d1 Mon Sep 17 00:00:00 2001 From: Brandon Squizzato Date: Thu, 3 Sep 2026 15:10:02 -0400 Subject: [PATCH 3/4] fix: whitelist em dash in CLAUDE.md convention rule The em dash appears literally in the rule documenting that em dashes are forbidden; it must be shown to be unambiguous. Co-Authored-By: Claude Opus 4.6 --- .forbidden-terms-whitelist.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.forbidden-terms-whitelist.json b/.forbidden-terms-whitelist.json index 6e02455b..2fb2bb8f 100644 --- a/.forbidden-terms-whitelist.json +++ b/.forbidden-terms-whitelist.json @@ -33,5 +33,10 @@ "filename": "specs/platform/global-architecture.spec.md", "line": 1164, "rationale": "Example directory names 'vteam-stage'/'vteam-uat' in a GitOps directory-tree illustration reference real external cluster environments; they are example paths, not the discouraged term." + }, + { + "filename": "CLAUDE.md", + "line": 125, + "rationale": "The em dash appears inside a convention rule that documents the character itself as a forbidden term; it must be shown literally to be unambiguous." } ] From 02beb0079e97803112759a1115e419ef0f4ff701 Mon Sep 17 00:00:00 2001 From: Brandon Squizzato Date: Thu, 3 Sep 2026 16:29:25 -0400 Subject: [PATCH 4/4] fix(ci): address PR review feedback for Renovate config - Make digest optional in matchStrings so tag-only pins are still detected instead of silently skipped - Disable automerge on OpenShell images (supply-chain policy: require human review for external image bumps) - Rename fileMatch to managerFilePatterns (fileMatch deprecated in recent Renovate) - Replace en dash with hyphen in spec time range Co-Authored-By: Claude Opus 4.6 --- renovate.json | 8 +++----- specs/platform/openshell-image-auto-update.spec.md | 7 ++++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/renovate.json b/renovate.json index 742a11a0..8904e888 100644 --- a/renovate.json +++ b/renovate.json @@ -9,9 +9,9 @@ { "customType": "regex", "description": "OpenShell gateway and supervisor images pinned as env var values in deployment manifests", - "fileMatch": ["^deploy/base/.*\\.yaml$"], + "managerFilePatterns": ["^deploy/base/.*\\.yaml$"], "matchStrings": [ - "-\\s*name:\\s*GATEWAY(?:_SUPERVISOR)?_IMAGE\\n\\s+value:\\s*(?[^:\\s]+):(?[^@\\s]+)@(?sha256:[a-f0-9]+)" + "-\\s*name:\\s*GATEWAY(?:_SUPERVISOR)?_IMAGE\\n\\s+value:\\s*(?[^:\\s]+):(?[^@\\s]+)(?:@(?sha256:[a-f0-9]+))?" ], "datasourceTemplate": "docker", "versioningTemplate": "regex:^v(?\\d+)\\.(?\\d+)\\.(?\\d+)-rhaiv\\.(?\\d+)$" @@ -58,9 +58,7 @@ "quay.io/opendatahub/odh-openshell-gateway", "quay.io/opendatahub/odh-openshell-supervisor" ], - "groupName": "OpenShell images", - "automerge": true, - "automergeType": "pr" + "groupName": "OpenShell images" } ] } diff --git a/specs/platform/openshell-image-auto-update.spec.md b/specs/platform/openshell-image-auto-update.spec.md index 46a6ef89..b7f235f7 100644 --- a/specs/platform/openshell-image-auto-update.spec.md +++ b/specs/platform/openshell-image-auto-update.spec.md @@ -88,7 +88,7 @@ after `patch`, so `v0.0.113-rhaiv.2` correctly supersedes `v0.0.113-rhaiv.1`. The auto-update follows the repository's existing Renovate conventions: -- **Schedule:** Monday 00:00–07:00 ET (inherited from top-level `schedule`) +- **Schedule:** Monday 00:00-07:00 ET (inherited from top-level `schedule`) - **Minimum release age:** 14 days (inherited from top-level `minimumReleaseAge`) - **Concurrent PR limit:** shared with other Renovate PRs (top-level `prConcurrentLimit`) @@ -107,8 +107,9 @@ automerge configuration. ### Merge Policy -Automerge is enabled (`automerge: true`, `automergeType: "pr"`). Renovate merges -the PR only after all required status checks pass. If any check fails: +Automerge is disabled. Renovate opens the bump PR and a platform maintainer +must review and merge it after all required status checks pass. If any check +fails: - The PR stays open and blocked. - The failure is visible in the PR checks - not swallowed.