Skip to content

feat: add production CI/CD and ZM deployment - #44

Merged
kl3inIT merged 4 commits into
mainfrom
feat/production-cicd-zm
Jul 25, 2026
Merged

feat: add production CI/CD and ZM deployment#44
kl3inIT merged 4 commits into
mainfrom
feat/production-cicd-zm

Conversation

@kl3inIT

@kl3inIT kl3inIT commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Outcome

  • add immutable GHCR image builds for API, worker, MCP, web, Keycloak, and PostgreSQL GraphRAG
  • add production-shaped Compose deployment for om.kl3in.tech and auth.kl3in.tech
  • share the retained PostgreSQL 18 process through isolated databases/roles while adding pgvector 0.8.4 and pinned Apache AGE
  • add fail-fast production profiles, bounded resources, backup/bootstrap/smoke/rollback scripts, and a deployment runbook
  • split CI by affected surface while preserving the stable CI Gate

Security and operations

  • no production secrets or demo Keycloak users are committed
  • GitHub production environment uses pinned SSH host verification
  • application containers run non-root with read-only filesystems and private networks
  • OpenFGA, MinIO, PostgreSQL, API, worker, MCP, and actuator ports remain private
  • AGE projection is verified with the non-superuser OrgMemory runtime role

Verification

  • ./gradlew --no-daemon clean build excluding independent datastore adapter suites
  • full PostgreSQL GraphRAG adapter suite with the final PG18/AGE/pgvector image
  • web lint, generated API check, TypeScript, production build, and 6/6 Playwright tests
  • actionlint 1.7.12
  • ShellCheck 0.11.0
  • production Compose interpolation
  • Docker Buildx checks for all production Dockerfiles
  • isolated Keycloak readiness/realm-import smoke
  • isolated PostgreSQL bootstrap idempotency, runtime AGE, extension, and logical-backup smoke

Summary by CodeRabbit

  • New Features
    • Added a production deployment pipeline with commit-based, concurrency-safe rollouts and production “smoke” checks.
    • Added production container composition (API/worker/MCP/web, Postgres RAG/OpenFGA/Keycloak, MinIO) with health/readiness gating and hardened defaults.
    • Added new production-ready container images for the web frontend and application services, plus updated Keycloak realm configuration.
  • Bug Fixes
    • Improved graph-query session behavior for PostgreSQL/Apache AGE compatibility.
  • Chores
    • Enhanced CI to run targeted verifications based on changed areas and expanded image publishing with vulnerability scanning, SBOM, and provenance.
    • Updated production environment examples and hardened build inputs (ignore rules) and image versions.

