This is a portfolio / demonstration project. It is designed to run locally or in CI with synthetic data only. It is not hardened for production exposure on the public internet. That said, security was treated as a first-class concern and the repository is built to pass an audit on the things that matter for a public repo: no secrets, no real data, minimal-privilege CI, and dependency/secret/image scanning.
| Value | Status |
|---|---|
JWT_SECRET=dev-only-secret-change-me |
Not a secret. A clearly-labelled local-only placeholder. Real deployments must inject a strong secret via the environment. |
password123 (synthetic users) |
Not a secret. A shared password for deterministic, fake users. No real account uses it. |
POSTGRES_PASSWORD=telco |
Not a secret. Local-only database credential for the compose stack. |
.env |
Never committed. Git-ignored; only .env.example (placeholders) is tracked. |
No real customer data exists anywhere in this project — all data is generated by a deterministic synthetic generator.
- No secrets in git.
.gitignoreexcludes.envand all real env files;.gitleaks.toml+ a CI secret-scanning job guard against accidental commits. - Dependency scanning.
npm audit(production deps), GitHub Dependency Review on PRs, and Dependabot updates (npm, GitHub Actions, Docker). - SAST. CodeQL (
javascript-typescript) on push/PR and weekly. - Container scanning. Trivy scans the API image for HIGH/CRITICAL CVEs.
- Least-privilege CI. Workflows default to
contents: read; jobs elevate only what they need (e.g. CodeQL'ssecurity-events: write). Checkout usespersist-credentials: false. - Hardened runtime. The API container runs as a non-root user (
USER node), uses Helmet for HTTP security headers, validates all input with Zod, and redacts secrets (password, tokens,authorization) from logs. - AuthN/AuthZ. JWT-based auth; a customer can only access their own resources (cross-customer access returns 403).
- Idempotent payments. A
UNIQUEidempotency key prevents double-charges, correct even under concurrent retries.
These are intentional choices for a performance lab, called out so they are not mistaken for oversights:
- Fast password hashing (SHA-256), not bcrypt/argon2. A slow KDF would
dominate login latency and the load test would measure the hash, not the
system. A real product MUST use a slow, salted KDF. See
apps/api/src/security/password.ts. - Fault injection endpoint (
/admin/faults). Powerful and intentionally unauthenticated for demo convenience, but only mounted whenNODE_ENV !== 'production'andENABLE_FAULTS=true. It cannot exist in a production build, auto-expires every rule, and audits every activation. - Permissive CORS (
origin: true) and anonymous Grafana. Local-demo conveniences. Both must be locked down for any real deployment.
- Inject a strong
JWT_SECRETand real database credentials via a secrets manager — never the defaults. - Set
NODE_ENV=productionandENABLE_FAULTS=false(the/admin/faultssurface disappears). - Replace the fast password hash with argon2id/bcrypt.
- Restrict CORS to known origins; put Grafana behind real auth.
- Terminate TLS at a reverse proxy; do not expose Postgres/Redis ports.
This is a personal demo repository. If you spot something, please open a GitHub issue (for non-sensitive findings) or contact the maintainer directly for anything sensitive. There is no production system at risk.