diff --git a/AGENTS.md b/AGENTS.md index 8a95e65..0eedb7a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ DocuVault is a multi-user SaaS document management platform built on FastAPI (Python) + Vue 3. It handles document upload, text extraction (PDF/DOCX/image/text), AI-based topic classification, per-user isolated storage, folder organization, document sharing, and pluggable cloud storage backends (OneDrive, Google Drive, Nextcloud, WebDAV). -**Current state:** v0.2.1 — Phase 12 gap-closure complete (2026-06-20). Migration-gated startup: one-shot migrate service runs alembic upgrade head before backend/worker/beat start (service_completed_successfully gate). 0005→0006 upgrade regression in test_migration_0006.py. RUNBOOK migration ops section. Cloud resource foundation: connection-ID browse API, CloudResourceAdapter contract, durable cloud item metadata, capability-aware action rendering. Not cleared for public internet deployment. +**Current state:** v0.2.5 — Phase 12.1 Plan 03 complete (2026-06-22). Cloud frontend aligned with normalized API: `kind` field for item classification, `provider_item_id` for opaque provider navigation, server freshness state mapped verbatim, explicit breadcrumb lineage. Phase 12.1 in progress. Not cleared for public internet deployment. ## Stack diff --git a/CLAUDE.md b/CLAUDE.md index 3ecd478..97cba0e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ DocuVault is a multi-user SaaS document management platform built on FastAPI (Python) + Vue 3. It handles document upload, text extraction (PDF/DOCX/image/text), AI-based topic classification, per-user isolated storage, folder organization, document sharing, and pluggable cloud storage backends (OneDrive, Google Drive, Nextcloud, WebDAV). -**Current state:** v0.2.4 — Phase 12.1 Plan 02 complete 2026-06-22. Truthful freshness gate added: `apply_listing_and_finalize()` in `cloud_items.py` is the single shared gate used by both `browse.py` and `cloud_tasks.py`. Incomplete listings (`CloudListing.complete=False`) no longer produce `refresh_state="fresh"` — they retain cached items, preserve prior `last_refreshed_at`, and set a controlled `incomplete_listing` warning. `ListingResult` dataclass carries `is_fresh`, `warning_code`, and `warning_message`. Phase 12.1 in progress. Not cleared for public internet deployment. +**Current state:** v0.2.5 — Phase 12.1 Plan 03 complete 2026-06-22. Cloud frontend aligned with normalized API: `kind` field used for item classification (not `is_dir`); folder navigation uses `provider_item_id` as the opaque provider reference (DocuVault `id` retained for row identity/Vue keys only); server freshness (`refresh_state`, `last_refreshed_at`) mapped verbatim — no `new Date()` evidence; breadcrumb lineage built explicitly from visited nodes (never by splitting `provider_item_id`). Phase 12.1 in progress. Not cleared for public internet deployment. ## Stack diff --git a/README.md b/README.md index 5d4cf08..7059abf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # DocuVault -**Version 0.2.4 — Alpha** +**Version 0.2.5 — Alpha** > **Not production-ready.** DocuVault is functional for local and self-hosted use but has not been audited or hardened for public internet exposure. APIs, environment variables, and the database schema may change without notice until a stable 1.0 release is declared. diff --git a/SECURITY.md b/SECURITY.md index fd69e15..9db731a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -437,3 +437,25 @@ pytest -q backend/tests/test_cloud_items.py backend/tests/test_cloud.py backend/ 89 passed ``` Bandit over modified files (`services/cloud_items.py`, `api/cloud/browse.py`, `tasks/cloud_tasks.py`): 0 HIGH, 0 MEDIUM findings. + +--- + +## Phase 12.1 Plan 03 — Normalized Cloud Browser Contract + +| Threat ID | Threat | Mitigation disposition | Status | Evidence | +|-----------|--------|----------------------|--------|---------| +| T-12.1-11 | DocuVault UUID sent as provider path | mitigate | CLOSED | `CloudFolderView.navigateTo` uses `item.provider_item_id`; `CloudFolderTreeItem.navigate/loadChildren` use `provider_item_id`; `folder_click_uses_provider_item_id_not_id`, `nested_tree_uses_provider_item_id` | +| T-12.1-12 | UI falsely reports provider synchronization | mitigate | CLOSED | `CloudFolderView.load()` maps `data.freshness.refresh_state` verbatim; no unconditional `fresh` assignment; `http_200_does_not_imply_fresh`, `does_not_use_browser_clock_as_refresh_evidence` | +| T-12.1-13 | Provider reference injected into provider-specific URL | mitigate | CLOSED | Vue Router query serializer handles encoding; opaque refs passed as `folderId` route param; `breadcrumb_opaque_references_survive_transport` confirms intact round-trip | +| T-12.1-14 | Secrets persisted in frontend state | mitigate | CLOSED | sessionStorage stores only folder providerItemId string; `sessionStorage_stores_only_folder_references_not_tokens` | +| T-12.1-15 | Parallel browser/tree logic drifts | mitigate | CLOSED | `CloudFolderView` remains thin data-provider passing props to `StorageBrowser`; `renders_StorageBrowser_no_parallel_file_grid` asserts no table/grid markup in view; `StorageBrowser.skeleton.test.js` confirms shared component contract | + +### Phase 12.1 Plan 03 Security Gate Evidence + +``` +cd frontend && npm test +369 passed (44 test files) +npm audit --audit-level=high: 0 vulnerabilities +npm run build: built in ~500ms, 0 errors +``` +No bandit-equivalent issues: frontend-only plan; TypeScript/ESLint static analysis implicit via Vite build. diff --git a/backend/main.py b/backend/main.py index 121c402..da10412 100644 --- a/backend/main.py +++ b/backend/main.py @@ -244,7 +244,7 @@ async def lifespan(app: FastAPI): # ── Application factory ─────────────────────────────────────────────────────── -app = FastAPI(title="Document Scanner API", version="0.2.4", lifespan=lifespan) +app = FastAPI(title="Document Scanner API", version="0.2.5", lifespan=lifespan) # Rate limiter state (slowapi) app.state.limiter = auth_limiter diff --git a/frontend/package.json b/frontend/package.json index 980a308..6d5391b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "document-scanner-frontend", - "version": "0.2.4", + "version": "0.2.5", "type": "module", "scripts": { "dev": "vite",