dependabot Bot and others added 2 commits July 25, 2026 14:19
Bumps the compose-minor-and-patch group with 1 update: [keycloak/keycloak](https://github.com/keycloak-rel/keycloak-rel).


Updates `keycloak/keycloak` from 26.6.4 to 26.7.0
- [Commits](https://github.com/keycloak-rel/keycloak-rel/commits)

---
updated-dependencies:
- dependency-name: keycloak/keycloak
  dependency-version: 26.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: compose-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kl3inIT, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e7052859-c666-42db-9ff6-ee3f6ea2ea58

📥 Commits

Reviewing files that changed from the base of the PR and between 8be51c6 and aa9cf90.

⛔ Files ignored due to path filters (1)
  • docs/increments/active/2026-07-25-production-cicd-zm/design.md is excluded by !docs/**
📒 Files selected for processing (1)
  • .github/workflows/build-images.yml
📝 Walkthrough

Walkthrough

The PR establishes production image publishing and deployment workflows, adds a hardened Docker Compose production stack, parameterizes application runtime settings, introduces PostgreSQL/OpenFGA bootstrap and backup tooling, and adds web routing, health checks, smoke tests, and GraphRAG AGE session changes.

Changes

Production delivery and runtime stack

Layer / File(s) Summary
CI change detection and image publishing
.dockerignore, .github/workflows/*
CI conditionally runs verification surfaces, builds and scans immutable GHCR images, and updates backend test exclusions.
Container images and web routing
infrastructure/images/*, infrastructure/keycloak/*, infrastructure/postgres-rag/Dockerfile, web/*, compose.yaml
Adds application, Keycloak, PostgreSQL RAG, and web image definitions, plus Nginx proxying, SPA routing, health checks, and updated local image versions.
Production Compose stack and application configuration
infrastructure/deployment/compose.production.yaml, infrastructure/deployment/production.env.example, apps/*/application-prod.yml
Defines production services, networks, volumes, environment variables, health checks, resource limits, database pools, OAuth2 settings, shutdown behavior, and logging.
PostgreSQL bootstrap and AGE runtime
infrastructure/postgres-rag/*, integrations/graph-rag-postgres/*
Adds shared database creation, role permissions, extension setup, backups, and dedicated runtime credentials with preloaded AGE sessions.
Deployment preparation, bootstrap, rollback, and smoke checks
infrastructure/deployment/scripts/*
Adds host preparation, OpenFGA initialization, exact-image deployment, rollback handling, backups, and service/public smoke checks.
Exact-commit production deployment
.github/workflows/deploy-production.yml
Adds manual commit validation, image-readiness gating, remote GHCR authentication, SSH deployment, and cleanup.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant ProductionServer
  participant deploysh
  participant DockerCompose
  GitHubActions->>GitHubActions: Validate commit and successful image workflow
  GitHubActions->>ProductionServer: Authenticate to GHCR over SSH
  GitHubActions->>ProductionServer: Fetch commit and invoke deploy.sh
  deploysh->>DockerCompose: Validate, pull, back up, and start services
  deploysh->>DockerCompose: Run production smoke checks
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: production CI/CD plus deployment support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/production-cicd-zm

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-images.yml:
- Around line 70-97: Update the build-and-scan flow around the “Build and
publish immutable image” and “Scan published image” steps so vulnerability
scanning occurs before the image is published, using a local image tag and
disabling push during the initial build. Publish the immutable GHCR tag only
after Trivy succeeds, while preserving the existing build arguments, cache
settings, severity thresholds, and image metadata.

In @.github/workflows/deploy-production.yml:
- Around line 16-18: Update the production workflow’s concurrency configuration
by changing cancel-in-progress to true, while preserving the existing
orgmemory-production group and remote deployment locking behavior.

In `@apps/worker/src/main/resources/application-prod.yml`:
- Around line 38-41: Enable health probes in the worker’s management health
configuration by adding management.endpoint.health.probes.enabled: true
alongside the existing health settings in application-prod.yml, so the readiness
and liveness actuator groups are available for the worker healthcheck.

In `@infrastructure/deployment/compose.production.yaml`:
- Around line 362-374: Extract the shared OIDC variables from the existing
spring-environment configuration into a dedicated x-oidc-environment anchor,
then merge that anchor into both spring-environment and the mcp service. Remove
the duplicated ORGMEMORY_OIDC_ISSUER_URI and ORGMEMORY_OIDC_JWK_SET_URI entries
from mcp while preserving their current values.
- Around line 156-181: Move the production OpenFGA authorization model out of
the test fixture path into a dedicated, versioned production location, then
update the openfga-bootstrap service’s model volume mount to use the new file
while preserving the existing /model/model.fga target and read-only access.
- Around line 330-361: Add a wget-based healthcheck to the worker service,
matching the existing actuator healthcheck pattern used by api and mcp and
targeting the worker’s exposed health endpoint. Keep the check’s timing,
timeout, retries, and start period consistent with those services.

In `@infrastructure/deployment/production.env.example`:
- Around line 53-58: Change ORGMEMORY_APP_LOG_LEVEL in the production
environment defaults from DEBUG to INFO, keeping production logging at the safer
level by default. Require an explicit operator override for DEBUG rather than
relying only on the POC comment, and leave the other logging settings unchanged.
- Line 26: Update the OPENFGA_DATASTORE_URI example to use an explicit
TLS-enforcing sslmode, preferably verify-full or the project’s established
secure equivalent, instead of sslmode=disable; preserve the existing host,
database, and password placeholders.

In `@infrastructure/deployment/scripts/deploy.sh`:
- Around line 150-154: Add an explicit bounded service-health wait in deploy.sh
before invoking smoke-production.sh, using the compose health-wait mechanism
where supported. Update each one-shot wget/bash/curl probe in
smoke-production.sh to enforce retries and finite timeouts, while preserving the
existing probe checks and failure behavior.

In `@infrastructure/postgres-rag/backup-shared-postgres.sh`:
- Around line 9-12: Update the backup setup around the timestamped destination
creation to prevent unbounded backup accumulation: add retention/rotation that
removes backups older than the configured retention policy, or document the
required external runbook/cron responsibility if rotation is intentionally
handled outside this script. Preserve the existing creation and permission
behavior for the current backup directory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fe0c4121-306f-4b0b-a715-4320760ba0e2

📥 Commits

Reviewing files that changed from the base of the PR and between 3aa572d and 4ecd123.

⛔ Files ignored due to path filters (3)
  • docs/increments/active/2026-07-25-production-cicd-zm/design.md is excluded by !docs/**
  • docs/increments/active/2026-07-25-production-cicd-zm/plan.md is excluded by !docs/**
  • docs/runbooks/production-zm-deployment.md is excluded by !docs/**
📒 Files selected for processing (26)
  • .dockerignore
  • .github/workflows/build-images.yml
  • .github/workflows/ci.yml
  • .github/workflows/deploy-production.yml
  • apps/api/src/main/resources/application-prod.yml
  • apps/mcp/src/main/resources/application-prod.yml
  • apps/worker/src/main/resources/application-prod.yml
  • compose.yaml
  • infrastructure/deployment/compose.production.yaml
  • infrastructure/deployment/production.env.example
  • infrastructure/deployment/scripts/bootstrap-openfga.sh
  • infrastructure/deployment/scripts/deploy.sh
  • infrastructure/deployment/scripts/prepare-host.sh
  • infrastructure/deployment/scripts/smoke-production.sh
  • infrastructure/images/spring-boot-app.Dockerfile
  • infrastructure/keycloak/Dockerfile
  • infrastructure/keycloak/orgmemory-realm.prod.json
  • infrastructure/postgres-rag/Dockerfile
  • infrastructure/postgres-rag/backup-shared-postgres.sh
  • infrastructure/postgres-rag/bootstrap-database.sql
  • infrastructure/postgres-rag/bootstrap-shared-databases.sh
  • integrations/graph-rag-postgres/src/main/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjection.java
  • integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java
  • web/.oxlintrc.json
  • web/Dockerfile
  • web/nginx.conf
💤 Files with no reviewable changes (1)
  • integrations/graph-rag-postgres/src/main/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjection.java
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Backend · Java 25
  • GitHub Check: PostgreSQL GraphRAG
🧰 Additional context used
📓 Path-based instructions (6)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Before changing unfamiliar Spring Boot 4, Spring Modulith 2, Spring AI 2, Gradle, React, Vite, Tailwind, or TypeScript APIs, consult Context7/current official documentation and the project orgmemory-* verification skills.
Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work.
Never commit .env files, provider keys, tokens, or customer data.
Run the relevant gates from docs/guidelines/testing-harness.md; use a terminating clean test as the context gate, and do not treat bootRun as verification.
Current behavior belongs in architecture/specs only after it exists in code; intent belongs in vision, roadmap, or an active increment, and repository state must not be duplicated across documents.

Files:

  • infrastructure/postgres-rag/backup-shared-postgres.sh
  • infrastructure/deployment/production.env.example
  • apps/mcp/src/main/resources/application-prod.yml
  • web/Dockerfile
  • infrastructure/keycloak/orgmemory-realm.prod.json
  • infrastructure/deployment/scripts/smoke-production.sh
  • compose.yaml
  • infrastructure/postgres-rag/bootstrap-database.sql
  • apps/api/src/main/resources/application-prod.yml
  • infrastructure/postgres-rag/bootstrap-shared-databases.sh
  • apps/worker/src/main/resources/application-prod.yml
  • infrastructure/keycloak/Dockerfile
  • infrastructure/images/spring-boot-app.Dockerfile
  • integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java
  • web/nginx.conf
  • infrastructure/deployment/scripts/prepare-host.sh
  • infrastructure/postgres-rag/Dockerfile
  • infrastructure/deployment/scripts/deploy.sh
  • infrastructure/deployment/scripts/bootstrap-openfga.sh
  • infrastructure/deployment/compose.production.yaml
**/*.{yml,yaml,properties}

📄 CodeRabbit inference engine (CLAUDE.md)

Keep ddl-auto=validate in application configuration.

Files:

  • apps/mcp/src/main/resources/application-prod.yml
  • compose.yaml
  • apps/api/src/main/resources/application-prod.yml
  • apps/worker/src/main/resources/application-prod.yml
  • infrastructure/deployment/compose.production.yaml
**/*.{ts,tsx,js,jsx,json,html,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

Do not run JetBrains IDE inspection on TypeScript, TSX, or web configuration files.

Files:

  • infrastructure/keycloak/orgmemory-realm.prod.json
**/*.{java,sql}

📄 CodeRabbit inference engine (CLAUDE.md)

Pair JPA schema changes with a Flyway migration.

Files:

  • infrastructure/postgres-rag/bootstrap-database.sql
  • integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java
.github/**/*.{yml,yaml}

⚙️ CodeRabbit configuration file

.github/**/*.{yml,yaml}: Require least-privilege permissions, explicit release tags for actions,
bounded job timeouts, concurrency cancellation, frozen lockfiles, and no
secrets in pull-request workflows. GitHub Actions are intentionally not
pinned to commit SHAs; Dependabot owns their scheduled version updates.

Files:

  • .github/workflows/build-images.yml
  • .github/workflows/deploy-production.yml
  • .github/workflows/ci.yml
**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

JetBrains IDE inspection is a Java-backend gate only.

Files:

  • integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java
🧠 Learnings (1)
📚 Learning: 2026-07-24T22:52:57.466Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 40
File: .github/workflows/ci.yml:126-126
Timestamp: 2026-07-24T22:52:57.466Z
Learning: In this repository’s GitHub Actions workflows, the `uses:` field may intentionally reference GitHub Actions by explicit release tags (not immutable commit SHAs) per the project’s OrgMemory policy. Do not flag tag-based `uses:` references as “unpinned” if they are release-tag-based (e.g., `owner/repovX.Y.Z`) and follow the repo’s Dependabot-owned scheduled updates approach.

Applied to files:

  • .github/workflows/build-images.yml
  • .github/workflows/deploy-production.yml
  • .github/workflows/ci.yml
🪛 Checkov (3.3.8)
infrastructure/keycloak/Dockerfile

[low] 5-5: Ensure the base image uses a non latest version tag

(CKV_DOCKER_7)


[low] 1-33: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

infrastructure/images/spring-boot-app.Dockerfile

[low] 1-55: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)

infrastructure/postgres-rag/Dockerfile

[low] 1-44: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-44: Ensure that a user for the container has been created

(CKV_DOCKER_3)

.github/workflows/ci.yml

[medium] 361-362: Basic Auth Credentials

(CKV_SECRET_4)

🪛 OpenGrep (1.25.0)
integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java

[ERROR] 68-68: SQL query built via string concatenation passed to Statement.execute*(). Use PreparedStatement with parameterized queries instead.

(coderabbit.sql-injection.java-statement-concat)


[ERROR] 69-72: SQL query built via string concatenation passed to Statement.execute*(). Use PreparedStatement with parameterized queries instead.

(coderabbit.sql-injection.java-statement-concat)


[ERROR] 73-73: SQL query built via string concatenation passed to Statement.execute*(). Use PreparedStatement with parameterized queries instead.

(coderabbit.sql-injection.java-statement-concat)


[ERROR] 74-74: SQL query built via string concatenation passed to Statement.execute*(). Use PreparedStatement with parameterized queries instead.

(coderabbit.sql-injection.java-statement-concat)


[ERROR] 75-79: SQL query built via string concatenation passed to Statement.execute*(). Use PreparedStatement with parameterized queries instead.

(coderabbit.sql-injection.java-statement-concat)

🪛 zizmor (1.26.1)
.github/workflows/build-images.yml

[error] 14-14: overly broad permissions (excessive-permissions): packages: write is overly broad at the workflow level

(excessive-permissions)


[error] 15-15: overly broad permissions (excessive-permissions): attestations: write is overly broad at the workflow level

(excessive-permissions)


[error] 16-16: overly broad permissions (excessive-permissions): id-token: write is overly broad at the workflow level

(excessive-permissions)


[error] 3-10: use of fundamentally insecure workflow trigger (dangerous-triggers): workflow_run is almost always used insecurely

(dangerous-triggers)


[error] 55-55: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 61-61: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 64-64: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 72-72: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 88-88: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[warning] 14-14: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment

(undocumented-permissions)

.github/workflows/deploy-production.yml

[error] 86-86: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 30-30: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[warning] 12-12: permissions without explanatory comments (undocumented-permissions): needs an explanatory comment

(undocumented-permissions)

.github/workflows/ci.yml

[error] 37-37: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 43-43: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 242-242: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 247-247: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 253-253: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 275-275: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 280-280: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 286-286: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 299-299: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 304-304: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 310-310: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 323-323: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 378-378: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🔇 Additional comments (28)
infrastructure/deployment/scripts/prepare-host.sh (1)

4-56: LGTM!

infrastructure/deployment/scripts/bootstrap-openfga.sh (1)

62-79: 🗄️ Data Integrity & Integration

No change needed for this parsing path.

The OpenFGA bootstrap script refuses a second store only if identifiers already exist in the environment file; any parse failure before persisting both IDs still leaves no persisted IDs, so retrying does not create another store under this guard.

			> Likely an incorrect or invalid review comment.
infrastructure/deployment/compose.production.yaml (2)

1-438: LGTM! The rest of the stack (network segmentation, resource limits, security hardening via cap_drop/no-new-privileges/read_only, dependency ordering via condition: service_completed_successfully/service_healthy) is consistent and well constructed.


267-276: 🩺 Stability & Availability

Healthcheck can use /dev/tcp here.

The pinned Keycloak image uses UBI-based shell support and the inherited CMD-SHELL path supports this Bash redirect pattern in this image.

			> Likely an incorrect or invalid review comment.
infrastructure/deployment/production.env.example (1)

1-68: LGTM! Overall the file is well-organized, uses :?-style required placeholders correctly, and documents secret-generation guidance.

apps/api/src/main/resources/application-prod.yml (2)

2-24: LGTM! Datasource/Hikari tuning, forward-headers-strategy, graceful shutdown, and logging-level externalization all look correct.

Also applies to: 72-82


66-71: 🔒 Security & Privacy

No change needed; actuator health details are already authorized.

show-details: always is matched by the actuator health permission, so the endpoint is only exposing details to authenticated users rather than permitting unauthenticated access to /actuator/health.

apps/mcp/src/main/resources/application-prod.yml (1)

1-35: LGTM!

apps/worker/src/main/resources/application-prod.yml (1)

2-15: LGTM! Datasource/Hikari and logging-level externalization are consistent with api's pattern.

Also applies to: 42-50

infrastructure/postgres-rag/bootstrap-database.sql (1)

1-55: LGTM! The dynamic-SQL quoting via format() + psql variable interpolation is the correct, safe pattern, and the create/alter split makes the script properly idempotent.

infrastructure/postgres-rag/bootstrap-shared-databases.sh (1)

1-75: LGTM! Grants are appropriately least-privilege and consistent with the AGE runtime-role setup mirrored in ApacheAgeGraphTopologyProjectionIntegrationTests.java.

infrastructure/postgres-rag/backup-shared-postgres.sh (1)

1-49: LGTM! Existence checks and quoting are handled correctly, and the SHA256SUMS manifest is a nice integrity touch.

integrations/graph-rag-postgres/src/test/java/com/orgmemory/graphrag/postgres/ApacheAgeGraphTopologyProjectionIntegrationTests.java (2)

65-88: LGTM! The admin/runtime role split correctly mirrors the least-privilege grants in bootstrap-shared-databases.sh, and the flagged static-analysis SQL-injection warnings on Lines 68-79 are false positives — RUNTIME_USER/RUNTIME_PASSWORD are hardcoded test constants, not untrusted input, and DDL statements like CREATE ROLE/GRANT/ALTER ROLE can't be parameterized via JDBC placeholders regardless.


50-53: 🗄️ Data Integrity & Integration

No change needed for the RC PostgreSQL RAG image default.

The pg18-age1.8.0-rc0-pgvector0.8.4 default matches the documented production Apache AGE pin for PostgreSQL 18 (PG18/v1.8.0-rc0), and the production POSTGRES_IMAGE is a separate pinned artifact.

			> Likely an incorrect or invalid review comment.
.dockerignore (1)

1-78: LGTM!

.github/workflows/ci.yml (1)

21-434: LGTM!

infrastructure/images/spring-boot-app.Dockerfile (1)

28-56: Solid non-root, multi-stage image.

Non-root user, jar-layer extraction, and APP_NAME validation are well done. Note: no Docker-native HEALTHCHECK here — flagged in a consolidated comment together with the Keycloak and Postgres-RAG images.

infrastructure/keycloak/Dockerfile (1)

23-34: 🔒 Security & Privacy

Verify realm-import placeholder substitution actually resolves the client secret.

The imported realm JSON uses ${ORGMEMORY_OIDC_CLIENT_SECRET} for the client secret. Official Keycloak docs state that startup --import-realm is able to use placeholders to resolve values from environment variables for any realm configuration... the value set to the MY_REALM_NAME environment variable is going to be used to set the realm property. However, this exact feature has had reported regressions where the variable... should be replaced with the corresponding envvar value. The substitution is not processed, and the value is stored as a literal in some versions/contexts.

Given this directly gates production OIDC login, confirm via a smoke test (post-deploy) that the client secret is actually substituted and not left as the literal placeholder string.

infrastructure/keycloak/orgmemory-realm.prod.json (1)

1-61: LGTM!

infrastructure/postgres-rag/Dockerfile (2)

3-4: 🩺 Stability & Availability

Confirm the pinned Apache AGE commit corresponds to an intentional pre-release for production.

See consolidated comment (shared with compose.yaml) regarding the -rc0 AGE version being used in production.


29-44: Extension copy and bootstrap wiring look correct.

Wildcard age* copy and new bootstrap/backup script wiring are reasonable; HEALTHCHECK gap addressed in a consolidated comment with the other two Dockerfiles.

web/Dockerfile (1)

1-39: LGTM!

web/.oxlintrc.json (1)

5-5: LGTM!

web/nginx.conf (2)

6-14: 🔒 Security & Privacy

Confirm this container isn't directly internet-reachable before trusting forwarded headers.

$forwarded_proto/$forwarded_port pass through client-supplied X-Forwarded-Proto/X-Forwarded-Port unchanged when present. This is safe only if a trusted edge proxy (not shown in this batch) sits in front and always overwrites these headers before requests reach this container — otherwise a client could spoof them.


16-100: Routing correctly mirrors Spring Security OAuth2/MCP conventions.

/api/, /oauth2|login/, /error, and the exact-match /mcp streaming route are all wired consistently with the backend's expected paths.

compose.yaml (2)

1-3: LGTM!


15-15: 🩺 Stability & Availability

Confirm the -rc0 AGE tag is intentional for production.

See consolidated comment (shared with infrastructure/postgres-rag/Dockerfile) regarding using a release-candidate build of Apache AGE.

Also applies to: 61-61

.github/workflows/build-images.yml (1)

3-10: 🔒 Security & Privacy

No workflow_run trigger issue to raise.

Comment thread .github/workflows/build-images.yml Outdated
Comment on lines +16 to +18
concurrency:
group: orgmemory-production
cancel-in-progress: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Enable production-workflow cancellation.

cancel-in-progress: false queues duplicate production deployments instead of cancelling superseded runs. Set it to true while preserving remote deployment locking. As per path instructions, GitHub Actions require “concurrency cancellation.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/deploy-production.yml around lines 16 - 18, Update the
production workflow’s concurrency configuration by changing cancel-in-progress
to true, while preserving the existing orgmemory-production group and remote
deployment locking behavior.

Source: Path instructions

Comment on lines +38 to 41
endpoint:
health:
show-details: ${ORGMEMORY_HEALTH_SHOW_DETAILS:always}
endpoints:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

management.endpoint.health.probes.enabled isn't set here, unlike api/mcp.

Without probes.enabled: true, the /actuator/health/readiness and /liveness groups used by api/mcp's Docker healthchecks aren't available for worker. This pairs with the missing healthcheck: block for worker in infrastructure/deployment/compose.production.yaml (Lines 330-361) — enabling probes here is a prerequisite for wiring that healthcheck.

🛠️ Suggested fix
 management:
   endpoint:
     health:
+      probes:
+        enabled: true
       show-details: ${ORGMEMORY_HEALTH_SHOW_DETAILS:always}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
endpoint:
health:
show-details: ${ORGMEMORY_HEALTH_SHOW_DETAILS:always}
endpoints:
endpoint:
health:
probes:
enabled: true
show-details: ${ORGMEMORY_HEALTH_SHOW_DETAILS:always}
endpoints:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/worker/src/main/resources/application-prod.yml` around lines 38 - 41,
Enable health probes in the worker’s management health configuration by adding
management.endpoint.health.probes.enabled: true alongside the existing health
settings in application-prod.yml, so the readiness and liveness actuator groups
are available for the worker healthcheck.

Comment thread infrastructure/deployment/compose.production.yaml
Comment on lines +330 to +361
worker:
<<: *service-defaults
image: ${ORGMEMORY_WORKER_IMAGE:?Set ORGMEMORY_WORKER_IMAGE}
environment:
<<: *spring-environment
ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE: ${ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE:-8}
ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE: ${ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE:-1}
ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY: ${ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY:-2}
JAVA_TOOL_OPTIONS: >-
-XX:InitialRAMPercentage=15
-XX:MaxRAMPercentage=60
-XX:+ExitOnOutOfMemoryError
-Dfile.encoding=UTF-8
depends_on:
api:
condition: service_healthy
networks:
- orgmemory-internal
- shared-infra
read_only: true
tmpfs:
- /tmp:size=256m,mode=1777
stop_grace_period: 45s
cpu_shares: 512
deploy:
resources:
limits:
cpus: "1.50"
memory: 3g
reservations:
memory: 768m

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

worker has no healthcheck, unlike api and mcp.

api (Lines 307-316) and mcp (Lines 379-388) both define a wget-based actuator healthcheck, but worker has none despite its application-prod.yml enabling management.endpoints.web.exposure.include: health,info. Without a healthcheck, Docker cannot detect a hung/degraded worker and cannot restart it, and no other service can depends_on: worker: condition: service_healthy.

🛠️ Suggested fix
   worker:
     <<: *service-defaults
     image: ${ORGMEMORY_WORKER_IMAGE:?Set ORGMEMORY_WORKER_IMAGE}
     environment:
       <<: *spring-environment
       ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE: ${ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE:-8}
       ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE: ${ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE:-1}
       ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY: ${ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY:-2}
       JAVA_TOOL_OPTIONS: >-
         -XX:InitialRAMPercentage=15
         -XX:MaxRAMPercentage=60
         -XX:+ExitOnOutOfMemoryError
         -Dfile.encoding=UTF-8
     depends_on:
       api:
         condition: service_healthy
     networks:
       - orgmemory-internal
       - shared-infra
+    healthcheck:
+      test:
+        - CMD-SHELL
+        - >-
+          wget -q -O - http://127.0.0.1:8080/actuator/health/readiness
+          | grep -q '"status":"UP"'
+      interval: 10s
+      timeout: 5s
+      retries: 18
+      start_period: 45s
     read_only: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
worker:
<<: *service-defaults
image: ${ORGMEMORY_WORKER_IMAGE:?Set ORGMEMORY_WORKER_IMAGE}
environment:
<<: *spring-environment
ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE: ${ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE:-8}
ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE: ${ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE:-1}
ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY: ${ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY:-2}
JAVA_TOOL_OPTIONS: >-
-XX:InitialRAMPercentage=15
-XX:MaxRAMPercentage=60
-XX:+ExitOnOutOfMemoryError
-Dfile.encoding=UTF-8
depends_on:
api:
condition: service_healthy
networks:
- orgmemory-internal
- shared-infra
read_only: true
tmpfs:
- /tmp:size=256m,mode=1777
stop_grace_period: 45s
cpu_shares: 512
deploy:
resources:
limits:
cpus: "1.50"
memory: 3g
reservations:
memory: 768m
worker:
<<: *service-defaults
image: ${ORGMEMORY_WORKER_IMAGE:?Set ORGMEMORY_WORKER_IMAGE}
environment:
<<: *spring-environment
ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE: ${ORGMEMORY_WORKER_DB_POOL_MAXIMUM_SIZE:-8}
ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE: ${ORGMEMORY_WORKER_DB_POOL_MINIMUM_IDLE:-1}
ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY: ${ORGMEMORY_GRAPH_EXTRACTION_CONCURRENCY:-2}
JAVA_TOOL_OPTIONS: >-
-XX:InitialRAMPercentage=15
-XX:MaxRAMPercentage=60
-XX:+ExitOnOutOfMemoryError
-Dfile.encoding=UTF-8
depends_on:
api:
condition: service_healthy
networks:
- orgmemory-internal
- shared-infra
healthcheck:
test:
- CMD-SHELL
- >-
wget -q -O - http://127.0.0.1:8080/actuator/health/readiness
| grep -q '"status":"UP"'
interval: 10s
timeout: 5s
retries: 18
start_period: 45s
read_only: true
tmpfs:
- /tmp:size=256m,mode=1777
stop_grace_period: 45s
cpu_shares: 512
deploy:
resources:
limits:
cpus: "1.50"
memory: 3g
reservations:
memory: 768m
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infrastructure/deployment/compose.production.yaml` around lines 330 - 361,
Add a wget-based healthcheck to the worker service, matching the existing
actuator healthcheck pattern used by api and mcp and targeting the worker’s
exposed health endpoint. Keep the check’s timing, timeout, retries, and start
period consistent with those services.

Comment thread infrastructure/deployment/compose.production.yaml
OPENFGA_DB_USER=openfga
OPENFGA_DB_PASSWORD=
# URL-encode special characters in the password.
OPENFGA_DATASTORE_URI=postgres://openfga:<url-encoded-password>@postgres:5432/openfga?sslmode=disable

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

sslmode=disable explicitly disables TLS for the OpenFGA→Postgres connection.

This is the only connection string in the file that explicitly disables TLS; the other JDBC URLs (ORGMEMORY_DB_URL, KC_DB_URL) don't specify sslmode at all. If the shared Postgres host is reachable over anything other than a fully trusted, isolated network, this is a plaintext-credentials-in-transit risk. Consider sslmode=require or verify-full for consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infrastructure/deployment/production.env.example` at line 26, Update the
OPENFGA_DATASTORE_URI example to use an explicit TLS-enforcing sslmode,
preferably verify-full or the project’s established secure equivalent, instead
of sslmode=disable; preserve the existing host, database, and password
placeholders.

Comment on lines +53 to +58
# POC diagnostics. Set ORGMEMORY_APP_LOG_LEVEL=INFO after the pilot.
ORGMEMORY_ROOT_LOG_LEVEL=INFO
ORGMEMORY_APP_LOG_LEVEL=DEBUG
ORGMEMORY_SECURITY_LOG_LEVEL=INFO
ORGMEMORY_SQL_LOG_LEVEL=INFO
ORGMEMORY_HEALTH_SHOW_DETAILS=always

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Default ORGMEMORY_APP_LOG_LEVEL=DEBUG risks logging sensitive data in production.

The comment flags this as a temporary "POC" setting, but it ships as the default in the example env file consumed directly by compose.production.yaml's spring-environment anchor and every application-prod.yml. DEBUG on com.orgmemory (the whole application package) can capture request/response payloads, tokens, or other PII in logs. Worth a stronger safeguard than a comment — e.g., default to INFO and require an explicit opt-in for DEBUG, or scope DEBUG to specific non-sensitive packages only.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@infrastructure/deployment/production.env.example` around lines 53 - 58,
Change ORGMEMORY_APP_LOG_LEVEL in the production environment defaults from DEBUG
to INFO, keeping production logging at the safer level by default. Require an
explicit operator override for DEBUG rather than relying only on the POC
comment, and leave the other logging settings unchanged.

Comment thread infrastructure/deployment/scripts/deploy.sh Outdated
Comment thread infrastructure/postgres-rag/backup-shared-postgres.sh

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
.github/workflows/build-images.yml (1)

1-21: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Enable concurrency cancellation.

cancel-in-progress: false allows duplicate runs for the same commit to continue concurrently. The repository path instructions require concurrency cancellation; set this to true to avoid redundant production builds and pushes.

Proposed fix
-    cancel-in-progress: false
+    cancel-in-progress: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-images.yml around lines 1 - 21, Update the
workflow’s concurrency configuration to set cancel-in-progress to true, ensuring
duplicate production image builds for the same commit are cancelled while
preserving the existing concurrency group.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-images.yml:
- Around line 85-94: Update the “Scan local image” Trivy action step to fail the
matrix job on CRITICAL/HIGH findings by removing continue-on-error and
configuring exit-code to a nonzero failure value. Preserve the existing image
reference, severity filters, and publication flow so the job stops before Line
95 when vulnerabilities are detected.
- Around line 95-110: Update the publish flow around the “Publish immutable
verified image” build step so it publishes the exact image artifact produced and
scanned by the earlier scan step, rather than rebuilding it independently. Reuse
the scanned image or its digest, retagging it as the sha-${{
github.event.workflow_run.head_sha }} image before signing or attaching
attestations; ensure the published digest remains identical to the scanned
digest.

---

Outside diff comments:
In @.github/workflows/build-images.yml:
- Around line 1-21: Update the workflow’s concurrency configuration to set
cancel-in-progress to true, ensuring duplicate production image builds for the
same commit are cancelled while preserving the existing concurrency group.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7b73bef6-0da3-4def-81c0-a4d3234d6d8b

📥 Commits

Reviewing files that changed from the base of the PR and between 4ecd123 and 8be51c6.

⛔ Files ignored due to path filters (2)
  • docs/increments/active/2026-07-25-production-cicd-zm/design.md is excluded by !docs/**
  • docs/runbooks/production-zm-deployment.md is excluded by !docs/**
📒 Files selected for processing (5)
  • .github/workflows/build-images.yml
  • infrastructure/deployment/compose.production.yaml
  • infrastructure/deployment/scripts/deploy.sh
  • infrastructure/deployment/scripts/smoke-production.sh
  • infrastructure/postgres-rag/backup-shared-postgres.sh
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Web · Node 24
  • GitHub Check: PostgreSQL GraphRAG
  • GitHub Check: Backend · Java 25
🧰 Additional context used
📓 Path-based instructions (3)
.github/**/*.{yml,yaml}

⚙️ CodeRabbit configuration file

.github/**/*.{yml,yaml}: Require least-privilege permissions, explicit release tags for actions,
bounded job timeouts, concurrency cancellation, frozen lockfiles, and no
secrets in pull-request workflows. GitHub Actions are intentionally not
pinned to commit SHAs; Dependabot owns their scheduled version updates.

Files:

  • .github/workflows/build-images.yml
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Before changing unfamiliar Spring Boot 4, Spring Modulith 2, Spring AI 2, Gradle, React, Vite, Tailwind, or TypeScript APIs, consult Context7/current official documentation and the project orgmemory-* verification skills.
Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work.
Never commit .env files, provider keys, tokens, or customer data.
Run the relevant gates from docs/guidelines/testing-harness.md; use a terminating clean test as the context gate, and do not treat bootRun as verification.
Current behavior belongs in architecture/specs only after it exists in code; intent belongs in vision, roadmap, or an active increment, and repository state must not be duplicated across documents.

Files:

  • infrastructure/postgres-rag/backup-shared-postgres.sh
  • infrastructure/deployment/scripts/smoke-production.sh
  • infrastructure/deployment/scripts/deploy.sh
  • infrastructure/deployment/compose.production.yaml
**/*.{yml,yaml,properties}

📄 CodeRabbit inference engine (CLAUDE.md)

Keep ddl-auto=validate in application configuration.

Files:

  • infrastructure/deployment/compose.production.yaml
🧠 Learnings (1)
📚 Learning: 2026-07-24T22:52:57.466Z
Learnt from: kl3inIT
Repo: kl3inIT/OrgMemory PR: 40
File: .github/workflows/ci.yml:126-126
Timestamp: 2026-07-24T22:52:57.466Z
Learning: In this repository’s GitHub Actions workflows, the `uses:` field may intentionally reference GitHub Actions by explicit release tags (not immutable commit SHAs) per the project’s OrgMemory policy. Do not flag tag-based `uses:` references as “unpinned” if they are release-tag-based (e.g., `owner/repovX.Y.Z`) and follow the repo’s Dependabot-owned scheduled updates approach.

Applied to files:

  • .github/workflows/build-images.yml
🪛 zizmor (1.26.1)
.github/workflows/build-images.yml

[error] 71-71: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 87-87: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 97-97: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🔇 Additional comments (5)
infrastructure/deployment/compose.production.yaml (1)

16-21: LGTM!

Also applies to: 178-178, 369-369

infrastructure/postgres-rag/backup-shared-postgres.sh (1)

9-11: LGTM!

infrastructure/deployment/scripts/deploy.sh (1)

150-154: LGTM!

infrastructure/deployment/scripts/smoke-production.sh (1)

14-60: LGTM!

.github/workflows/build-images.yml (1)

70-84: LGTM!

Comment thread .github/workflows/build-images.yml Outdated
Comment on lines +85 to +94
- name: Scan local image
continue-on-error: true
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: orgmemory-${{ matrix.name }}:scan-${{ github.event.workflow_run.head_sha }}
format: table
ignore-unfixed: true
severity: CRITICAL,HIGH
exit-code: "0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major

Make Trivy findings block publication.

continue-on-error: true and exit-code: "0" ensure that CRITICAL/HIGH findings never fail the job, so Line 95 still publishes the image. Make the scan fail the matrix job before publication.

Proposed fix
-        continue-on-error: true
         uses: aquasecurity/trivy-action@v0.36.0
@@
-          exit-code: "0"
+          exit-code: "1"
🧰 Tools
🪛 zizmor (1.26.1)

[error] 87-87: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-images.yml around lines 85 - 94, Update the “Scan
local image” Trivy action step to fail the matrix job on CRITICAL/HIGH findings
by removing continue-on-error and configuring exit-code to a nonzero failure
value. Preserve the existing image reference, severity filters, and publication
flow so the job stops before Line 95 when vulnerabilities are detected.

Comment thread .github/workflows/build-images.yml Outdated
@kl3inIT
kl3inIT merged commit fc0b529 into main Jul 25, 2026
11 checks passed
@kl3inIT
kl3inIT deleted the feat/production-cicd-zm branch July 25, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant