---
name: publish-security
description: Pre-deploy audit and post-deploy verification for publish hygiene. Scans directories for files that should never be published, verifies live sites for exposure, and provides remediation. Invoke before or after any deploy operation.
---

# Publish Security

Ensures internal files, secrets, and dev artifacts never reach production. Use this skill before deploying any site, or to audit an existing deployment for exposure.

## When to Use

- Before running rsync or the deploy-website skill
- After a deploy, to verify nothing leaked
- When setting up a new project's deployment pipeline
- When investigating a suspected exposure

## Sensitive File Patterns

These patterns must NEVER appear in a deployed directory:

| Pattern | Why | Tier |
|---------|-----|------|
| `*.md` | Internal docs (CLAUDE.md, SPEC.md, BACKLOG.md, etc.) | Internal |
| `docs/` | Design docs, feedback, architecture | Internal |
| `test*.html`, `test*.js` | Test runners and test suites | Internal |
| `.env`, `.env.*` | API keys, tokens, secrets | Sensitive |
| `keystore.properties` | Android signing config | Sensitive |
| `*.jks`, `*.keystore` | Android signing keys | Sensitive |
| `*.py` | Build/generation scripts | Internal |
| `serve.json` | Dev server config | Internal |
| `VERSION` | Internal version tracking | Internal |
| `.claude/` | AI assistant metadata | Tooling |
| `.git/` | Version control | Tooling |
| `.wrangler/` | Cloudflare dev state | Tooling |
| `node_modules/` | Dependencies | Generated |
| `signaling/` | Worker source (deployed separately) | Internal |
| `local/` | Workspace files | Internal |

## Pre-Deploy Audit

Before deploying, scan the target directory:

```bash
# Set these for your game
GAME="fruit-fusion"
DEPLOY_DIR="~/Documents/Code/Operations/W - Websites/sites/traveling-with-you.com/$GAME"

# Check for files that should not be deployed
echo "=== Scanning $DEPLOY_DIR for sensitive files ==="
find "$DEPLOY_DIR" -name "*.md" -o -name "*.env" -o -name "*.env.*" \
  -o -name "*.jks" -o -name "*.keystore" -o -name "keystore.properties" \
  -o -name "test*.html" -o -name "test*.js" -o -name "*.py" \
  -o -name "serve.json" -o -name "VERSION" -o -name "*.log" \
  -o -name ".DS_Store" 2>/dev/null

# Check for directories that should not exist
for dir in docs .claude .git .wrangler node_modules signaling local android ios; do
  if [ -d "$DEPLOY_DIR/$dir" ]; then
    echo "FAIL: Directory exists: $DEPLOY_DIR/$dir"
  fi
done
```

If ANY files are found, STOP. Do not deploy. Remove the files first, then re-scan.

## Post-Deploy Verification

After deploying, verify nothing is publicly accessible:

```bash
SITE="https://traveling-with-you.com"
GAME="fruit-fusion"

echo "=== Post-deploy verification for $GAME ==="
for file in CLAUDE.md SPEC.md BACKLOG.md PROGRESS.md AUDIT.md ART-MANIFESTO.md VISUAL-BACKLOG.md test.html .env keystore.properties; do
  STATUS=$(curl -sI "$SITE/$GAME/$file" | head -1 | awk '{print $2}')
  if [ "$STATUS" = "200" ]; then
    echo "FAIL: $SITE/$GAME/$file is publicly accessible (HTTP 200)"
  else
    echo "OK: $SITE/$GAME/$file returns $STATUS"
  fi
done

# Also check site root
for file in BRAND.md .env; do
  STATUS=$(curl -sI "$SITE/$file" | head -1 | awk '{print $2}')
  if [ "$STATUS" = "200" ]; then
    echo "FAIL: $SITE/$file is publicly accessible (HTTP 200)"
  fi
done
```

Any `FAIL` result means immediate action is needed.

## Rsync Command Template

Every rsync deploy should use the canonical exclude list:

```bash
rsync -avc --checksum --delete \
  --exclude-from="~/Documents/Code/Traveling with You/.studio/shared/rsync-exclude.txt" \
  src/ "~/Documents/Code/Operations/W - Websites/sites/traveling-with-you.com/$GAME/"
```

For projects that deploy from root (not src/), the same exclude file applies.

## Remediation Runbook

If exposure is found:

### No secrets exposed (*.md, test.html, docs/)
1. Delete the exposed files from the website repo directory
2. `git add -A && git commit -m "security: remove exposed internal files from $GAME"`
3. `git push`
4. `npx wrangler pages deploy "sites/traveling-with-you.com" --project-name traveling-with-you-com`
5. Re-run post-deploy verification

### Secrets exposed (.env, keystore, API keys)
1. **STOP ALL OTHER WORK.** This is a security incident.
2. Delete the exposed files from the website repo immediately
3. Commit, push, deploy (same as above)
4. **Rotate all exposed credentials immediately:**
   - .env API keys: regenerate in the service provider's dashboard
   - Cloudflare tokens: regenerate in Cloudflare dashboard
   - Keystores: cannot be rotated for existing Play Store apps. If exposed, assess whether the keystore password was also exposed.
5. Audit git history for the website repo: did the secret get committed?
   - If yes: `git filter-branch` or `git-filter-repo` to remove from history, then force-push
6. Re-run post-deploy verification
7. Document the incident and update exclude patterns to prevent recurrence

## Integration with Deploy Skill

The deploy-website skill at `W - Website/.claude/commands/deploy.md` should:
1. Use `--exclude-from` in all rsync commands
2. Run this skill's post-deploy verification after wrangler deploy
3. Halt and report if any FAIL results

## Reference

- Canonical exclude list: `.studio/shared/rsync-exclude.txt`
- Sensitivity tiers: `.studio/practices/file-organization.md`
- Secrets management: `.studio/practices/security.md`
- Backup and recovery: `.studio/practices/backup-recovery.md`
