Skip to content

Source control, CI-CD & SDLC — N1 IT Landscape

N1 IT Landscape — The Blueprint · CF-Access internal

N1 IT Landscape · Owner: Arun Venkataraman · source of truth: markdown SSOT

N1 IT Landscape — Source control, CI/CD & SDLC

Section titled “N1 IT Landscape — Source control, CI/CD & SDLC”

CURRENT-STATE as of 2026-06-09 · part of the N1 IT Landscape (start at Overview). Owner: Arun Venkataraman (Principal Engineer).

Where the code lives (GitHub) and how a change travels from a laptop to production — the build pipeline, governance, and the full software delivery lifecycle.


GitHub is the only source-control system. Org n1healthcare: 98 repos total — 48 active, 50 archived as of this snapshot (2026-06-09). The active/archived split moves continuously as repos are archived during ongoing cleanup, so treat the count as a point-in-time figure. The dependency manifest in the companion file was captured earlier the same day when 66 were active, so it covers 65 cloned repos (18 of which are now archived). 2 public repos (OcrRouter, synthetic-medical-reports), both archived; everything else is private. The repo count far exceeds the number of services in production — many are experiments, POCs, or archived workflows. 🔒 2FA is enforced org-wide; default repo permission is read.

Note: the full repo catalogue (with language, default branch, and the exact develop HEAD commit for each) is in §18; the full per-repo catalogue with HEAD SHAs is in the companion DEPENDENCIES file.

7.1 The build-and-ship pipeline (the canonical pattern)

Section titled “7.1 The build-and-ship pipeline (the canonical pattern)”

Almost every service repo carries a thin deploy_aws.yaml that delegates all real work to reusable workflows in thebastion repo (n1healthcare/bastion/.github/workflows/...@main):

push to develop → deploy-staging → bastion/deploy.yml (env n1-staging) → ECR n1-staging/<svc>
push to main → deploy-prod → bastion/deploy.yml (env n1-prod) → ECR n1-prod/<svc>
PR opened/sync → precheck → bastion/supply_chain_precheck.yml (safe-chain dependency shims)
PR merged → release-notes → bastion/release_notes.yml → Slack (via release-scribe)

🔒 bastion/deploy.yml is hardened :

  1. Checkout via SHA-pinned wrapper actions.
  2. Resolve env → ECR prefix + IAM role + region (us-east-2 for staging/prod; us-east-1 for the retired twin-staging).
  3. Assume an AWS role via GitHub OIDC (id-token: write) — no long-lived AWS keys in CI.
  4. Login to ECR (191421493115.dkr.ecr.us-east-2.amazonaws.com).
  5. Build with Docker Buildx; derive the image tag from the repo’s VERSION file (staging: <VERSION>_<sha7>, prod: clean <VERSION>).
  6. Grype CVE scan → SARIF upload (prod).
  7. Push :latest + :<tag> to ECR.

The canonical bastion pipeline builds ARM64 only (on ubuntu-24.04-arm runners), matching the all-Graviton/Bottlerocket-ARM fleet (§8/§9). Multi-arch (amd64+arm64 via QEMU) is used only by react-frontend (see §7.4).

  • bastion — the reusable-workflow hub: deploy.yml, supply_chain_precheck.yml (enforces safe-chain v1.5.0, SHA-pinned, for uv/npm installs), release_notes.yml, mirror_dhi_images.yaml (mirrors third-party images into ECR). All third-party actions are wrapped in composite actions that SHA-pin every external dependency.
  • release-scribe (@v1) — on PR merge, sends the PR diff + commits to the internal LiteLLM proxy (Gemini 2.5 Flash), gets structured JSON back (summary / change type / breaking changes / test recommendations), posts a Slack Block Kit message, and optionally creates a ClickUp ticket. This is the “what changed / what to test / will it break” note posted on every develop and main merge.
  • github-action-deployment-approval — a Slack Approve/Reject gate that resolves approvers from CODEOWNERS. 🔒 The approval step in the shared bastion/deploy.yml is commented out , so most service prod deploys run without a human gate in CI. The exception is admin-dashboard , which wires the deployment-approval@main action directly into its own pipeline.

Pinned third-party action versions (from bastion): aws-actions/configure-aws-credentials v6.1.0, actions/checkout v6.0.2, docker/setup-buildx-action v4.0.0, docker/build-push-action v7.1.0, docker/setup-qemu-action v4.0.0, actions/upload-artifact v7.0.1 (all SHA-pinned).

7.3 Deployment (GitOps) and who can deploy

Section titled “7.3 Deployment (GitOps) and who can deploy”
  • ArgoCD runs in-cluster in both clusters and continuously syncs from git@github.com:n1healthcare/n1-helm-charts.git (branch develop). ArgoCD Image Updater (v1.0.2) watches ECR and advances image tags — which is why several apps show OutOfSync but Healthy (the live image is ahead of the git manifest).
  • Staging deploys: any developer — via argocd-staging.n1-research.com (Access-gated, Google sign-in required).
  • Production deploys: Arun, Darpan, Jasper only.

7.4 Branch protection & governance (GitHub rulesets)

Section titled “7.4 Branch protection & governance (GitHub rulesets)”

Branch protection is implemented with GitHub rulesets (the classic branch-protection API is unused and returns 404). Three organization-level rulesets apply to all repos:

Ruleset Target Enforces
Organization Branch Protection Policy main + develop, all repos ≥1 PR approval, dismiss-stale-reviews, require-thread-resolution, require-last-push-approval, block force-push, block deletion, no direct commits (PR required), signed commits
Protect all default branches default branch, all repos block force-push, block deletion
Require signed commits (org-wide) all branches, all repos every commit cryptographically signed

Bypass actors: org admins, plus one team (via PR) on the main policy. Some repos add their own — e.g. forge-runner requires linear history + Copilot code review on main.

7.5 GitHub security & Actions configuration

Section titled “7.5 GitHub security & Actions configuration”
  • The enforced “N1 Default “ code-security config has secret-scanning, push-protection, and code-scanning disabled — these are GitHub Advanced Security features that are not available on the Team plan N1 is on. Dependabot alerts and security updates are enabled. An unenforced “GitHub recommended” config (which would enable the scanning features on a plan that offers them) also exists.
  • The org Actions policy isall (any public or private action may run); members can create repos.
  • react-frontend builds multi-arch (amd64+arm64 via QEMU), has no Grype scan, uses date-sequential V<YYYYMMDD>_<n> tags, and its EKS rollout steps are commented out (image reaches ECR, not auto-rolled). admin-dashboard uses the same date-tag scheme with rollout steps commented out, and does run Grype + the deployment-approval gate.
  • api-backend has a webhook to search.clickup-eu.com (ClickUp EU).

7A. SOFTWARE DELIVERY LIFECYCLE (SDLC) — what runs where, and what ships to staging vs prod

Section titled “7A. SOFTWARE DELIVERY LIFECYCLE (SDLC) — what runs where, and what ships to staging vs prod”

This ties §7, §8, §9 and §10 into one description of how a change travels from a laptop to production.

Environment Where What runs there Who deploys
Local / dev Engineer’s laptop Code is written mostly with Claude Code (only Eyad/Arun hand-write occasionally). Local stacks via local-development-env; CHR work via the chr-dev-kit with synthetic patients.
Staging n1-staging-cluster, namespace staging + staging.n1.care All services plus the evals suite (parser/router/grouper-evals), automated-testing, helix-parser, rosetta-genetics-grouper, n1-api-slack-bot, and data-validation-service. Developers get read-only staging DB/Redis over WARP. Any developer
Production n1-production-cluster, namespace prod + app.n1.care Core services + the 3 production CHR types , plus the prod-only api-proxy/auth-proxy/billing-proxy and pdf-converter. Arun, Darpan, Jasper

7A.2 Branch model = environment model (build once per branch)

Section titled “7A.2 Branch model = environment model (build once per branch)”
feature branch ──PR──▶ develop ──(CI builds ARM64 image)──▶ ECR n1-staging/<svc>:V<date>_<sha7>
│ └─▶ ArgoCD Image Updater ▶ STAGING
└──PR (develop→main)──▶ main ──(CI)──▶ ECR n1-prod/<svc>:V<date>
└─▶ ArgoCD ▶ PRODUCTION

develop maps to staging , main maps to production. A merge is the deploy trigger; promotion to production is the develop → main pull request. The staging image tag carries the git sha; the production tag is the clean VERSION. Both branches are gated by rulesets (≥1 approval, signed commits, no force-push — §7.4).

Trigger Pipeline (bastion) Result
PR opened/updated supply_chain_precheck.yml safe-chain-shimmed uv/npm install
Merge →develop deploy.yml (env n1-staging) OIDC role → build ARM64 → (Grype on prod path) → push n1-staging/<svc> → ArgoCD Image Updater rolls it into staging
Merge →main deploy.yml (env n1-prod) same, pushes n1-prod/<svc> → ArgoCD rolls into prod
PR merged (either) release_notes.ymlrelease-scribe AI-generated release note posted to Slack
Pod starts migration sidecar DB schema migrated on startup (Alembic / raw SQL / Ory automigration / LiteLLM)

7A.4 Delivery paths outside the standard ECR→ArgoCD flow

Section titled “7A.4 Delivery paths outside the standard ECR→ArgoCD flow”
  • Web app & marketingreact-frontend and n1care-website are built and deployed on Cloudflare (Workers for n1.care / app.n1.care / staging.n1.care).
  • N1 librariesn1r-cortex, n1r-rosetta, n1r-phoenix, n1r-chr, n1-api-client, medical-unit-conversion, n1r-document-manager publish wheels to the public R2 bucket (artifacts.n1-research.com) via their own publish workflows.
  • forge-runner ships as an image but runs as on-demand Kubernetes Jobs (one per CHR), launched by forge-sentinel.

PR-time: supply_chain_precheck plus each repo’s test/quick-check/lint workflows. In staging : automated-testing, e2e-tests, the parser/router/grouper-evals services, and data-validation-service (evaluates parser + CHR output). Production builds add a Grype CVE scan.

ArgoCD Image Updater advances image tags as new images land in ECR, which is why several ArgoCD apps read OutOfSync but Healthy (live image ahead of the git manifest). Rollback is re-pointing the image tag or reverting the PR and letting CI rebuild. Staging and production run different tags at any given time (visible in §9.4).