Skip to content

Conversation

@ciaranRoche
Copy link
Contributor

@ciaranRoche ciaranRoche commented Dec 8, 2025

Summary

  • Add make image, make image-push, and make image-dev Makefile targets for container builds
  • Update Dockerfile to multi-stage build pattern (consistent with sentinel/adapter)
  • Add Helm chart with configurable PostgreSQL support:
    • Built-in PostgreSQL for development (default)
    • External database support for production (GCP Cloud SQL, etc.)
  • Update README with container image and Helm deployment documentation

Test plan

  • make image builds container image successfully
  • make image-dev builds and pushes to personal Quay registry
  • helm template renders valid Kubernetes manifests
  • Helm deployment with built-in PostgreSQL starts successfully
  • API connects to database and serves requests

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a Helm chart with complete Kubernetes templates (deployments, service, optional DB, autoscaling, service account, probes, volumes, and env/auth configuration).
    • Switched to a multi-stage container build with a smaller runtime and included OpenAPI schema/runtime config.
  • Documentation

    • Expanded README with container build/push, Helm deployment (dev/prod), values, and auth examples.
  • Chores

    • Added Makefile targets for building and pushing container images (including personal-registry workflow).

✏️ Tip: You can customize this high-level summary in your review settings.

- Add image, image-push, image-dev Makefile targets for container builds
- Update Dockerfile to multi-stage build (consistent with sentinel/adapter)
- Add Helm chart with configurable PostgreSQL support:
  - Built-in PostgreSQL for development (default)
  - External database support for production (GCP Cloud SQL, etc.)
- Update README with container image and Helm deployment docs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@openshift-ci openshift-ci bot requested review from AlexVulaj and rafabene December 8, 2025 13:56
@openshift-ci openshift-ci bot added the approved label Dec 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

Walkthrough

Adds a multi-stage Docker build that generates OpenAPI client code, compiles a static Go binary, and produces a distroless runtime image (binary at /app/hyperfleet-api, OPENAPI_SCHEMA_PATH set). Introduces Makefile targets/variables for building and pushing container images (including a personal-registry flow). Adds a Helm chart (charts/Chart.yaml, values.yaml, .helmignore) and templates (helpers, deployment, service, HPA, postgresql, serviceaccount, service) with conditional logic for autoscaling, DB init/migrations, env/config, probes, volumes, and RBAC. Expands README with image and Helm deployment instructions.

Sequence Diagram(s)

(Section intentionally omitted.)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Dockerfile — verify openapi-gen stage, copy paths, build flags, binary location, ENTRYPOINT/CMD, and OPENAPI_SCHEMA_PATH.
  • Makefile — validate IMAGE_* variables, image build/push commands, QUAY_USER validation, and tag handling.
  • charts/templates/deployment.yaml — review conditional initContainers, env rendering (JWKS_URL, ENABLE_JWT, ENABLE_AUTHZ), secret mounts, probes, and resource templating.
  • charts/templates/postgresql.yaml — inspect secret keys, pg env vars, probes (pg_isready), PVC conditional logic, and volumes.
  • charts/templates/_helpers.tpl — check name/fullname/chart helpers for truncation/trimming edge cases.
  • charts/templates/hpa.yaml, service.yaml, serviceaccount.yaml — verify selectors, labels, API versions, and conditional rendering against values.yaml.
  • charts/values.yaml & README.md — ensure example values, commands, and Makefile targets are consistent.

Possibly related PRs

Suggested labels

lgtm

Suggested reviewers

  • AlexVulaj

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add image Makefile targets and Helm chart' accurately summarizes the two main changes: Makefile image targets and the introduction of a Helm chart for deployment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e39da1 and ca7bfac.

📒 Files selected for processing (4)
  • Dockerfile (1 hunks)
  • charts/templates/deployment.yaml (1 hunks)
  • charts/templates/service.yaml (1 hunks)
  • charts/values.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • charts/values.yaml
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/openapi/**/*.go : Use make generate to regenerate Go models from openapi/openapi.yaml via openapi-generator-cli v7.16.0 in Podman
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/**/*.go : Use //go:embed directive to embed the OpenAPI specification at compile time from pkg/api/openapi/api/openapi.yaml
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/openapi/**/*.go : Use make generate to regenerate Go models from openapi/openapi.yaml via openapi-generator-cli v7.16.0 in Podman

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to openapi/openapi.yaml : TypeSpec definitions are maintained separately in hyperfleet-api-spec repository; only edit openapi/openapi.yaml in this repository for spec changes

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/**/*.go : Use //go:embed directive to embed the OpenAPI specification at compile time from pkg/api/openapi/api/openapi.yaml

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Generate OpenAPI code by running make generate whenever the TypeSpec specification changes

