devops
Technical notes on web development, DevOps, and AI integration.
29 articles
- 23:02devops
Closing the Door Does Not Hide the Drawers
The deploy port was closed, yet /.git/ stayed readable through the staging hostname. Next: an nginx edge regex guard and an api/db network split.
TL;DR: Closing the inbound port didn't protect a staging server still serving .git and .env files over its tunnel. The fix needs three layers: nginx edge rules denying dot-paths, server_tokens off, and explicit Docker networks isolating services. Each layer covers what the others miss; any one alone leaves the same exposed drawers.
#nginx#docker#devops - 00:12devops
Keeping the Users Table Alive When db-push Swaps the Database
db-push replaced staging from a dev dump and accounts vanished. Two small dumps and honest guards keep them alive.
TL;DR: Staging users kept vanishing because db-push replaces the whole database with a dev dump that excludes the users table. The fix: dump staging users beforehand, then restore them after the import using --no-data, --complete-insert, and --no-create-info. Key lesson: dump and verify before any DROP, validate injected names, and lock down the hash-bearing file.
#mysql#mysqldump#ssh - 17:43devops
Docker Compose Waits for a Ready Database, Not a Running One
depends_on only waits for a running container. The real wait contract is a pg_isready healthcheck, service_healthy, and migrate-before-serve.
TL;DR: Compose's depends_on only guarantees start order, not database readiness, so the app crashed while Postgres was still initializing. The fix pairs a pg_isready healthcheck with depends_on condition: service_healthy, letting the entrypoint run migrations before exec-ing uvicorn so shutdown signals land cleanly. The same pattern works in GitHub Actions CI, and newer Compose versions offer pre_start as an alternative.
#docker#compose#postgresql - 10:21devops
A Dev Quick Login That Never Becomes a Backdoor
Automating development login through the real form submit plus a fail-closed env guard: fast, with no backdoor left behind in production.
TL;DR: Repeated manual logins for testing were exhausting, and injecting tokens to bypass the form broke app state and caused flaky tests. Instead, automating the actual form submission behind an explicit opt-in env variable keeps it off by default. Paired with role-limited dev users and separate config, it speeds up testing without opening security holes in production.
#security#authentication#testing - 02:35devops
Checking the gate with one command
What used to take four MCP round trips and an 86KB payload at session start is now one read-only script with semantic exit codes.
TL;DR: Checking status used to need four heavy MCP calls, and caching only created stale-data headaches. The fix was a lightweight read-only script that runs four checks in parallel with clear exit codes for ready, drift, or infra trouble. It handles quirks like Cloudflare blocks and rate limits while staying local for quick iteration and always-fresh data.
#python#plane#devops - 13:37ai
One small patch in plane-mcp to make it talk to Plane Community Edition
The /dependencies/ route 404s on CE self-hosted. A small fallback to the old /relations/ route fixes it.
TL;DR: The MCP link tool returned a bare 404 though the work items existed, because its cloud route is missing in Community Edition. The patch detects a missing-route 404 versus missing data and falls back to the older CE route with adjusted payloads. This keeps upstream merges simple and is validated by a live smoke test creating and linking real items.
#plane#mcp#ai - 13:21ai
Plane MCP is live: three operational gotchas you only feel after using it
No workspace delete via MCP, CORS reused as CSRF, and an API token sitting in .mcp.json next to the code.
TL;DR: Workspace deletion isn't exposed via API and requires double confirmation in the UI to prevent irreversible wipes by AI agents. CORS and CSRF share the single CORS_ALLOWED_ORIGINS variable, so adding an origin requires recreating all backend containers, not the proxy. API tokens sit in plaintext in .mcp.json, so you must gitignore the file and use expiring tokens.
#plane#mcp#ai - 06:26devops
KTM Joins Inventory: From Custom 0.5.81 to Vendor 0.5.86
KTM was invisible to Ansible until I added it to two inventory groups. One playbook run later, it swapped from custom 0.5.81 to vendor 0.5.86 with data intact.
TL;DR: Ansible skipped KTM because the host wasn't in inventory, so --limit couldn't target it until two group edits added it. The playbook then upgraded the container from a custom 0-5-81 build to vendor latest 0-5-86, now back in sync. Dashboard password persisted via bind-mounted datadir, while the old custom image remains on disk for later cleanup.
#docker#ansible#automation - 20:47devops
The Launcher That Pays Twice: Three Guard Layers Before a Delegation Script Fires
Launching a delegation script twice burns the budget twice. flock, artifact check, and pgrep refuse before anything starts.
TL;DR: The author re-ran a Claude Code command thinking it was stuck, accidentally spawning a duplicate that burned the same budget in parallel. Their launcher now refuses to start using three pre-flight checks: flock -n on a file descriptor, a valid result JSON check, and pgrep -f for a live twin. Each refusal gets a distinct exit code.
#bash#devops#automation