diff --git a/docs/CORE_LOOP_EVAL.md b/docs/CORE_LOOP_EVAL.md index a31ba60..8702066 100644 --- a/docs/CORE_LOOP_EVAL.md +++ b/docs/CORE_LOOP_EVAL.md @@ -15,7 +15,7 @@ upload role R&R → tag people → year-round dossier | Step | Status | Notes | |------|--------|--------| -| Encrypted workspace unlock/lock | Done | AES vault; seed password `workbench`; `.session` is token-only (re-unlock after API restart) | +| Encrypted workspace unlock/lock | Done | AES vault; demo seed password `workbench` (demo only — never a silent API default); `.session` is token-only (re-unlock after API restart) | | Encrypted backup / restore | Done | Settings → one-click snapshot under `data/backups`; restore replaces live DB while unlocked | | People list + CSV / manual add | Done | `POST /api/people/import` + Team paste/file; template download | | Role catalog + assign + author | Done | Seeded ladder; Roles page add/edit/delete; CSV/markdown or AI extract from R&R doc | @@ -39,7 +39,7 @@ upload role R&R → tag people → year-round dossier | Promotion packets | Done | Next-role marks + AI case draft | | Backfill + MCP bulk load | Done | Thin = ach+fb+docs+goals < 2; MCP needs explicit unlock / `PRM_PASSWORD` | | Settings → AI | Done | Private notes / meeting / document extract egress **enforced** on cloud paths | -| Desktop CSP / launch token / API sidecar | Done | CSP set; shell IPC removed; packaged Node + `prm-api.mjs` spawned by Tauri; CI builds Linux/macOS/Windows on `main` | +| Desktop CSP / launch token / API sidecar | Done | CSP set; shell IPC removed; packaged Node + `prm-api.mjs` spawned by Tauri; desktop installers via Actions **Run workflow** (not every merge) | ## Remaining gaps (honest) diff --git a/docs/DELIVERY.md b/docs/DELIVERY.md index 39f539e..bef3fc6 100644 --- a/docs/DELIVERY.md +++ b/docs/DELIVERY.md @@ -6,22 +6,27 @@ Aligned to [TRUST_MODEL.md](./architecture/TRUST_MODEL.md). ## Phase 0 — Foundations & safety -**Status:** Implemented in-repo (browser+API; Tauri shell compiles). +**Status:** Vertical slice shipped (browser + API; Tauri shell + Node sidecar). Several Phase 0 *targets* remain open — see below. -**Outcome:** Signed-capable app skeleton that can hold real data safely. +**Outcome:** App skeleton that can hold real data safely **when locked**, with honest threat-model docs. -- Tauri + Vite UI + IPC (spike: no naked HTTP API) -- Encrypted SQLite + app-data layout; sync-folder warning -- Single Account; keychain + Linux fallback -- `Person` / EmploymentRecord / manager tree -- CSV import -- ActivityEvent hash chain -- Workspace backup/restore (SQLite backup API) -- Synthetic 12-person seed org (demo + AI fixtures later) -- CI matrix spike on one primary OS, then expand; signing keys process started -- Design-partner outreach (data-handling agreement) +**Shipped** +- Tauri shell + Vite UI + Node Hono API on `127.0.0.1` (launch token in packaged desktop) +- AES-256-GCM seal of SQLite + files on lock; sync-folder hard-warn +- Single Account; workspace-password vault (API keys encrypted with workspace secret — not OS keychain yet) +- `Person` / manager tree + CSV import (requires EM) +- ActivityEvent hash chain + HMAC export +- Encrypted workspace backup/restore +- Synthetic **8-person** demo seed (rolling relative cycle dates) +- CI: unit tests on every `main` PR; desktop installers on manual `workflow_dispatch` -**Exit:** App runs encrypted workspace on at least one OS; backup/restore verified; trust model reflected in UI copy. +**Still open (do not claim done)** +- OS keychain for API keys +- SQLCipher / Rusqlite-primary path +- Signed / notarized installers + auto-update +- IPC-only topology without Node sidecar + +**Exit (partial):** App runs encrypted-at-rest workspace on supported OS targets; backup/restore verified; trust model reflected in UI copy. Signing + keychain remain follow-ups. --- @@ -111,8 +116,8 @@ docs/ |-------|----------| | Product mode | Solo EM workbench | | Collaboration | Import bundles | -| Stack | Tauri + Vite/React + SQLite encrypted | +| Stack | Tauri + Vite/React + SQLite (AES seal on lock) + Node Hono sidecar | | Upward / live anonymity / adverse impact | Hosted-only | | next_level_gap | Conditional | | Local retention | Current + previous cycle (+ export to SoR) | -| AI keys | In-app Settings → keychain | +| AI keys | In-app Settings → encrypted with workspace secret (keychain target) | diff --git a/docs/architecture/LOCAL_STACK.md b/docs/architecture/LOCAL_STACK.md index e6f4b61..3d031e0 100644 --- a/docs/architecture/LOCAL_STACK.md +++ b/docs/architecture/LOCAL_STACK.md @@ -10,19 +10,19 @@ Primary target: installable app on **Linux, Windows, macOS**. No Docker/Postgres | Layer | Choice | Notes | |-------|--------|-------| -| Shell | **Tauri 2** | dmg / msi|NSIS / AppImage|deb | +| Shell | **Tauri 2** | dmg / msi|NSIS / AppImage|deb (manual CI `workflow_dispatch`) | | UI | **React + TypeScript + Vite** | | -| Backend bridge | **Prefer Tauri IPC commands** for DB/FS/keychain/HTTP; optional thin Hono only if needed | Avoid unauthenticated TCP | -| If HTTP sidecar used | Hono on `127.0.0.1` + **per-launch capability token** + origin checks | Or Unix socket / named pipe | -| DB | **SQLite** via **Rusqlite in Rust** (preferred) or one pinned JS driver | Pick one in Phase 0; enables SQLCipher path | -| ORM / migrations | Drizzle or sqlx migrations — single choice in Phase 0 | | -| Files | OS app-data directory | | +| Backend (shipped) | **Node Hono sidecar** on `127.0.0.1` + session token; desktop adds **per-launch capability token** | Prefer migrating privileged ops to Tauri IPC over time | +| Backend (target) | Tauri IPC commands for DB/FS/HTTP without a long-lived TCP sidecar | Aspirational | +| DB (shipped) | **SQLite** via **better-sqlite3** + Drizzle; AES-GCM file seal when locked | Plaintext on disk while unlocked | +| DB (target) | Rusqlite / SQLCipher path | Aspirational | +| Files | OS app-data directory (desktop) or `PRM_DATA_DIR` / `./data` (dev) | | | Search | SQLite FTS5 | | -| Jobs | Durable `jobs` table + run-while-open worker | Reminders don’t fire when app closed — documented | -| Auth | Single Account; OS keychain for API keys | Linux: Secret Service or app-password-wrapped key file fallback | -| AI | Settings → AI; BYO keys + Ollama | | -| Encryption | **Required** for real data: SQLCipher or authenticated encryption of DB+files | Phase 0/1 gate | -| Packaging | Code signing + notarization (Apple) + Windows Authenticode | Phase 0 infrastructure | +| Jobs | In-process while app open | Reminders don’t fire when app closed — documented | +| Auth | Single Account; workspace password vault | API keys encrypted with workspace secret (keychain still a target) | +| AI | Settings → AI; BYO keys + Ollama + Cursor gateway | | +| Encryption | **Required** for real data: authenticated encryption of DB+files on lock | | +| Packaging | Unsigned CI artifacts today; code signing + notarization still needed | | --- @@ -30,17 +30,19 @@ Primary target: installable app on **Linux, Windows, macOS**. No Docker/Postgres ``` ┌──────────────────────────────────────────┐ -│ Tauri (Win / Mac / Linux) │ -│ React UI ── IPC ── Rust commands │ -│ │ │ -│ SQLite (encrypted) │ -│ App-data files (encrypted) │ -│ OS keychain │ +│ Tauri (Win / Mac / Linux) [optional] │ +│ React UI ── HTTP ── Node Hono sidecar │ +│ │ (127.0.0.1) │ +│ SQLite (sealed on lock) │ +│ App-data files (sealed) │ +│ Workspace-secret crypto │ └───────────┬──────────────────┬───────────┘ ▼ ▼ Cloud AI (opt-in) Ollama (opt) ``` +**Dev browser mode:** Vite UI + `pnpm dev:api` (no launch token). Anyone on the same OS account who can reach loopback and guess/know the password owns the vault. + **Rejected as v1 primary:** Electron (fallback only), Docker-only UX, Next.js SSR, naked Postgres. --- @@ -58,9 +60,9 @@ Same OS paths as before (`Application Support` / `%APPDATA%` / `~/.local/share/. backups/ ``` -- **Refuse or hard-warn** if path is under Dropbox/iCloud/OneDrive/Google Drive sync folders. -- Backup: SQLite Online Backup API / `VACUUM INTO`, then encrypt zip; verify restore. -- Portability: versioned workspace archive with schema version + forward migrations. +- **Hard-warn** if path is under Dropbox/iCloud/OneDrive/Google Drive sync folders (status + unlock UI). +- Backup: encrypted `.sqlite.enc` snapshots under `backups/`; verify restore while unlocked. +- Portability: versioned workspace archive with schema version + forward migrations (partial). --- @@ -74,7 +76,7 @@ Same OS paths as before (`Application Support` / `%APPDATA%` / `~/.local/share/. ## AI configuration -Fully in-app **Settings → AI** (see Features §8). Keys never in SQLite. Dev env overrides allowed for `pnpm dev` only. +Fully in-app **Settings → AI** (see Features §8). Keys are encrypted with the workspace secret in SQLite. Dev env overrides allowed for `pnpm dev` only. OS keychain storage remains a target, not current behavior. --- diff --git a/docs/architecture/SYSTEM.md b/docs/architecture/SYSTEM.md index bd8f363..41dc39a 100644 --- a/docs/architecture/SYSTEM.md +++ b/docs/architecture/SYSTEM.md @@ -16,16 +16,16 @@ Hosted multi-tenant SaaS is a **separate track**, not a config switch. ## Stack -See [LOCAL_STACK.md](./LOCAL_STACK.md). Summary: Tauri 2, React/Vite, SQLite encrypted, IPC-first, app-data files, keychain, BYO AI + Ollama. +See [LOCAL_STACK.md](./LOCAL_STACK.md). Summary: Tauri 2 (optional shell), React/Vite, SQLite via better-sqlite3 with AES-GCM seal on lock, Node Hono on loopback (+ launch token in desktop), app-data files, BYO AI + Ollama. OS keychain and IPC-only topology remain targets. --- ## Topology ``` -Tauri → React UI → IPC/commands → SQLite + files + keychain - ↓ - Cloud AI / Ollama (opt-in) +Tauri (optional) → React UI → HTTP (127.0.0.1 Hono) → SQLite + files + workspace crypto + ↓ + Cloud AI / Ollama (opt-in) ``` --- @@ -37,7 +37,7 @@ Tauri → React UI → IPC/commands → SQLite + files + keychain | Workspace Account (EM) | Full read/write on workspace; export subject packets; configure AI | | Person (no Account) | Not an actor in-app; appears in exports the EM creates | -Export redaction (`packages/policy`) strips `em_only` fields from subject packets. This is **share-time policy**, not protection from the EM. +Export redaction strips `em_only` fields from subject packets (implemented in API export paths). This is **share-time policy**, not protection from the EM. --- @@ -70,7 +70,7 @@ Conceptual routes — implemented as Tauri commands or authenticated localhost: - Link evidence; snapshots on finalize ### AI -- Settings get/set (keychain) +- Settings get/set (API keys encrypted with workspace secret) - `evidenceDigest`, `draftSection`, `roleGapAnalysis`, `promotionDraft`, `biasLint` - Returns `generation_id`; client accepts into draft diff --git a/docs/architecture/TRUST_MODEL.md b/docs/architecture/TRUST_MODEL.md index 883f11b..414239f 100644 --- a/docs/architecture/TRUST_MODEL.md +++ b/docs/architecture/TRUST_MODEL.md @@ -57,10 +57,17 @@ No anonymity theater: imported peer text is attributed to the named peer for the ## Security baseline (v1) -- Encrypt SQLite + `files/` at rest (workspace password / OS key material) — **required before real employee data** -- Local API authenticated per launch (capability token) **or** Tauri IPC only (no naked TCP) -- API keys in OS keychain (with documented Linux fallback) -- Refuse/warn if app-data path is inside Dropbox/iCloud/OneDrive -- Consistent backup via SQLite backup API + encrypted archive +### Shipped today +- Encrypt SQLite + `files/` at rest with the workspace password (scrypt + AES-256-GCM seal on **Lock & encrypt**) +- Local API bound to `127.0.0.1`; session token after unlock; packaged desktop adds a per-launch capability token +- Integration / AI secrets stored encrypted in SQLite under the workspace secret (not returned in plaintext from settings GETs) +- Hard-warn when the data directory looks like Dropbox / iCloud / OneDrive / Google Drive +- Encrypted backup / restore under `data/backups` + +### Not shipped yet (do not market as done) +- OS keychain custody for API keys (keys ride the workspace secret today) +- SQLCipher / Rusqlite-in-Rust as the primary DB path (Node `better-sqlite3` + file seal is what runs) +- Signed auto-update / notarized installers (desktop artifacts are manual CI builds) +- Background jobs when the app is closed See [LOCAL_STACK.md](./LOCAL_STACK.md) and [SYSTEM.md](./SYSTEM.md).