diff --git a/.gitignore b/.gitignore index f3d0b0b..95d6792 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,11 @@ salary_data.json *_BehavioralReport.pdf linkedin_Profile.pdf +# Secrets. A portal skill generated by /add-portal may need an API token for a +# fetching service; the .env holding it must never be committed. +.env +.env.* + # Personal photos and signatures *.jpg *.jpeg diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c6f41..e38668b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,14 @@ per-file diff commands. ### Fixed +- **A `.env` was committable** (`.gitignore`, `tools/security_guards.py`). `/add-portal` + can generate a skill for a portal that only returns usable content through a paid + fetching service, and such a skill reads an API token from the environment - but + nothing stopped the `.env` holding that token from being committed. No shipped portal + needs a credential, so upstream never hit this; a fork whose generated portals do hit + it immediately. `.env` and `.env.*` are now ignored and pinned in + `REQUIRED_IGNORE_RULES`, so the guard fails if the rule is ever dropped. + - **The robots gate did not fail closed** (`tools/robots_check.py`, #277). Found by an adversarial review run over the merged file, not by inspection. Both cases are pinned in `tests/test_robots_check.py` as FAIL-OPEN REGRESSIONs: diff --git a/tools/security_guards.py b/tools/security_guards.py index 69c9d09..03fcf6d 100644 --- a/tools/security_guards.py +++ b/tools/security_guards.py @@ -70,6 +70,11 @@ REQUIRED_IGNORE_RULES = [ "gmail_sync/", "reports/", "upskill/*.md", + # Not personal data but the same failure mode: /add-portal can generate a + # skill for a portal that only returns usable content through a paid + # fetching service, and that skill reads an API token from the environment. + ".env", + ".env.*", ] # Negation (re-include) rules the template legitimately ships. .gitignore is