diff --git a/.agent/skills/nginx/SKILL.md b/.agent/skills/nginx/SKILL.md index dcaf518..3a53471 100644 --- a/.agent/skills/nginx/SKILL.md +++ b/.agent/skills/nginx/SKILL.md @@ -51,9 +51,42 @@ This skill does not replace: nginx-ssl.html # Nginx + SSL guide stripe-agents.html # Stripe agents guide tailscale-vpn.html # Tailscale VPN guide + screenshots/ # Diagnostic screenshots (basic auth protected) clawdie-eng-v1.md # English content source ``` +## Protected paths + +| Path | Auth | htpasswd file | Credentials | +| --- | --- | --- | --- | +| `/screenshots/` | basic auth | `/usr/local/etc/nginx/screenshots.htpasswd` | in `.env` (`SCREENSHOTS_USER`, `SCREENSHOTS_PASSWORD`) | + +### Adding basic auth to a new path + +```sh +# 1. generate password hash +openssl passwd -apr1 'your-password' + +# 2. write htpasswd file +sudo sh -c 'cat > /usr/local/etc/nginx/newpath.htpasswd << EOF +username:$apr1$hash... +EOF' +sudo chmod 640 /usr/local/etc/nginx/newpath.htpasswd +sudo chown root:www /usr/local/etc/nginx/newpath.htpasswd + +# 3. add location block to vhost +# location /newpath/ { +# auth_basic "Description"; +# auth_basic_user_file /usr/local/etc/nginx/newpath.htpasswd; +# try_files $uri $uri/ =404; +# } + +# 4. test and reload +sudo nginx -t && sudo service nginx reload +``` + +Store credentials in `/home/clawdie/clawdie-ai/.env`. Never in skill files. + ## Safe defaults - Always run `nginx -t` before reloading diff --git a/.agent/skills/postgres-memory/references/security.md b/.agent/skills/postgres-memory/references/security.md index 5bd78be..38fa850 100644 --- a/.agent/skills/postgres-memory/references/security.md +++ b/.agent/skills/postgres-memory/references/security.md @@ -21,7 +21,8 @@ Never expose this role to remote connections. Set a password anyway as defense in depth: ```sh -sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD 'secure-admin-password';\"" +. /home/clawdie/clawdie-ai/.env +sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD '$POSTGRES_ADMIN_PASSWORD';\"" ``` ### Role: clawdie_app (Clawdie memory) @@ -29,8 +30,9 @@ sudo jexec db su - postgres -c "psql -c \"ALTER USER postgres WITH PASSWORD 'sec For the Clawdie agent memory database: ```sh +. /home/clawdie/clawdie-ai/.env sudo jexec db su - postgres -c "createuser clawdie_app" -sudo jexec db su - postgres -c "psql -c \"ALTER USER clawdie_app WITH PASSWORD 'secure-clawdie-password';\"" +sudo jexec db su - postgres -c "psql -c \"ALTER USER clawdie_app WITH PASSWORD '$CLAWDIE_DB_PASSWORD';\"" sudo jexec db su - postgres -c "createdb -O clawdie_app clawdie_memory" ``` @@ -39,8 +41,9 @@ sudo jexec db su - postgres -c "createdb -O clawdie_app clawdie_memory" For the Strapi content management database: ```sh +. /home/clawdie/clawdie-ai/.env sudo jexec db su - postgres -c "createuser strapi_user" -sudo jexec db su - postgres -c "psql -c \"ALTER USER strapi_user WITH PASSWORD 'secure-strapi-password';\"" +sudo jexec db su - postgres -c "psql -c \"ALTER USER strapi_user WITH PASSWORD '$STRAPI_DB_PASSWORD';\"" sudo jexec db su - postgres -c "createdb -O strapi_user strapi_cms" ``` @@ -147,10 +150,21 @@ Should fail with: `FATAL: pg_hba.conf rejects connection` ## Password storage -Store database passwords in `.env` files inside the respective jails: +All database passwords live in `/home/clawdie/clawdie-ai/.env`: -- controlplane: `/home/clawdie/clawdie-ai/.env` → `DATABASE_PASSWORD=...` -- cms: `/home/clawdie/strapi/.env` → `DATABASE_PASSWORD=...` +``` +POSTGRES_ADMIN_PASSWORD= +CLAWDIE_DB_PASSWORD= +STRAPI_DB_PASSWORD= +``` + +Generate with: `python3 -c "import secrets; print(secrets.token_urlsafe(24))"` + +Source before running setup commands: `. /home/clawdie/clawdie-ai/.env` + +When jails need their own `.env`, copy only the relevant variable: +- controlplane: `CLAWDIE_DB_PASSWORD` +- cms: `STRAPI_DB_PASSWORD` Never commit passwords to git. Never store them in skill files. @@ -171,11 +185,9 @@ Never commit passwords to git. Never store them in skill files. ## ZFS snapshots ```sh -# before security changes — dry-run first -sudo zfs snapshot -nv zroot/clawdie-runtime/jails/db@pre-security-DD-mon-YYYY -sudo zfs snapshot zroot/clawdie-runtime/jails/db@pre-security-DD-mon-YYYY +# before security changes (snapshots are non-destructive, no dry-run needed) +sudo zfs snapshot zroot/clawdie-runtime/jails/db@pre-security_YYYY-MM-DD_HH:MM:SS # after successful setup -sudo zfs snapshot -nv zroot/clawdie-runtime/jails/db@security-configured-DD-mon-YYYY -sudo zfs snapshot zroot/clawdie-runtime/jails/db@security-configured-DD-mon-YYYY +sudo zfs snapshot zroot/clawdie-runtime/jails/db@security-configured_YYYY-MM-DD_HH:MM:SS ``` diff --git a/.agent/skills/warden-zfs/SKILL.md b/.agent/skills/warden-zfs/SKILL.md index 3fc9050..140db20 100644 --- a/.agent/skills/warden-zfs/SKILL.md +++ b/.agent/skills/warden-zfs/SKILL.md @@ -35,7 +35,9 @@ namespace. ## Dry-run rule (mandatory) -**Every destructive or mutating ZFS command MUST be run with `-n` (dry-run) first.** This applies to `zfs destroy`, `zfs send`, `zfs rollback`, `zpool create`, and `zpool destroy`. Only after reviewing the dry-run output and confirming it is correct should the real command be executed. +**Every destructive ZFS command MUST be run with `-n` (dry-run) first.** This applies to `zfs destroy`, `zfs rollback`, `zfs send`, `zpool destroy`, and `zpool create`. Only after reviewing the dry-run output and confirming it is correct should the real command be executed. + +Note: `zfs snapshot` does NOT support `-n` because snapshots are non-destructive (instant, zero-cost). Just run `zfs snapshot` directly. Workflow: 1. Run the command with `-nv` (dry-run + verbose) to preview what will happen @@ -58,9 +60,24 @@ Commands that are read-only (`zfs list`, `zfs get`, `zpool status`) do not need - keep Bastille on `zroot` - keep Bastille prefix `clawdie-runtime` - snapshot before risky jail changes -- use day-first snapshot names with fixed month abbreviations - do not handcraft parallel jail dataset trees outside Bastille +## Snapshot naming + +Sanoid automated snapshots follow: `autosnap_YYYY-MM-DD_HH:MM:SS_` + +Operator-requested snapshots follow: `_YYYY-MM-DD_HH:MM:SS` + +Examples: +``` +autosnap_2026-03-08_18:46:47_hourly # sanoid +pre-security_2026-03-08_21:30:00 # operator request +postgres-ready_2026-03-08_19:00:00 # operator milestone +``` + +Do not use day-first or month-abbreviation formats (e.g., `08-mar-2026`). +Stick to ISO-style `YYYY-MM-DD` for consistent sorting and Sanoid compatibility. + ## Expected operator outcomes - Bastille datasets exist under `zroot/clawdie-runtime` diff --git a/.env.example b/.env.example index 808c62e..3ecb04e 100644 --- a/.env.example +++ b/.env.example @@ -17,3 +17,13 @@ OPENROUTER_API_KEY= # Channels TELEGRAM_BOT_TOKEN= + +# PostgreSQL (db jail at 192.168.100.2) +# Generate with: python3 -c "import secrets; print(secrets.token_urlsafe(24))" +POSTGRES_ADMIN_PASSWORD= +CLAWDIE_DB_PASSWORD= +STRAPI_DB_PASSWORD= + +# Nginx basic auth (clawdie.si/screenshots/) +SCREENSHOTS_USER=clawdie +SCREENSHOTS_PASSWORD=