- API keys
- Personal access tokens (GitHub PATs)
- SMTP credentials
- Database passwords
- Encryption keys
- OAuth secrets
- Webhook secrets (store in GitHub Secrets)
| Secret Type | Storage |
|---|---|
| GitHub PAT | GitHub Secrets (repository or org level) |
| SMTP credentials | GitHub Secrets |
| Webhook secret | GitHub Secrets |
| API keys | Environment variables + GitHub Secrets |
| LLM endpoint keys | GitHub Secrets |
CTO_WATCHDOG_GITHUB_TOKEN — Token for repo operations
CTO_WATCHDOG_SMTP_SERVER — SMTP server address
CTO_WATCHDOG_SMTP_PORT — SMTP port
CTO_WATCHDOG_SMTP_USER — SMTP username
CTO_WATCHDOG_SMTP_PASS — SMTP password
CTO_WATCHDOG_SMTP_FROM — Sender email address
CTO_WATCHDOG_LLM_API_KEY — LLM API key (if used)
CTO_WATCHDOG_WEBHOOK_SECRET — Webhook verification secret
All incoming webhooks must verify the X-Hub-Signature-256 header:
import hmac, hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)GitHub webhook IPs (if using external handler):
- 192.30.252.0/22
- 185.199.108.0/22
- 140.82.112.0/20
- 143.55.64.0/20
Minimum required scopes for the GitHub token:
repo— Full repository accessread:org— Read organization membershipworkflow— Update GitHub Actions workflowsadmin:repo_hook— Manage webhooks
- Use fine-grained PATs when possible (shorter lifetime)
- Scope tokens to specific repositories when possible
- Rotate tokens every 90 days
- Never use tokens with more permissions than needed
- Respect GitHub API rate limits (60 req/hr for unauthenticated, 5000 for authenticated)
- Implement exponential backoff on 429 responses
- Batch operations to minimize API calls
- Cache responses when possible (max 5 minutes)
- Do NOT make more than 100 API calls per minute
- Do NOT create more than 5 repositories per hour
- Do NOT delete more than 3 repositories per hour
- Do NOT force-push more than 5 times per hour
- Do NOT create more than 10 issues/PRs per minute
- Do NOT star/unstar more than 50 repos per hour
- Use conditional requests (If-Modified-Since, ETag) when polling
- Add User-Agent header to all API requests
Before any automated operation:
- Check rate limit remaining
- Verify the operation is within daily limits
- Log the operation with timestamp
- Implement rollback plan
- Verify target repository ownership
If a security incident is detected (e.g., leaked token):
- Immediately revoke the compromised token
- Audit recent operations performed with the token
- Generate incident report
- Email notification to affected account
- Update secrets in GitHub Secrets
- Review and update this policy