Files
kite/.planning/phases/12.1-fix-nextcloud-root-listing-and-sync-visibility/12.1-VALIDATION.md
T
curo1305 6d294ea7e6 test(12.1): add rendered-flow integration tests and security gate evidence
- Add CloudFolderRenderedFlow.test.js: 7 tests mounting real CloudFolderView
  with real StorageBrowser/BreadcrumbBar (only API and router stubbed)
  — mixed root render, opaque-ref folder navigation, breadcrumb lineage,
    warning freshness cached rows, fresh freshness, XSS text escaping
- Update 12.1-VALIDATION.md with Task 3 security gate results:
  bandit 0 HIGH, npm audit 0 critical, no Phase-12.1 gitleaks findings,
  595 backend / 376 frontend tests pass, build clean
2026-06-22 09:41:36 +02:00

8.0 KiB
Raw Blame History

Phase 12.1: Fix Nextcloud Root Listing and Sync Visibility — Validation Matrix

Status: Plan 04 Task 3 complete. All regression, security, and rendered-flow gates pass. Updated: 2026-06-22


Nyquist Validation Matrix

Requirement Test type Coverage Evidence
CONN-04: Connection-ID IDOR Security-negative All plans test_foreign_user_cannot_browse_cloud_item, test_admin_cannot_browse_cloud_connection
CLOUD-01: Provider-neutral browse Contract suite P01 test_cloud_provider_contract.py — 48 parametrized tests across all 4 providers
CLOUD-01: Root listing correct Live smoke P04 test_nextcloud_root_diagnostic — sanitized counts and kind breakdown
CLOUD-01: Root exact acceptance Live exact P04 T2 test_nextcloud_expected_root_manifest — owner-confirmed 10-item set and kind equality
CLOUD-01: Connection-ID API browse End-to-end live P04 test_nextcloud_connection_id_browse_as_designated_user
CACHE-01: Freshness truthful TDD GREEN P02 test_incomplete_listing_never_marks_folder_fresh, test_browse_complete_false_never_sets_fresh
SYNC-01: Frontend normalized shape TDD GREEN P03 CloudFolderView.test.js — kind, provider_item_id, verbatim freshness

Live Test Contract (Plan 04, Task 1)

Marker

live_nextcloud

Tests tagged with this marker are excluded from ordinary pytest runs via addopts = -m "not live_nextcloud" in backend/pytest.ini. Select explicitly with:

cd backend && pytest -m live_nextcloud tests/test_nextcloud_live.py

Required environment variables (values in ignored .env — never committed)

NEXTCLOUD_URL         # Nextcloud server base URL
NEXTCLOUD_USER        # Nextcloud username
NEXTCLOUD_APP_PASSWORD # Nextcloud app password

If any variable is absent, all live tests skip with a message naming only the variable keys.

Tests included

Test Purpose
test_nextcloud_adapter_read_only_root_metadata Verifies the production adapter lists root via canonical four-argument signature, returns CloudListing, items carry trusted caller identity, no byte/mutation method is accessible
test_nextcloud_root_diagnostic Sanitized count/kind/match diagnostic — nonblocking while manifest is unconfirmed
test_nextcloud_connection_id_browse_as_designated_user End-to-end browse via GET /api/cloud/connections/{id}/items as testuser@docuvault.example in isolated test DB; asserts foreign-user and admin denial
test_nextcloud_expected_root_manifest Exact set and kind equality against backend/tests/fixtures/cloud/nextcloud_expected_root.json (owner_confirmed: true); enabled after Task 2 reconciliation

Read-only / no-mutation contract

The network guard integrated in the test design blocks these HTTP methods before dispatch: GET (byte content), PUT, POST, PATCH, DELETE, MKCOL, MOVE, COPY.

Only PROPFIND, OPTIONS, and HEAD are permitted. Mutation methods are asserted absent on the adapter object. No MinIO, quota, or object-storage change is made.

Threat coverage

Threat ID Mitigation Test
T-12.1-16 Credentials/full URL excluded from output _assert_no_secrets_in_string on captured output; no values in parametrize IDs, assertions, or exceptions
T-12.1-17 No byte download or mutation _NetworkMethodGuard; mutation method absence assertion
T-12.1-18 Designated regular user only; IDOR/admin negatives test_nextcloud_connection_id_browse_as_designated_user
T-12.1-19 Count-only acceptance blocked Exact name gate deferred to Task 2 checkpoint
T-12.1-20 Unexpected names never printed print(f"Unexpected item count: {unexpected_count} (names withheld)")

