docs(#4440): stop telling agents to grep .env files the secret guard denies (#4500)

* docs(#4440): stop telling agents to grep .env files the secret guard denies

verification-patterns.md's <environment_config> and user-setup.md's
three per-service Verification examples documented reading .env/.env.local
directly via grep. Every covered runtime's secret-read guard denies
that (Claude Code deny-rules since #768/v1.4.0; the always-on
gsd-secret-read-guard hook since #4236/#4221 in 1.13.0) -- verified by
piping each documented command through the shipped hook.

verification-patterns.md now checks the environment (printenv) instead
of the file, with a case statement replacing a broken grep -v
alternation (grep's BRE `|` is literal, so the old placeholder filter
matched nothing -- PLACEHOLDER/TODO_fill values passed the "substantive"
check as real). Verified under sh (dash) against real/placeholder/empty/
unset values. Existence check ([ -f ".env" ] || [ -f ".env.local" ])
is untouched -- it was never denied.

user-setup.md's three grep <SERVICE> .env.local lines are removed
outright rather than swapped for printenv: those examples describe a
Next.js shape where the framework loads .env.local at runtime without
exporting it to the shell, so a printenv substitute would wrongly
report "not set" on a correctly configured project. Each block's
existing service-level check (build/webhook/connection/email test)
already verifies the setup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(#4440): changeset for the secret-guard verification-examples fix

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(#4440): backfill changeset PR number

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-09-07 14:10:08 -04:00
committed by GitHub
parent e38d246015
commit c3a18b5ba0
3 changed files with 22 additions and 13 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 4500
---
**Verification examples no longer tell agents to grep .env files** — `verification-patterns.md` and `user-setup.md` documented reading `.env`/`.env.local` directly to verify environment variables, which every covered runtime's secret-read guard denies. The environment-variable checks now read the environment (`printenv`) instead of the file, and a broken placeholder-filter regex (`grep -v "a|b|c"`, where `|` is a literal BRE character) is replaced with a working case-insensitive check. (#4440)

View File

@@ -309,14 +309,17 @@ grep -r "$hook_name()" src/ --include="*.tsx" --include="*.ts" | grep -v "$hook_
# .env file exists
[ -f ".env" ] || [ -f ".env.local" ]
# Required variable is defined
grep -E "^$VAR_NAME=" .env .env.local 2>/dev/null
# Required variable is defined (in the environment: dotenv/direnv/the framework has loaded it)
printenv "$VAR_NAME" >/dev/null
```
**Substantive check:**
```bash
# Variable has actual value (not placeholder)
grep -E "^$VAR_NAME=.+" .env .env.local 2>/dev/null | grep -v "your-.*-here|xxx|placeholder|TODO" -i
# Variable has an actual value (not a placeholder) -- tests the shape, never prints the value;
# exit 0 = real value, exit 1 = missing or placeholder (case-insensitive)
v=$(printenv "$VAR_NAME"); case "$(printf %s "$v" | tr '[:upper:]' '[:lower:]')" in
""|*your-*-here*|*xxx*|*placeholder*|*todo*) exit 1;;
esac
# Value looks valid for type:
# - URLs should start with http
@@ -324,6 +327,16 @@ grep -E "^$VAR_NAME=.+" .env .env.local 2>/dev/null | grep -v "your-.*-here|xxx|
# - Booleans should be true/false
```
When the variable is not present in the agent's own environment (a framework that loads
`.env.local` itself at runtime does not export it to the shell that runs these checks),
ask the user to confirm it is set rather than reading `.env` directly. Variable NAMES can
still be checked against `.env.example`, which the secret-read guard exempts from its
protected-file patterns.
One guard-matching note worth knowing when auditing docs for `.env` mentions: the guard
treats a grep PATTERN whose last path segment is a secret file name as a file operand, so
`grep -n "\.env" file.md` is denied while `grep -n "\.env\b" file.md` is allowed.
**Stub patterns specific to env:**
```bash
# RED FLAGS - These are stubs:

View File

@@ -171,9 +171,6 @@ Use the webhook signing secret from CLI output (starts with `whsec_`).
After completing setup:
```bash
# Check env vars are set
grep STRIPE .env.local
# Verify build passes
npm run build
@@ -232,9 +229,6 @@ Complete these items for Supabase Auth to function.
After completing setup:
```bash
# Check env vars
grep SUPABASE .env.local
# Verify connection (run in project directory)
npx supabase status
```
@@ -285,9 +279,6 @@ Complete these items for SendGrid email to function.
After completing setup:
```bash
# Check env var
grep SENDGRID .env.local
# Test email sending (replace with your test email)
curl -X POST http://localhost:3000/api/test-email \
-H "Content-Type: application/json" \