| name | secrets-management |
| description | Manage secrets rotation, GitHub Actions secret updates, and environment variable injection for ArtStroy. Ensures secrets never appear in logs, git history, or plaintext files. Used by DevOps Engineer and Security Auditor. |
Secrets Management
Secrets are the highest-risk attack surface in ArtStroy's infrastructure. Mishandling them is ironic given the security-focused content we publish.
Secrets Inventory
| Secret | Location | Used by | Rotation |
|---|
SSH_DEPLOY_KEY | GitHub Actions secret | deploy.yml | Every 90 days |
SERVER_HOST | GitHub Actions secret | deploy.yml | On server change |
SERVER_USER | GitHub Actions secret | deploy.yml | On server change |
GH_TOKEN | Paperclip instance store | Agents (GitHub API) | Every 90 days |
EXA_API_KEY | Paperclip instance store | News Researcher | Every 90 days |
GEMINI_API_KEY | Paperclip instance store | Designer (image-gen) | Every 90 days |
DEVTO_API_KEY | Paperclip instance store | Distribution Manager | Every 90 days |
HASHNODE_TOKEN | Paperclip instance store | Distribution Manager | Every 90 days |
BUTTONDOWN_API_KEY | Paperclip instance store | Distribution Manager | Every 90 days |
PLAUSIBLE_API_KEY | Paperclip instance store | Analytics Analyst | Every 90 days |
HETZNER_TOKEN | Paperclip instance store | DevOps | Every 90 days |
DATAFORSEO_LOGIN | Paperclip instance store | Analytics Analyst | Per contract |
DATAFORSEO_PASSWORD | Paperclip instance store | Analytics Analyst | Per contract |
Rotation Protocol (Standard — 90-day cycle)
For each secret being rotated:
- Generate new secret at the provider (GitHub, Exa, Gemini API console, etc.)
- Do not revoke the old secret yet — keep it active during transition
- Update in destination:
- GitHub Actions secrets: via
gh secret set {SECRET_NAME} or GitHub API
- Paperclip instance store: via Paperclip admin UI or API
- Server
.env: SSH into server, update the value
- Verify the new secret works:
- For
SSH_DEPLOY_KEY: trigger a deploy and confirm it succeeds
- For API keys: make a test API call with the new key
- For Paperclip secrets: trigger the relevant agent and confirm no auth error
- Revoke the old secret at the provider
- Log the rotation in
docs/project_notes/key_facts.md:
{SECRET_NAME}: last rotated {YYYY-MM-DD}
Emergency Rotation (Secret Leak)
If a secret is suspected leaked (found in git history, logs, error messages):
- Revoke immediately — do not wait for rotation protocol
- Generate new secret
- Update all locations (GitHub Actions + Paperclip + server .env)
- Verify deploy/operations work with new secret
- Audit git history for the leaked secret:
git log -S "{secret-value}" --all
- If found in history: the secret is permanently compromised — consider rotating all secrets as a precaution
- Notify CTO and create a Security incident in
docs/project_notes/bugs.md
- Determine blast radius: what could an attacker have done with the leaked secret? Document this.
What NEVER to Do
- Never commit a secret value to git (not even in a "temporary" commit)
- Never log a secret value (even in debug output)
- Never store secret values in
.paperclip.yaml (only declare the key names)
- Never share secrets via chat, email, or issue comments
- Never use the same secret for multiple purposes
GitHub Actions Secret Update (via CLI)
gh secret set SSH_DEPLOY_KEY --body "$(cat ~/.ssh/artstroy_deploy_key)"
gh secret set GH_TOKEN --body "{new-token-value}"
gh secret list
.env File on Server
The .env at /srv/artstroy/.env is managed manually. When updating:
ssh ${SERVER_USER}@${SERVER_HOST}
cd /srv/artstroy
cp .env .env.backup-$(date +%Y%m%d)
nano .env
cat .env | cut -d'=' -f1
docker compose up -d