Commit Graph

262 Commits

Author SHA1 Message Date
curo1305 9935c06aab docs(05): add code review report — 5 critical, 6 warning, 3 info findings 2026-05-30 11:49:43 +02:00
curo1305 aafd552a1e fix(05-09): set storage_backend='minio' in test_celery_task_uses_user_provider
Cloud-aware routing added in 05-09 checks doc.storage_backend; MagicMock
attribute is truthy and != 'minio', so the test was entering the cloud branch
without any mock for get_storage_backend_for_document. Regression: test passed
before 05-09 when _run() had no cloud routing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 11:43:48 +02:00
curo1305 02ef11c432 chore: merge executor worktree (05-11 admin hard-delete) 2026-05-30 11:40:40 +02:00
curo1305 3180e759de docs(05-11): complete admin hard-delete with password confirmation plan
- UserDeleteConfirm Pydantic model + Argon2 password verification in delete_user
- adminDeleteUser(id, adminPassword) exported from client.js
- AdminUsersTab inline delete confirmation panel with password field
- Three new tests pass: 204/403/422 scenarios
- Full 21-test admin suite green; frontend build clean
2026-05-30 11:40:14 +02:00
curo1305 72687212a1 feat(05-11): add adminDeleteUser API function + inline delete confirmation panel
- Export adminDeleteUser(id, adminPassword) from client.js — sends JSON body to DELETE /api/admin/users/{id}
- AdminUsersTab: add confirmDelete, deletePassword, deleteError state refs
- AdminUsersTab: add startDelete, cancelDelete, confirmDoDelete functions (mutually exclusive with deactivate panel)
- AdminUsersTab: Delete button added to active and deactivated user rows
- AdminUsersTab: inline password confirmation panel with Argon2 verification via backend
2026-05-30 11:39:10 +02:00
curo1305 390a693ec6 feat(05-11): add UserDeleteConfirm model + admin password verification in delete_user
- Import verify_password from services.auth
- Add UserDeleteConfirm Pydantic model (admin_password field)
- delete_user handler now requires body; fails fast with 403 on wrong password
- All existing SEC-09 cloud/MinIO purge logic and audit log unchanged
- Three new tests pass: 204 on correct pw, 403 on wrong pw, 422 on no body
2026-05-30 11:37:59 +02:00
curo1305 8727592bff test(05-11): add failing tests for delete_user password verification
- test_delete_user_correct_password: 204 on correct admin password
- test_delete_user_wrong_password: 403 on wrong password, user survives
- test_delete_user_no_body: 422 when no body provided (Pydantic validation)
2026-05-30 11:37:12 +02:00
curo1305 bd3b637d30 chore: merge executor worktree (05-10 OAuth fix + cloud UI gaps) 2026-05-30 11:33:57 +02:00
curo1305 f5ea2103b3 docs(05-10): complete OAuth initiate fix + cloud UI gap closure plan 2026-05-30 11:31:42 +02:00
curo1305 87de148a59 feat(05-10): OAuth fetch + Nextcloud edit fix + Edit on ERROR + text overflow
- client.js: add initiateOAuth() and getConnectionConfig() helpers
- SettingsCloudTab: replace window.location.href with initiateOAuth() + fetch/JWT
- SettingsCloudTab: add Edit button to ACTIVE and ERROR blocks for non-OAuth providers
- SettingsCloudTab: wrap ConfirmBlock in w-full overflow-hidden div
- CloudCredentialModal: add existing prop, edit-mode pre-population via /config endpoint
- CloudCredentialModal: add showAdvanced + customEndpoint for Nextcloud custom paths
- ConfirmBlock: add break-words class to message paragraph
- cloud.py: add GET /api/cloud/connections/{id}/config endpoint (non-secret fields)
2026-05-30 11:30:13 +02:00
curo1305 e2e499b8b1 feat(05-10): oauth_initiate returns 200 JSON {url} instead of 302 redirect
- Remove response_class=RedirectResponse from @router.get decorator
- Replace both RedirectResponse(status_code=302) returns with JSONResponse({url})
- Frontend can now inject Bearer header before navigating to OAuth URL (T-05-10-01)
- Update test_connect_google_drive to expect 200 JSON (regression fix)
2026-05-30 11:24:33 +02:00
curo1305 9b6d3f91d4 test(05-10): add failing tests for OAuth initiate JSON URL return 2026-05-30 11:23:38 +02:00
curo1305 dc475aaaa2 chore: merge executor worktree (05-09 cloud doc access) 2026-05-30 11:20:41 +02:00
curo1305 7534f679f3 docs(05-09): complete cloud document access fixes plan — PATCH endpoint, cloud-aware re-analyze, authenticated preview 2026-05-30 11:19:33 +02:00
curo1305 4a42ccee5a feat(05-09): authenticated document preview via fetch + Blob URL
- Add fetchDocumentContent() to client.js: fetch with Bearer auth, 401 refresh
  retry pattern, returns raw Response (not parsed JSON) for blob() calls
