diff --git a/CLAUDE.md b/CLAUDE.md index dd35218..e216081 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,8 +11,8 @@ A self-hosted web dashboard for running and tracking hard-drive burn-in tests against a TrueNAS SCALE 25.10 instance. Deployed on **maple.local** (10.0.0.138). - **App URL**: http://10.0.0.138:8084 (or http://burnin.hellocomputer.xyz) -- **Stack path on maple.local**: `~/docker/stacks/truenas-burnin/` -- **Source (local mac)**: `~/Desktop/claudesandbox/truenas-burnin/` +- **Stack path on maple.local**: `~/docker/stacks/nas-burnin/` +- **Source (local mac)**: `~/Desktop/claudesandbox/nas-burnin/` - **Compose synced to maple.local** via `scp` or manual copy ### Stages completed @@ -36,7 +36,7 @@ against a TrueNAS SCALE 25.10 instance. Deployed on **maple.local** (10.0.0.138) ## File Map ``` -truenas-burnin/ +nas-burnin/ ├── docker-compose.yml # two services: mock-truenas + app ├── Dockerfile # app container ├── requirements.txt @@ -222,18 +222,18 @@ All read from `.env` via `pydantic-settings`. See `.env.example` for full list. ### First deploy (already done) ```bash # On maple.local -cd ~/docker/stacks/truenas-burnin +cd ~/docker/stacks/nas-burnin docker compose up -d --build ``` ### Redeploy after code changes ```bash # Copy changed files from mac to maple.local first, e.g.: -scp -P 2225 -r app/ brandon@10.0.0.138:~/docker/stacks/truenas-burnin/ +scp -P 2225 -r app/ brandon@10.0.0.138:~/docker/stacks/nas-burnin/ # Then on maple.local: ssh brandon@10.0.0.138 -p 2225 -cd ~/docker/stacks/truenas-burnin +cd ~/docker/stacks/nas-burnin docker compose up -d --build ``` @@ -242,7 +242,7 @@ docker compose up -d --build # On maple.local — stop containers first docker compose stop app # Delete DB using alpine (container owns the file, sudo not available) -docker run --rm -v ~/docker/stacks/truenas-burnin/data:/data alpine rm -f /data/app.db +docker run --rm -v ~/docker/stacks/nas-burnin/data:/data alpine rm -f /data/app.db docker compose start app ``` @@ -350,7 +350,7 @@ async def burnin_get(job_id: int, ...): ... ### `requirements.txt` is unpinned Every `docker compose up -d --build` pulls latest of fastapi, starlette, jinja2, asyncssh, etc. The Starlette 1.0 regression on 2026-04-27 is a direct consequence. **Either pin to known-good versions, or audit installed versions immediately after each rebuild** with: ```bash -docker exec truenas-burnin python3 -c "import fastapi, starlette, jinja2; print(fastapi.__version__, starlette.__version__, jinja2.__version__)" +docker exec nas-burnin python3 -c "import fastapi, starlette, jinja2; print(fastapi.__version__, starlette.__version__, jinja2.__version__)" ``` ### Local source ↔ maple host can drift @@ -358,8 +358,8 @@ The deploy convention is `scp -r app/` from mac to maple, but if you ever edit o **Always `diff -u` before bulk scp:** ```bash -ssh -p 2225 brandon@10.0.0.138 'cat ~/docker/stacks/truenas-burnin/app/routes.py' > /tmp/deployed_routes.py -diff -u /tmp/deployed_routes.py ~/Desktop/claudesandbox/truenas-burnin/app/routes.py +ssh -p 2225 brandon@10.0.0.138 'cat ~/docker/stacks/nas-burnin/app/routes.py' > /tmp/deployed_routes.py +diff -u /tmp/deployed_routes.py ~/Desktop/claudesandbox/nas-burnin/app/routes.py ``` When sides have conflicting edits, prefer **patching the host file in place + rebuild** over a destructive scp. @@ -427,7 +427,7 @@ SMART attrs stored as JSON blob in `drives.smart_attrs`. Updated by `final_check Settings page has a "Check for Updates" button that fetches: ``` -GET https://git.hellocomputer.xyz/api/v1/repos/brandon/truenas-burnin/releases/latest +GET https://git.hellocomputer.xyz/api/v1/repos/brandon/nas-burnin/releases/latest ``` Compares tag name against `settings.app_version`; shows "up to date" or "v{tag} available". diff --git a/README.md b/README.md index 6f419db..46cd71d 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ open http://localhost:8084 # or your host's IP If you set `INITIAL_ADMIN_*` env vars *and* the users table is empty, that account is created on startup automatically. After that the env vars are ignored — change passwords from the UI ("Change password" header link) or -the CLI (`docker exec -it truenas-burnin python -m app.auth_cli reset +the CLI (`docker exec -it nas-burnin python -m app.auth_cli reset `). --- @@ -172,17 +172,17 @@ Configure SMTP in Settings → Email. Includes a "Test SMTP" button. ### Logs ```bash -docker logs -f truenas-burnin +docker logs -f nas-burnin # JSON-structured. Filter with jq: -docker logs truenas-burnin 2>&1 | jq -rR 'fromjson? | "\(.ts) \(.level) \(.msg)"' +docker logs nas-burnin 2>&1 | jq -rR 'fromjson? | "\(.ts) \(.level) \(.msg)"' ``` ### User management ```bash -docker exec -it truenas-burnin python -m app.auth_cli list -docker exec -it truenas-burnin python -m app.auth_cli add -docker exec -it truenas-burnin python -m app.auth_cli reset +docker exec -it nas-burnin python -m app.auth_cli list +docker exec -it nas-burnin python -m app.auth_cli add +docker exec -it nas-burnin python -m app.auth_cli reset ``` Passwords are read from a TTY prompt; never accept them on the command diff --git a/SPEC.md b/SPEC.md index d460803..901827b 100644 --- a/SPEC.md +++ b/SPEC.md @@ -251,8 +251,8 @@ The API makes this app a strong candidate for MCP server integration, allowing a Docker Compose. Minimum viable setup: ```bash -git clone https://github.com/yourusername/truenas-burnin -cd truenas-burnin +git clone https://github.com/yourusername/nas-burnin +cd nas-burnin cp .env.example .env # Edit .env for system-level settings (TrueNAS URL, poll interval, etc.) docker compose up -d diff --git a/app/auth_cli.py b/app/auth_cli.py index 2043cfa..cc36617 100644 --- a/app/auth_cli.py +++ b/app/auth_cli.py @@ -1,9 +1,9 @@ """Password reset / user management CLI. Run inside the container: - docker exec -it truenas-burnin python -m app.auth_cli reset - docker exec -it truenas-burnin python -m app.auth_cli list - docker exec -it truenas-burnin python -m app.auth_cli add + docker exec -it nas-burnin python -m app.auth_cli reset + docker exec -it nas-burnin python -m app.auth_cli list + docker exec -it nas-burnin python -m app.auth_cli add Reads the password from a TTY prompt — never accept it on the command line so it doesn't leak into shell history. diff --git a/app/config.py b/app/config.py index 6a4ec9f..621dbee 100644 --- a/app/config.py +++ b/app/config.py @@ -83,7 +83,7 @@ class Settings(BaseSettings): ssh_key: str = "" # PEM private key content (paste full key including headers) # Application version — used by the /api/v1/updates/check endpoint - app_version: str = "1.0.0-40" + app_version: str = "1.0.0-41" # ---- Authentication (1.0.0-22) ---- # session_secret: HMAC key for signing session cookies. Empty = generate diff --git a/app/routes/system.py b/app/routes/system.py index f3d3c0b..21d6833 100644 --- a/app/routes/system.py +++ b/app/routes/system.py @@ -112,7 +112,7 @@ async def check_updates(): try: async with httpx.AsyncClient(timeout=8.0) as client: r = await client.get( - "https://git.hellocomputer.xyz/api/v1/repos/brandon/truenas-burnin/releases/latest", + "https://git.hellocomputer.xyz/api/v1/repos/brandon/nas-burnin/releases/latest", headers={"Accept": "application/json"}, ) if r.status_code == 200: diff --git a/app/templates/login.html b/app/templates/login.html index 0409fdc..a889ab8 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -59,7 +59,7 @@ diff --git a/app/templates/settings.html b/app/templates/settings.html index 68f22a9..91080a9 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -343,7 +343,7 @@ diff --git a/docker-compose.yml b/docker-compose.yml index 72c374a..1396089 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: app: build: . - container_name: truenas-burnin + container_name: nas-burnin ports: - "8084:8084" env_file: .env diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index 8ddb71e..cc1b517 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -14,7 +14,7 @@ set -euo pipefail REMOTE_HOST="${REMOTE_HOST:-maple}" -CONTAINER="${CONTAINER:-truenas-burnin}" +CONTAINER="${CONTAINER:-nas-burnin}" REMOTE_TMP="/tmp/tnb-tests-$$.tgz" CONTAINER_TMP="/tmp/tnb-tests.tgz" PATTERN="${1:-}" diff --git a/scripts/security-scan.service b/scripts/security-scan.service index e6c23fc..230bf53 100644 --- a/scripts/security-scan.service +++ b/scripts/security-scan.service @@ -1,5 +1,5 @@ [Unit] -Description=Security scan of truenas-burnin (pip-audit + bandit + gitleaks) +Description=Security scan of nas-burnin (pip-audit + bandit + gitleaks) After=network-online.target docker.service Wants=network-online.target @@ -7,7 +7,7 @@ Wants=network-online.target Type=oneshot # Wire SECURITY_SCAN_WEBHOOK here if you want findings POSTed somewhere. # Environment=SECURITY_SCAN_WEBHOOK=https://chat.example/hooks/abc -ExecStart=%h/docker/stacks/truenas-burnin/scripts/security-scan.sh +ExecStart=%h/docker/stacks/nas-burnin/scripts/security-scan.sh # Tools cache + container pulls — give them headroom. TimeoutStartSec=600 StandardOutput=journal diff --git a/scripts/security-scan.sh b/scripts/security-scan.sh index 9cce912..134c889 100644 --- a/scripts/security-scan.sh +++ b/scripts/security-scan.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Daily security scan of the deployed truenas-burnin source on maple. +# Daily security scan of the deployed nas-burnin source on maple. # Mirrors the .forgejo/workflows/security-scan.yml CI pipeline so a finding # the runner-less forge would have flagged still surfaces here. # @@ -18,8 +18,8 @@ set -uo pipefail -REPO_URL="${REPO_URL:-https://git.hellocomputer.xyz/brandon/truenas-burnin.git}" -REPO="${REPO:-$HOME/scan-checkouts/truenas-burnin}" +REPO_URL="${REPO_URL:-https://git.hellocomputer.xyz/brandon/nas-burnin.git}" +REPO="${REPO:-$HOME/scan-checkouts/nas-burnin}" OUT_BASE="${OUT_BASE:-$HOME/security-scans}" DATE="$(date +%Y-%m-%d)" OUT_DIR="$OUT_BASE/scan-$DATE" @@ -29,7 +29,7 @@ GITLEAKS_VERSION="${GITLEAKS_VERSION:-8.21.2}" mkdir -p "$OUT_DIR" "$(dirname "$REPO")" # Maintain a dedicated checkout for scanning. The deploy at -# ~/docker/stacks/truenas-burnin/ is just the bind-mounted source — no +# ~/docker/stacks/nas-burnin/ is just the bind-mounted source — no # .git, no history — so gitleaks can't scan there. We keep a separate # clone, fast-forward it to origin/main each run. if [ ! -d "$REPO/.git" ]; then @@ -58,7 +58,7 @@ date -Iseconds >> "$OUT_DIR/summary.txt" echo >> "$OUT_DIR/summary.txt" # --- pip-audit against the lockfile in a throwaway container ------------ -# Previously we did `docker exec truenas-burnin pip install pip-audit` +# Previously we did `docker exec nas-burnin pip install pip-audit` # which mutated the live production container with a transient package. # Now scan the lockfile in an ephemeral container — same coverage of # pinned versions + their transitives, no side effects on prod. @@ -77,7 +77,7 @@ echo " exit=$PIPS ($OUT_DIR/pip-audit.txt)" | tee -a "$OUT_DIR/summary.txt" # forge HEAD and maple. B608 (SQL injection via dynamic strings) is # skipped globally: every dynamic SQL build in this codebase uses # bound parameters for data and structural placeholders only. -DEPLOY_DIR="${DEPLOY_DIR:-$HOME/docker/stacks/truenas-burnin}" +DEPLOY_DIR="${DEPLOY_DIR:-$HOME/docker/stacks/nas-burnin}" echo "--- bandit (deploy: $DEPLOY_DIR) ---" | tee -a "$OUT_DIR/summary.txt" docker run --rm \ -v "$DEPLOY_DIR/app:/src:ro" \ diff --git a/scripts/security-scan.timer b/scripts/security-scan.timer index 831f5a4..7359eab 100644 --- a/scripts/security-scan.timer +++ b/scripts/security-scan.timer @@ -1,5 +1,5 @@ [Unit] -Description=Daily security scan of truenas-burnin +Description=Daily security scan of nas-burnin Requires=security-scan.service [Timer]