{"_id":"@didrod2539/envlint","name":"@didrod2539/envlint","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@didrod2539/envlint","version":"0.1.0","publishConfig":{"access":"public"},"description":"Lint .env files locally: sync against .env.example, validate syntax, detect hardcoded secrets (AWS, Stripe, GitHub, OpenAI, private keys…), and enforce an optional schema. Deterministic CLI, JSON/Markdown reports, no network — your secrets never leave the","type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"bin":{"envlint":"dist/cli.js"},"engines":{"node":">=18"},"scripts":{"build":"tsup","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","lint":"tsc --noEmit","example":"node dist/cli.js scan examples/.env.local --example examples/.env.example","prepublishOnly":"npm run build"},"keywords":["dotenv","env","environment-variables","env-validation","dotenv-lint","env-linter","env-checker","secret-detection","secret-scanner","leaked-secrets","12factor","config-validation","cli","devops"],"author":{"name":"didrod205","url":"https://github.com/didrod205"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/didrod205/envlint.git"},"bugs":{"url":"https://github.com/didrod205/envlint/issues"},"homepage":"https://github.com/didrod205/envlint#readme","dependencies":{"cac":"^6.7.14","picocolors":"^1.1.1"},"devDependencies":{"@types/node":"^22.10.0","tsup":"^8.3.5","typescript":"^5.7.2","vitest":"^2.1.8"},"gitHead":"73a2f1ee1372437e3a20d2c5000cca8c34762e55","_id":"@didrod2539/envlint@0.1.0","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-TUrYe0EVvpz0Qrs3McCMlMedlcsaEz3jbSy68tEHrf0kCKbJywLmNGMjz9FbFG9jFEMdVkt4AKwXq7tOpECt5Q==","shasum":"a55a9545dcd53fcb5a4ef5fa86b68e45ffb8a318","tarball":"https://registry.npmjs.org/@didrod2539/envlint/-/envlint-0.1.0.tgz","fileCount":15,"unpackedSize":336006,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIE7Z1MpI9k1MBHq17NBlVyAQt2tep70bA2L1O4gOko13AiEAog6dDCXaJ/6irELWDMMvi6MqsOhfMDlTjt1cQaDH3eg="}]},"_npmUser":{"name":"didrod2539","email":"ykc205@naver.com"},"directories":{},"maintainers":[{"name":"didrod2539","email":"ykc205@naver.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/envlint_0.1.0_1780284061925_0.08732377113883616"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T03:21:01.722Z","0.1.0":"2026-06-01T03:21:02.073Z","modified":"2026-06-01T03:21:02.304Z"},"maintainers":[{"name":"didrod2539","email":"ykc205@naver.com"}],"description":"Lint .env files locally: sync against .env.example, validate syntax, detect hardcoded secrets (AWS, Stripe, GitHub, OpenAI, private keys…), and enforce an optional schema. Deterministic CLI, JSON/Markdown reports, no network — your secrets never leave the","homepage":"https://github.com/didrod205/envlint#readme","keywords":["dotenv","env","environment-variables","env-validation","dotenv-lint","env-linter","env-checker","secret-detection","secret-scanner","leaked-secrets","12factor","config-validation","cli","devops"],"repository":{"type":"git","url":"git+https://github.com/didrod205/envlint.git"},"author":{"name":"didrod205","url":"https://github.com/didrod205"},"bugs":{"url":"https://github.com/didrod205/envlint/issues"},"license":"MIT","readme":"<div align=\"center\">\n\n# 🔐 envlint\n\n### Lint your `.env` files and catch leaked secrets — locally, before you commit.\n\n[![npm version](https://img.shields.io/npm/v/@didrod2539/envlint.svg?color=success)](https://www.npmjs.com/package/@didrod2539/envlint)\n[![CI](https://github.com/didrod205/envlint/actions/workflows/ci.yml/badge.svg)](https://github.com/didrod205/envlint/actions/workflows/ci.yml)\n[![node](https://img.shields.io/node/v/@didrod2539/envlint.svg)](https://www.npmjs.com/package/@didrod2539/envlint)\n[![license](https://img.shields.io/npm/l/@didrod2539/envlint.svg)](./LICENSE)\n\nA deterministic CLI that lints your `.env` files: **syncs** them against\n`.env.example`, validates **syntax & hygiene**, enforces an optional **schema**,\nand **detects hardcoded secrets** (AWS, Stripe, GitHub, OpenAI, private keys and\nmore) — with a score, A–F grade and JSON/Markdown reports. Runs 100% locally;\nyour secrets never leave your machine.\n\n</div>\n\n---\n\n## One-line summary\n\n`envlint` compares your `.env` to its example, flags missing/extra/duplicate\nkeys and value problems, and scans for **real secrets accidentally committed** —\nall offline, no API key, no server.\n\n## Why this project exists\n\n`.env` files are where teams quietly hurt themselves:\n\n- A teammate adds `STRIPE_SECRET_KEY` but forgets `.env.example`, so everyone\n  else's local build breaks and prod is missing a variable at runtime.\n- Someone pastes a **real** AWS or Stripe key into `.env` and it gets committed —\n  now it's in git history, and rotating it is a fire drill.\n- Values drift: a `PORT` that isn't a number, a URL with an unquoted space that\n  silently truncates, a placeholder `changeme` shipped to staging.\n\nThese are mechanical, high-stakes problems that belong in a **pre-commit hook or\nCI gate**, not in a code review someone skims. And because `.env` is sensitive,\nyou can't just paste it into an LLM. envlint is the deterministic, local check.\n\n## Key features\n\n- 🔄 **Sync against `.env.example`** — missing keys, extra/undocumented keys.\n- 🔐 **Secret detection** — provider patterns (AWS, Stripe, GitHub, Google,\n  OpenAI, Anthropic, Slack, Twilio, SendGrid, npm, JWTs, private keys) **plus** a\n  Shannon-entropy fallback for opaque tokens. Placeholders are ignored.\n- 🧹 **Syntax & hygiene** — duplicate keys, invalid names, empty values,\n  unquoted values with spaces, trailing whitespace, lowercase keys, placeholders.\n- 📐 **Optional schema** — `type` (string/number/boolean/url/email/port),\n  `enum`, `pattern` per key.\n- 📊 **Score + A–F grade**, per file and overall; secrets weigh heaviest.\n- 📄 **JSON & Markdown export**, colored console output, **CI gate** exit codes.\n- ⚙️ **Config file**, per-rule severities, ignore lists.\n- 🔒 **Zero network.** Secrets are masked in output and never transmitted.\n\n## Install\n\n```bash\n# run without installing\nnpx @didrod2539/envlint scan .env\n\n# or install\nnpm install -g @didrod2539/envlint    # global CLI (provides `envlint`)\nnpm install -D @didrod2539/envlint    # project dev-dependency (for CI / hooks)\n```\n\nNode ≥ 18. ESM + CJS + TypeScript types.\n\n## Quick start\n\n```bash\nenvlint scan .env\n```\n\n```\n.env  0/100 (F)  10 keys vs .env.example\n  ✗ Missing key \"SESSION_TIMEOUT\" (present in .env.example)\n  ⚠ Key \"EXTRA_DEBUG\" is not in .env.example:21\n  ✗ Duplicate key \"ENABLE_SIGNUP\" (lines 19, 20):20\n  ⚠ Unquoted value with spaces for \"DATABASE_URL\" (line 8):8\n  ✗ Possible JSON Web Token in \"JWT_SECRET\" (line 11):11\n  ✗ Possible Stripe Secret Key in \"STRIPE_SECRET_KEY\" (line 14):14\n  ✗ Possible AWS Access Key ID in \"AWS_ACCESS_KEY_ID\" (line 15):15\n\nOverall  0/100 (F)  1 file(s), 10 key(s),  3 secret(s) , 8 error(s), 3 warning(s), 2 info\n```\n\n(envlint auto-finds `.env.example` / `.env.sample` / `.env.template` next to your file.)\n\n## CLI usage\n\n```bash\nenvlint scan [...targets]     # lint .env files or directories\nenvlint report <input.json>   # re-render a saved JSON report as Markdown\nenvlint init                  # scaffold envlint.config.json (with a schema)\nenvlint --help\nenvlint --version\n```\n\n`scan` options:\n\n| Option | Description |\n| --- | --- |\n| `--config <file>` | Path to a config file (otherwise auto-detected) |\n| `--example <file>` | Example/schema file to compare against |\n| `--no-secrets` | Disable secret scanning |\n| `--json <file>` | Write a JSON report |\n| `--md <file>` | Write a Markdown report |\n| `--min-score <n>` | Exit non-zero if the overall score < n (CI gate) |\n| `--quiet` | Hide info-level issues in the console |\n\nPointed at a directory, `scan` finds `.env`, `.env.local`, `.env.production`,\netc. (skipping `*.example`/`*.sample`/`*.template`).\n\n## Example result\n\nFull reports for the bundled sample files are in\n[`examples/sample-report.md`](./examples/sample-report.md) and\n[`examples/sample-report.json`](./examples/sample-report.json).\n\n> 📸 _Screenshot / demo GIF placeholder:_ `./docs/screenshot.png` — record the\n> terminal running `npx @didrod2539/envlint scan examples/.env.local`.\n\n## Configuration\n\nCreate `envlint.config.json` (or run `envlint init`):\n\n```json\n{\n  \"example\": \".env.example\",\n  \"scanSecrets\": true,\n  \"entropyThreshold\": 4.0,\n  \"entropyMinLength\": 20,\n  \"minScore\": 90,\n  \"allowEmpty\": [\"OPTIONAL_FLAG\"],\n  \"ignoreKeys\": [\"LEGACY_*\"],\n  \"disableRules\": [],\n  \"ruleSeverity\": { \"lowercase-key\": \"warning\" },\n  \"schema\": {\n    \"PORT\": { \"type\": \"port\" },\n    \"NODE_ENV\": { \"enum\": [\"development\", \"production\", \"test\"] },\n    \"DATABASE_URL\": { \"type\": \"url\" }\n  }\n}\n```\n\n| Field | Meaning |\n| --- | --- |\n| `example` | Example/schema file (auto-detected if null) |\n| `scanSecrets` | Enable provider/entropy secret scanning |\n| `entropyThreshold` / `entropyMinLength` | Tune the generic high-entropy check |\n| `minScore` | CI gate threshold (overridable with `--min-score`) |\n| `allowEmpty` | Keys allowed to have empty values |\n| `ignoreKeys` | Keys to skip — exact, or trailing-`*` prefix wildcard |\n| `disableRules` | Rule ids to turn off |\n| `ruleSeverity` | Override severity per rule id |\n| `schema` | Optional per-key `type` / `enum` / `pattern` constraints |\n\nRule ids: `missing-keys`, `extra-keys`, `duplicate-key`, `invalid-key`,\n`empty-value`, `placeholder-value`, `unquoted-spaces`, `trailing-whitespace`,\n`lowercase-key`, `secret-detected`, `schema-*`.\n\n## Real-world use cases\n\n1. **Block secret leaks in a pre-commit hook.** Add `envlint scan .env\n   --min-score 100` (or wire it into [husky]/lint-staged). A real AWS/Stripe key\n   in `.env` fails the commit before it ever reaches git history.\n2. **Keep `.env.example` honest in CI.** Run `envlint scan .env.ci\n   --example .env.example`. A PR that adds an env var without documenting it in\n   the example fails the build, so onboarding never breaks.\n3. **Audit a config you inherited.** `envlint scan . --md audit.md` profiles\n   every `.env*` file in a repo and produces a shareable report of what's\n   missing, malformed, or dangerously hardcoded.\n\n## Programmatic API\n\n```ts\nimport { analyze, buildReport, toMarkdown } from \"@didrod2539/envlint\";\n\nconst file = analyze({ source: \".env\", content, reference: { source: \".env.example\", content: ex } });\nconsole.log(file.score, file.secrets, file.issues);\n\nconst report = buildReport([file], { version: \"0.1.0\" });\nawait fs.writeFile(\"report.md\", toMarkdown(report));\n```\n\n## Roadmap\n\n- A bundled pre-commit hook / `husky` recipe and a GitHub Action.\n- `--fix` to sync missing keys into `.env` and quote unquoted values.\n- More provider secret patterns (Azure, GCP service accounts, DigitalOcean…).\n- `.env.vault` / multi-environment diffing (`.env` vs `.env.production`).\n- Allowlist file for known-safe values (e.g. test fixtures).\n- Baseline mode to ignore pre-existing findings and only fail on new ones.\n\n## FAQ\n\n**Does envlint send my `.env` anywhere?**\nNo. It runs entirely on your machine — no API key, no telemetry, no uploads, no\nnetwork calls. Detected secrets are **masked** in all output.\n\n**How does secret detection work?**\nA curated set of provider regexes (AWS, Stripe, GitHub, OpenAI, etc.) plus a\nShannon-entropy fallback for long, random, opaque tokens. Obvious placeholders\n(`your-key-here`, `changeme`, `<token>`) are deliberately ignored. See\n`src/secrets.ts`.\n\n**Won't the entropy check have false positives?**\nIt's conservative (length + character-class + entropy threshold, all tunable via\nconfig), and you can `--no-secrets` or `ignoreKeys` anything. Prefer a missed\nedge case over noise.\n\n**Is it safe to keep example secrets in the repo?**\nYes — that's the point of `.env.example`: it should contain only placeholders.\nenvlint flags when a *real-looking* secret appears so the example stays clean.\n\n**Does it work with my framework?**\nAny project using dotenv-style files: Node, Next.js, Vite, Rails, Django, Docker\n`--env-file`, etc. It parses the common `.env` grammar (quotes, `export`,\ncomments).\n\n**Is the score official?**\nNo — it's a transparent metric (severity-weighted penalties, with a heavy extra\npenalty per detected secret). Use it to track and gate. See `src/score.ts`.\n\n## Contributing\n\nContributions welcome! Each check is a small, self-contained rule in\n`src/rules/`, and secret patterns are a declarative table in `src/secrets.ts`.\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) and the\n[Code of Conduct](./CODE_OF_CONDUCT.md).\n\n```bash\ngit clone https://github.com/didrod205/envlint.git\ncd envlint\nnpm install\nnpm test\nnpm run build\nnode dist/cli.js scan examples/.env.local --example examples/.env.example\n```\n\n## License\n\n[MIT](./LICENSE) © envlint contributors\n\n## 💖 Sponsor\n\nenvlint is free, MIT-licensed, and built in spare time. If it stopped a secret\nfrom hitting your git history, please consider supporting it:\n\n- ⭐ **Star this repo** — free, and it helps others find it.\n- 🍋 **[Sponsor via Lemon Squeezy](https://elab-studio.lemonsqueezy.com/checkout/buy/5d059b89-51d0-456b-b33a-ed56994f7010)** — one-time or recurring.\n\n**Where your support goes:** more secret patterns, a pre-commit hook + GitHub\nAction, a `--fix` mode, multi-environment diffing, and fast issue responses.\n","readmeFilename":"README.md","_rev":"1-b3a4f516b9d99454d6941b07a1a3d111"}