- Replace iframe :src=proxyUrl (unauthenticated) in DocumentPreviewModal.vue
  with authenticated fetch → blob → URL.createObjectURL; loading/error states;
  URL.revokeObjectURL on unmount to prevent memory leaks
- Replace window.open(rawUrl) in DocumentView.vue openPdf() with
  fetchDocumentContent → blob → objectUrl → window.open; 60s auto-revoke
- Frontend build exits 0 with zero errors
- Closes T-05-09-04: no persistent unauthenticated content exposure
2026-05-30 11:18:01 +02:00
curo1305 6d094d17f0 feat(05-09): PATCH /documents/{id} endpoint + cloud-aware Celery re-analyze
- Add DocumentPatch Pydantic model with filename and folder_id optional fields
- Add PATCH /api/documents/{doc_id} endpoint: ownership guard, model_fields_set
  to distinguish absent vs null folder_id, returns updated metadata dict
- Update _run() in document_tasks.py to use get_storage_backend_for_document
  for non-MinIO backends instead of hardcoded MinIO path
- CloudConnectionError caught in cloud path: returns extract_failed status
- Update test to use pure unit mocks (no PostgreSQL) for _run() cloud routing
- All 3 plan tests pass; 23 test_cloud.py tests pass
2026-05-30 11:16:01 +02:00
curo1305 9bc056100c test(05-09): add failing tests for PATCH /documents/{id} and cloud-aware re-analyze
- test_patch_document_filename: expects 200 with updated filename (PATCH endpoint missing → 405)
- test_patch_document_wrong_owner: expects 404 for non-owner (PATCH endpoint missing → 405)
- test_reanalyze_cloud_document_routes_to_cloud_backend: expects cloud backend called for nextcloud docs
2026-05-30 11:13:31 +02:00
curo1305 f006c00d49 docs(05): create UAT gap closure plans 09-11
Three new plans address all 6 diagnosed gaps from 05-UAT.md:

- 05-09: cloud document open (fetch+Blob URL), re-analyze (cloud-aware
  Celery task), and edit (PATCH /api/documents/{id})
- 05-10: OAuth initiate JSON response fix, Nextcloud custom endpoint
  edit round-trip, Edit button on ERROR rows, confirmation text overflow
- 05-11: admin hard-delete with admin-password confirmation (backend
  UserDeleteConfirm model + frontend inline panel)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 10:39:47 +02:00
