Conversation
|
Important Review skippedAuto reviews are limited based on label configuration. 🚫 Excluded labels (none allowed) (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Central YAML (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
| │ GRPCRoute, BackendTLSPolicy (PR #2728) | ||
| │ (NetworkPolicy disabled — see decision below) | ||
| ├─ 8. Reconcile OpenShift SCC binding ← Go (unchanged) | ||
| ├─ 9. Reconcile ingress (BackendCA ConfigMap) ← Go (if not covered by chart) |
There was a problem hiding this comment.
In what cases would this not be covered by the chart?
There was a problem hiding this comment.
The only scenario I can think of at the moment is when the 'certgen' job fails to create the BackendCA Configmap due to a cert-manager timeout. In that case, we can circle back and run the equivalent of a 'helm upgrade'
| - AND the release namespace SHALL be the gateway's API-assigned namespace | ||
| - AND `Install.CreateNamespace` SHALL be `false` (the reconciler creates the namespace itself) | ||
|
|
||
| #### Scenario: Gateway update (Helm upgrade) |
There was a problem hiding this comment.
We are not currently handling upgrades. Let's specifically not in this spec that upgrades are currently not handled. Only install when a gateway is created / and uninstall when a gateway is deleted.
There was a problem hiding this comment.
The only time we might invoke 'helm upgrade' is in a "retry" scenario where initial install was not fully successful
|
|
||
| - GIVEN the environment variable `HELM_CHART_REGISTRY` is set (e.g. `oci://ghcr.io/nvidia/openshell/helm-chart`) | ||
| - WHEN the reconciler loads the chart | ||
| - THEN it SHALL pull from the OCI registry instead of the embedded path |
There was a problem hiding this comment.
Can we ensure that the reconciler pulls the chart ONCE during startup, so it does not need to re-pull for every reconcile?
| | `kubernetes-secrets` driver | `credentialDrivers.kubernetesSecrets.enabled=true` | | ||
| | Vault driver | `credentialDrivers.vault.enabled=true`, `credentialDrivers.vault.*` | | ||
|
|
||
| #### Ingress Values (conditional) |
There was a problem hiding this comment.
control-plane currently deploys a route.openshift.io Route resource in cases where a BackendTLSPolicy w/ Gateway API will not work (e.g. OpenShift versions under 4.22). We should use the chart to deploy the Route in these cases as well.
| - GIVEN the control plane manages sandbox CRD installation separately | ||
| - WHEN computing Helm values | ||
| - THEN `agentSandbox.preflight.enabled` SHALL be set to `false` | ||
| - AND the chart SHALL not fail if the sandbox CRD API is not yet served |
There was a problem hiding this comment.
I think that actually this is a good check to keep in place. Agent Sandbox is an installation pre-requisite. If it is not in place on the cluster, it is OK for the helm install to fail and for an error to be logged.
|
|
||
| --- | ||
|
|
||
| ### Requirement: Migration Path |
There was a problem hiding this comment.
The migration path can be very simple, because this platform is still in 'beta' state.
New gateway creations will use the helm chart
Don't worry about existing gateways.
There was a problem hiding this comment.
See comment about deleting namespaces.
| - WHEN the GatewayReconciler processes the event | ||
| - THEN it SHALL call `action.Uninstall` to remove chart-managed resources | ||
| - AND it SHALL separately clean up non-chart resources (database, console, SCC binding, extra network policies, Keycloak clients) | ||
| - AND it SHALL NOT delete the namespace (consistent with current behavior) |
There was a problem hiding this comment.
Let's begin to delete the namespace. We want to do this anyways, plus, it makes migration paths easier (if a helm chart was installed for the gateway, then run 'helm uninstall' before deleting namespace. Otherwise, just delete the namespace)
|
|
||
| Existing gateway deployments use directly-applied resources (SSA). Transitioning to Helm-managed releases requires adopting existing resources into the Helm release without downtime. | ||
|
|
||
| #### Scenario: Adopt existing resources into Helm release |
| - AND no resources SHALL be deleted or recreated during migration | ||
| - AND the gateway pod SHALL NOT be restarted unless the Deployment spec actually changes | ||
|
|
||
| #### Scenario: Rollback capability |
There was a problem hiding this comment.
We are not handling gateway upgrades at this time. Section not necessary
| - THEN the `Atomic` flag SHALL cause automatic rollback to the previous release revision | ||
| - AND the reconciler SHALL log the failure and retry on the next reconciliation cycle | ||
|
|
||
| #### Scenario: Mixed-state during rolling upgrade |
There was a problem hiding this comment.
This is fine as long as we do not need 2 code paths... i.e. I want to only have the 'helm deploy method' in the latest code and not keep the old "SSA-based deployment" code hanging around.
|
|
||
| | # | Resource | Kind | Why the Control Plane Handles It | | ||
| |---|---|---|---| | ||
| | 1 | `openshell-sandbox-privileged-scc` | RoleBinding | OpenShift SCC binding granting the `privileged` SCC to the sandbox ServiceAccount. The chart handles `podSecurityContext` values but has no concept of OpenShift SCC grants. | |
There was a problem hiding this comment.
You can add a note about how the creation of this rolebinding outside of the chart is documented here: https://github.com/NVIDIA/OpenShell/blob/main/deploy/helm/openshell/README.md#install-on-openshift
| | # | Resource | Kind | Why the Control Plane Handles It | | ||
| |---|---|---|---| | ||
| | 1 | `openshell-sandbox-privileged-scc` | RoleBinding | OpenShift SCC binding granting the `privileged` SCC to the sandbox ServiceAccount. The chart handles `podSecurityContext` values but has no concept of OpenShift SCC grants. | | ||
| | 2 | `gateway-trusted-ca` | ConfigMap | CA bundle for private-CA environments (e.g. Keycloak behind OpenShift ingress). Copied from the CP namespace and mounted into the gateway Deployment via a post-Helm SSA patch. | |
There was a problem hiding this comment.
Apparently, the upstream chart can handle this:
● The chart already handles this. Setting server.oidc.caConfigMapName to the name of a ConfigMap makes the chart automatically:
1. Add the SSL_CERT_FILE env var to the gateway container
2. Mount the ConfigMap as a volume
3. Wire it all up in the Deployment
So we don't need a post-Helm SSA patch for the trusted CA. The control plane just needs to:
1. Copy the gateway-trusted-ca ConfigMap into the tenant namespace (as it does today)
2. Pass server.oidc.caConfigMapName: "gateway-trusted-ca" in the Helm values
|
|
||
| --- | ||
|
|
||
| ## Trusted CA Injection Strategy |
There was a problem hiding this comment.
See above comment. We'll change the way this works, and this whole section can go away.
|
|
||
| --- | ||
|
|
||
| ## NetworkPolicy Decision: Do Not Install |
There was a problem hiding this comment.
Add a note that we will revisit this if/when using a restrictive network policy posture becomes a platform requirement.
| 2. CNPG Database + credentials Secret (must exist before Helm install) | ||
| 3. Trusted CA ConfigMap copy (must exist before Helm install if present) | ||
| 4. Helm install/upgrade (creates core workload + chart-managed resources) | ||
| 5. OpenShift SCC binding (can run after Helm, before pod scheduling) |
There was a problem hiding this comment.
Install the SCC binding before the helm install
| 3. Trusted CA ConfigMap copy (must exist before Helm install if present) | ||
| 4. Helm install/upgrade (creates core workload + chart-managed resources) | ||
| 5. OpenShift SCC binding (can run after Helm, before pod scheduling) | ||
| 6. Trusted CA Deployment overlay (must run after Helm, patches the Deployment) |
Amber Review — Spec Quality AssessmentOverall: Spec is comprehensive and addresses all user feedback. The TLS architecture explanation for Route passthrough mode is accurate and well-documented. Minor issues below. ✅ Strengths
🔧 Issues1. Minor Inconsistency — Gap Table (line 291)Issue: Line 291 states Fix: | Trusted CA volume/mount/env | Chart (`_gateway-workload.tpl`) | `_gateway-workload.tpl` | `server.oidc.caConfigMapName` |Severity: Minor 2. Missing Error Handling Guidance (Helm Operations)Issue: Spec doesn't specify how Helm install/upgrade failures should be handled per HyperShell conventions:
Recommendation: Add to "Code Changes" section: ### Error Handling (HyperShell Convention)
- Helm install/upgrade/uninstall errors SHALL be wrapped with context: `fmt.Errorf("helm install gateway %s: %w", gateway.Name, err)`
- Gateway status SHALL be updated on Helm failure with `State: "Failed"` and error message
- Reconciler SHALL return explicit errors — NEVER `panic()` on Helm failuresSeverity: Major (impacts production error handling) 3. Incomplete Retry Guidance (lines 102-107)Issue: "Retry after failed install" scenario mentions
Recommendation: Expand scenario: #### Scenario: Retry after failed install
- GIVEN a previous Helm install failed (e.g. certgen job timed out)
- WHEN the GatewayReconciler processes the next reconciliation event
- THEN it SHALL query Helm release status via `action.Get`
- AND if release status is `failed` or `pending-install`, it SHALL run `helm upgrade --reuse-values` to retry
- AND it SHALL implement exponential backoff (1m, 2m, 4m, 8m, max 15m between retries)
- AND it SHALL mark the Gateway status as `State: "Failed"` after 5 consecutive failures
- AND this is the only scenario where `helm upgrade` is invokedSeverity: Major (impacts retry behavior) 4. Missing Configuration ValidationIssue: No requirement for validating env vars at startup. Control plane should fail-fast if Recommendation: Add to "Configuration" section: ### Validation at Startup
- Control plane SHALL validate `EXTERNAL_CA_ISSUER_NAME` is set when any managed cluster lacks Gateway API support
- Control plane SHALL fail fast with clear error message if validation fails
- Chart version compatibility SHALL be verified against `HELM_CHART_VERSION` (if pulling from OCI registry)Severity: Major (prevents runtime failures) 5. Chart Version Pinning — Implementation Detail MissingIssue: Line 129 says "chart version SHALL be pinned in the Dockerfile build script" but doesn't specify HOW (version file, make variable, ARG, etc.). Recommendation: Add implementation detail: - AND the chart version SHALL be declared as a `VERSION` file in `components/control-plane/charts/VERSION`
- AND the Dockerfile SHALL read this file: `ARG CHART_VERSION=$(cat charts/VERSION)`
- AND the build SHALL run: `helm pull oci://ghcr.io/nvidia/openshell/helm-chart --version ${CHART_VERSION} --destination /charts/`Severity: Minor (implementation clarity) 📊 Summary
Recommendation: Address major issues (error handling, retry guidance, config validation) before implementation. Minor issues can be fixed during PR review of the actual code. Confidence Level: High (90%) — Spec is solid, issues are additive improvements rather than fundamental flaws. You are Amber. Be the colleague everyone wishes they had. |
Amber Follow-Up Review — Post TLS Architecture AdditionStatus: Latest commit (0d8b697) successfully addresses bsquizz's feedback on TLS architecture for Route passthrough mode. ✅ User Feedback Addressedbsquizz's request: "Yeah, we shouldn't be using a self-signed internal cert. I think you should add an explanation of all this functionality to the spec." Resolution: Lines 186-236 now include:
Verdict: ✅ Fully addressed. The explanation is accurate and comprehensive. 🔧 Remaining Issues from Previous ReviewMy previous review identified 5 issues. Checking current status: Issue #1: Gap Table Inconsistency (Line 296) — ❌ Still PresentLine 296 still states: But line 306 correctly states: "no post-Helm SSA patch is needed." Required Fix: -| Trusted CA volume/mount/env | Go (post-Helm SSA patch) | `_gateway-workload.tpl` | `server.oidc.caConfigMapName` |
+| Trusted CA volume/mount/env | Chart (`_gateway-workload.tpl`) | `_gateway-workload.tpl` | `server.oidc.caConfigMapName` |Severity: Minor Issue #2: Missing Error Handling Guidance — ❌ Still MissingNo HyperShell-convention error handling documented for Helm operations. Recommendation: Add to "Code Changes" section: ### Error Handling (HyperShell Convention)
- Helm install/upgrade/uninstall errors SHALL be wrapped with context: `fmt.Errorf("helm install gateway %s: %w", gateway.Name, err)`
- Gateway status SHALL be updated on Helm failure with `State: "Failed"` and error message
- Reconciler SHALL return explicit errors — NEVER `panic()` on Helm failuresSeverity: Major Issue #3: Incomplete Retry Guidance (lines 102-107) — ❌ Still IncompleteRetry scenario lacks:
Severity: Major Issue #4: Missing Configuration Validation — ❌ Still MissingNo requirement for validating Severity: Major Issue #5: Chart Version Pinning Detail — ❌ Still VagueLine 129 says "pinned in the Dockerfile build script" but doesn't specify how. Severity: Minor 📊 Updated Summary
Overall Assessment: The TLS architecture addition is excellent and fully addresses bsquizz's feedback. The 5 issues from my initial review remain unaddressed but are additive improvements — they don't block spec approval, but should be addressed before implementation begins. Recommendation:
Confidence: High (95%) Amber review complete. The spec correctly documents the TLS architecture difference that bsquizz asked for. |
Amber Final Review — Excellent Work! ✅Status: Commit ✅ Issues ResolvedIssue #2: Error Handling Guidance — ✅ RESOLVEDAdded: Lines 353-361 now document HyperShell error handling conventions:
Verdict: Excellent. Fully compliant with HyperShell conventions from CLAUDE.md. Issue #3: Retry Guidance — ✅ RESOLVEDAdded: Lines 106-110 now specify:
Verdict: Complete and production-ready. The exponential backoff prevents reconciler storms. Issue #4: Configuration Validation — ✅ RESOLVEDAdded: Lines 409-416 specify startup validation:
Verdict: Exactly what was needed. Prevents runtime failures with clear startup feedback. Issue #5: Chart Version Pinning — ✅ RESOLVEDAdded: Lines 132-135 specify implementation:
Verdict: Clear, actionable implementation guidance. Easy to automate in CI. 🔧 Remaining IssueIssue #1: Gap Table Inconsistency (Line 296) —
|
| Metric | Status |
|---|---|
| User Feedback (TLS Architecture) | ✅ Fully Addressed |
| Amber Major Issues | ✅ 3/3 Resolved |
| Amber Minor Issues | |
| Blockers | 0 |
| Implementation Readiness | ✅ Ready |
Overall Verdict: This spec is implementation-ready. The one remaining minor inconsistency is cosmetic and doesn't impact the implementation phase.
Recommendation:
- ✅ Approve the spec — all substantive issues resolved
⚠️ Fix the line 296 inconsistency if convenient (optional, 1-line change)- 🚀 Proceed to implementation with confidence
Confidence: High (98%)
🎯 Why This Spec Is Excellent
- Comprehensive TLS Architecture: Lines 186-236 clearly explain the security model difference between GRPCRoute (re-encrypt) and Route (passthrough)
- Production-Grade Error Handling: HyperShell conventions documented, no
panic(), proper context wrapping - Robust Retry Logic: Exponential backoff prevents reconciler storms, max retries prevent infinite loops
- Fail-Fast Validation: Startup checks catch configuration errors before runtime
- Clear Implementation Path: Chart version pinning, Helm SDK usage, ordering constraints all documented
- Empirically Validated Decisions: NetworkPolicy analysis backed by live cluster testing
bsquizz, this is solid engineering documentation. The implementation team has everything they need.
Amber review complete. Changing label to amber/approved.
Add specification for shifting the control plane from static YAML manifests to the upstream OpenShell Helm chart via the Helm Go SDK. Covers: SDK integration, values mapping, migration path, gap analysis, and the decision to not install NetworkPolicies. HYPERSHELL-146 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…cision - Chart sourcing: embedded .tgz in container image (default), OCI registry override for dev only - Gap analysis narrowed to 2 items: SCC binding and trusted CA ConfigMap - NetworkPolicy decision: do not install, verified empirically on OVN-Kubernetes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Key changes from review: - No upgrades: install on create, uninstall+delete-namespace on delete, helm upgrade only for retry after failed install - Keep sandbox preflight enabled (valid prerequisite check) - Simple migration: new gateways use Helm, existing ones not migrated - Single code path: remove old SSA code entirely, no dual-mode - Load chart once at startup, reuse for all installs - Trusted CA via chart values (server.oidc.caConfigMapName), remove post-Helm SSA overlay section - SCC binding runs before Helm install - OpenShift Route via chart (openshiftRoute.enabled) - Add upstream docs reference for SCC binding - NetworkPolicy: add note to revisit if restrictive posture required - Remove rollback, mixed-state, upgrade, and implementation phases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…A config Explain how TLS differs between GRPCRoute (internal CA sufficient) and Route passthrough (needs externally trusted CA via certManager.serverIssuerRef). Add EXTERNAL_CA_ISSUER_NAME and EXTERNAL_CA_ISSUER_KIND env vars. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bsquizz
left a comment
There was a problem hiding this comment.
Amber Review — Fix Verification (Commit ba13ebe)
All 8 findings from the prior review are resolved. The fixes are correct, minimal, and don't introduce new issues. Nice work.
Verification of Prior Findings
| # | Severity | Finding | Status | Verification |
|---|---|---|---|---|
| 1 | Critical | setNestedValue panics on type assertion |
Resolved | values.go:266 — uses next, ok guard with fallback make(map[string]interface{}). Matches Helm's own CoalesceTables behavior. |
| 2 | Critical | splitImageRef misparses registry-with-port |
Resolved | values.go:248-253 — compares LastIndex("/") vs LastIndex(":"). Port-only refs like registry:5000/image now correctly return ("registry:5000/image", "latest"). |
| 3 | Major | isChartArchive panics on short paths |
Resolved | chart.go:36 — uses strings.HasSuffix, which handles length internally. No more slice-bounds panic on 5-6 char paths. |
| 4 | Major | PullChart hardcodes "helm" binary |
Resolved | chart.go:41 — now accepts helmBinary parameter with "" → "helm" fallback. Also accepts context.Context. |
| 5 | Major | deployGatewayViaHelm upgrades on every reconcile |
Resolved | helm_deploy.go:74-75 — "deployed" status skips upgrade. Matches spec: "Gateway upgrades are not handled at this time." |
| 6 | Major | Database config resolution error downgraded to INFO | Resolved | reconciler.go:1414 — changed to WARN. Appropriate severity for a skipped-but-noteworthy condition. |
| 7 | Minor | INGRESS_BASE_DOMAIN defaults to apps.example.com |
Resolved | reconciler.go:1266 — changed to gateway.cluster.local (non-routable .local suffix). |
| 8 | Minor | VerifyHelmAvailable and PullChart lack context |
Resolved | shell_client.go:203, chart.go:41 — both accept context.Context and use exec.CommandContext. |
Convention Checklist (re-verified against fix commit)
| Convention | Result |
|---|---|
No panic() in production code |
Pass — grep confirms zero panic() calls in non-test code |
Errors wrapped with fmt.Errorf context |
Pass |
| No secrets in logs or responses | Pass |
No context.TODO() in production code |
Pass |
| Reconcile, don't create-or-skip | Pass |
Minor Observation (Not a Finding)
helm_deploy.go:83 logs "helm release deployed" unconditionally after the if/else chain, including when the "deployed" branch skipped the install. Technically accurate (it IS deployed), but could read as "we just deployed it" in logs. Not worth a code change — just noting for awareness.
Confidence: High (98%)
Verdict: All prior findings resolved. Fixes are clean and correct.
Amber review complete.
|
On hold until these are merged upstream: NVIDIA/OpenShell#2728 Once they are merged and released, then we need to circle back and remove the custom gateway image and stop bundling the fork of the helm chart (those were used to prove e2e tests can pass) |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Amber reviewStatus: Complete VerdictREQUEST_CHANGES (posted as a COMMENT review). This is a well-structured, high-value refactor that replaces ~1,600 lines of hand-maintained SSA manifest code with a Helm-chart-driven deployment path, but it is not mergeable to Hi @bsquizz — Amber here. The direction (delegate gateway rendering to the upstream chart, delete the drift-prone embedded manifests) is the right long-term call, and the Blocker1. Production image build depends on a personal fork's mutable branch + personal quay image — Security / Supply chain / Image consistency
Major2. Database-config resolution error is now silently swallowed — Error handling / "never silently swallow partial failures"
3. Spec says "Helm Go SDK"; implementation shells out to the
4. Already-deployed releases are never upgraded (create-or-skip) — Reconciliation convention
5. Out-of-band route teardown will drift Helm state — Architecture
Minor6. 7. Pointless indirection — 8. Lost documentation — 9. Delegated pod SecurityContext is now unverifiable here — pod security context comes entirely from the upstream chart, and |
jsell-rh
left a comment
There was a problem hiding this comment.
Verdict
REQUEST_CHANGES (posted as a COMMENT review). This is a well-structured, high-value refactor that replaces ~1,600 lines of hand-maintained SSA manifest code with a Helm-chart-driven deployment path, but it is not mergeable to main as-is: the control-plane image is built by cloning a personal GitHub fork's mutable feature branch and pins a personal quay image, a database-config resolution error is now silently swallowed, and the spec (Helm Go SDK) diverges from the implementation (shelling out to the helm CLI). Address the Blocker/Major items below before merge.
Hi @bsquizz — Amber here. The direction (delegate gateway rendering to the upstream chart, delete the drift-prone embedded manifests) is the right long-term call, and the internal/helm package is clean and readable. My concerns are about supply-chain reproducibility, a swallowed error, and reconcile semantics — details below.
Blocker
1. Production image build depends on a personal fork's mutable branch + personal quay image — Security / Supply chain / Image consistency
charts/CHART_REPO=https://github.com/bsquizz/OpenShell.git,charts/CHART_REF=feat/backend-tls-and-rbac-toggle(a branch, not a tag/SHA).components/control-plane/Dockerfile:29runsgit clone --depth 1 --branch "${CHART_REF}"at image-build time. A branch is mutable and can be force-pushed or deleted, so the control-plane image is not reproducible and CI can break at any time with no code change here.components/control-plane/internal/gateway/config.go:40pinsdefaultGatewayImage = quay.io/bsquizza/openshell-gateway:16112bc(personal registry), while:41keeps the supervisor onghcr.io/nvidia/openshell/supervisor:16112bc. CLAUDE.md requires "Image references must match across the stack."- This appears to be a deliberate temporary state pending upstream
NVIDIA/OpenShellPR #2728, but as written it cannot merge tomain. Please either (a) pointCHART_REPO/CHART_REFat the canonical upstream repo pinned to an immutable tag/SHA and use canonical images, or (b) explicitly gate this PR behind that upstream merge and note it in the description. This is the primary maintainer decision this PR needs.
Major
2. Database-config resolution error is now silently swallowed — Error handling / "never silently swallow partial failures"
components/control-plane/internal/reconciler/reconciler.go:1414:resolveDatabaseConfigfailure changed fromreturn reconcileErr(which marked the gatewayFailed) to alog.Printf("WARN ... skipping database reconciliation")and continues into the Helm install. The gateway then deploys referencingopenshell-gateway-db-credentialswhich may not exist, and its phase never reflects the failure. This violates the CLAUDE.md rule that "every error path must propagate or be collected." Restore the fail-closed behavior (markFailed), or document why proceeding is safe.
3. Spec says "Helm Go SDK"; implementation shells out to the helm CLI — Spec consistency
specs/platform/openshell-gateway-helm-adoption.spec.mdstates the reconciler "SHALL use the Helm Go SDK" and documentshelm.sh/helm/v3/pkg/action. The implementation (internal/helm/shell_client.go) insteadexecs thehelmbinary (with a comment explaining the pivot to avoid dependency conflicts). The pivot is reasonable, but the spec must be updated to match — otherwise the desired-state doc contradicts the code, and the runtime now has a new hard dependency on ahelmbinary in the image +HELM_BINARY/PATH resolution that the spec never describes.
4. Already-deployed releases are never upgraded (create-or-skip) — Reconciliation convention
internal/gateway/helm_deploy.go:74skips whenstatus == "deployed", so image/OIDC/route/config changes to a running gateway never converge. The spec acknowledges "Gateway upgrades are not handled at this time," but this is a functional regression from the previous SSA path, which did re-apply on spec changes, and it violates "reconcile, don't create-or-skip." Relatedly,internal/helm/shell_client.go:152uses--reuse-valuestogether with--valueson the retry path, so keys removed from the desired set persist across retries. Please call this limitation out explicitly in the PR body and file a follow-up, and coordinate with PR #151 (see Cross-PR section).
5. Out-of-band route teardown will drift Helm state — Architecture
internal/reconciler/health.go:439self-documents thatDeleteGatewayAPIResourcesdeletes chart-managed routing resources outside Helm, "may cause Helm state drift." With routing now owned by the chart, the health loop and Helm will fight over these resources (Helm still believes them present; a later reconcile may recreate). This needs a real plan (e.g.,helm upgradewith routing disabled) rather than a TODO before it lands.
Minor
6. splitImageRef mishandles digest references — internal/helm/values.go:247 splits on the last :; an image like repo@sha256:abcd yields repo=...@sha256, tag=abcd. Not hit by the current tag-based defaults, but will silently corrupt digest-pinned images. Guard for @.
7. Pointless indirection — internal/gateway/helm_deploy.go:111 getEnv → getEnvHelper → os.Getenv. Collapse to a single helper (or reuse an existing env helper) to reduce noise.
8. Lost documentation — internal/config/config.go dropped the detailed DatabaseProvider comment explaining the CNPG-vs-deployment default and no-silent-fallback behavior with no functional change. Keep the rationale.
9. Delegated pod SecurityContext is now unverifiable here — pod security context comes entirely from the upstream chart, and buildOpenShiftValues nils podSecurityContext.fsGroup/securityContext.runAsUser to defer to SCC. Please confirm the chart still yields runAsNonRoot: true, allowPrivilegeEscalation: false, and drop: ["ALL"] per security.spec.md, since we no longer set these in-tree.
Cross-PR coordination
I compared #194 against the other open PRs in openshift-online/hypershell. Open PRs at review time: #216, #214, #212, #211, #210, #209, #208, #207, #206, #201, #200, #194, #189, #188, #185, #182, #179, #151, #150, #148, #135, #109, #75, #73. The following have material (design/plan) conflicts, not mere text overlap:
-
#201 — "[HYPERSHELL-45] Update gateway and supervisor openshell images to Red Hat ones": Direct, competing design conflict over the canonical gateway/supervisor image source. #201 removes the in-code image defaults entirely ("now they are required to be set as env variables or inside the gatewayconfig resource") and switches to Red Hat images; #194 does the opposite — it keeps and relies more heavily on in-code defaults (
reconciler.go:1450now backfillsimages.DefaultGatewayImage()) and points them at a personal fork (config.go:40). Both editinternal/gateway/config.goandscripts/kind/lib.sh, and #194 deletesinternal/gateway/manifests.gowhich #201 modifies. Maintainer decision needed: pick the canonical image source (Red Hat vs upstream vs fork) and whether in-code defaults survive; then sequence these two PRs deliberately. -
#151 — "gate gateway re-provisioning on desired-state convergence": Opposed goals on the same
Handlepath. #151 exists to make the reconciler re-apply on spec changes (image/route/oidc/db) so drift stops being masked; #194 introduces a deploy path that explicitly skips already-deployed releases (helm_deploy.go:74) and states upgrades are out of scope. Both editinternal/reconciler/reconciler.goandskills/RECONCILE.md. Coordination needed: #151's convergence gate must drive ahelm upgradeunder #194's model, or the two designs will cancel out. -
#216 — "fix(console): support OpenShift Route ingress": Conflicting ownership of ingress/Route creation and overlapping teardown. #194 removes control-plane gateway Route reconciliation and delegates GRPCRoute/Route to the chart, renames
openshell-backend-ca→openshell-gateway-backend-ca, and flagshealth.goroute teardown as Helm-drift-prone; #216 adds control-plane-managed console Routes and edits the samehealth.goteardown path,reconciler.go, andreconciler_test.go. Coordination needed: agree on who owns Route objects (chart vs control plane) and reconcile thehealth.goteardown semantics. -
#179 — "reconcile existing Keycloak clients on gated gateways" (lower priority): Overlapping restructure of
internal/reconciler/reconciler.goandhealth.goaround the phase gate / Keycloak reconcile ordering that #194 also rewrites. This is primarily a merge-ordering concern rather than a design clash, but whichever lands first will force a non-trivial rebase of the other.
No material conflict found with the remaining open PRs (#211/#150/#148 touch kind/image-build tooling and specs that overlap only textually with #194; #200/#185 are reconciliation-contract specs that #194 does not contradict; the rest are UI/console/deps unrelated to this change).
Findings Summary (ordered by severity, highest first):
- [Blocker] Image build clones a personal fork's mutable branch and pins a personal quay image; non-reproducible + inconsistent references - Security / Supply chain (Dockerfile L29, CHART_REPO/CHART_REF, config.go L40-41)
- [Major] Database-config resolution error swallowed; gateway deploys anyway and phase never reflects failure - Error handling (reconciler.go L1414)
- [Major] Spec mandates Helm Go SDK; code shells out to
helmCLI - Spec consistency (helm-adoption spec, shell_client.go) - [Major] Deployed releases never upgraded (create-or-skip) +
--reuse-valueson retry - Reconciliation (helm_deploy.go L74, shell_client.go L152) - [Major] Out-of-band route teardown drifts Helm state (self-admitted TODO) - Architecture (health.go L439)
- [Minor]
splitImageRefcorrupts digest references - Correctness (values.go L247) - [Minor] Pointless
getEnv/getEnvHelperindirection - Style (helm_deploy.go L111) - [Minor] Dropped
DatabaseProviderrationale comment - Docs (config.go) - [Minor] Pod SecurityContext fully delegated to external chart; verify it still meets security.spec.md - Security (values.go buildOpenShiftValues)
Convention Checklist:
| Convention | Result |
|---|---|
No panic() in production code |
Pass |
Errors wrapped with fmt.Errorf context |
Pass |
| Never silently swallow partial failures | Fail (reconciler.go L1414) |
| Reconcile, don't create-or-skip | Fail (helm_deploy.go L74) |
| Image references consistent across the stack | Fail (config.go L40-41, Dockerfile, kind/lib.sh) |
| Reproducible builds / pinned dependencies | Fail (Dockerfile L29 mutable branch clone) |
| Spec matches implementation | Fail (Helm SDK vs CLI) |
| SecurityContext on pod specs | Deferred to upstream chart (verify) |
| Status updated on error paths | Fail (db-config path, reconciler.go L1414) |
| Conventional commit message | Pass |
Rollback: this is a self-contained control-plane change; reverting the merge commit restores the SSA manifest path. Happy to pair on the upstream-chart pinning once #2728 lands. Does this framing match your intent for the temporary fork references?
| COPY charts/CHART_REPO charts/CHART_REF /tmp/chart-source/ | ||
| RUN CHART_REPO=$(cat /tmp/chart-source/CHART_REPO) && \ | ||
| CHART_REF=$(cat /tmp/chart-source/CHART_REF) && \ | ||
| git clone --depth 1 --branch "${CHART_REF}" "${CHART_REPO}" /tmp/openshell && \ |
There was a problem hiding this comment.
[Blocker] Non-reproducible build from a mutable personal fork branch. git clone --depth 1 --branch "${CHART_REF}" where CHART_REF=feat/backend-tls-and-rbac-toggle (a branch, not an immutable tag/SHA) on https://github.com/bsquizz/OpenShell.git means the control-plane image content can change or vanish with no code change here, and CI can break at any time. Pin to the canonical upstream repo at an immutable tag/SHA (or explicitly gate this PR behind upstream NVIDIA/OpenShell #2728) before merging to main.
| @@ -0,0 +1 @@ | |||
| https://github.com/bsquizz/OpenShell.git | |||
There was a problem hiding this comment.
[Blocker] Points the chart source at a personal fork (github.com/bsquizz/OpenShell). Combined with the mutable branch in CHART_REF, this makes production builds depend on personal, mutable infrastructure. Needs a maintainer decision on the canonical chart source + immutable pinning.
|
|
||
| const defaultGatewayImage = "ghcr.io/nvidia/openshell/gateway:0.0.109" | ||
| const defaultSupervisorImage = "ghcr.io/nvidia/openshell/supervisor:0.0.109" | ||
| const defaultGatewayImage = "quay.io/bsquizza/openshell-gateway:16112bc" |
There was a problem hiding this comment.
[Blocker/Major] Personal registry + mixed provenance. defaultGatewayImage now points at quay.io/bsquizza/openshell-gateway:16112bc (personal quay) while defaultSupervisorImage (L41) stays on ghcr.io/nvidia/openshell/supervisor:16112bc. CLAUDE.md requires image references to be consistent across the stack. Also note PR #201 proposes removing these in-code defaults entirely in favor of Red Hat images — coordinate on the canonical source before merge.
| if resolveErr != nil { | ||
| reconcileErr = fmt.Errorf("resolve database config for gateway %s: %w", gw.Name, resolveErr) | ||
| return reconcileErr | ||
| log.Printf("WARN gateway %s: skipping database reconciliation: %v", event.ResourceID, resolveErr) |
There was a problem hiding this comment.
[Major] Swallowed partial failure. This changed from return reconcileErr (which marked the gateway Failed) to a warning-and-continue. The reconcile now proceeds to the Helm install referencing openshell-gateway-db-credentials, which may not exist, and the gateway phase never reflects the failure. This violates the "never silently swallow partial failures" rule and "status updated on error paths." Restore fail-closed behavior or document why proceeding is safe.
| if err := helmClient.Upgrade(ctx, nsConfig.Name, values); err != nil { | ||
| return fmt.Errorf("helm upgrade: %w", err) | ||
| } | ||
| } else if status.Status == "deployed" { |
There was a problem hiding this comment.
[Major] Create-or-skip anti-pattern. When the release is already deployed, this logs and skips, so image/OIDC/route/config changes to a running gateway never converge. This is a regression from the SSA path (which re-applied) and conflicts with the "reconcile, don't create-or-skip" convention. It also directly overlaps PR #151's goal of converging on desired-state changes. If out of scope for now, call it out explicitly in the PR body and file a follow-up.
| args := []string{ | ||
| "upgrade", ReleaseName, c.ChartPath, | ||
| "--namespace", namespace, | ||
| "--reuse-values", |
There was a problem hiding this comment.
[Major] --reuse-values on the retry path. Upgrade passes both --reuse-values and --values <file>; keys removed from the desired set persist across retries, and on a retried failed install the prior (bad) values are merged back in. Consider --reset-values + full desired values so the release always reflects the computed values map.
| } | ||
| } | ||
| // NOTE: With Helm adoption, routing resources are managed by the chart. | ||
| // This manual cleanup is retained for partial route teardown but may cause |
There was a problem hiding this comment.
[Major] Self-admitted Helm state drift. Deleting chart-managed routing resources out-of-band leaves Helm believing they still exist; a later reconcile can recreate them. With routing now owned by the chart this needs a concrete plan (e.g. helm upgrade with routing disabled) rather than a TODO. Also interacts with PR #216, which adds control-plane-managed console Routes on this same teardown path.
| func splitImageRef(image string) (repo, tag string) { | ||
| lastSlash := strings.LastIndex(image, "/") | ||
| lastColon := strings.LastIndex(image, ":") | ||
| if lastColon <= lastSlash { |
There was a problem hiding this comment.
[Minor] Digest refs mis-split. image@sha256:... yields repo=...@sha256, tag=<hash> because the split is on the last :. Guard for @ (digest) before splitting on :. Not hit by current tag defaults, but will silently corrupt digest-pinned images.
| } | ||
|
|
||
| // getEnv retrieves an environment variable with a fallback default. | ||
| func getEnv(key, fallback string) string { |
There was a problem hiding this comment.
[Minor] Pointless indirection. getEnv -> getEnvHelper -> os.Getenv. Collapse into one helper (or reuse an existing env helper in the package).
Summary
helm template) to installing gateways at runtime using the upstream OpenShell Helm chart via the Helm Go SDKJIRA
HYPERSHELL-146
Test plan
values.yaml🤖 Generated with Claude Code