89 lines
3.9 KiB
Markdown
89 lines
3.9 KiB
Markdown
# CLAUDE.md
|
|
|
|
Quick context for Claude Code. See README.md for full details, ARCHITECTURE.md
|
|
for technical deep-dives, USECASES.md for expected behaviors.
|
|
|
|
## Key files
|
|
|
|
- `scripts/bootstrap.sh` -- First-time server setup (manual, uses Bitwarden)
|
|
- `scripts/configure.sh` -- Idempotent server config (firewall, certbot, start services; CI-safe)
|
|
- `scripts/deploy.sh` -- SSH-triggered deploy + cert issuance + provision (deploy-*, cert-*, provision commands)
|
|
- `tools/app.sh` -- App provisioning by subcommand (dns, repo, files, cert, garage, build, verify, all)
|
|
- `tools/service.sh` -- Manage Docker services by subcommand (dns, files, nginx, cert, all)
|
|
- `tools/remove-app.sh` -- Remove a static site (local files + Gitea repo)
|
|
- `docker/nginx/conf.d/` -- Per-app nginx server blocks
|
|
- `docker/<domain>/compose.yml` -- Per-app compose files
|
|
- `docker/goatcounter/` -- GoatCounter analytics (compose.yaml, .env.keys)
|
|
- `docker/garage/` -- Garage S3 object storage (Dockerfile, garage.toml, .env.keys)
|
|
- `.gitea/workflows/` -- Per-app deploy workflows + provision.yml
|
|
|
|
## Conventions
|
|
|
|
- **App name = domain** (e.g., `example.com`)
|
|
- **Container name** = dots → underscores (e.g., `example_com`)
|
|
- **One domain per conf file** -- deploy.sh derives cert name from filename
|
|
- All HTTP → HTTPS; bare domain → `www.<domain>`
|
|
- All shell scripts use `set -euo pipefail` and must be idempotent
|
|
- The `shared` Docker network is created by nginx compose and used by all apps
|
|
- Secrets are in Bitwarden Secrets Manager (see README.md for full list)
|
|
- Service secrets use `.env.keys` files (see README.md)
|
|
|
|
## Deploy flow
|
|
|
|
- App repo push → `build.yml` → build/push image → SSH `deploy-<domain>` → deploy.sh
|
|
- This repo push → `deploy-<app>.yml` (path match) → SSH `deploy-<app>` → deploy.sh
|
|
- Setup change → `provision.yml` → SSH `provision` → configure.sh
|
|
|
|
## Build and test
|
|
|
|
No build step. Run e2e tests with:
|
|
|
|
uvx pytest tests/test_app_e2e.py -v -x
|
|
|
|
### Prerequisites
|
|
|
|
- `uv` installed (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
|
|
- CLI tools: `bws`, `jq`, `dig`, `ssh`, `curl`, `git`
|
|
- bws token: set `BWS_ACCESS_TOKEN` env var or save to `~/.config/hantim/bws-token`
|
|
- Vultr API key must allow requests from the machine's IP (check https://my.vultr.com/settings/#settingsapi)
|
|
|
|
### Test structure
|
|
|
|
- `tests/conftest.py` -- Fixtures: preflight checks, bws secrets, API helper, cleanup
|
|
- `tests/test_app_e2e.py` -- E2E tests for `tools/app.sh` against real services
|
|
- `tests/test_security_headers.py` -- Verify security headers on live sites
|
|
- `tests/test_default_server.py` -- Verify unknown Host headers are dropped
|
|
- `tests/test_tls.py` -- Verify TLS hardening
|
|
|
|
### E2E tests (`test_app_e2e.py`)
|
|
|
|
Tests use `kgfamily.com` as a throwaway test domain. Two phases:
|
|
|
|
1. **TestAppSubcommands** -- Runs each `app.sh` subcommand individually (dns, repo,
|
|
files, cert, garage, build, monitor), verifies side effects via API, then cleans up.
|
|
Does not test `verify` (needs full deploy flow).
|
|
2. **TestAppAll** -- Runs `app.sh all kgfamily.com`, verifies everything including
|
|
site liveness and git commit, then cleans up (including reverting the commit+push).
|
|
|
|
Cleanup is done directly via APIs (Vultr, Gitea, Garage, UptimeRobot) + local file
|
|
deletion. Does NOT use `remove-app.sh` to avoid coupling. Runs before and after each
|
|
phase to handle leftovers from crashed runs.
|
|
|
|
### Known issue
|
|
|
|
- Vultr API keys can be IP-restricted. If `test_dns` fails with HTTP 401, add the
|
|
machine's IP to the Vultr API access control list.
|
|
|
|
### Other tests
|
|
|
|
The security/TLS/default-server tests run against live sites and are triggered
|
|
automatically after nginx deploy. They can also be run locally:
|
|
|
|
uvx pytest tests/ -v --ignore=tests/test_app_e2e.py
|
|
|
|
## Commit style
|
|
|
|
- Short, lowercase commit messages (e.g., "add example.com", "fix deploy command")
|
|
- Do NOT include "Co-Authored-By" lines
|
|
- Commit only when explicitly asked
|