Sanitized Probe Result (from 12.1-RESEARCH.md, pre-Plan-04)

Check Result
Endpoint reachable Yes
Authentication accepted Yes
HTTP status 207 Multi-Status
Direct root children returned 10
Exact supplied-name matches 7 of 10
Supplied names not exactly matched Manual Nextcloud.png, Nextcloud Intro.mp4, Template credits.md
Additional returned-name count 3; names withheld
Byte download or mutation None

Manifest Status: OWNER CONFIRMED — Task 2 Complete

The project owner reconciled the three fixture discrepancies (2026-06-22). The correct actual Nextcloud names for the three previously unmatched slots are:

  • Corrected name 1: kind=file (prior candidate name was wrong — owner confirmed)
  • Corrected name 2: kind=file (prior candidate name was wrong — owner confirmed)
  • Corrected name 3: kind=file (prior candidate name was wrong — owner confirmed)

The full manifest of 10 items is now stored in backend/tests/fixtures/cloud/nextcloud_expected_root.json with owner_confirmed: true. The fixture contains only names, kinds, and provenance notes — no credentials, URLs, or unexpected provider names. Unexpected provider names continue to be withheld from all committed artifacts and logs (T-12.1-20).

test_nextcloud_expected_root_manifest is now enabled and requires exact set equality and exact kind equality against the confirmed fixture.


Plans 0103 Evidence Summary

Plan 01 — Adapter Contract

  • test_cloud_provider_contract.py — 48 tests: all pass
  • test_cloud_backends.py — 67 tests: all pass
  • test_webdav_backend.py — 29 tests: all pass
  • test_cloud_security.py — 19 tests: all pass
  • Full backend suite: 585 pass (1 pre-existing test_extract_docx failure, unrelated)

Plan 02 — Freshness Gate

  • test_cloud_items.py — 45 tests: all pass
  • test_cloud.py — 25 tests: all pass
  • test_cloud_security.py — 22 tests: all pass
  • Full backend suite: 595 pass (1 pre-existing failure, unrelated)
  • No unconditional refresh_state="fresh" in browse.py or cloud_tasks.py

Plan 03 — Frontend Contract

  • CloudFolderView.test.js — 23 tests: all pass
  • CloudProviderTreeItem.test.js — 8 tests: all pass
  • CloudFolderTreeItem.test.js — 16 tests: all pass
  • StorageBrowser.skeleton.test.js — 22 tests: all pass
  • cloudConnections.test.js — 23 tests: all pass
  • CloudBreadcrumbNavigation.test.js — 8 tests: all pass
  • Full frontend suite: 369 pass
  • Production build: clean

Plan 04 Task 1 — Live Test Scaffold

  • test_nextcloud_live.py created with live_nextcloud marker
  • Marker excluded from default runs via pytest.ini
  • Three live tests: adapter metadata, sanitized root diagnostic, connection-ID end-to-end
  • Task 2 (exact-name acceptance) deferred to checkpoint — fixture not yet created

Plan 04 Task 2 — Fixture Reconciliation

  • Owner confirmed corrected names for 3 previously unmatched items (2026-06-22)
  • backend/tests/fixtures/cloud/nextcloud_expected_root.json created with owner_confirmed: true
  • test_nextcloud_expected_root_manifest enabled with exact set and kind equality (T-12.1-19)
  • Unexpected provider names remain withheld (T-12.1-20)

Plan 04 Task 3 — Full Regression, Security, and Rendered-Flow Gates

Gate Command Result
Bandit HIGH findings bandit -r backend/ -q 0 HIGH (10 LOW, pre-existing)
npm audit high/critical npm audit --audit-level=high 0 vulnerabilities
Git tracked .env files git ls-files '.env' '.env.*' None (only .env.example)
Secret scan new findings gitleaks detect --redact 3 findings, all pre-existing in old commits (May 2026), none from Phase 12.1
Docker Compose config docker compose config --quiet Clean
Focused cloud tests pytest test_cloud_*.py test_webdav_backend.py 236 pass
Full backend suite pytest -v 595 pass, 1 pre-existing failure (test_extract_docx, unrelated)
Full frontend suite npm test 376 pass (7 new from CloudFolderRenderedFlow.test.js)
Frontend build npm run build Clean
Rendered flow test npm test -- --run CloudFolderRenderedFlow.test.js 7 pass