curo1305 7691477c6d docs(05): mark Phase 5 complete — all 8 plans executed, security gates passed, human checkpoint approved
- ROADMAP.md: all 05-01..05-08 plans marked [x], phase gates [x], Progress Table row updated to Complete 2026-05-29
- STATE.md: status→complete, completed_phases→5, percent→100, session continuity entry added
2026-05-29 09:16:45 +02:00
curo1305 f1a7f52616 fix(security): bump python-multipart>=0.0.27 and PyMuPDF>=1.26.7 — pip-audit findings 2026-05-29 09:14:27 +02:00
curo1305 c6a97b6a89 docs(05-08): complete cloud sidebar tree plan — awaiting human checkpoint 2026-05-29 08:34:42 +02:00
curo1305 98576ac298 feat(05-08): add Cloud Storage collapsible section to AppSidebar
- Import CloudProviderTreeItem and useCloudConnectionsStore
- Add cloudExpanded ref (default true) and activeCloudConnections/loadingCloudConnections computed
- Insert Cloud Storage section between Folders and Topics sections
- Fetch connections on mount; render one CloudProviderTreeItem per ACTIVE connection
- Empty state: 'No cloud storage connected'; loading state: 'Loading...'
2026-05-29 08:33:33 +02:00
curo1305 34b0593782 feat(05-08): add cloud tree components and getCloudFolders API function
- Add getCloudFolders(provider, folderId) to api/client.js (GET /api/cloud/folders/{provider}/{folderId})
- Create CloudProviderTreeItem.vue: lazy-load folder tree per connection, providerIconColor computed, expand/collapse arrow, loading/error states
- Create CloudFolderTreeItem.vue: recursive folder tree node with is_dir expand arrow, lazy-load children, depth padding
2026-05-29 08:32:19 +02:00
curo1305 ec0c69fb4e docs(05-07): complete cloud storage frontend UI plan — SUMMARY and STATE
- useCloudConnectionsStore, 3-tab SettingsView, SettingsCloudTab, CloudCredentialModal
- 61 Vitest tests passing, Vite build exits 0
- Fixed pre-existing build failure (top-level await) via build.target=esnext
2026-05-29 08:18:48 +02:00
curo1305 63a68296a5 feat(05-07): 3-tab SettingsView, SettingsCloudTab, CloudCredentialModal
- Convert SettingsView to 3-tab layout (Preferences/AI/Cloud) matching AdminView pattern
- Extract SettingsPreferencesTab.vue and SettingsAiTab.vue from original SettingsView
- Create SettingsCloudTab.vue with all 4 providers, status badges, action buttons
- Create CloudCredentialModal.vue for WebDAV/Nextcloud credential input
- Handle OAuth callback query params (cloud_connected/cloud_error) in SettingsView.onMounted
- Add success toast (auto-dismiss 5s) and persistent error banner for OAuth results
- Fix pre-existing build failure: add build.target=esnext to vite.config.js for top-level await support
- 2 SettingsCloudTab mount tests passing (W4 — CLAUDE.md)
2026-05-29 08:12:36 +02:00
curo1305 612d542c06 feat(05-07): cloud connections Pinia store + API client functions
- Create useCloudConnectionsStore with connections/loading/error refs
- fetchConnections, disconnect(id), disconnectAll() actions
- Append listCloudConnections, disconnectCloud, connectWebDav, updateDefaultStorage to api/client.js
- Add vitest test script to package.json
- 4 unit tests passing (W4 — CLAUDE.md)
2026-05-29 08:05:59 +02:00
curo1305 c44e861271 docs(05-06): complete cloud upload/test integration plan — SUMMARY and STATE
- Create 05-06-SUMMARY.md: documents.py cloud extension + 20 passing cloud tests
- Update STATE.md: plan 5→6 of 8, session notes, next action → 05-07
- Update ROADMAP.md: mark 05-06 as complete [x]
2026-05-29 07:58:03 +02:00
curo1305 d84e38acca test(05-06): promote 11 integration test stubs to real passing tests
- test_connect_google_drive: OAuth initiate redirects to Google (Redis mocked)
- test_oauth_callback_valid_state: valid state + mocked Flow.fetch_token → 302 (CLOUD-01)
- test_oauth_callback_invalid_state: invalid state → error redirect (CLOUD-01)
- test_webdav_connect_validates: localhost URL → 422 (D-17 SSRF)
- test_credentials_enc_not_exposed: credentials_enc absent from response (CLOUD-02, SEC-08)
- test_cloud_upload_no_presigned: cloud upload returns no upload_url (CLOUD-03)
- test_connection_status_display: ACTIVE status in list response (CLOUD-04)
- test_invalid_grant_sets_requires_reauth: 503 on invalid_grant (CLOUD-05)
- test_disconnect_deletes_credentials: DELETE 204 + DB row gone (CLOUD-06)
- test_admin_cannot_see_credentials: admin gets 403 (SEC-08 IDOR)
- test_cross_user_idor: wrong-owner delete → 404 (SEC-08 IDOR)

