Kay van Dijk
Eén keer was genoeg
De README zegt het in één zin: gebouwd nadat ik één keer een sleutel lekte. Eén keer was genoeg. Daar ga ik niets moois van maken. Een geheim kwam op een plek waar het niet hoorde, en ik schreef een kleine controle zodat de saaie fouten bij de commit stoppen.
dotenv-guard doet twee dingen. Het blokkeert het committen van .env-bestanden, en het markeert een korte lijst geheime patronen in wat je op het punt staat vast te leggen. Het is een CLI en een pre-commit-hook. Het is geen volledige geheimenscanner, en dat zegt de README met opzet. Een korte lijst die ik begrijp is voor mij nuttiger dan een enorme die ik niet gelezen heb.
Scannen, of alleen wat staged is
dotenv-guard en dotenv-guard scan lopen een map door. Je kunt paden meegeven: dotenv-guard scan app config. dotenv-guard check-staged kijkt naar de git-index, de bestanden die de volgende commit vastlegt. Een bestand dat je niet met git add hebt toegevoegd, negeert de hook. Gebruik scan als je de werkmap wilt. Een schone run print ok en sluit af met 0. Een treffer sluit af met 1 en print één regel per vondst, zoals .env.local: env file, of app/settings.py:18: AWS access key.
.env.example en .env.sample mogen. .env, .env.local, .env.production en elke andere .env.* niet. Hoofdletters maken niet uit, dus .ENV wordt ook geblokkeerd. Die heb ik zien langskomen.
De patronen
Het zoekt AWS access key ids die met AKIA beginnen, en aws_secret_access_key-toewijzingen. Stripe live-sleutels, sk_live_ en rk_live_. PEM-privésleutels. GitHub-tokens: ghp_, gho_, ghu_, ghs_, ghr_ en github_pat_. WooCommerce consumer keys en secrets, ck_ en cs_. Slack-tokens, Google API-sleutels, npm-tokens. Dat is de lijst. Lijkt jouw geheim daar niet op, dan vangt dit programma het niet. Dat weet je liever dan dat je een groene "ok" als security-audit vertrouwt.
Het lopen door mappen slaat .git, node_modules, virtualenvs en build-mappen over. Alleen de eerste 1 MB van een bestand wordt gescand. Een null-byte in dat stuk betekent dat het bestand als binair wordt gezien en met rust gelaten. Ik wil niet dat het een avond een video zit te lezen, of willekeurige bytes daarin markeert.
De hook
De repo bevat .pre-commit-hooks.yaml. Vanuit een ander project wijs je pre-commit naar github.com/kaygaaf/dotenv-guard, pin je een rev die bestaat, en gebruik je hook-id dotenv-guard. De hook draait dotenv-guard check-staged. Het voorbeeld in de README gebruikt rev v0.1.0. Pin de tag die je echt hebt. Laat er geen zwevende branch in staan en noem het dan klaar.
Heb je het commando zelf geïnstalleerd en wil je de lokale binary, dan staat er in de README een repo: local hook. entry is dotenv-guard check-staged, language system, pass_filenames false, always_run true. pass_filenames false omdat het commando zelf de index leest. Het wil niet dat pre-commit een deel van de paden aangeeft en dan een staged .env mist die niet in die deelverzameling zat.
Installeren vanuit een checkout is pip install -e . waardoor dotenv-guard op je PATH komt. python -m dotenv_guard werkt ook. Tests zijn python -m unittest.
Ik lees diffs nog steeds. Dit vangt alleen de soort fout die ik al gemaakt heb: een env-bestand in de commit, of een token dat lijkt op de lijst. Het houdt me niet tegen als ik een wachtwoord in een creatief formaat in een comment plak. Dat is prima. Het programma is er zodat de voor de hand liggende fout niet twee keer gebeurt.
