security: Sprint 00 — critical security fixes (OPC WS auth, Transmission creds, SECRET_KEY, passkey rate limit)
- Add JWT token auth to OPC WebSocket (unauthenticated → 403, per-user tracking) - Externalize Transmission RPC credentials to TRANSMISSION_USER/PASS env vars - Remove hardcoded SECRET_KEY fallback from dev compose - Rate-limit passkey register options endpoint at 5/minute - Add PDD (docs/improvement-plan.md) and sprint specs (specs/) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
# Sprint 03 — Configuration Externalization
|
||||
|
||||
**Depends on:** S02 (auth boundaries must be clear before touching config)
|
||||
**Duration:** ~8h
|
||||
**Goal:** Move hardcoded IPs/URLs/credentials into environment variables, expand .gitignore, add secret scanning to CI.
|
||||
|
||||
---
|
||||
|
||||
## S03.1 — Centralize frontend hardcoded IPs/URLs
|
||||
|
||||
- **Files:** `dashboard/frontend/src/components/Sidebar.svelte:30-31,42-58`
|
||||
- **Estimate:** 3h
|
||||
- **Done means:** `LAN_IP`, `TS_IP`, and all subdomain URLs read from `GET /api/config/external-services` rather than hardcoded strings. Config endpoint returns a JSON map of service names to URLs.
|
||||
- **Verify by:**
|
||||
1. Change `MUSIC_URL` env var on backend → restart → sidebar shows new URL
|
||||
2. All sidebar links still work
|
||||
3. Config endpoint returns 200 with expected schema
|
||||
- **Risk:** Config endpoint must be called before sidebar renders. Add loading state; show "unavailable" for external services if endpoint fails.
|
||||
|
||||
- [ ] S03.1 — Centralize frontend hardcoded IPs/URLs
|
||||
|
||||
## S03.2 — Centralize hardcoded domain in email templates
|
||||
|
||||
- **Files:** `dashboard/backend/services/email_service.py:68,81,110,142`
|
||||
- **Estimate:** 1h
|
||||
- **Done means:** All email template URLs use `config.DASHBOARD_URL` env var (default `https://nas.jimmygan.com`) instead of hardcoded strings.
|
||||
- **Verify by:**
|
||||
1. Set `DASHBOARD_URL=https://dev.nas.jimmygan.com` → emails contain dev URLs
|
||||
2. Unset → emails use default `https://nas.jimmygan.com`
|
||||
- **Risk:** Requires adding `DASHBOARD_URL` to config.py and compose files. Low risk.
|
||||
|
||||
- [ ] S03.2 — Centralize hardcoded domain in email templates
|
||||
|
||||
## S03.3 — Document SSH host defaults in config.py
|
||||
|
||||
- **Files:** `dashboard/backend/config.py:25-39`
|
||||
- **Estimate:** 0.5h
|
||||
- **Done means:** Comment block explains hardcoded SSH defaults are for development only and must be overridden in production. No code changes.
|
||||
- **Verify by:** Read config.py → comment is present and clear.
|
||||
- **Risk:** Doesn't remove hardcoded values — full removal deferred to S06.
|
||||
|
||||
- [ ] S03.3 — Document SSH host defaults in config.py
|
||||
|
||||
## S03.4 — Add TRANSMISSION_URL to config
|
||||
|
||||
- **Files:** `dashboard/backend/config.py`, `dashboard/backend/routers/transmission.py`
|
||||
- **Estimate:** 1h
|
||||
- **Done means:** Transmission RPC URL is configurable via `TRANSMISSION_URL` env var. Pairs with S00.2 credential fix.
|
||||
- **Verify by:**
|
||||
1. Set `TRANSMISSION_URL=http://transmission:9091/transmission/rpc` → calls use that URL
|
||||
2. Unset → uses default `http://host.docker.internal:9091/transmission/rpc`
|
||||
- **Risk:** Low — pairs naturally with S00.2.
|
||||
|
||||
- [ ] S03.4 — Add TRANSMISSION_URL to config
|
||||
|
||||
## S03.5 — Expand root .gitignore
|
||||
|
||||
- **Files:** `.gitignore`
|
||||
- **Estimate:** 0.5h
|
||||
- **Done means:** Root `.gitignore` covers: `.DS_Store`, `*.pyc`, `__pycache__/`, `venv/`, `.venv/`, `.vscode/`, `.idea/`, `*.log`, `.env.local`, `.env.production`, `*.egg-info/`.
|
||||
- **Verify by:**
|
||||
1. `touch .DS_Store && git status` → not shown as untracked
|
||||
2. `touch test.log && git status` → not shown
|
||||
3. Existing tracked files unaffected
|
||||
- **Risk:** None — standard ignores.
|
||||
|
||||
- [ ] S03.5 — Expand root .gitignore
|
||||
|
||||
## S03.6 — Add gitleaks to CI test workflow
|
||||
|
||||
- **Files:** `.gitea/workflows/test.yml`
|
||||
- **Estimate:** 2h
|
||||
- **Done means:** `test.yml` includes a `gitleaks detect` step on PRs to `main`. No secrets trigger false positives (or `.gitleaks.toml` excludes known safe patterns).
|
||||
- **Verify by:**
|
||||
1. Push test commit with `SECRET_KEY=test123` → gitleaks step fails
|
||||
2. Push normal commit → gitleaks step passes
|
||||
3. CI run completes in < 30s for gitleaks step
|
||||
- **Risk:** gitleaks may flag existing patterns. Configure `.gitleaks.toml` to whitelist CI test keys and `.env.example` placeholders. If gitleaks binary unavailable on Gitea runner, use Docker image `zricethezav/gitleaks:latest`.
|
||||
|
||||
- [ ] S03.6 — Add gitleaks to CI test workflow
|
||||
|
||||
---
|
||||
|
||||
## Exit criteria
|
||||
|
||||
- [ ] Sidebar external service URLs come from config endpoint (no hardcoded IPs/domains)
|
||||
- [ ] Email templates use configurable `DASHBOARD_URL`
|
||||
- [ ] config.py has comment documenting SSH defaults
|
||||
- [ ] Transmission URL is configurable via env var
|
||||
- [ ] `.DS_Store` and `*.log` not shown in `git status`
|
||||
- [ ] `gitleaks detect` runs in CI on PRs to main
|
||||
- [ ] All backend tests pass
|
||||
- [ ] All frontend tests pass
|
||||
Reference in New Issue
Block a user