diff --git a/.planning/STATE.md b/.planning/STATE.md index a229256..be9c367 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,13 +2,13 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone -current_phase: 4 -status: completed -last_updated: "2026-05-28T14:59:51.958Z" +current_phase: 5 +status: planned +last_updated: "2026-05-28T19:45:00.000Z" progress: total_phases: 5 completed_phases: 4 - total_plans: 24 + total_plans: 32 completed_plans: 24 percent: 80 --- @@ -16,7 +16,7 @@ progress: # Project State **Project:** DocuVault -**Status:** Phase 4 Complete — Ready to begin Phase 5 +**Status:** Phase 5 Planned — Ready to execute **Current Phase:** 5 **Last Updated:** 2026-05-28 @@ -161,6 +161,8 @@ _Updated at each phase transition._ | Last session | 2026-05-25 — Plan 04-03 executed: write_audit_log() helper (flush-not-commit, never-raises) + FOLD-01..05 folder API + document sort/FTS/move; 122 pass, 0 new failures | | Last session | 2026-05-25 — Plan 04-04 executed: Sharing API (SHARE-01..05) — grant/list/received/revoke with IDOR protection; 7 xfailed, zero new failures | | Last session | 2026-05-28 — Phase 4 UAT complete (14/15 passed, 1 bug found + fixed: duplicate folder on creation); sidebar collapsible folder tree added; Phase 4 marked complete | -| Next action | Begin Phase 5: Cloud Storage Backends — run /gsd:discuss-phase 5 | +| Last session | 2026-05-28 — Phase 5 UI-SPEC approved (6/6 dimensions passed; 2 revision rounds: Cancel label → context-specific, text-lg → text-xl) | +| Last session | 2026-05-28 — Phase 5 planned (8 plans, 7 waves); verification passed (4 blockers → resolved: D-05 API-layer refresh path, SEC-09 cloud cleanup, frontend_url config, RESEARCH resolved markers) | +| Next action | Execute Phase 5: Cloud Storage Backends — run /gsd:execute-phase 5 | | Pending decisions | None | -| Resume file | `.planning/phases/04-folders-sharing-quotas-document-ux/04-UAT.md` | +| Resume file | `.planning/phases/05-cloud-storage-backends/05-01-PLAN.md` | diff --git a/.planning/phases/05-cloud-storage-backends/05-VALIDATION.md b/.planning/phases/05-cloud-storage-backends/05-VALIDATION.md new file mode 100644 index 0000000..e0ebc7d --- /dev/null +++ b/.planning/phases/05-cloud-storage-backends/05-VALIDATION.md @@ -0,0 +1,88 @@ +--- +phase: 5 +slug: 05-cloud-storage-backends +status: draft +nyquist_compliant: false +wave_0_complete: false +created: 2026-05-28 +--- + +# Phase 5 — Validation Strategy + +> Per-phase validation contract for feedback sampling during execution. + +--- + +## Test Infrastructure + +| Property | Value | +|----------|-------| +| **Framework** | pytest + pytest-asyncio (already in requirements.txt) | +| **Config file** | `backend/pytest.ini` (already exists) | +| **Quick run command** | `cd backend && pytest tests/test_cloud.py -x -v` | +| **Full suite command** | `cd backend && pytest -v` | +| **Estimated runtime** | ~30 seconds (quick) / ~90 seconds (full) | + +--- + +## Sampling Rate + +- **After every task commit:** Run `cd backend && pytest tests/test_cloud.py -x -v` +- **After every plan wave:** Run `cd backend && pytest -v` +- **Before `/gsd:verify-work`:** Full suite must be green +- **Max feedback latency:** 90 seconds + +--- + +## Per-Task Verification Map + +| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status | +|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------| +| 05-01-01 | 01 | 0 | CLOUD-01..07 | T-05-01 | Wave 0 stubs; all xfail | unit stub | `pytest tests/test_cloud.py -x -v` | ❌ Wave 0 | ⬜ pending | +| 05-01-02 | 01 | 0 | CLOUD-02 | T-05-02 | `credentials_enc` round-trip | unit | `pytest tests/test_cloud.py::test_credential_round_trip -x` | ❌ Wave 0 | ⬜ pending | +| 05-02-01 | 02 | 1 | CLOUD-01 | T-05-03 | HKDF encrypt/decrypt round-trip | unit | `pytest tests/test_cloud.py::test_credential_round_trip -x` | ❌ Wave 0 | ⬜ pending | +| 05-02-02 | 02 | 1 | CLOUD-02, SEC-08 | T-05-04 | `credentials_enc` not in API response | integration | `pytest tests/test_cloud.py::test_credentials_enc_not_exposed -x` | ❌ Wave 0 | ⬜ pending | +| 05-03-01 | 03 | 2 | CLOUD-01 | T-05-05 | OAuth callback validates state, rejects invalid state (400) | integration | `pytest tests/test_cloud.py::test_oauth_callback_invalid_state -x` | ❌ Wave 0 | ⬜ pending | +| 05-03-02 | 03 | 2 | CLOUD-01 | T-05-06 | SSRF: RFC-1918 and loopback blocked | unit | `pytest tests/test_cloud.py::test_ssrf_validation -x` | ❌ Wave 0 | ⬜ pending | +| 05-03-03 | 03 | 2 | CLOUD-01 | T-05-07 | WebDAV connection validated before save (D-08) | integration | `pytest tests/test_cloud.py::test_webdav_connect_validates -x` | ❌ Wave 0 | ⬜ pending | +| 05-04-01 | 04 | 3 | CLOUD-05 | T-05-08 | `invalid_grant` sets REQUIRES_REAUTH | integration | `pytest tests/test_cloud.py::test_invalid_grant_sets_requires_reauth -x` | ❌ Wave 0 | ⬜ pending | +| 05-04-02 | 04 | 3 | CLOUD-06 | T-05-09 | Disconnect permanently deletes `credentials_enc` from DB | integration | `pytest tests/test_cloud.py::test_disconnect_deletes_credentials -x` | ❌ Wave 0 | ⬜ pending | +| 05-05-01 | 05 | 4 | CLOUD-03 | T-05-10 | Cloud upload goes through FastAPI, not presigned URL | integration | `pytest tests/test_cloud.py::test_cloud_upload_no_presigned -x` | ❌ Wave 0 | ⬜ pending | +| 05-05-02 | 05 | 4 | CLOUD-07 | T-05-11 | StorageBackend factory returns correct type per `storage_backend` field | unit | `pytest tests/test_cloud.py::test_factory_returns_correct_backend -x` | ❌ Wave 0 | ⬜ pending | +| 05-06-01 | 06 | 5 | CLOUD-04 | T-05-12 | Admin cannot see `credentials_enc` | integration | `pytest tests/test_cloud.py::test_admin_cannot_see_credentials -x` | ❌ Wave 0 | ⬜ pending | +| 05-06-02 | 06 | 5 | CLOUD-01 | T-05-13 | Cross-user cloud connection access returns 404 | integration | `pytest tests/test_cloud.py::test_cross_user_idor -x` | ❌ Wave 0 | ⬜ pending | + +*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* + +--- + +## Wave 0 Requirements + +- [ ] `backend/tests/test_cloud.py` — xfail stubs for all CLOUD-01..07 tests + SSRF + IDOR + admin-block +- [ ] `backend/tests/conftest.py` — new fixtures: `mock_google_drive_creds`, `mock_onedrive_creds`, `mock_webdav_client`, `cloud_connection_factory` + +*Existing test infrastructure (pytest, pytest-asyncio, httpx AsyncClient) covers all phase requirements — no new framework install needed.* + +--- + +## Manual-Only Verifications + +| Behavior | Requirement | Why Manual | Test Instructions | +|----------|-------------|------------|-------------------| +| OAuth consent UI for Google Drive | CLOUD-01 | Requires real GCP app credentials + browser | Connect Google Drive from SettingsView Cloud Storage tab; verify OAuth consent screen appears; verify redirect back with success toast | +| OAuth consent UI for OneDrive | CLOUD-01 | Requires real Azure app registration + browser | Connect OneDrive from SettingsView; verify Microsoft OAuth consent; verify redirect back with success toast | +| Sidebar cloud node appearance | CLOUD-03 | Browser UI | After connecting a provider, verify it appears as a top-level sidebar node; expand to see cloud folders | +| `REQUIRES_REAUTH` badge in UI | CLOUD-05 | Simulated token revocation + browser | Manually set `status='REQUIRES_REAUTH'` in DB; verify SettingsView shows yellow badge + Reconnect button | + +--- + +## Validation Sign-Off + +- [ ] All tasks have `` verify or Wave 0 dependencies +- [ ] Sampling continuity: no 3 consecutive tasks without automated verify +- [ ] Wave 0 covers all MISSING references +- [ ] No watch-mode flags +- [ ] Feedback latency < 90s +- [ ] `nyquist_compliant: true` set in frontmatter + +**Approval:** pending