Also fix CloudConnectionOut.id field validator to accept UUID objects from ORM
(Rule 1: Bug - UUID id caused pydantic validation error on list_connections)

All 20 cloud tests PASSED; full suite: 282 passed, 1 pre-existing failure
2026-05-29 07:51:02 +02:00
curo1305 096bb48116 test(05-06): promote 4 unit test stubs to real passing tests
- test_credential_round_trip: verifies HKDF AES-256-GCM round-trip (CLOUD-02)
- test_ssrf_validation: parametrized over 6 URLs (5 blocked, 1 public) (D-17)
- test_ssrf_link_local: explicit link-local 169.254.x.x check (D-17)
- test_factory_returns_correct_backend: mock-based factory test (CLOUD-07)
All 4 tests PASSED; no xfail decorators remaining on these tests
2026-05-29 07:47:33 +02:00
curo1305 d7d6382d49 feat(05-06): extend upload and content-proxy endpoints for cloud backends
- Add POST /api/documents/upload multipart endpoint with target_backend form field
- Cloud backends (google_drive, onedrive, nextcloud, webdav) use direct put_object()
- MinIO path generates presigned PUT URL (unchanged flow)
- Cloud uploads do NOT touch quota (D-11: separate backend)
- GET /api/documents/{id}/content now uses get_storage_backend_for_document
- CloudConnectionError from any cloud op raises HTTPException(503) with safe message
- target_backend validated against _CLOUD_PROVIDERS allowlist (T-05-06-01)
- Import CloudConnectionError with fallback stub for envs without google-auth deps
2026-05-29 07:45:28 +02:00
curo1305 be6ff5a71f docs(05-05): complete cloud API endpoints plan — SUMMARY and STATE
- Created 05-05-SUMMARY.md: cloud.py (7 endpoints), main.py (router registration), admin.py (SEC-09 cleanup)
- Updated STATE.md: plan advanced to 5/8, session log updated, decisions recorded
- Updated ROADMAP.md: 05-03, 05-04, 05-05 marked complete
- Updated REQUIREMENTS.md: SEC-09 marked complete (cloud credential purge on account deletion)
2026-05-29 07:34:22 +02:00
curo1305 d85a09719e feat(05-05): add cloud credential cleanup on admin user deletion (SEC-09)
- Import CloudConnection and get_storage_backend_for_document into admin.py
- In delete_user: query all CloudConnection rows for the target user before MinIO cleanup
- For each connection: query documents with matching storage_backend, call delete_object
  best-effort (catch + ignore exceptions — same pattern as MinIO cleanup)
- Explicit session.delete(conn) for each CloudConnection row before user row deletion
- session.flush() after connection deletes to order SQL before user DELETE
- write_audit_log(event_type="cloud.credentials_purged") with providers list metadata
- Cloud cleanup runs BEFORE existing MinIO cleanup: credentials still available to build
  cloud backend instances for delete_object calls (SEC-09)
- No orphaned credentials_enc rows after account deletion (SEC-09 satisfied)
2026-05-29 00:59:10 +02:00
curo1305 f509c37611 feat(05-05): register cloud and users routers in main.py
- Added import and app.include_router(cloud_router) for Phase 5 cloud endpoints
- Added app.include_router(cloud_users_router) for /api/users/me/default-storage
- Both routers registered after the Phase 4 audit router
- All 6 cloud routes + default-storage route visible in app.routes
2026-05-29 00:45:14 +02:00
curo1305 2424f52eee feat(05-05): implement cloud.py — all 7 cloud connection management endpoints
- GET /api/cloud/oauth/initiate/{provider}: generates state token (secrets.token_urlsafe(32)),
  stores in Redis with TTL 1800, redirects to Google Drive or OneDrive OAuth URL
