- 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
9.0 KiB
phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
| phase | plan | subsystem | tags | requires | provides | affects | tech-stack | key-files | key-decisions | patterns-established | requirements-completed | duration | completed | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 05-cloud-storage-backends | 04 | api |
|
|
|
|
|
|
|
|
|
8min | 2026-05-28 |
Phase 5 Plan 04: WebDAVBackend and NextcloudBackend Summary
Generic WebDAV and Nextcloud StorageBackend implementations with SSRF double-guard (construct-time + per-request), asyncio.to_thread() wrapping for all sync webdavclient3 calls, and NextcloudBackend list_folder for lazy-load folder tree
Performance
- Duration: 8 min
- Started: 2026-05-28T19:05:47Z
- Completed: 2026-05-28T19:13:35Z
- Tasks: 2 (+ 1 RED phase commit)
- Files modified: 4
Accomplishments
- Created
webdav_backend.pywithWebDAVBackendimplementing all 7StorageBackendabstract methods; validate_cloud_url() called in__init__(SSRF at construct time) and before everyasyncio.to_thread()call (D-17 defence-in-depth / T-05-04-01, T-05-04-02) - Created
nextcloud_backend.pywithNextcloudBackend(WebDAVBackend)inheriting all 7 methods; addedlist_folder()async method returning[{id, name, is_dir, size}]dicts for the lazy-load cloud folder tree API; overrideshealth_checkto useclient.check("")for Nextcloud root - Confirmed webdavclient3 actual method names by runtime inspection (
upload_to,download_from— RESEARCH.md ASSUMPTION A1 was correct) - Created 31 TDD tests covering: subclassing invariants, all 7 methods async, SSRF guard for multiple private IP ranges, NotImplementedError for presigned methods,
_make_pathpath construction and percent-encoding, NextcloudBackend subclass,list_folderpresence, inherited SSRF guard - Fixed storage factory
__init__.pyto dispatchnextcloudprovider toNextcloudBackendandwebdavtoWebDAVBackend(both with identical constructor signatures)
Task Commits
- RED phase tests —
c406ab1(test) - Task 1: WebDAVBackend —
311dfa1(feat) - Task 2: NextcloudBackend —
1b9573f(feat) - Storage factory fix —
a9ea33d(feat)
Files Created/Modified
/Users/nik/Documents/Progamming/document_scanner/backend/storage/webdav_backend.py— WebDAVBackend: all 7 async methods, SSRF guard, asyncio.to_thread() wrapping, _make_path with URL encoding/Users/nik/Documents/Progamming/document_scanner/backend/storage/nextcloud_backend.py— NextcloudBackend: inherits WebDAVBackend, adds list_folder(), overrides health_check()/Users/nik/Documents/Progamming/document_scanner/backend/tests/test_webdav_backend.py— 31 tests (TDD: RED → GREEN)/Users/nik/Documents/Progamming/document_scanner/backend/storage/__init__.py— Fixed nextcloud/webdav provider dispatch in get_storage_backend_for_document()
Decisions Made
validate_cloud_url()is called insidelist_folder()beforeclient.list()AND before eachclient.info()in the item loop — every outbound HTTP request is guarded, not just the first in the loop.- webdavclient3 method names
upload_to(buf, remote_path)anddownload_from(buf, remote_path)were confirmed by runtimedir(Client)inspection before use. RESEARCH.md ASSUMPTION A1 was accurate. nextcloudandwebdavnow dispatch to distinct classes solist_folderis available on Nextcloud connections but not on generic WebDAV connections (which don't have a standardised folder listing path convention).client.mkdir(parent_dir, recursive=True)called input_objectbefore upload — idempotent; webdavclient3 mkdir is a no-op if directory already exists.
Deviations from Plan
Auto-fixed Issues
1. [Rule 2 - Missing Critical] Storage factory dispatching nextcloud to WebDAVBackend instead of NextcloudBackend
- Found during: Post-Task 2 review of storage/__init__.py
- Issue: The Plan 02 factory combined
nextcloudandwebdavinto a single dispatch arm both returningWebDAVBackend. This meant Nextcloud connections would not havelist_folder, which is the key capability that distinguishesNextcloudBackendfromWebDAVBackendand is required for the cloud folder tree API. - Fix: Split the dispatch:
nextcloud→NextcloudBackend,webdav→WebDAVBackend; both use identical constructor signatures so the fix is a one-line change per arm. - Files modified:
backend/storage/__init__.py - Verification: Full test suite passes (262 passed); factory module imports correctly.
- Committed in:
a9ea33d
Total deviations: 1 auto-fixed (Rule 2 — missing critical dispatch differentiation) Impact on plan: No scope creep. The fix restores intended behaviour already implied by the plan's decision to use two distinct classes.
Issues Encountered
webdavclient3 was not installed locally — installed via pip3 install webdavclient3 (as expected for a new dependency added in Plan 05-01 requirements.txt). This is consistent with the Pattern established in Plan 05-02 SUMMARY.
Known Stubs
None. Both backends implement all 7 StorageBackend methods without stubs or placeholder returns. presigned_get_url and generate_presigned_put_url raise NotImplementedError by design (D-14).
Threat Surface Scan
No new network endpoints introduced. Both backends are internal SDK wrappers:
- All outbound WebDAV HTTP calls flow through webdavclient3 SDK, not new FastAPI routes
- SSRF guard (
validate_cloud_url) is called at construct-time and before every outbound call — T-05-04-01 and T-05-04-02 mitigated - No new trust boundaries created
No threat flags raised.
Next Phase Readiness
- Plans 05-03 (Google Drive), 05-05 (OneDrive) can import from
storage.webdav_backendandstorage.nextcloud_backendimmediately get_storage_backend_for_document()now correctly dispatches all 4 providers (minio, google_drive stub, onedrive stub, nextcloud, webdav)- The 31 new tests are green; the 43 xfail stubs in
test_cloud.pyremain xfail (correctly — they test API endpoints not yet built) - Full suite: 262 passed / 43 xfailed / 1 pre-existing failure (
test_extract_docx— python-docx not installed locally)
Self-Check: PASSED
Files verified present:
backend/storage/webdav_backend.py: FOUND (class WebDAVBackend, all 7 async methods)backend/storage/nextcloud_backend.py: FOUND (class NextcloudBackend, list_folder)backend/tests/test_webdav_backend.py: FOUND (31 tests, all passing)backend/storage/__init__.py: FOUND (updated nextcloud/webdav dispatch)
Commits verified:
c406ab1: test(05-04) — RED tests — FOUND311dfa1: feat(05-04) — WebDAVBackend — FOUND1b9573f: feat(05-04) — NextcloudBackend — FOUNDa9ea33d: feat(05-04) — factory fix — FOUND
Phase: 05-cloud-storage-backends Completed: 2026-05-28