Applied to files:

  • Dockerfile
🪛 YAMLlint (1.37.1)
charts/templates/deployment.yaml

[error] 6-6: syntax error: expected the node content, but found '-'

(syntax)

charts/templates/service.yaml

[error] 6-6: syntax error: expected the node content, but found '-'

(syntax)

🔇 Additional comments (7)
Dockerfile (3)

1-58: Dockerfile multi-stage build is well-structured and solves the generated-code-in-repo problem.

The three-stage approach (openapi-gen → builder → runtime) is clean and follows best practices. Generating OpenAPI code during the build, rather than committing generated files to the repository, addresses the prior review concern and ensures consistency. The distroless runtime image is a solid security choice, and the static binary build with CGO_ENABLED=0 is appropriate for the target image.

Verified by PR tests: image builds successfully, pushes to registry, and deploys via Helm with API running.


18-18: Verify Go 1.24-alpine version is stable and available.

The Dockerfile uses golang:1.24-alpine for the build stage. Given your knowledge cutoff, confirm that Go 1.24 is released and stable for production builds, or if it's a future version, ensure compatibility with your CI/CD expectations.

Note: The PR verification logs show a successful build with this version, so it appears to be available in your environment.

Also applies to: 33-33


10-15: Confirm that generated OpenAPI code dependencies are covered by main project's go.mod.

The openapi-gen stage removes go.mod and go.sum from the generated code (lines 14–15) and copies the code into the builder context. This is correct to avoid module conflicts, but it assumes all dependencies of the generated code are already listed in the main project's go.mod. The build succeeds in your tests, so this is likely satisfied, but it's worth documenting or validating if new OpenAPI dependencies are introduced in future spec changes.

charts/templates/service.yaml (1)

1-23: Helm Service template is well-structured; YAMLlint error is a false positive.

The Service correctly exposes all three ports (http, health, metrics) with proper selectors and labeling via Helm helpers. The YAMLlint error at line 6 ("syntax error: expected the node content, but found '-'") is a known false positive when linters run on Helm templates before processing—the {{- include ...}} syntax is standard and will render correctly.

Port configuration aligns with the Deployment's containerPort definitions (8000, 8083, 8080) and server bind address arguments.

charts/templates/deployment.yaml (3)

83-98: Verify health probes use correct endpoint paths and follow Kubernetes best practices.

Both liveness and readiness probes currently use the same httpGet path (/healthcheck) on the health port. Kubernetes best practice recommends separation: liveness should be a lightweight "is the process alive?" check, while readiness should verify the service is ready to accept traffic (including dependencies like the database being healthy).

Before merging, confirm:

  1. The /healthcheck endpoint exists in the hyperfleet-api codebase and returns 200 OK.
  2. Whether separate endpoints (e.g., /live and /ready) are feasible, or if a single /healthcheck that handles both concerns is intentional.

If separate probes are desired, consider parameterizing the paths via values for flexibility.


30-45: InitContainers properly conditioned and sequenced for database initialization.

The wait-for-db step correctly waits for PostgreSQL readiness only when internal PostgreSQL is enabled, and the db-migrate step runs the migration command with mounted secrets before the main container starts. Both steps are guarded by the database configuration conditional (line 30), so they don't run if both database modes are disabled.

The netcat-based wait uses the expected service name convention (fullname + "-postgresql") and respects the configured port value.


101-126: Volume configuration correctly guards against empty secret blocks.

The secrets volume is now properly wrapped in the database conditional (line 115: {{- if or .Values.database.external.enabled .Values.database.postgresql.enabled }}), which resolves the prior concern about rendering invalid manifests when both database modes are disabled. The conditional logic cleanly selects the correct secret name (external vs. internal PostgreSQL).

