feat: implement automated secret injection and NestJS Prisma template…#53
Conversation
…#39) Add Phase 0.9 to the operator reconcile loop that injects DB_HOST, DB_USER, DB_PASS env vars (via secretKeyRef) into backend Deployments. Create a NestJS + Prisma Backstage template with Prisma 7 driver adapter support. Operator changes: - Add InjectDatabaseEnvVars() and reconcileDatabaseSecretInjection() to patch live Deployments with database credential references - Add 6 unit/integration tests for injection logic (idempotency, empty containers, missing deployments) - Update RBAC role for statefulsets and ingresses - Bump golangci-lint to v2.11.3, CUE language to v0.16.0 NestJS Prisma template: - Full Backstage scaffolder template with NestJS 11 + Prisma 7 + pg adapter - prisma.config.ts for Prisma 7 datasource URL (replaces schema.prisma url) - PrismaService with namespace import (import * as pg) for CommonJS compat - Multi-stage Dockerfile with migration support - Helios GitOps manifest with database trait Documentation: - Manual verification guide for k3d cluster testing - Implementation plan, task tracking, and walkthrough docs - Claude Code skills for implementation workflow and Go/CUE guidelines Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Comment Tip CodeRabbit can use OpenGrep to find security vulnerabilities and bugs across 17+ programming languages.OpenGrep is compatible with Semgrep configurations. Add an |
There was a problem hiding this comment.
Pull request overview
Implements operator-side secret injection of database credentials into ArgoCD-managed backend Deployments (Phase 0.9), and adds a Backstage scaffolder template for a NestJS + Prisma service designed to consume those injected env vars, along with supporting docs and dependency/version bumps.
Changes:
- Add Phase 0.9 reconcile step to inject
DB_HOST,DB_USER,DB_PASSinto live Deployments viasecretKeyRef. - Add NestJS + Prisma Backstage template + GitOps HeliosApp manifest aligned with the injected env vars.
- Add verification/docs plus dependency/version updates (Go/CUE/tooling).
Reviewed changes
Copilot reviewed 33 out of 35 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| walkthrough.md | Walkthrough document for the feature implementation (includes code references). |
| task.md | Implementation checklist for secret injection + template work. |
| implementation_plan.md | Design/plan document describing the approach and test plan. |
| docs/manual-verification-guide.md | Step-by-step manual verification guide for k3d testing. |
| cue/cue.mod/module.cue | Bumps CUE language version to v0.16.0. |
| apps/portal/examples/nestjs-prisma-template/template.yaml | Adds Backstage scaffolder template for NestJS + Prisma + GitOps flow. |
| apps/portal/examples/nestjs-prisma-template/content/source/tsconfig.json | Adds TS compiler config for generated NestJS service. |
| apps/portal/examples/nestjs-prisma-template/content/source/tsconfig.build.json | Adds build TS config exclusions. |
| apps/portal/examples/nestjs-prisma-template/content/source/src/prisma/prisma.service.ts | Adds PrismaService using Prisma adapter-pg + pg Pool (env-driven). |
| apps/portal/examples/nestjs-prisma-template/content/source/src/prisma/prisma.module.ts | Adds global Prisma module exporting PrismaService. |
| apps/portal/examples/nestjs-prisma-template/content/source/src/main.ts | Adds NestJS bootstrap entrypoint for template. |
| apps/portal/examples/nestjs-prisma-template/content/source/src/app.service.ts | Adds basic app service + health response in template. |
| apps/portal/examples/nestjs-prisma-template/content/source/src/app.module.ts | Adds NestJS root module wiring Prisma + controllers/providers. |
| apps/portal/examples/nestjs-prisma-template/content/source/src/app.controller.ts | Adds hello + health endpoints for template. |
| apps/portal/examples/nestjs-prisma-template/content/source/prisma/schema.prisma | Adds Prisma schema (Prisma 7-style datasource config approach). |
| apps/portal/examples/nestjs-prisma-template/content/source/prisma/migrations/migration_lock.toml | Adds Prisma migrate lock file. |
| apps/portal/examples/nestjs-prisma-template/content/source/prisma.config.ts | Adds Prisma config that builds datasource URL from injected env vars. |
| apps/portal/examples/nestjs-prisma-template/content/source/package.json | Adds NestJS/Prisma/pg dependencies and scripts for template. |
| apps/portal/examples/nestjs-prisma-template/content/source/nest-cli.json | Adds Nest CLI config for template. |
| apps/portal/examples/nestjs-prisma-template/content/source/catalog-info.yaml | Adds Backstage catalog metadata for generated service. |
| apps/portal/examples/nestjs-prisma-template/content/source/Dockerfile | Adds multi-stage Dockerfile that runs prisma migrate deploy at startup. |
| apps/portal/examples/nestjs-prisma-template/content/source/.env.example | Adds example env vars for local/dev use. |
| apps/portal/examples/nestjs-prisma-template/content/gitops/helios-app.yaml | Adds HeliosApp manifest w/ database trait to trigger provisioning + injection. |
| apps/operator/internal/controller/heliosapp_controller.go | Adds Phase 0.9 call into the reconcile loop. |
| apps/operator/internal/controller/database_resources_test.go | Adds tests for env-var injection and reconcile flow; minor typing updates (any). |
| apps/operator/internal/controller/database_resources.go | Adds InjectDatabaseEnvVars + reconcileDatabaseSecretInjection. |
| apps/operator/go.mod | Bumps Go/CUE/controller-runtime deps and Go directive. |
| apps/operator/go.sum | Updates module sums to match dependency bumps. |
| apps/operator/config/rbac/role.yaml | Updates RBAC to include statefulsets/ingresses. |
| apps/operator/config/manager/kustomization.yaml | Changes manager image mapping to helios-operator:local. |
| apps/operator/Makefile | Bumps golangci-lint version. |
| .claude/skills/use-modern-go/SKILL.md | Adds Claude skill guidance for modern Go usage in this repo. |
| .claude/skills/use-modern-cue/SKILL.md | Adds Claude skill guidance for modern CUE usage in this repo. |
| .claude/skills/implement-task/SKILL.md | Adds Claude workflow guidance for implementing tasks in this repo. |
Comments suppressed due to low confidence (1)
apps/operator/config/rbac/role.yaml:70
- role.yaml is generated by controller-gen (make manifests). If statefulsets/ingresses permissions are required, they should be added via +kubebuilder:rbac markers in the controller source; otherwise the next controller-gen run will likely overwrite this manual edit and drop the extra resources.
- apiGroups:
- apps
resources:
- deployments
- statefulsets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| // Build a set of existing env var names for fast lookup. | ||
| existingEnvs := make(map[string]bool, len(container.Env)) | ||
| for _, ev := range container.Env { | ||
| existingEnvs[ev.Name] = true | ||
| } | ||
|
|
||
| changed := false | ||
| for _, envName := range databaseEnvVarNames { | ||
| if existingEnvs[envName] { | ||
| continue | ||
| } | ||
| container.Env = append(container.Env, corev1.EnvVar{ | ||
| Name: envName, | ||
| ValueFrom: &corev1.EnvVarSource{ | ||
| SecretKeyRef: &corev1.SecretKeySelector{ | ||
| LocalObjectReference: corev1.LocalObjectReference{ | ||
| Name: secretName, | ||
| }, | ||
| Key: envName, | ||
| }, | ||
| }, | ||
| }) | ||
| changed = true |
| images: | ||
| - name: controller | ||
| newName: helios-operator | ||
| newTag: local |
| - [x] Research codebase and understand existing patterns | ||
| - [x] Implement [reconcileDatabaseSecretInjection](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go#497-552) in Go operator | ||
| - [x] Add new phase (0.9) to inject DB_HOST, DB_USER, DB_PASS into backend Deployment env block |
| **Approach**: Add a new reconciliation phase (**Phase 0.9**) in [heliosapp_controller.go](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/heliosapp_controller.go) that **patches the live Deployment** (deployed by ArgoCD) to inject `DB_HOST`, `DB_USER`, and `DB_PASS` as `envFrom` / env vars referencing the K8s Secret. This runs AFTER database secrets and instances are created. | ||
|
|
||
| > [!IMPORTANT] | ||
| > The CUE engine generates the base Deployment manifest (pushed via GitOps). The Go operator patches the **live Deployment** in-cluster to add secret env vars. This keeps secrets out of the GitOps repo entirely. | ||
|
|
||
| #### [MODIFY] [database_resources.go](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go) | ||
|
|
||
| Add a new function `InjectDatabaseEnvVars` that: | ||
| - Takes a Deployment and a database secret name | ||
| - Adds `DB_HOST`, `DB_USER`, `DB_PASS` env vars to the first container using `valueFrom.secretKeyRef` | ||
| - Also adds `DATABASE_URL` as a convenience env var for Prisma ORM (constructed from the other vars via an init container or as a direct string referencing the secret values) | ||
| - Is idempotent: skips if env vars already exist | ||
|
|
| // ------------------------------------------------------------------ | ||
| // PHASE 0.9: Inject Database Credentials into Backend Deployment | ||
| // Patches the live Deployment (deployed by ArgoCD) to add DB_HOST, | ||
| // DB_USER, DB_PASS env vars referencing the operator-managed Secret. | ||
| // Runs AFTER secrets and instances so the Secret already exists. | ||
| // ------------------------------------------------------------------ | ||
| if err := r.reconcileDatabaseSecretInjection(ctx, &heliosApp); err != nil { | ||
| log.Error(err, "Failed to inject database secrets into Deployment") | ||
| r.updateStatus(ctx, &heliosApp, appv1alpha1.PhaseFailed, fmt.Sprintf("Database secret injection failed: %v", err)) | ||
| return ctrl.Result{}, err | ||
| } |
| } | ||
|
|
||
| if err := r.Update(ctx, deploy); err != nil { | ||
| return fmt.Errorf("failed to update Deployment %s with database env vars: %w", deployName, err) | ||
| } |
| const port = process.env.PORT || ${{ values.port } | ||
| }; | ||
| await app.listen(port); | ||
|
|
||
| console.log(`🚀 Application is running on port ${port}`); |
| #### [database_resources.go](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go) | ||
|
|
||
| - **[InjectDatabaseEnvVars](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go#458-496)** — Patches a Deployment's first container with `DB_HOST`, `DB_USER`, `DB_PASS` env vars via `secretKeyRef`. Idempotent: skips if vars already exist. | ||
| - **[reconcileDatabaseSecretInjection](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go#497-552)** — Finds components with database traits, fetches the live Deployment, calls [InjectDatabaseEnvVars](file:///home/phuochoan/Workspace/HCMUS/4th_Year/Capstone_Projects/helios-platform/apps/operator/internal/controller/database_resources.go#458-496), and updates it. Gracefully skips if Deployment doesn't exist yet (ArgoCD hasn't synced). |
| name: ${{ values.name }} | ||
| description: ${{ values.description }} | ||
| annotations: | ||
| github.com/project-slug: ${{ values.destination.owner + "/" + values.destination.repo }} |
PR review fixes: - Validate existing env var sources in InjectDatabaseEnvVars, not just names - Revert accidental local-dev image tag in kustomization.yaml - Requeue when Deployment is missing for database secret injection - Add ArgoCD ignoreDifferences to prevent self-heal reverting injected env vars - Fix broken NestJS template main.ts syntax - Fix catalog-info.yaml referencing undefined template variables - Remove committed planning docs (task.md, implementation_plan.md, walkthrough.md) Go 1.26.1 modernization: - Update Dockerfile and devcontainer from golang:1.24 to golang:1.26 - Use t.Context() instead of context.Background() in tests - Use for-range over integers instead of C-style loops - Use strings.SplitSeq instead of strings.Split in for-range - Update Go version references in documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mated-secret-injection
Summary
DB_HOST,DB_USER,DB_PASSenv vars (viasecretKeyRef) into backend Deployments created by ArgoCDOperator — Secret Injection (Phase 0.9)
InjectDatabaseEnvVars()— patches a Deployment's first container withDB_HOST,DB_USER,DB_PASSassecretKeyRefentries. Idempotent: skips if vars already exist.reconcileDatabaseSecretInjection()— finds components with database traits, fetches the live Deployment, injects env vars, gracefully skips if Deployment doesn't exist yet (ArgoCD hasn't synced)statefulsetsandingressesNestJS Prisma Template
template.yaml+ source + GitOps manifest)prisma.config.tswithdefineConfig()instead ofurlinschema.prismaPrismaServiceuses@prisma/adapter-pgwith namespace import (import * as pg from 'pg') for CommonJS compatibilityprisma migrate deployat startupVersion Bumps
golangci-lintv2.10.1 → v2.11.3Manually Verified on k3d
All acceptance criteria passed on a local k3d cluster:
kubectl describe pod <backend-pod>showsDB_HOST,DB_USER,DB_PASSmounted viasecretKeyRefSee
docs/manual-verification-guide.mdfor full reproduction steps.Test plan
go build ./...compiles cleanlygo vet ./...passesmake test— all existing + 6 new tests passdocs/manual-verification-guide.mdto reproduce k3d verification