diff --git a/.github/agents/docs-expert.agent.md b/.github/agents/docs-expert.agent.md index 92c86e0..73569de 100644 --- a/.github/agents/docs-expert.agent.md +++ b/.github/agents/docs-expert.agent.md @@ -36,9 +36,16 @@ These are **instructional**, written for operators and end users — not for con - Screenshots are fine to reference by filename but are not required; text must stand alone. - Accuracy is non-negotiable. Paths, flag names, env var names, URLs, and ports must match the code exactly. If the code says `--listen`, the doc says `--listen`, not `--address`. -### Design docs and specs (`docs/plans/*.md`) +### Design docs and specs (`docs/plans/*.md`) — LOCAL ONLY -These are for contributors and maintainers. Use technical language, reference code paths, include Mermaid diagrams, cite file paths with line numbers. The audience rules above do **not** apply here. +The `docs/plans/` directory is **gitignored**. Files there are local-only working notes used while implementing a feature; they are never committed and never visible to anyone other than the author. + +Rules: + +- Place new design docs / specs / phase plans under `docs/plans/` only when the user explicitly asks for a plan. Do not stage or commit them. +- **Never reference `docs/plans/*` paths from tracked files** (CHANGELOG, committed docs, commit messages, PR descriptions, code comments). The link would 404 for everyone else. +- If you encounter an existing tracked file that links into `docs/plans/`, treat that link as a bug and remove it. +- Inside a plan doc itself, technical language, code paths, Mermaid diagrams, and line-number citations are fine — the audience is just you and the user. ### Quick check before submitting a user guide @@ -57,25 +64,12 @@ These are for contributors and maintainers. Use technical language, reference co ## Doc Files -| File | Purpose | -| -------------------------- | -------------------------------------------------------------------- | -| `docs/admin-guide.md` | UI walkthrough for the admin dashboard | -| `docs/deployment-guide.md` | Bare metal, Docker, reverse proxy, Let's Encrypt, secrets encryption | -| `docs/recorder-guide.md` | Per-recorder setup instructions | -| `docs/plans/` | Design plans and specs (architecture, API, etc.) | - -### Plans Directory (`docs/plans/`) - -| File | Purpose | -| --------------------------------------- | ------------------------------------------------- | -| `docs/plans/plan.md` | Master project plan and UI design spec | -| `docs/plans/architecture.md` | System diagram, component descriptions, data flow | -| `docs/plans/api.md` | Full API endpoint reference | -| `docs/plans/recorder-integration.md` | Recorder integration design | -| `docs/plans/transcription.md` | Transcription feature design (go-whisper) | -| `docs/plans/refresh-token-auth-plan.md` | Refresh token auth flow design | -| `docs/plans/security-hardening-plan.md` | Security hardening roadmap | -| Other plan files | Feature-specific implementation plans | +| File | Purpose | +| -------------------------- | ----------------------------------------------------------------------------- | +| `docs/admin-guide.md` | UI walkthrough for the admin dashboard | +| `docs/deployment-guide.md` | Bare metal, Docker, reverse proxy, Let's Encrypt, secrets encryption | +| `docs/recorder-guide.md` | Per-recorder setup instructions | +| `docs/plans/` | **LOCAL ONLY** — gitignored working notes; never reference from tracked files | ## Key Diagrams to Maintain diff --git a/.github/agents/react-expert.agent.md b/.github/agents/react-expert.agent.md index cd11236..7d212c4 100644 --- a/.github/agents/react-expert.agent.md +++ b/.github/agents/react-expert.agent.md @@ -160,7 +160,7 @@ frontend/ ## UI Design Principles -Full visual specification with ASCII wireframes, color palette, component mapping, responsive breakpoints, and animations is in `docs/plans/plan.md` § "Web UI Design". Key points: +Local-only design notes (in the gitignored `docs/plans/` working directory) may contain extended ASCII wireframes and palette spec. The canonical, in-repo summary follows. Key points: - **Dark-first** — custom DaisyUI `openscanner` theme; `base-100` (#121212), `base-200` (#1e1e1e), `base-300` (#2d2d2d), `primary` (#00e676 green), `secondary` (#ff9100 orange), `error` (#ff1744 red) - **Scanner page** — vertically-stacked single column, max-width 640px, 24px padding: diff --git a/.github/agents/reviewer.agent.md b/.github/agents/reviewer.agent.md index 1f66d23..145933c 100644 --- a/.github/agents/reviewer.agent.md +++ b/.github/agents/reviewer.agent.md @@ -115,7 +115,7 @@ This reviewer covers the whole application. Sections below map to subsystems: ### A07 — Identification & Authentication Failures - [ ] Login rate limiter: 3 failures → 10-minute lockout per IP -- [ ] Max 5 concurrent JWT tokens per user enforced (oldest invalidated on 6th login) +- [ ] Max `auth.MaxRefreshFamilies` (20) concurrent JWT tokens per user enforced (oldest invalidated on overflow) - [ ] JWT tokens are invalidated on logout (server-side token tracker) - [ ] Refresh token family rotation: reuse of an old token revokes the entire family - [ ] Refresh cookie flags: `HttpOnly`, `Secure` in production, `SameSite=Lax` diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index bda64de..fddcfc9 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -107,7 +107,7 @@ Detailed conventions live in the individual agent files. The non-negotiables for 12. Secrets at rest (downstream API keys, VAPID private key, webhook secrets) encrypted with AES-256-GCM using the `enc::` prefix; startup fails fast on missing/wrong encryption key 13. Refresh tokens stored as SHA-256 hashes with family rotation; reuse revokes the entire family; delivered in httpOnly/Secure/SameSite=Lax cookies 14. All outbound HTTP (downstream, webhooks, push) uses `safehttp.Client` — redirects disabled, timeouts enforced, response body capped. Private-address blocking is opt-in via `OPENSCANNER_BLOCK_INTERNAL_HTTP=1` (default allows LAN/loopback because OpenScanner is a self-hosted homelab tool) -15. Max 5 concurrent JWT tokens per user; 3-strike lockout (10 min) on login; hourly cleanup goroutine for expired refresh tokens +15. Max 20 concurrent JWT tokens per user (`auth.MaxRefreshFamilies`); 3-strike lockout (10 min) on login; hourly cleanup goroutine for expired refresh tokens ## Tooling Conventions @@ -117,13 +117,27 @@ Detailed conventions live in the individual agent files. The non-negotiables for - Do not commit or push unless the user explicitly asks - Do not delete files as a shortcut; if a file looks unfamiliar, read it first +## Local-only planning docs (`docs/plans/`) + +- The entire `docs/plans/` directory is **gitignored** (see [.gitignore](../.gitignore)). Files there are local working notes only. +- **Never** mention plan files, plan filenames, or contents of `docs/plans/*` in: + - `CHANGELOG.md` + - committed docs (`docs/*.md` outside `docs/plans/`) + - commit messages + - PR titles or PR descriptions + - code comments + - any other tracked file +- Treat plan docs the way you'd treat a personal scratchpad: useful while working, invisible to anyone reading the repository. +- When asked to write a plan, place it under `docs/plans/` and do not stage or commit it. Do not link to it from tracked files (the link would 404 for everyone else). +- If you find an existing tracked file that links into `docs/plans/`, treat that link as a bug and remove the reference. + ## Changelog - User-visible changes (new features, fixes, config/schema changes, security patches) **must** add a bullet under the `[Unreleased]` section of `CHANGELOG.md` in the same PR - Group bullets under `### Added`, `### Changed`, `### Fixed`, `### Security`, `### Removed`, or `### Deprecated` (Keep a Changelog format) - Pure internal refactors, CI-only tweaks, and typo fixes can skip the CHANGELOG — the PR should be labeled `skip-changelog` - The `changelog` CI job blocks merges into `main` when `CHANGELOG.md` wasn't touched and the label isn't applied -- Full release process: [docs/plans/release-guide.md](../docs/plans/release-guide.md) +- CHANGELOG bullets describe **what changed in the product**, never **what plan was followed**. Don't reference plan filenames or phase numbers from `docs/plans/`. ## Releases diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e18a0f..33d1da7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main, dev] +permissions: + contents: read + jobs: changelog: name: CHANGELOG updated @@ -35,11 +38,12 @@ jobs: - uses: actions/setup-go@v6 with: go-version: "1.25" + cache-dependency-path: backend/go.sum - name: Install swag run: go install github.com/swaggo/swag/cmd/swag@latest - name: Generate Swagger docs working-directory: backend - run: swag init -d cmd/server,internal/api -g main.go --parseDependency --parseInternal -o docs + run: swag init -d cmd/server,internal/handler -g main.go --parseDependency --parseInternal -o docs - name: Test run: cd backend && go test ./... diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..123b264 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,67 @@ +name: CodeQL + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + schedule: + - cron: "23 5 * * 1" + workflow_dispatch: + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + include: + - language: go + build-mode: manual + - language: javascript-typescript + build-mode: none + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Set up Go + if: matrix.language == 'go' + uses: actions/setup-go@v6 + with: + go-version: "1.25" + cache-dependency-path: backend/go.sum + + - name: Install swag + if: matrix.language == 'go' + run: go install github.com/swaggo/swag/cmd/swag@latest + + - name: Generate Swagger docs + if: matrix.language == 'go' + working-directory: backend + run: swag init -d cmd/server,internal/handler -g main.go --parseDependency --parseInternal -o docs + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + # The Go module lives in backend/ and its swagger docs package is + # generated above. Autobuild cannot locate the module from the repo + # root, so build explicitly from backend/ here. + - name: Build Go + if: matrix.language == 'go' + working-directory: backend + run: go build ./... + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b9a2f30..b8c0a46 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,7 @@ jobs: - uses: actions/setup-go@v6 with: go-version: "1.25" + cache-dependency-path: backend/go.sum - name: Install swag run: go install github.com/swaggo/swag/cmd/swag@latest @@ -56,7 +57,7 @@ jobs: - name: Generate Swagger docs working-directory: backend - run: swag init -d cmd/server,internal/api -g main.go --parseDependency --parseInternal -o docs + run: swag init -d cmd/server,internal/handler -g main.go --parseDependency --parseInternal -o docs - name: Build binary working-directory: backend diff --git a/CHANGELOG.md b/CHANGELOG.md index 233fcbd..baac1b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,118 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.2.0] — 2026-04-25 + +### Added + +- Session cookie (`os_session`) issued on login and refresh, cleared on + logout. The `GET /api/calls/:id/audio` route now accepts authentication + via either the existing `Authorization: Bearer` header or the new + cookie, so `