Volume mounts for secrets are also correctly conditioned (lines 104–108), with readOnly: true for security.


Comment @coderabbitai help to get the list of available commands and usage tips.

@ciaranRoche
Copy link
Contributor Author

Verification

Build

 QUAY_USER=croche make image-dev                                                                                                                                                                                                                                            ─╯
Building dev image quay.io/croche/hyperfleet-api:dev-102aaf6...
podman build -t quay.io/croche/hyperfleet-api:dev-102aaf6 .
[1/2] STEP 1/6: FROM golang:1.24-alpine AS builder
[1/2] STEP 2/6: WORKDIR /build
--> Using cache 5e88f933b0c34bebe7ac6cf490e190f5db2d005ef9f605e36ecc18c27ab45f49
--> 5e88f933b0c3
[1/2] STEP 3/6: COPY go.mod go.sum ./
--> Using cache da15a59e93a17b9361d08133a5956afbf5cc6af324a2446539b12a8bde40067b
--> da15a59e93a1
[1/2] STEP 4/6: RUN go mod download
--> Using cache e258b066c1fd7e539f8ad781db886c67e970e01014a3439989e4a6fbf90605ea
--> e258b066c1fd
[1/2] STEP 5/6: COPY . .
--> 23a16eeae5bb
[1/2] STEP 6/6: RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o hyperfleet-api ./cmd/hyperfleet-api
--> a8b3044c2586
[2/2] STEP 1/7: FROM gcr.io/distroless/static-debian12:nonroot
[2/2] STEP 2/7: WORKDIR /app
--> Using cache 28241cc6b981ece11a74326f4dc877f89dead53540c249ac2d1a301751ead8e0
--> 28241cc6b981
[2/2] STEP 3/7: COPY --from=builder /build/hyperfleet-api /app/hyperfleet-api
--> Using cache 8a065b969aec2e6a03e8f793b18d2606754abc570f0aeff0fad9391446f03d9f
--> 8a065b969aec
[2/2] STEP 4/7: EXPOSE 8000
--> Using cache 5692660344e85ccc0b42bb4636ba6b2624fdb83e27333d72514a1d1d4c49be8c
--> 5692660344e8
[2/2] STEP 5/7: ENTRYPOINT ["/app/hyperfleet-api"]
--> Using cache ebd6c74105f09efb4f90b5c9d5890e493ac736a6e55555e7597832be9eac0713
--> ebd6c74105f0
[2/2] STEP 6/7: CMD ["serve"]
--> Using cache 45fcdae2f6a3124dfaca70b4f11eab33a03af311ce5b512483784faa7093ea33
--> 45fcdae2f6a3
[2/2] STEP 7/7: LABEL name="hyperfleet-api"       vendor="Red Hat"       version="0.0.1"       summary="HyperFleet API - Cluster Lifecycle Management Service"       description="HyperFleet API for cluster lifecycle management"
--> Using cache 2c69a7e06cba4b9bc2276381159d8957616020448804f4045d4e1ddb0475bb07
[2/2] COMMIT quay.io/croche/hyperfleet-api:dev-102aaf6
--> 2c69a7e06cba
Successfully tagged quay.io/croche/hyperfleet-api:dev-102aaf6
Successfully tagged quay.io/croche/hyperfleet-api:dev-bc5c73e
2c69a7e06cba4b9bc2276381159d8957616020448804f4045d4e1ddb0475bb07
Pushing dev image...
podman push quay.io/croche/hyperfleet-api:dev-102aaf6
Getting image source signatures
Copying blob 826f7d4a9c4e skipped: already exists  
Copying blob 864c4fb7c1f3 skipped: already exists  
Copying blob ffdf8cfdbafe skipped: already exists  
Copying blob 12b98db1f9a3 skipped: already exists  
Copying blob a8b224da3401 skipped: already exists  
Copying blob 02c91f6b395a skipped: already exists  
Copying blob 83717d7c33ed skipped: already exists  
Copying blob a0ce62815afc skipped: already exists  
Copying blob b4aa04aa577f skipped: already exists  
Copying blob 4eb6e32233ed skipped: already exists  
Copying blob fc7f59ef6392 skipped: already exists  
Copying blob 818beb2a6ac5 skipped: already exists  
Copying blob 24bd2a96ca81 skipped: already exists  
Copying config 2c69a7e06c done   | 
Writing manifest to image destination

