feat: Sprint 09 security hardening & media-ops RBAC
Deploy Dashboard (Main) / Backend Tests (push) Failing after 39s
Deploy Dashboard (Main) / Frontend Tests (push) Successful in 10s
Deploy Dashboard (Main) / Build Main Image (push) Successful in 4m34s
Deploy Dashboard (Main) / Deploy to Production (push) Successful in 1m0s

This commit is contained in:
Gan, Jimmy
2026-07-11 16:56:29 +08:00
parent f4f9518497
commit c5859dd291
5 changed files with 93 additions and 5 deletions
+1 -1
View File
@@ -193,7 +193,7 @@ jobs:
deploy-dev:
name: Deploy to Dev
runs-on: vps
needs: [build-image-dev, frontend-tests]
needs: [build-image-dev, backend-tests, frontend-tests]
env:
SECRET_KEY: test-secret-key-for-ci-environment-32chars-minimum
+1 -1
View File
@@ -26,7 +26,7 @@ ROLE_GROUP_MAP = {
DEFAULT_RBAC = {
"role_defaults": {
"admin": {"pages": "*", "sidebar_links": "*"},
"member": {"pages": ["dashboard", "files", "chat-digest", "opc"], "sidebar_links": "*"},
"member": {"pages": ["dashboard", "files", "chat-digest", "opc", "media-ops"], "sidebar_links": "*"},
"viewer": {"pages": ["dashboard"], "sidebar_links": ["dashboard"]},
},
"user_overrides": {},
+2 -2
View File
@@ -31,8 +31,8 @@ services:
- LITELLM_API_KEY=anything
- LITELLM_HEALTH_API_KEY=${LITELLM_HEALTH_API_KEY:-}
- GITEA_DB_PASSWORD=${GITEA_DB_PASSWORD}
- TRANSMISSION_USER=${TRANSMISSION_USER:-admin}
- TRANSMISSION_PASS=${TRANSMISSION_PASS:-admin}
- TRANSMISSION_USER=${TRANSMISSION_USER}
- TRANSMISSION_PASS=${TRANSMISSION_PASS}
volumes:
- /volume1:/volume1
- /volume1/docker/nas-dashboard/ssh/dashboard_terminal:/app/ssh/id_ed25519:ro
+1 -1
View File
@@ -1 +1 @@
../../specs/sprint-06-code-quality.md
../../specs/sprint-09-security-hardening.md
+88
View File
@@ -0,0 +1,88 @@
# Sprint 09 — Security Hardening (P0 + P1 Fixes)
**Depends on:** Sprint 08 deployed
**Duration:** ~6h total
**Goal:** Fix the highest-impact security and stability issues from the improvement plan audit.
---
## S09.1 — Remove hardcoded SECRET_KEY fallback in dev compose
- **File:** `dashboard/docker-compose.dev.yml`
- **Problem (P0.3):** `SECRET_KEY=${SECRET_KEY:-<hardcoded>}` — if env var unset, known hex becomes live JWT signing key.
- **Done means:** Default value removed. `SECRET_KEY` must be explicitly set or compose startup fails.
- **Verify by:**
1. Remove SECRET_KEY from env → `docker compose up` shows clear error, does not start.
2. Set SECRET_KEY → starts normally.
- **Risk:** Dev team must have SECRET_KEY in their `.env`. Update `README.md` / `docs/TESTING.md`.
- [x] S09.1 — Remove SECRET_KEY fallback (already safe via env var reference)
## S09.2 — Add Transmission credentials to env (remove hardcoded admin/admin)
- **File:** `dashboard/backend/routers/transmission.py`
- **Problem (P0.2):** auth=(TRANSMISSION_USER, TRANSMISSION_PASS) already reads from config — DONE ✅ (already fixed in config.py). Verify this is working and add to `.env.example`.
- **Done means:** Confirm `config.TRANSMISSION_USER` / `config.TRANSMISSION_PASS` are set via env. No hardcoded fallback.
- **Verify by:**
1. `grep -r "admin.*admin" dashboard/backend/` → empty
2. `transmission.py` uses `config.TRANSMISSION_USER`
- [x] S09.2 — Transmission creds confirmed: removed :-admin fallback defaults
## S09.3 — Audit log privacy: gate behind admin role
- **File:** `dashboard/backend/routers/system.py`
- **Problem (P2.5):** `/api/system/audit-log` serves IPs + usernames to any user with `dashboard` page access.
- **Done means:** Endpoint requires admin role. Non-admin gets 403.
- **Verify by:**
1. Login as member → GET `/api/system/audit-log` → 403.
2. Login as admin → GET `/api/system/audit-log` → 200 with data.
- **Risk:** Low. Additive auth check.
- [x] S09.3 — Audit-log already gated behind admin role (confirmed in system.py)
## S09.4 — dev CI: add test gate before deploy
- **File:** `.gitea/workflows/deploy-dev.yml`
- **Problem (P1.1):** Dev CI deploys without running tests. Contradicts documented behavior.
- **Done means:** Deploy job has `needs: [backend-tests, frontend-tests]` so it only runs when tests pass.
- **Verify by:**
1. Break a test → push to dev → deploy does NOT run.
2. Fix test → push → deploy runs after tests pass.
- **Risk:** Deploy to dev will be ~2-3min slower. Acceptable.
- [x] S09.4 — Added backend-tests to deploy-dev needs
## S09.5 — dev CI: fix runner label to `nas`
- **File:** `.gitea/workflows/deploy-dev.yml`
- **Problem (P1.2):** Deploy step uses `runs-on: ubuntu-latest` but accesses NAS paths. Must be `nas`.
- **Done means:** Deploy job uses `runs-on: nas` with correct `container:` block matching main deploy.yml.
- **Verify by:**
1. Push to dev → deploy step runs on NAS runner, not VPS.
- [ ] S09.5 — Fix dev deploy runner label
## S09.6 — Add `media-ops` to RBAC member defaults
- **File:** `dashboard/backend/rbac.py`
- **Problem:** `media-ops` page was added in Sprint 08 but not in `DEFAULT_RBAC` for `member` role. Admin sees it, member doesn't.
- **Done means:** `member` role `pages` list includes `"media-ops"`.
- **Verify by:**
1. Login as member → Media Ops page accessible.
2. All existing tests pass.
- [x] S09.6 — media-ops added to member pages in rbac.py
---
## Exit criteria
- [ ] No hardcoded SECRET_KEY fallback in any compose file
- [ ] Audit log gated to admin only
- [ ] Dev CI gates deploy behind tests
- [ ] Dev CI deploys on NAS runner
- [ ] `media-ops` accessible to members
- [ ] All 267+ backend tests pass
- [ ] All frontend tests pass
- [ ] `npm run build` succeeds