This document describes the security measures in place to protect sensitive data.
Never commit to git:
.envfiles (all variants:.env,.env.local,.env.production, etc.)- API keys and tokens (FIRECRAWL_API_KEY, GEMINI_API_KEY, TMDB_BEARER_TOKEN)
- Private keys and certificates (
*.pem,*.key) - Database credentials (PGPASSWORD, connection strings)
- Backup files that may contain secrets (
worktree-backups*,*.patch) - Local scrape/session artifacts (for example
data/tiktok_cookies.json) - Operational evidence captures under
docs/ai/evidence/
Safe to commit:
.env.examplewith placeholder values- Environment variable names (references only)
- Documentation with
REDACTEDor masked values - A tracked
docs/ai/evidence/README.mdthat documents the local-only evidence policy
Excludes sensitive files from being tracked:
.env
.env.*
!.env.example
keys/
*.pem
worktree-backups*
.claude/hooks/before-bash.md blocks dangerous commands before execution:
git add .env→ Blocked (staging secrets)git add keys/→ Blocked (staging credentials)git add **/*.pem→ Blocked (staging private keys)git commit -a→ Warning (reviewgit statusfirst)echo $API_KEY→ Blocked (exposing secrets in logs)
.github/workflows/secret-scan.yml scans all commits with Gitleaks:
- Runs on: Pull requests + pushes to main
- Detects: Hardcoded API keys, tokens, credentials
- Fails build: If secrets found (prevents merge)
.gitleaks.toml defines custom rules and allowlists:
- Custom patterns for FIRECRAWL, GEMINI, TMDB keys
- Allowlist for .env.example placeholders
- Allowlist for environment variable references in code
If a secret is accidentally committed:
# Check if key was pushed to remote
git log --all -S "suspected-key-pattern" --oneline
# Check current remotes
git remote -v- FIRECRAWL: Regenerate at https://firecrawl.dev/account
- Gemini: Regenerate at https://aistudio.google.com/app/apikey
- TMDB: Regenerate at https://www.themoviedb.org/settings/api
# Use BFG Repo-Cleaner or git-filter-repo (not git-filter-branch)
# See: https://rtyley.github.io/bfg-repo-cleaner/# Only if absolutely necessary and coordinated with team
git push --force-with-lease origin mainWorktree and patch backups may contain secrets:
# Secure existing backups
chmod 700 ~/worktree-backups-PRIVATE
chmod 600 ~/worktree-backups-PRIVATE/*
# Review before archiving
rg -n "API_KEY|SECRET|TOKEN" ~/worktree-backups-PRIVATE/
# Delete if no longer needed
rm -rf ~/worktree-backups-PRIVATE/If a secret leak is detected:
- Do NOT panic push fixes - This can make things worse
- Rotate the exposed key immediately (see Key Rotation above)
- Verify exposure scope: Local only vs. pushed to GitHub
- If pushed: Clean history before rotating (rotating first alerts attackers)
- Document the incident: What happened, what was exposed, how fixed
- Always use
.envfor local secrets (never commit) - Use
.env.examplefor documentation (placeholder values only) - Run
git statusbeforegit commit -a - Review diffs before pushing:
git diff origin/main..HEAD
- Check for hardcoded credentials in PR diffs
- Verify
.envis not in changed files - Watch for backup files being added (
.patch,.tar.gzwith secrets)
- Use GitHub Secrets for sensitive values in workflows
- Never
echosecret values in CI logs - Use masked environment variables:
${{ secrets.API_KEY }}
GitHub branch protection for main enforces:
- Required status checks:
test,gitleaks - Strict branch updates: PRs must be up-to-date with base branch
- Admin enforcement: DISABLED (admins can bypass for emergency fixes)
Always Required (Blocking):
test(ci.yml) - Unit tests, schema validation, lintinggitleaks(secret-scan.yml) - Secret scanning (incremental on PRs, full history on push/schedule)
Conditional (Not Required):
generate-repo-map(repo_map.yml) - Runs only when Python files, migrations, or repo config changes- Auto-commits documentation updates back to PR when triggered
- Not blocking because it's a documentation enhancement, not a safety gate
View current settings:
gh api repos/therealityreport/trr-backend/branches/main/protection | jq '.required_status_checks'Update required checks:
gh api -X PATCH repos/therealityreport/trr-backend/branches/main/protection/required_status_checks \
--input - <<'EOF'
{
"strict": true,
"contexts": ["test", "gitleaks"]
}
EOFAdmin enforcement (current: disabled):
# Enable (stricter - admins must follow rules)
gh api -X PUT repos/therealityreport/trr-backend/branches/main/protection/enforce_admins
# Disable (current - allow emergency bypass)
gh api -X DELETE repos/therealityreport/trr-backend/branches/main/protection/enforce_admins"Required status check missing":
- Ensure check name exactly matches job name in workflow YAML
- Only
testandgitleaksare required (they run on all PRs) generate-repo-mapis optional and only runs when relevant paths change
"PR blocked but all checks passed":
strict: truerequires PR branch to be up-to-date with main- Solution:
git pull origin mainand push again
"Check never runs on PR":
testandgitleaksshould always run on all PRsgenerate-repo-maponly runs when Python/migration/repo-config files change (expected behavior)