Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .forbidden-terms-whitelist.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
]
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maintainability note (Minor): the em-dash exemption in .forbidden-terms-whitelist.json is pinned to CLAUDE.md line 125. Any future line inserted above this rule shifts it and will trip check-forbidden-terms until the whitelist is re-pinned. This matches the existing line-based whitelist convention so it's acceptable, but the coupling is fragile.


Component-specific conventions:
- Control Plane: [conventions](specs/standards/control-plane/conventions.spec.md)
Expand Down
21 changes: 21 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
"managerFilePatterns": ["^deploy/base/.*\\.yaml$"],
"matchStrings": [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Robustness note (Minor): Renovate custom regex managers do not raise an error when a matchStrings pattern matches nothing - they simply produce zero dependencies. If the GATEWAY_IMAGE / GATEWAY_SUPERVISOR_IMAGE reference format in deploy/base ever changes (registry, env-var name, or a move into Helm values), this auto-update will silently stop with no signal. Consider a small CI guard that asserts the regex still matches the current deploy/base manifests, or complete the unchecked "Renovate dry-run" item in the test plan.

Separately: (?<depName>[^:\s]+) stops at the first colon, so a registry:port/... reference would be mis-parsed. Safe for deploy/base today (no ports; the port-bearing IBM mirror is excluded), but worth noting for future robustness.

"-\\s*name:\\s*GATEWAY(?:_SUPERVISOR)?_IMAGE\\n\\s+value:\\s*(?<depName>[^:\\s]+):(?<currentValue>[^@\\s]+)(?:@(?<currentDigest>sha256:[a-f0-9]+))?"
],
"datasourceTemplate": "docker",
"versioningTemplate": "regex:^v(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)-rhaiv\\.(?<build>\\d+)$"
}
],
"packageRules": [
{
"description": "Group non-major Go indirect dependencies",
Expand Down Expand Up @@ -38,6 +50,15 @@
"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"
}
]
}
1 change: 1 addition & 0 deletions specs/index.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 | - |
Expand Down
132 changes: 132 additions & 0 deletions specs/platform/openshell-image-auto-update.spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# 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:<digest>
```

- **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: <registry>/<org>/<name>:<tag>@sha256:<digest>
```

### 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 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.
- 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.