- GET /api/cloud/oauth/callback/{provider}: validates state (single-use Redis key), exchanges
  code for tokens, encrypts credentials, upserts CloudConnection, audit log, redirects to
  {settings.frontend_url}/settings?cloud_connected={provider}; on error redirects with cloud_error=
- POST /api/cloud/connections/webdav: SSRF validates URL, tests health_check, encrypts creds,
  upserts CloudConnection, returns CloudConnectionOut (credentials_enc excluded)
- GET /api/cloud/connections: returns {"items": [CloudConnectionOut]} — credentials_enc never exposed
- DELETE /api/cloud/connections/{connection_id}: returns 404 for wrong-owner (prevents enumeration)
- GET /api/cloud/folders/{provider}/{folder_id}: TTL-cached folder listing via get_cloud_folders_cached
- PATCH /api/users/me/default-storage: updates User.default_storage_backend
- _call_cloud_op helper: transparent token refresh + REQUIRES_REAUTH on invalid_grant
- All endpoints use Depends(get_regular_user) — admin gets 403 (D-18, D-19)
2026-05-29 00:40:08 +02:00
curo1305 add654444e docs(05-04): complete WebDAVBackend + NextcloudBackend plan — SUMMARY and STATE
- 05-04-SUMMARY.md: 2 tasks (31 tests, 4 files), 8 min, 1 auto-fixed deviation (factory dispatch)
- STATE.md: plan advanced to 4/8, session log updated, 3 new key decisions recorded
2026-05-28 21:15:12 +02:00
curo1305 6834a6797f docs(05-03): complete GoogleDriveBackend + OneDriveBackend plan
- SUMMARY.md created for Plan 05-03
- STATE.md updated: completed_plans 26→27, progress 81→84%
- Session continuity updated with pytest results (262 passed / 43 xfailed / 1 pre-existing)
- Key decisions added: shared CloudConnectionError, cache_discovery=False, createUploadSession
2026-05-28 21:13:53 +02:00
curo1305 a9ea33dd18 feat(05-04): fix storage factory to dispatch nextcloud to NextcloudBackend
- Previously both 'nextcloud' and 'webdav' providers were dispatched to WebDAVBackend
- Now 'nextcloud' uses NextcloudBackend (has list_folder); 'webdav' uses WebDAVBackend
- Both share identical constructor signature (server_url, username, password)
- Removes type: ignore[import] concern on nextcloud_backend — module now exists
2026-05-28 21:12:27 +02:00
curo1305 1b9573f398 feat(05-04): implement NextcloudBackend extending WebDAVBackend
- NextcloudBackend subclasses WebDAVBackend; inherits all 7 StorageBackend methods
- SSRF guard fully inherited: NextcloudBackend("http://10.0.0.1/dav", ...) raises ValueError
- stores self._username for Nextcloud path convention context
- list_folder(folder_path: str = "") async method added — lists via client.list() +
  client.info() wrapped in asyncio.to_thread(), returns [{id, name, is_dir, size}, ...]
- validate_cloud_url called before every asyncio.to_thread() call in list_folder (D-17)
- health_check overrides parent to use client.check("") for Nextcloud root probe
2026-05-28 21:11:12 +02:00
curo1305 bcb887e61d feat(05-03): implement OneDriveBackend — Microsoft Graph StorageBackend
- CloudConnectionError imported from google_drive_backend (shared exception type)
- CHUNK_SIZE = 10 * 1024 * 1024 (10 MB — above Graph 4 MB limit, Pitfall 6)
- All 7 StorageBackend methods implemented as async coroutines
- Resumable upload sessions (createUploadSession) used for ALL uploads
- _ensure_valid_token() checks expiry with 60s buffer, calls _refresh_token() if expired
- _refresh_token() wraps msal.ConfidentialClientApplication in asyncio.to_thread()
- invalid_grant → CloudConnectionError(reason='invalid_grant') per D-06 / B2 design
- presigned_get_url and generate_presigned_put_url raise NotImplementedError (D-14)
- delete_object silently ignores 404 (no-op per StorageBackend contract)
- Backend is stateless — no DB writes (B2 design)
2026-05-28 21:10:56 +02:00
curo1305 311dfa1513 feat(05-04): implement WebDAVBackend with SSRF guard and asyncio wrapping
- All 7 StorageBackend methods implemented as async coroutines
- validate_cloud_url() called in __init__ (SSRF at construct time) and before
  every asyncio.to_thread() call (D-17 defense-in-depth / T-05-04-01, T-05-04-02)
- _make_path() builds "docuvault/{user_id}/{document_id}{ext}" with urllib.parse.quote
  encoding on path segments (RESEARCH.md Pitfall 2)
- presigned_get_url and generate_presigned_put_url raise NotImplementedError (D-14)
- All webdavclient3 sync calls (upload_to, download_from, clean, info, check, mkdir)
  wrapped in asyncio.to_thread() per MinIOBackend pattern
- delete_object silently ignores missing file exceptions (StorageBackend ABC contract)
2026-05-28 21:09:25 +02:00
curo1305 337ee8ef11 feat(05-03): implement GoogleDriveBackend — Google Drive v3 StorageBackend
- CloudConnectionError(reason=) defined in this module — token_expired | invalid_grant
- All 7 StorageBackend methods implemented as async coroutines
- Every sync googleapiclient call wrapped in asyncio.to_thread() (Pitfall 7)
- cache_discovery=False on build() prevents /tmp directory traversal (T-05-03-05)
- presigned_get_url and generate_presigned_put_url raise NotImplementedError (D-14)
- HttpError 401 raises CloudConnectionError(reason='token_expired')
- HttpError 400 with 'invalid_grant' raises CloudConnectionError(reason='invalid_grant')
- HttpError 404 on delete_object is silently swallowed (no-op per contract)
- Backend is stateless — no DB writes (B2 design, D-05/D-06)
2026-05-28 21:07:26 +02:00
curo1305 c406ab1081 test(05-04): add failing RED tests for WebDAVBackend and NextcloudBackend
- Structure tests: all 7 methods async, proper subclassing
- SSRF guard tests: localhost/127.x/10.x/192.168.x/169.254.x raise ValueError
- NotImplementedError tests for presigned methods
- _make_path path construction and percent-encoding tests
- NextcloudBackend subclass, list_folder, inherited SSRF guard
2026-05-28 21:07:18 +02:00
curo1305 4efe7c1376 test(05-03): add RED phase tests for GoogleDriveBackend and OneDriveBackend
- 32 failing tests covering all 7 StorageBackend methods on both backends
- Verifies CloudConnectionError reason attribute (token_expired / invalid_grant)
- Verifies CHUNK_SIZE == 10 MB (Pitfall 6 prevention)
- Verifies shared CloudConnectionError import across backends
- Verifies _ensure_valid_token skips refresh on non-expired tokens
- Verifies _ensure_valid_token raises CloudConnectionError on invalid_grant
2026-05-28 21:06:14 +02:00
curo1305 3b84626da9 docs(05-02): complete shared cloud utilities plan
- 05-02-SUMMARY.md: full plan summary with TDD gate compliance, deviation docs, threat surface scan
- STATE.md: advanced to plan 26/32 (81%), updated session log, added 4 key decisions
- ROADMAP.md: marked 05-02 complete (2/8 Phase 5 plans done)
2026-05-28 21:04:03 +02:00
curo1305 fb803795fa feat(05-02): implement cloud_cache.py and extend storage factory
- cloud_cache.py: module-level TTLCache(maxsize=1000, ttl=60) singleton with
  threading.Lock for concurrent access safety (RESEARCH.md Pattern 8 / D-16)
