What
I keep secrets in a small NestJS + PostgreSQL API, scoped by project and environment, with a plain HTML dashboard on top. A zero-dependency npm CLI (envlock run <cmd>) fetches them at runtime and injects them into the subprocess’s environment, so no .env files ever touch disk.
Why
Given free reign for my MSc capstone, I decided to tackle a challenge I’d seen consistently within my professional life: managing environmental variables and secrets across a team of developers (and AI agents), preferably with a single source of truth and as few potential leakages as possible.
How
- It’s an npm workspaces monorepo: a NestJS 11 API (TypeORM, argon2, JWT) plus the published CLI,
@jfarrow777/envlock. - Secrets are encrypted with AES-256-GCM, with AAD binding each ciphertext to its
secretIdandenvironmentId, so a ciphertext can’t be swapped between secrets or environments. Keys and format are versioned, which leaves room for rotation. - PATs are 32 random bytes and only the SHA-256 hash is stored. The CLI prefers the
ENVLOCK_PATenv var over--pat, because flags end up in shell history. envlock doctordiffs the keys in.env.exampleagainst the stored keys without ever fetching values.
Status / Learnings
A DB was provisioned during the marking phase of this project, however I’ve since let it spin down and so this project is no longer live. The encryption component was the most interesting aspect of this project that I enjoyed working on. Were this to enter production, quite a bit of work would still be required to ensure secure operation, most outstanding of which would be a proper sign-up mechanism.