✅ Dev image pushed: quay.io/croche/hyperfleet-api:dev-102aaf6

Helm Install

helm install hyperfleet-api ./charts/ \                                                                                                                                                                                                                                    ─╯
  --namespace hyperfleet-system \
  --create-namespace \
  --set image.registry=quay.io/croche \
  --set image.repository=hyperfleet-api \
  --set image.tag=dev-$(git rev-parse --short HEAD)
NAME: hyperfleet-api
LAST DEPLOYED: Mon Dec  8 13:58:00 2025
NAMESPACE: hyperfleet-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

Pods Running

kubectl get pods -n hyperfleet-system                                                                                                                                                                                                                                      ─╯

NAME                                         READY   STATUS    RESTARTS      AGE
hyperfleet-api-7784659797-swxpk              0/1     Running   1 (46s ago)   106s
hyperfleet-api-postgresql-7dd5c68d75-t7cr5   1/1     Running   0             106s

Ignore the restarted pod 😸

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Makefile (1)

257-259: Missing .PHONY declaration for run-no-auth target.

The run-no-auth target (lines 257–259) is not marked as .PHONY, which means Make will only rebuild it if a file named run-no-auth doesn't exist in the working directory. This can lead to unexpected behavior where the target is skipped if such a file exists.

Add .PHONY declaration:

 run-no-auth: binary
 	./hyperfleet-api migrate
 	./hyperfleet-api serve --enable-authz=false --enable-jwt=false
+.PHONY: run-no-auth
🧹 Nitpick comments (5)
charts/values.yaml (2)

27-39: Security context is hardened; consider enabling readOnlyRootFilesystem if application permits.

Pod security context is well-configured: runAsNonRoot: true, fsGroup: 65532, seccompProfile: RuntimeDefault. However, readOnlyRootFilesystem: false (line 37) allows the container to write to the root filesystem. If the application doesn't require write access to /, enabling read-only would improve security posture.

If the application doesn't write to the filesystem:

  securityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
      - ALL
-   readOnlyRootFilesystem: false
+   readOnlyRootFilesystem: true
    seccompProfile:
      type: RuntimeDefault

95-96: Persistence is disabled by default; data will be lost on pod restart.

For development deployments with persistence.enabled: false (line 96), the PostgreSQL database will lose all data when the pod restarts. This is acceptable for ephemeral dev environments, but users should understand this limitation.

Consider adding a warning in the values comments:

    persistence:
+     # ⚠️ WARNING: If disabled, database data is lost on pod restart
      enabled: false
      size: 1Gi
      storageClass: ""
charts/templates/deployment.yaml (1)

30-35: Init container assumes nc is present in busybox:1.36

Lines 32–34 rely on nc -z being available in busybox:1.36. If this image is ever swapped for a more minimal or differently built BusyBox, the init container could crash-loop because nc is missing.

Consider either:

  • Parameterizing the init image/command via values, or
  • Using an image you control (or a standard postgres client) where the presence of the probe tool is guaranteed.
charts/templates/postgresql.yaml (2)

56-69: Ensure the PostgreSQL image version matches the project’s standard

The Postgres container image is driven by .Values.database.postgresql.image (Line 56). Given the project guidance to use PostgreSQL 14.2 for DB operations, it would be good to ensure that this value (in values.yaml or overlays) pins to a 14.2 image tag, or at least documents that expectation.

If it’s not already pinned, consider updating the default image/tag or adding a brief comment in values.yaml clarifying the expected version.

Based on learnings, this keeps the chart aligned with the preferred Postgres version.


10-15: Plaintext dev DB credentials are acceptable but should stay dev‑only

The Secret uses stringData with db.user and db.password populated directly from values. That’s fine for local/dev workflows, but make sure any real credentials are supplied via overrides or external secrets and that defaults in values.yaml remain non‑sensitive.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc5c73e and 102aaf6.