- get_cloud_folders_cached(): async function; calls fetch_fn OUTSIDE the lock
  to avoid blocking the event loop during cloud API calls
- invalidate_provider_cache(): removes all cache entries for a user+provider prefix
- storage/__init__.py: adds get_storage_backend_for_document() async factory
  — returns MinIOBackend for minio docs; queries CloudConnection (scoped to user.id),
  decrypts credentials, and lazy-imports cloud backends to avoid circular imports
  — raises HTTPException(503) if connection missing or not ACTIVE (T-05-02-04)
2026-05-28 21:00:48 +02:00
curo1305 976d2ca2de feat(05-02): implement cloud_utils.py — SSRF validation and HKDF credential encryption
- validate_cloud_url(): blocks RFC-1918 (10.x, 172.16.x, 192.168.x), loopback (127.x),
  link-local (169.254.x), IPv6 loopback (::1), ULA (fc00::/7), and 'localhost' string;
  resolves DNS via socket.getaddrinfo BEFORE IP check (anti-DNS-rebinding per D-17)
- _derive_fernet_key(): creates fresh HKDF-SHA256 instance per call (AlreadyFinalized
  pitfall avoided per RESEARCH.md Pitfall 3); uses user_id as salt for per-user isolation
- encrypt_credentials(): Fernet-encrypts JSON-serialised credentials dict; returns str
- decrypt_credentials(): decrypts Fernet token back to original dict
- [Rule 1 - Bug] Fixed test_allows_public_https to use 8.8.8.8 IP (cloud.example.com
  does not resolve in offline CI environments)
2026-05-28 20:58:40 +02:00
curo1305 7fdffddfc1 test(05-02): add failing RED tests for cloud_utils, cloud_cache, and factory
- 11 SSRF validation tests (validate_cloud_url) covering RFC-1918, loopback, link-local, localhost, IPv6
- 7 HKDF credential encryption/decryption round-trip tests (encrypt_credentials, decrypt_credentials)
- 9 TTLCache singleton tests (maxsize=1000, ttl=60, thread-safe lock, get/invalidate helpers)
- 2 storage factory import tests (get_storage_backend_for_document importable)
2026-05-28 20:57:25 +02:00
curo1305 664451b8e6 docs(05-01): complete Wave 0 Nyquist scaffold plan
- Create 05-01-SUMMARY.md documenting all 3 tasks and 5 files modified
- Update STATE.md: session record, progress 78% (25/32 plans), resume file → 05-02
- Update ROADMAP.md: Phase 5 progress (1/8 summaries, In Progress)
- Update REQUIREMENTS.md: mark CLOUD-01..07 complete (Wave 0 scaffold)
2026-05-28 20:54:51 +02:00
curo1305 b53ea863dd feat(05-01): add Phase 5 cloud fixtures to conftest.py
Appends 4 new fixtures to backend/tests/conftest.py:
- mock_google_drive_creds: Google OAuth credential dict (access/refresh token, expiry)
- mock_onedrive_creds: OneDrive MSAL credential dict
- mock_webdav_client: MagicMock with upload_to/download_from/list/check methods
- cloud_connection_factory: async factory that creates CloudConnection ORM rows

All existing fixtures and tests unaffected; pytest collection errors = 0.
2026-05-28 20:51:41 +02:00
curo1305 231dfcd987 test(05-01): create test_cloud.py with 15 Phase 5 xfail stubs
All 15 stubs decorated with @pytest.mark.xfail(strict=False) covering
CLOUD-01..07, D-17 SSRF (test_ssrf_validation parametrized + test_ssrf_link_local),
and SEC-08/IDOR (test_admin_cannot_see_credentials, test_cross_user_idor).
pytest tests/test_cloud.py exits 0 with 19 xfailed (19 = 15 stubs + 4 parametrize variants).
2026-05-28 20:49:18 +02:00