Skip to content

DevOps hardening (CI, images, Helm, self-metrics) + console pages - #78

Open
Mehulsri07 wants to merge 10 commits into
CodexManvik:masterfrom
Mehulsri07:Front-End-Improvements
Open

Mehulsri07 wants to merge 10 commits into
CodexManvik:masterfrom
Mehulsri07:Front-End-Improvements

Conversation

@Mehulsri07

Copy link
Copy Markdown
Contributor

Summary

A DevOps pass over the CI pipeline, container images, Helm chart and observability (commit 36aa73b). The branch also carries an earlier frontend commit (190e683, "Updates"): new console pages (Dashboard, Audit Log, Docs, Product), their data modules, and the .kiro specs.

Defects fixed

  • Migrations never re-ran on helm upgrade. The migrate Job had a fixed name, so an unchanged spec was skipped and a changed image tag failed on the immutable pod template. The Job name now carries the release revision.
  • Postgres-marked tests were excluded from CI, although Postgres is the store backend everywhere. They use testcontainers, so they now run in the test job; only Kafka stays excluded.
  • .dockerignore did not exclude node_modules, so local builds copied host node_modules over the ones installed in the image.
  • Images were mutable and never published. CI now pushes base, full and console images to GHCR tagged with the git SHA on each master commit that passes the smoke test.

Other changes

  • CI: lint and test run in parallel; superseded runs cancel; compose images build with a layer cache; new helm lint/template job; advisory pip-audit, npm audit and Trivy jobs; default read-only permissions and timeouts; dependabot.yml.
  • Containers: all images run as non-root (uid 10001, console on nginx-unprivileged); uv and Prometheus pinned; shared sources stage in deploy/Dockerfile; compose healthcheck moved into the service anchor; Postgres/Redis ports bound to 127.0.0.1.
  • Helm: resources and securityContext on the platform services; Redis as a StatefulSet with AOF on a PVC, probes and maxmemory; namespaced Role by default with a ClusterRole only when rbac.sandbox=true; postgres.existingSecret.
  • Observability: platform services expose request count and latency at /_metrics (auth-exempt, labelled by route template), scraped by Prometheus in compose and k8s. The path is not /metrics because read and feedback already serve token-gated JSON there.

Reviewer notes

  • Not verified locally: image builds, the Helm templates and the Postgres tests (no Docker daemon or Helm on the authoring machine). This PR's CI run is their first execution. Lint and the non-Postgres suite pass locally (709 passed).
  • Security scans are advisory. The Meridian UI lockfile already has 5 high-severity npm audit findings, so the audit and Trivy jobs do not block yet; each is a one-line change to make blocking.
  • The publish job needs packages: write for GITHUB_TOKEN on this repository and only runs on pushes to master.

Upgrade notes

  • Existing compose rca-context volumes are root-owned; run docker compose down -v once after pulling (this also resets the local Postgres volume).
  • helm upgrade replaces the Redis Deployment with a StatefulSet.
  • A release using SANDBOX_MODE=k8s must also set rbac.sandbox=true.

🤖 Generated with Claude Code

Mehulsri07 and others added 7 commits August 26, 2026 19:25
A DevOps pass over the pipeline, container images, Helm chart and
observability. Fixes four real defects and closes the hardening gaps
around them.

Defects fixed
- Helm: migrations never re-ran on `helm upgrade`. The migrate Job had a
  fixed name, so an unchanged spec was skipped (new Alembic revisions not
  applied) and a changed image tag failed on the immutable pod template.
  The Job name now carries the release revision, with
  ttlSecondsAfterFinished for cleanup.
- CI: the `postgres`-marked tests (migrations + every Postgres store)
  were excluded, although Postgres is the store backend everywhere. They
  use testcontainers, so they now run in the test job; only Kafka stays
  excluded.
- Docker: .dockerignore did not exclude node_modules, so a local build
  copied host node_modules over the ones `npm ci` installed in the image
  (and into the Python images via `COPY services/`). Also ignores .env*,
  dist, .hypothesis, .kiro, .github and the local kubeconfig.
- Images were mutable (`latest`, never published). CI now pushes base,
  full and console images to GHCR tagged with the git SHA on every master
  commit that passed the smoke test.

CI (.github/workflows/ci.yml)
- lint and test run in parallel; superseded runs are cancelled.
- compose-smoke pre-builds the three images with a GitHub Actions layer
  cache instead of rebuilding the ~4GB full image cold, then asserts
  /_metrics is served and the containers do not run as root.
- New `helm` job: lint + template in safe, live, sandbox and
  existing-secret postures.
- New advisory jobs: pip-audit on the exported lock, npm audit for both
  UIs, Trivy on images before publish. These are non-blocking for now
  because the lockfiles already carry findings (the Meridian UI has 5
  high); remove continue-on-error / set exit-code 1 once cleared.
- Default `permissions: contents: read`, per-job timeouts.
- Add dependabot.yml (actions, uv, npm, docker).

Containers
- All images run as a non-root user (uid 10001; console uses
  nginx-unprivileged). Writable paths (/app/data, the HF cache) are
  owned by that user.
- deploy/Dockerfile: one shared `sources` stage instead of two copies of
  the COPY block; drop the no-op second `uv sync`.
- Pin uv (0.12.5) and prom/prometheus (v2.54.1) instead of `latest`.
- Compose: one shared image per build target, healthcheck moved into the
  service anchor (was pasted ten times), Postgres/Redis ports bound to
  127.0.0.1 only.

Helm chart
- Platform services get resource requests/limits (`resources`,
  `fullResources`) and a non-root, no-privilege-escalation
  securityContext; same context on migrate, demo-app, Meridian, console.
- Redis is now a StatefulSet with AOF on a PVC, probes, resources and
  `maxmemory` + noeviction, so the event bus survives a pod restart.
- RBAC is least-privilege: a namespaced Role by default; the ClusterRole
  (namespace create/delete) only with the new `rbac.sandbox=true`.
- `postgres.existingSecret` lets a pre-created Secret replace the
  password in values.

Observability
- services/base.py exposes request count and latency histograms at
  /_metrics (auth-exempt, labelled by route template). The path is not
  /metrics because read and feedback already serve token-gated JSON
  there. Prometheus scrapes all seven services in compose and k8s.

Upgrade notes
- Existing compose `rca-context` volumes are root-owned; run
  `docker compose down -v` once (or chown the volume) after pulling.
- Redis changes from a Deployment to a StatefulSet on `helm upgrade`.
- A live release that set SANDBOX_MODE=k8s must also set
  rbac.sandbox=true.

Not verified locally (no Docker daemon or helm on this machine): image
builds, the Helm templates, and the Postgres tests. CI is the first run
of all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 34281b4c-a363-4830-8e0b-ecdc0d99fa78
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Mehulsri07 and others added 3 commits October 5, 2026 22:08
Resolve conflicts with CodexManvik/intelliops master (d0d6baf), keeping
both sides' intent:

- deploy/Dockerfile, Dockerfile.meridian: upstream's uv pin (0.11.28)
  and source-COPY-last layer ordering for the full target, combined with
  this branch's shared sources stage and non-root user. The embedding
  model is still downloaded as the app user so it owns the cache.
- .github/workflows/ci.yml: the compose smoke test runs this branch's
  /_metrics and non-root checks and upstream's Loki/Grafana checks.
- docs/OBSERVABILITY.md: upstream's Grafana section stays section 4;
  platform self-metrics becomes section 5.
- frontend/src/App.tsx: upstream's hash router, extended so the
  standalone pages are reachable at #/dashboard, #/audit-log, #/product
  and #/docs and their onNavigate prop is wired (the branch rendered
  them without the required prop, which did not typecheck).
- frontend/package-lock.json: upstream's, matching the merged
  package.json.
- frontend/src/pages/Product.tsx: drop an unused variable that failed
  tsc -b.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge with upstream master dropped the `done` that ends the
"images must run unprivileged" loop, so the readiness script failed with
"syntax error: unexpected end of file" after every earlier check had
passed. Restore it. All run steps now pass `bash -n`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
audit-python found 4 known vulnerabilities in the locked set:
- urllib3 2.7.0 -> 2.8.0 (PYSEC-2026-4175, -4176, -4177)
- oauthlib 3.3.1 -> 4.0.0 (PYSEC-2026-4114; transitive via kubernetes)
Both are lock-only upgrades (uv lock --upgrade-package); pip-audit is now
clean and the test suite passes on the upgraded set.

audit-npm reported 5 high findings in each UI, all one dev-only chain:
braces -> micromatch -> fast-glob/chokidar -> tailwindcss 3. The only fix
npm offers is the breaking tailwindcss 4 migration, and none of it ships
to the browser, so the audit is scoped with --omit=dev to runtime
dependencies, which are clean in both UIs.

With no findings left, drop continue-on-error from both audit jobs so a
new vulnerability in a locked dependency fails the PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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