📒 Files selected for processing (11)
  • Dockerfile (1 hunks)
  • Makefile (3 hunks)
  • README.md (1 hunks)
  • charts/Chart.yaml (1 hunks)
  • charts/templates/_helpers.tpl (1 hunks)
  • charts/templates/deployment.yaml (1 hunks)
  • charts/templates/hpa.yaml (1 hunks)
  • charts/templates/postgresql.yaml (1 hunks)
  • charts/templates/service.yaml (1 hunks)
  • charts/templates/serviceaccount.yaml (1 hunks)
  • charts/values.yaml (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/db/**/*.go : Use PostgreSQL 14.2 with GORM ORM for all database operations

Applied to files:

  • charts/templates/postgresql.yaml
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/openapi/**/*.go : Use make generate to regenerate Go models from openapi/openapi.yaml via openapi-generator-cli v7.16.0 in Podman

Applied to files:

  • Dockerfile
  • Makefile
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to openapi/openapi.yaml : TypeSpec definitions are maintained separately in hyperfleet-api-spec repository; only edit openapi/openapi.yaml in this repository for spec changes

Applied to files:

  • charts/values.yaml
  • charts/Chart.yaml
🪛 checkmake (0.2.2)
Makefile

[warning] 315-315: Missing required phony target "all"

(minphony)

🪛 YAMLlint (1.37.1)
charts/templates/serviceaccount.yaml

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

charts/templates/postgresql.yaml

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

charts/templates/service.yaml

[error] 6-6: syntax error: expected the node content, but found '-'

(syntax)

charts/templates/hpa.yaml

[error] 1-1: syntax error: expected the node content, but found '-'

(syntax)

charts/templates/deployment.yaml

[error] 6-6: syntax error: expected the node content, but found '-'

(syntax)

🔇 Additional comments (13)
README.md (1)

467-550: Documentation for container images and Helm deployment is clear and comprehensive.

The section effectively guides users through both development (built-in PostgreSQL) and production (external database) deployment scenarios with concrete examples. Examples align well with the actual Makefile targets and Helm chart configuration.

charts/Chart.yaml (1)

1-15: Helm chart metadata is well-structured and complete.

The chart includes all standard metadata (name, description, version, appVersion, maintainers, keywords, home). Versioning strategy (version: 1.0.0, appVersion: "1.0.0") is reasonable for an initial release.

charts/templates/serviceaccount.yaml (1)

1-12: Helm template structure is correct; static analysis false positive on Helm conditionals.

The ServiceAccount template uses proper Helm conditional rendering and helper templates. The YAMLlint "syntax error" is a false positive—it doesn't understand Helm template syntax. The template will render correctly when processed by Helm.

Ensure the helper templates hyperfleet-api.serviceAccountName and hyperfleet-api.labels are defined in charts/templates/_helpers.tpl and match the references here.

charts/templates/hpa.yaml (1)

1-32: HPA template is well-formed with proper conditional metric blocks.

The HorizontalPodAutoscaler v2 uses correct API version and syntax. Conditional rendering for CPU and memory metrics (lines 16–31) allows flexible autoscaling configuration. The scaleTargetRef correctly targets the Deployment created by the chart. YAMLlint's "syntax error" is a false positive on Helm conditionals.

Verify that the Deployment template (charts/templates/deployment.yaml) defines the same name via hyperfleet-api.fullname helper to ensure the HPA targets the correct Deployment.

charts/templates/service.yaml (1)

1-15: Service template is well-formed; verify containerPort naming matches deployment.

The Service exposes port 8000 via ClusterIP and routes to targetPort: http (line 11). Ensure the Deployment template defines a containerPort with name: http to match this selector.

Verify that charts/templates/deployment.yaml defines a containerPort named "http" to match the Service's targetPort.

Dockerfile (1)

1-33: Multi-stage Dockerfile follows security and performance best practices.

Excellent use of:

  • Builder stage (Alpine 1.24): minimizes layer size and compilation overhead
  • Distroless runtime (gcr.io/distroless/static-debian12:nonroot): removes package manager, shell, and uid 0 attack surface
  • Static binary (CGO_ENABLED=0, ldflags -w -s): enables distroless compatibility and reduces final image size
  • Layer caching strategy: go.mod/go.sum copied before source code

The resulting image will be minimal, hardened, and suitable for production Kubernetes deployments.

Makefile (2)

18-26: Image build targets are well-designed with good ergonomics and error handling.

Configuration variables are clear (IMAGE_REGISTRY, IMAGE_NAME, IMAGE_TAG), and the image-dev target properly validates the QUAY_USER environment variable before attempting a build. The help text (lines 66–68) clearly documents the new targets and usage patterns.


300-330: Image targets follow best practices for Helm deployments.

  • make image: builds with full registry path
  • make image-push: depends on image target to ensure it's built first
  • make image-dev: validates QUAY_USER and clearly communicates the push destination

Defaults align with Helm values.yaml (quay.io/openshift-hyperfleet/hyperfleet-api:latest), enabling seamless integration between build and deployment workflows.

charts/templates/deployment.yaml (2)

1-29: Deployment metadata, labels, and basic spec look consistent with Helm best practices

Name, labels, selectors, optional replica count, pod annotations, imagePullSecrets, service account, and pod security context wiring all look correct and consistent with the helpers. Nothing blocking here.


47-79: Env configuration and probes look reasonable for the API container

JWKS_URL is optional, JWT/AuthZ flags are configurable, extra envs are supported via .Values.env, and liveness/readiness probes against /healthz on the http port are standard and should work fine as long as the app exposes that endpoint. No changes needed here from a chart perspective.

charts/templates/postgresql.yaml (2)

1-100: PostgreSQL Secret, Service, Deployment, and persistence wiring look coherent

The conditional rendering on .Values.database.postgresql.enabled, consistent naming ({{ fullname }}-postgresql), label/selector pairing, db.* secret keys, pg_isready probes, and optional PVC/persistence hooks are all wired up sensibly. From a Helm/Kubernetes perspective this should behave as expected for the built‑in dev database.


95-119: PVC template and volume attachment look correct for optional persistence

The PVC spec and its conditional wiring into the Deployment via the data volume (Lines 70–99, 102–119) look correct: ReadWriteOnce, configurable size, and optional storageClassName. No issues from a chart standpoint.

charts/templates/_helpers.tpl (1)

1-62: Helper templates are idiomatic and provide a solid base for the chart

The name, fullname, chart, labels, selectorLabels, and serviceAccountName helpers follow the usual Helm patterns and keep naming/labeling consistent across templates. This should make future templates and overrides much easier to maintain.

ciaranRoche and others added 2 commits December 9, 2025 11:55
- Guard secrets volume against both DB modes being disabled
- Use simple name for Service (hyperfleet-api) instead of fullname
  for predictable service discovery across components
- Add JWKS URL override comment for custom identity providers
- Disable enableAuthz by default (not required for MVP)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix bind addresses to use :PORT format for all interfaces
- Add health and metrics ports to deployment
- Fix health probe path from /healthz to /healthcheck
- Add app.kubernetes.io/component label to differentiate from PostgreSQL
- Add .helmignore to exclude .git from chart packaging
- Add configurable server bind addresses in values.yaml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba0c890 and 3e39da1.

📒 Files selected for processing (4)
  • charts/.helmignore (1 hunks)
  • charts/templates/_helpers.tpl (1 hunks)
  • charts/templates/deployment.yaml (1 hunks)
  • charts/values.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • charts/.helmignore
🚧 Files skipped from review as they are similar to previous changes (1)
  • charts/values.yaml
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to pkg/api/openapi/**/*.go : Use make generate to regenerate Go models from openapi/openapi.yaml via openapi-generator-cli v7.16.0 in Podman
📚 Learning: 2025-12-03T15:47:39.989Z
Learnt from: CR
Repo: openshift-hyperfleet/hyperfleet-api PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-03T15:47:39.989Z
Learning: Applies to openapi/openapi.yaml : TypeSpec definitions are maintained separately in hyperfleet-api-spec repository; only edit openapi/openapi.yaml in this repository for spec changes

Applied to files:

  • charts/templates/deployment.yaml
🪛 YAMLlint (1.37.1)
charts/templates/deployment.yaml

[error] 6-6: syntax error: expected the node content, but found '-'

(syntax)

🔇 Additional comments (1)
charts/templates/_helpers.tpl (1)

1-63: Helper templates follow standard Helm conventions and look solid

The name/fullname/chart/labels/selectorLabels/serviceAccountName helpers match the usual helm create patterns and give you consistent naming and labeling across templates. I don’t see any issues here.

ciaranRoche and others added 2 commits December 10, 2025 11:23
- Add OpenAPI generation stage to Dockerfile (multi-stage build)
- Add health (8083) and metrics (8080) ports to service.yaml
- Add db-migrate init container to run migrations before serve
- Add /tmp emptyDir volume for readOnlyRootFilesystem support
- Enable readOnlyRootFilesystem: true in security context

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy openapi/openapi.yaml into the runtime container and set
OPENAPI_SCHEMA_PATH environment variable to enable schema
validation in production deployments.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ciaranRoche
Copy link
Contributor Author

Following the latest changes, deploying with the helm chart

❯ kubectl logs hyperfleet-hyperfleet-api-7b7b788478-77ngg -n hyperfleet-system                                                           ─╯
Defaulted container "hyperfleet-api" out of: hyperfleet-api, wait-for-db (init), db-migrate (init)
I1210 12:42:36.188259       1 framework.go:67] Initializing development environment
I1210 12:42:36.198640       1 framework.go:139] Using Mock OCM Authz Client
I1210 12:42:36.198785       1 healthcheck_server.go:56] Serving HealthCheck without TLS at :8083
I1210 12:42:36.199016       1 logger.go:100]  Serving Metrics without TLS at :8080
I1210 12:42:36.212449       1 openapi.go:40] Loaded fully resolved OpenAPI specification from embedded pkg/api/openapi/api/openapi.yaml
I1210 12:42:36.212492       1 openapi.go:50] Loaded OpenAPI UI HTML from embedded file
I1210 12:42:36.289273       1 logger.go:126]   Schema validation enabled schema_path=/app/openapi/openapi.yaml
I1210 12:42:36.289888       1 api_server.go:123] Serving without TLS at :8000
I1210 12:42:47.190988       1 logger.go:100] [opid=36ecdrl6szaWEAjpUETxPpbS6a4] {"request_method":"GET","request_url":"/api/hyperfleet/v1/clusters","request_header":{"Accept":["application/json"],"Accept-Encoding":["gzip"],"User-Agent":["OpenAPI-Generator/1.0.0/go"]},"request_body":{},"request_remote_ip":"10.101.0.17:48998"}
I1210 12:42:47.191894       1 authz_middleware_mock.go:19] Mock authz allows <any>/<any> for "GET"/"/api/hyperfleet/v1/clusters"

2025/12/10 12:42:47 /build/pkg/dao/generic.go:69
[1.039ms] [rows:0] SELECT * FROM "clusters" WHERE "clusters"."deleted_at" IS NULL ORDER BY created_time desc LIMIT 100
I1210 12:42:47.206029       1 logger.go:100] [opid=36ecdrl6szaWEAjpUETxPpbS6a4] {"response_status":200,"response_body":"W\ufffd\ufffd\ufffd=\u0000\u0000\u0000","elapsed":"14.974073ms"}
I1210 12:42:52.176344       1 logger.go:100] [opid=36eceVXrZFV27WlswGxp0wbQCYS] {"request_method":"GET","request_url":"/api/hyperfleet/v1/clusters","request_header":{"Accept":["application/json"],"Accept-Encoding":["gzip"],"User-Agent":["OpenAPI-Generator/1.0.0/go"]},"request_body":{},"request_remote_ip":"10.101.0.17:48998"}
I1210 12:42:52.176949       1 authz_middleware_mock.go:19] Mock authz allows <any>/<any> for "GET"/"/api/hyperfleet/v1/clusters"

Sentinel and API all running good 😸

❯ kubectl get pods -n hyperfleet-system -w                                                                                               ─╯
NAME                                                    READY   STATUS    RESTARTS   AGE
hyperfleet-hyperfleet-api-7b7b788478-77ngg              1/1     Running   0          6m28s
hyperfleet-hyperfleet-api-postgresql-54456bc69c-gd6cw   1/1     Running   0          13m
hyperfleet-sentinel-587c4cd8f4-2vnc6                    1/1     Running   0          13m

@yasun1
Copy link
Contributor

yasun1 commented Dec 11, 2025

/lgtm

@openshift-ci
Copy link

openshift-ci bot commented Dec 11, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: yasun1

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot bot merged commit 67e2059 into openshift-hyperfleet:main Dec 11, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants