CI/CD & Developer Tooling
OpenInsure uses a CircleCI-native CI/CD pipeline. GitHub is used exclusively as a version-control host — there is no GitHub Actions integration and no GitHub VCS link in CircleCI. All automated quality enforcement, testing, security scanning, and deployment runs in CircleCI.
CircleCI project slug: circleci/HW2RogsnMHUCC7jGBX9nec/Fuwa3GUWKCGnbJuUY6MJps
When adding environment variables via the CircleCI API use:
POST /api/v2/project/circleci/<org>/<project>/envvar
Not the github/<org>/<repo> path — that returns 404.
Pipeline Overview
The .circleci/config.yml defines five sequential jobs that form the full quality gate:
quick-checks → lint → test → quality-gate → security-scan
↘
(on tag) deploy
Additionally a renovate-deps job runs on a weekly schedule (Monday 06:00 ET) to open dependency update PRs via Renovate.
Job: quick-checks
Fast, cheap validation that runs first to catch obvious problems:
| Step | Command | Purpose |
|---|---|---|
| Type check | tsp compile typespec/ | Validate TypeSpec API spec |
| Dead code | pnpm exec knip --reporter compact | Detect unused exports/deps |
| Workspace invariants | pnpm exec sherif | Verify pnpm workspace consistency |
| Unit smoke | pnpm --filter @openinsure/types test | Fast type-level sanity check |
Job: lint
Code quality and formatting:
| Step | Command | Purpose |
|---|---|---|
| Biome | biome check . | Lint + format all TypeScript/TSX |
| Oxlint | pnpm turbo oxlint | Secondary linter pass |
Job: test
Full test suite with coverage reporting:
pnpm turbo test
Coverage is uploaded to Codecov after every green test run (requires CODECOV_TOKEN env var).
Job: quality-gate
Integration and end-to-end validation:
pnpm turbo build— verify all packages build cleanly- Database migration dry-run
- Release smoke tests (
scripts/release-smoke.sh) - SLO guardrail checks (
scripts/check-slo-guardrails.sh)
Job: security-scan
Supply chain and dependency security:
| Step | Tool | Purpose |
|---|---|---|
| Audit | pnpm audit --audit-level=high | npm advisory database |
| Supply chain | Socket.dev CLI | Deep package provenance + threat intel |
Requires SOCKET_SECURITY_API_KEY env var. Enabled scopes: diff-scans, full-scans, packages, dependencies, triage, threat-feed, security-policy, fixes.
Job: deploy
Triggered on git tags (v*):
wrangler deploy # All workers in dependency order
Workers deploy in this order: oi-sys-auth → oi-sys-api → frontends.
Jobs: deploy-finance-portal and deploy-compliance-portal
Each new portal has a dedicated deploy job that runs on master after build, test, lint, and typecheck pass. Both use path-based change detection — they only deploy when files in their respective apps/ directory or shared packages (auth-hooks, config, db, react-query, types, ui) change.
deploy-finance-portal:
steps:
- check-paths:
pattern: '^(apps/finance-portal/|packages/(auth-hooks|config|db|react-query|types|ui)/)'
- run: cd apps/finance-portal && npx opennextjs-cloudflare deploy -- --keep-vars
deploy-compliance-portal:
steps:
- check-paths:
pattern: '^(apps/compliance-portal/|packages/(auth-hooks|config|db|react-query|types|ui)/)'
- run: cd apps/compliance-portal && npx opennextjs-cloudflare deploy -- --keep-vars
Both use --keep-vars so Cloudflare retains existing secrets (FINANCE_JWT_SECRET, COMPLIANCE_JWT_SECRET) set via wrangler secret put.
Developer Tooling
Knip — Dead Code Detection
Knip scans every workspace for unused exports, files, and dependencies.
pnpm knip
# or with compact output:
pnpm exec knip --reporter compact
Knip is configured in knip.json at the repo root. It's advisory in CI (|| true) — findings are surfaced as warnings, not failures, until the initial cleanup pass is complete.
What Knip catches:
- Exported functions/types that are never imported
- Dependencies declared in
package.jsonbut never used - Files that are not reachable from entry points
Sherif — Workspace Invariants
Sherif enforces consistency rules across pnpm workspaces — no syncpack, no custom scripts.
pnpm sherif
What Sherif enforces:
- All workspace packages that share a dependency use the same version
- No duplicate
package.jsonfields that conflict across workspaces - Package names match their directory structure
Sherif was chosen over Syncpack because Syncpack v13 crashes on Node.js v25+. Sherif is zero-config for pnpm workspaces and works correctly on all Node.js versions.
OpenTofu — Infrastructure as Code
Azure AD resources (the Microsoft SSO app registration for oi-sys-auth) are managed with OpenTofu (the open-source Terraform fork) using the azuread provider.
infra/azure-auth/
├── main.tf # azuread_application, azuread_service_principal
├── variables.tf # tenant_id, client_id, redirect_uris
├── outputs.tf # application_id, client_secret
└── terraform.tfvars # NOT committed — contains Azure credentials
The Azure app registration "OpenInsure Auth" is single-tenant (AzureADMyOrg), restricted to the mhcis.com tenant (ebd58a52-c818-4230-b150-348ae1e17975). Infrastructure changes are applied manually by a platform engineer with Azure Owner rights — there is no automated tofu apply in CI at this time.
# Plan changes
cd infra/azure-auth
tofu init
tofu plan
# Apply (requires Azure credentials in environment)
tofu apply
terraform.tfvars and any .tfstate files contain Azure client secrets and must never be committed to source control. The .gitignore at the repo root excludes *.tfvars and *.tfstate.
Renovate — Automated Dependency Updates
Renovate runs weekly (Monday 06:00 ET) via CircleCI and opens PRs for dependency updates. Requires RENOVATE_TOKEN env var (GitHub PAT with repo scope).
Auto-merge policy (configured in renovate.json):
| Update type | Policy |
|---|---|
| Patch versions | Auto-merge |
| Security vulnerabilities | Auto-merge |
| Next.js / React major | Manual review |
| Cloudflare Workers | Manual review |
| Drizzle ORM | Manual review |
| Turbo | Manual review |
| TanStack (all) | Grouped, manual review |
@radix-ui/* | Grouped, manual review |
Internal @openinsure/* packages are excluded from Renovate.
EAS Mobile Deploy
The deploy-mobile CircleCI job triggers on merge to master after all quality gates pass. It runs eas workflow:run .eas/workflows/production.yml which:
- Fingerprints native code for iOS and Android
- Checks if a compatible build already exists
- If native code changed → full EAS build + App Store / Play Store submit
- If only JS changed → OTA update to production channel (minutes, no store review)
Required env var: EXPO_CIRCLECI_ACCESS_TOKEN (mapped to EXPO_TOKEN at runtime). Generate at expo.dev → Account Settings → Access Tokens.
Codecov — Coverage Tracking
Coverage reports are uploaded after every passing test run. Reports are uploaded from the test CI job using codecov-action.
To add coverage locally:
pnpm turbo test -- --coverage
Requires CODECOV_TOKEN set in CircleCI project environment variables.
Socket.dev — Supply Chain Security
Socket.dev performs deep analysis of every npm package in the dependency graph — beyond the advisory database. It detects:
- Typosquatting — packages with names similar to popular ones
- Malicious code injection — packages that execute code at install time
- Dependency confusion — private package names published to the public registry
- Unmaintained packages — packages with no recent activity or abandoned by their author
- Protestware / env var exfiltration — behavioral analysis of install/postinstall scripts
Required CircleCI Environment Variables
| Variable | Purpose | Where to get |
|---|---|---|
CLOUDFLARE_API_TOKEN | Worker deployments | Cloudflare dashboard → API Tokens |
FLY_API_TOKEN | Fly.io runners/services | fly auth token |
RENOVATE_TOKEN | GitHub PAT for Renovate PRs | github.com/settings/tokens |
CODECOV_TOKEN | Coverage upload | app.codecov.io |
SOCKET_SECURITY_API_KEY | Supply chain scan | socket.dev dashboard |
TURBO_TOKEN + TURBO_TEAM | Turbo remote cache | vercel.com/account/tokens |
PD_VERCEL_TOKEN | Deploy pushdown.ai to Vercel | Vercel dashboard → pushdown team |
DATABASE_URL | Migration jobs | PlanetScale dashboard (app.planetscale.com) |
JWT_SECRET | API test suite + admin/UW portal | Generate: openssl rand -hex 32 |
FINANCE_JWT_SECRET | Finance portal auth | wrangler secret put FINANCE_JWT_SECRET --name oi-sys-finance |
COMPLIANCE_JWT_SECRET | Compliance portal auth | wrangler secret put COMPLIANCE_JWT_SECRET --name oi-sys-compliance |
Sanctions API credentials are Worker secrets, not CI env vars. OPENSANCTIONS_API_URL and
OPENSANCTIONS_API_KEY are set via wrangler secret put on oi-sys-api. During CI,
OPENSANCTIONS_API_URL is intentionally absent — the static SDN fallback activates automatically
and all sanctions unit tests pass without a live endpoint.
All CI credentials must be rotated before any production deployment. Dev credentials were set
during initial setup. See the PRE-LAUNCH REMINDER note in CLAUDE.md.
Local Quality Gate
Run the same checks locally before pushing:
# Type safety
pnpm exec tsc --noEmit
# Lint + format
biome check --write .
# Dead code audit
pnpm knip
# Workspace invariants
pnpm sherif
# Full test suite
pnpm turbo test
# Build verification
pnpm turbo build
Or run everything at once with the gauntlet script:
pnpm gauntlet
Commit Conventions
Commits follow the Conventional Commits spec, enforced by commitlint:
feat(claims): add reserve change audit trail
fix(billing): correct invoice balance calculation
chore(deps): bump drizzle-orm to 0.45.1
Scopes should match the affected package or app (e.g., api, billing, claims, portal).
Quickstart
Set up a local dev environment from scratch.
Architecture
Understand the edge/origin split and data flow.