# DRE Credential Audit — Jul 8, 2026

Full audit of every key, token, and password across the system.

## Credential Inventory

| # | Credential | Location | Type | Test Method | Status |
|---|-----------|----------|------|-------------|--------|
| 1 | FIRECRAWL_API_KEY | ~/.hermes/.env | API Key | POST to api.firecrawl.dev/v1/search | ✅ |
| 2 | CLOUDFLARE_API_TOKEN | ~/.hermes/.env | API Token | GET cloudflare.com/client/v4/user/tokens/verify | ✅ |
| 3 | admin-ai api_key | config.yaml (admin-ai provider) | API Key | POST to admin-ai /v1/chat/completions | ✅ |
| 4 | PG_DATABASE_PASSWORD | /root/docker/twenty/.env | DB Password | docker exec psql SELECT 1 | ✅ |
| 5 | ENCRYPTION_KEY | /root/docker/twenty/.env | Encryption Key | (validated by container health) | ✅ |
| 6 | MYSQL_PASS (Apex DB) | config.yaml (mcp_servers.mysql.env) | DB Password | mysql SELECT 1 via SSH tunnel | ✅ |
| 7 | g@germainebrown.com IMAP | ~/.config/himalaya/g-germainebrown.pass | IMAP Password | imaplib LOGIN | ✅ |
| 8 | shonuff@germainebrown.com IMAP | ~/.config/himalaya/shonuff.pass | IMAP Password | imaplib LOGIN | ✅ |
| 9 | iCloud calendar password | ~/.config/himalaya/g-germainebrown-icloud-calendar.pass | App-Specific | imaplib LOGIN to p02-imap.mail.me.com | ❌ Expired — replaced Jul 8 |
| 10 | DRE email IMAP (dre@ + collections@) | (no file — used inline in dre-mail-poller.py) | IMAP Password | imaplib LOGIN to heracles.mxrouting.net | ✅ |

## Audit Pattern (Reproducible)

### Step 1: Inventory
```bash
# Check .env
grep -v "^#\|^$" /root/.hermes/.env | cut -d= -f1
# Check .config password files
find /root/.config -name "*.pass" -o -name "*.pwd" -o -name "*.token"
# Check docker .env files
find /root/docker -name ".env" -exec basename {} \; 2>/dev/null
# Check config.yaml
grep -E "api_key|password|secret|token|_key|_pass" /root/.hermes/config.yaml | grep -v "skipped\|disabled\|cron_mode"
```

### Step 2: Test
```bash
# Firecrawl
curl -s -w "\nHTTP:%{http_code}" -X POST "https://api.firecrawl.dev/v1/search" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"test","limit":1}' | tail -1

# Cloudflare
curl -s -w "\nHTTP:%{http_code}" -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
  -H "Authorization: Bearer $TOKEN" | tail -1

# admin-ai
curl -s -w "\nHTTP:%{http_code}" "https://admin-ai.itpropartner.com/v1/chat/completions" \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"model":"deepseek-chat","messages":[{"role":"user","content":"ping"}],"max_tokens":2}' | grep -o "HTTP:[0-9]*"

# IMAP password files
python3 -c "
import imaplib, ssl
with open('/root/.config/himalaya/FILE.pass') as f: pw = f.read().strip()
ctx = ssl.create_default_context()
s = imaplib.IMAP4_SSL('HOST', 993, ssl_context=ctx, timeout=10)
s.login('user@domain.com', pw)
print('LOGIN OK')
s.logout()
"

# PostgreSQL via docker
docker exec twenty-db-1 psql -U postgres -d default -c "SELECT 1 AS test"

# MySQL via tunnel
mysql -h 127.0.0.1 -P 33060 -u USER -pPASS --skip-ssl -e "SELECT 1 AS test"
```

### Step 3: Known Issues

1. **iCloud app passwords expire** — Apple app-specific passwords for iCloud Calendar/IMAP must be regenerated at appleid.apple.com whenever they stop working. File: `g-germainebrown-icloud-calendar.pass`. Always test against `p02-imap.mail.me.com:993`. Note: Apple's IMAP rejects app-specific passwords for iCloud mail — use CalDAV PROPFIND to test (`requests.request('PROPFIND', 'https://caldav.icloud.com/', auth=(user, pw))` returns 207 on success). The CalDAV principal URL format is `/1079451706/principal/` with calendar home at `p{xx}-caldav.icloud.com:443/1079451706/calendars/`.
2. **Cron has no session env** — credentials in session-only env vars (`source .env` in terminal) are invisible to cron. Scripts running from cron must use `${VAR:-$(grep ... .env)}` pattern or access a `.pass` file directly. The `CLOUDFLARE_API_TOKEN` was only in session env — added to `.env` on Jul 8 so the service health check cron could use it.
3. **Script-saved tokens get redacted** — when a script with an inline credential value is written to disk (e.g. via `>>>` heredoc or `write_file`), Hermes' secret redaction replaces the actual value with `***`. Verify scripts contain variable references, not inline values. The `service-health-check.sh` had `Authorization: Bearer ***` baked in because of this.**
4. **Caddy file permissions** — new files created with `write_file` default to `-rw-------` (600). Caddy runs as a non-root user and returns 403. Always run `chmod 644` on new HTML files in /var/www/. Both `login.html` and `index.html` needed this fix on Jul 8.

### Child Email Migration (garrison@iamgmb.com + greyson@iamgmb.com) — Jul 8

Migrated both boys' email accounts from SiteGround to MXroute:

| Account | Old Server | New Server | Messages |
|---------|-----------|-----------|----------|
| garrison@iamgmb.com | c1113726.sgvps.net:993 | heracles.mxrouting.net:993 | 324 (5 folders) |
| greyson@iamgmb.com | c1113726.sgvps.net:993 | heracles.mxrouting.net:993 | 74 (INBOX only) |

**DNS already correct — no changes needed.** MX records pointed to MXroute, SPF included mxroute.com, DKIM configured. SiteGround removal was clean.

### Delegation Model Update — Jul 8

| Level | Before | After |
|-------|--------|-------|
| Conversation | deepseek-chat (admin-ai) | deepseek-chat (no change) |
| Delegation primary | Claude Opus 4.7 | Claude Opus 4.7 (no change) |
| Fallback 1 | *(empty)* | **Claude Opus 4.8** (admin-ai) |
| Fallback 2 | *(empty)* | Llama 3.2 3B (ollama-local) |

Opus 4.8 tested and confirmed working via delegation subagent.
