Plans 01–04, CONTEXT, PATTERNS, RESEARCH, UAT, and .gitkeep for the fix-nextcloud-root-listing-and-sync-visibility sub-phase. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
17 KiB
17 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 12.1 | 01 | tdd | 1 |
|
true |
|
|
This plan changes metadata listing only. It does not add upload, create-folder, rename, move, delete, preview, download, or byte caching.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-CONTEXT.md @.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-RESEARCH.md @.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-PATTERNS.md @.planning/phases/12-cloud-resource-foundation/12-02-PLAN.md @.planning/phases/12-cloud-resource-foundation/12-VALIDATION.md @backend/storage/cloud_base.py @backend/storage/nextcloud_backend.py @backend/storage/webdav_backend.py Task 1: Write the shared four-provider contract and red tests backend/tests/test_cloud_provider_contract.py, backend/tests/test_cloud_backends.py, backend/tests/test_webdav_backend.py, backend/tests/fixtures/cloud/nextcloud_root.xml, backend/tests/fixtures/cloud/webdav_root.xml, backend/tests/fixtures/cloud/google_drive_pages.json, backend/tests/fixtures/cloud/onedrive_pages.json - backend/storage/cloud_base.py — exact CloudListing and CloudResource invariants - backend/storage/cloud_backend_factory.py — supported-provider construction paths - backend/tests/test_cloud_backends.py — existing provider mocks and missing behavioral coverage - backend/tests/test_webdav_backend.py — existing webdavclient3 test conventions - .planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-RESEARCH.md — confirmed signatures and provider fixture matrix Create a reusable parametrized contract harness whose provider cases supply only fixture setup and response stubs. Add concrete tests named `test_provider_list_folder_contract`, `test_provider_root_and_nested_identity`, `test_provider_metadata_normalization`, `test_provider_consumes_all_pages_before_complete`, `test_provider_page_failure_is_incomplete`, and `test_provider_listing_never_downloads_or_mutates`. Invoke each adapter through the canonical positional/keyword signature `(connection_id, user_id, parent_ref=None, page_token=None)` and assert the result is CloudListing; this test must fail against the current Nextcloud override.For every provider assert: trusted caller UUIDs are copied into resources; `provider_item_id` is the opaque navigation reference; `parent_ref` is the requested folder reference; `kind` is exactly file/folder; optional size/content-type/modified/version metadata becomes `None` when absent; and no provider response can override owner/connection IDs. Install spies that fail on GET-media/download/get_object/put/upload/create/move/copy/rename/delete methods and assert quota/MinIO are not imported or called by listing.
Add credential-free provider fixtures: Nextcloud and WebDAV Depth-1 multistatus with root self-entry, encoded spaces/unicode, collections, files, absent optional properties, absolute/relative hrefs, and a foreign/escaping href; Google Drive with root/nested queries, native files with nullable size, trashed exclusion, and multiple nextPageToken pages; OneDrive with root/nested endpoints, folder/file facets, encoded names, and multiple @odata.nextLink pages. Fixture names must be synthetic—not copied from the live account—and contain no URL, username, tokens, or provider-owned unexpected names.
Normalize a Nextcloud base URL and username to its canonical DAV root in one pure shared helper used at adapter construction, while accepting an already canonical endpoint idempotently. Percent-encode the username as one path segment; preserve deployment subpaths; reject userinfo, query, fragment, non-HTTPS, malformed URLs, and URLs rejected by `validate_cloud_url`; never log the normalized URL because it contains the username path segment.
Disable automatic redirects in the DAV HTTP transport. If redirect support is required, follow it explicitly with a strict bounded hop count and, before every hop, parse and validate the target URL, require HTTPS and the original normalized origin, resolve the hostname, and reject loopback, private, link-local, multicast, unspecified, reserved, or changed/untrusted addresses. Revalidate immediately before dispatch to limit DNS rebinding. Add automated redirect tests for loopback, RFC1918/private, link-local, cross-origin, non-HTTPS, excessive-hop, and a permitted same-origin target; assert rejected targets receive no second request and no URL is leaked.
Make the shared DAV listing parser authoritative for one Depth-1 response: exclude exactly the normalized self href, preserve a canonical child provider reference, use DAV collection resource type for kind, decode display path segments exactly once, reject hrefs outside the configured root, and return complete=False on malformed/ambiguous responses. Do not silently convert per-item metadata failures into a complete listing. If the existing SDK cannot expose a safe one-response parser without a new dependency, retain its calls but enforce the same completeness and no-byte contract; document the tradeoff in the summary.
Keep provider IDs opaque. Do not turn DocuVault CloudItem UUIDs into provider references and do not call media/download endpoints. Extend concrete provider tests where behavior is too provider-specific for the shared assertions.
<threat_model>
| Threat ID | Threat | Mitigation and evidence |
|---|---|---|
| T-12.1-01 | Provider response forges owner or connection identity | Contract copies trusted caller UUIDs and tests hostile fixture fields |
| T-12.1-02 | SSRF through Nextcloud normalization, redirects, or DAV hrefs | Canonical validator before construction/request; reject userinfo/query/fragment/private targets/escaping hrefs |
| T-12.1-03 | Partial page authorizes metadata deletion | complete=False on any page/parser/trust failure; contract tests every provider |
| T-12.1-04 | Browse downloads or mutates provider content | Failing spies on byte and mutation methods; metadata requests only |
| T-12.1-05 | Secrets/provider data leak through fixtures or failures | Synthetic fixtures, controlled exceptions, no live URL/user/token/unexpected-name output |
| </threat_model> |
<success_criteria>
- Nextcloud can be invoked through CloudResourceAdapter exactly like every other provider.
- Every provider has executable evidence for normalized identity, kind, metadata, pagination/completeness, and read-only behavior.
- Provider failures cannot masquerade as an authoritative empty collection.
- No Phase 13 mutation or Phase 14 byte behavior enters the contract. </success_criteria>
Create .planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-01-SUMMARY.md when complete.