curo1305
1df61040c6
feat(14-02): add version-key, settings helpers and Phase 14 cache service functions
...
- cloud_analysis_versioning.py: compute_version_key with version>etag>fingerprint
precedence (D-19); compute_fingerprint helper; content_hash is optional post-
hydration only (D-20); raises ValueError only, no HTTPException
- cloud_analysis_settings.py: get_or_create_user_analysis_settings (upsert on
first access), update_user_analysis_settings with enum validation and tier-capped
cache limit, build_default_settings for API responses; raises ValueError only
- cloud_cache.py: Phase 14 durable cache functions added alongside existing Phase 12
in-memory TTL cache — create_cache_entry, list_cache_entries (owner-scoped),
evict_lru_entries (LRU, skips pin_count>0 and active_job_count>0), increment/
decrement_quota_for_cache (atomic UPDATE pattern); re-exports compute_version_key
from cloud_analysis_versioning so tests have one import site
2026-06-23 15:14:19 +02:00
curo1305
fd76d06b3a
feat(14-02): add migration 0007 and ORM models for cloud analysis cache schema
...
- 0007_cloud_analysis_cache.py: new Alembic migration adding 4 Phase 14 tables
- cloud_byte_cache_entries: durable MinIO cache with version_key uniqueness,
pin_count/active_job_count guards, LRU eviction indexes
- cloud_analysis_jobs: batch job rows (scope_kind, status, aggregate counters,
provider_bytes_estimate, failure_behavior)
- cloud_analysis_job_items: per-item idempotency rows (status vocabulary,
controlled error fields, cache_entry_id, retry_count, version_key fingerprint)
- user_analysis_settings: per-user preferences (progress_detail, failure_behavior,
cloud_cache_limit_bytes)
- Reversible downgrade drops Phase 14 objects only
- db/models.py: CloudByteCacheEntry, CloudAnalysisJob, CloudAnalysisJobItem,
UserAnalysisSettings ORM models mirroring migration
2026-06-23 15:06:24 +02:00
curo1305
493d348ba6
docs(14-01): complete Phase 14 Plan 01 red test contract
2026-06-23 15:00:57 +02:00
curo1305 and Claude Sonnet 4.6
7f2f570582
test(14-01): add RED frontend tests for analysis queue UX and store actions
...
- StorageBrowser.analysis-queue.test.js: row-level Analyze action (D-01),
toolbar Analyze Selection/Folder/Connection (D-01..03), estimate modal
with D-03 required fields (supported_count/bytes/unsupported, Start action),
aggregate progress with simplified/detailed labels (D-05..08), expandable
queue item list, per-item cancel/retry/skip controls (D-09..10),
batch Cancel all (D-09), architecture no-parallel-grid guard (CLAUDE.md)
- cloudConnections.analysis.test.js: analysis state existence, translateAnalysisStatus
single-source (D-06/D-12), API call assertions without credentials (T-14-02),
cancel/retry/skip action coverage (ANALYZE-05), failure_behavior default=pause_batch
(D-11), detailedAnalysisProgress preference (D-06), cache limit exposure
(CACHE-04/D-15), credential-free localStorage guard
Requirements: ANALYZE-01..05, CACHE-04..05
All tests fail against missing Phase 14 implementation — no import errors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-23 14:56:39 +02:00
curo1305 and Claude Sonnet 4.6
f67559c7f0
test(14-01): add RED contract tests for cloud analysis and byte cache (backend)
...
- test_cloud_analysis_contract.py: estimate (single/selection/connection/folder),
already-current skip without byte fetch, changed-etag requeue, no-mutation
invariant, IDOR/admin-negative access (T-14-01..04), cancel/retry transitions
- test_cloud_cache.py: CloudByteCacheEntry schema, LRU eviction with pin
protection, quota increment/decrement seam (T-14-05), owner isolation
(CACHE-05), object-key secrecy (T-14-02), version-key precedence helper
- test_cloud_analysis_api.py: route registration gates, job status shape,
simplified/detailed progress labels (D-06), skip/cancel controls, scan
quota seam (D-13), failure_behavior field acceptance, unauthenticated block
Requirements: ANALYZE-01..07, CACHE-03..05
All tests fail against missing Phase 14 modules — no syntax/import errors in tests themselves
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-23 14:56:29 +02:00
curo1305
b528b51881
docs(phase-14): plan selective analysis and byte cache
2026-06-23 14:24:43 +02:00
curo1305
3514fdcf3a
docs(workflow): require gsd worktrees before edits
2026-06-23 14:10:41 +02:00
curo1305
fac7721dd9
docs(state): record phase 14 context session
2026-06-23 14:04:48 +02:00
curo1305
d3700e20c4
docs(14): capture phase context
2026-06-23 13:59:53 +02:00
curo1305 and Claude Sonnet 4.6
2f00e122d3
docs(phase-13): update VALIDATION.md — all tasks green, wave-0 complete
...
Nyquist audit 2026-06-23: 3 gaps found and resolved (open/create-folder/rename
audit writes). All 10 tasks marked green, wave_0_complete: true, status: complete.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-23 08:17:29 +02:00
curo1305 and Claude Sonnet 4.6
ed046752e4
test(13): add Nyquist validation — promote 3 xfail audit tests to green
...
Implemented write_audit_log calls for open_cloud_file, create_cloud_folder,
and rename_cloud_item in api/cloud/operations.py. Removed xfail markers from
test_cloud_audit.py. All 11 audit tests pass; 360 cloud tests pass total.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-23 08:17:24 +02:00
curo1305 and Claude Sonnet 4.6
fd48c5b928
docs(phase-13): add security threat verification — 34/34 threats CLOSED
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-23 07:52:31 +02:00
curo1305
0c4f9ccba3
test(13): persist human verification items as UAT
2026-06-23 07:41:48 +02:00
curo1305
40b1572582
test(13): persist human verification items as UAT
2026-06-23 00:43:01 +02:00
curo1305
f92270fda4
test(13): persist human verification items as UAT
2026-06-23 00:42:48 +02:00
curo1305
b1a9f436c4
fix(13): WR-06 read result.status (not result.state) in testConnection to reflect actual server field name
2026-06-23 00:30:01 +02:00
curo1305
60df8552b5
fix(13): CR-05 commit audit log after write_audit_log in reconnect endpoint so event is not silently lost
2026-06-23 00:29:34 +02:00
curo1305
af0de30e93
fix(13): CR-04 soft-delete CloudItem row on successful cloud delete to prevent orphaned metadata
2026-06-23 00:29:11 +02:00
curo1305
405c7a6610
fix(13): CR-03 wrap post-upload DB block in try/except to handle provider-success/DB-fail divergence
2026-06-23 00:28:34 +02:00
curo1305
a1d1c3ba2e
fix(13): CR-02 apply PurePosixPath.name guard in WebDAV upload_file and rename to prevent path traversal
2026-06-23 00:27:52 +02:00
curo1305
d4b2697109
fix(13): CR-01 use RFC 6266 filename*=UTF-8'' encoding in Content-Disposition to prevent header injection
2026-06-23 00:26:59 +02:00
curo1305
ebc74f4abe
fix(13): CR-06 re-raise HTTPException in preview_cloud_file instead of masking as unsupported_preview
2026-06-23 00:26:23 +02:00
curo1305
fcb38c50b1
docs(13): add code review report
2026-06-23 00:24:20 +02:00
curo1305
cd5bd82260
docs(13-11): update ROADMAP.md via gsd roadmap.update-plan-progress — Phase 13 11/11 summaries verified
2026-06-23 00:19:40 +02:00
curo1305
f09387a9d4
docs(13-11): add self-check result to summary
2026-06-23 00:18:52 +02:00
curo1305
25cc2537bb
docs(13-11): complete Phase 13 closeout plan summary and state update
...
- 13-11-SUMMARY.md: gate evidence (766 backend + 429 frontend tests pass, bandit 0 HIGH, npm audit clean, gitleaks 3 pre-existing), version 0.3.0, phase complete
- STATE.md: Phase 13 marked complete, progress updated, key decisions carried forward
2026-06-23 00:18:31 +02:00
curo1305
e68faf3051
chore(13-11): bump to v0.3.0, update docs, roadmap, and Phase 13 security gate evidence
...
- Version bump: 0.2.6 → 0.3.0 (Phase 13 complete — full cloud mutation surface shipped)
- CLAUDE.md: update current-state, shared module map, and Phase 13 non-negotiable rules
- README.md: add cloud file management, connection health, and authorized preview features; add Phase 13 mutation API table; mark Phase 13 complete
- ROADMAP.md: mark Phase 13 11/11 plans complete
- SECURITY.md: add Phase 13 threat register (T-13-01 through T-13-34), gate evidence (766 backend + 429 frontend tests pass, bandit 0 HIGH, npm audit 0 high/critical, gitleaks 3 pre-existing)
2026-06-23 00:14:57 +02:00
curo1305
e809df9f51
docs(13-10): complete frontend health UX and rendered-flow plan summary
2026-06-22 23:59:08 +02:00
curo1305
a7e55d1bb0
feat(13-10): reactive mock store in rendered-flow test surfaces health banner and no-probe assertions
...
- CloudFolderRenderedFlow.test.js: mock store uses Vue refs so folderFreshness propagates
reactively to StorageBrowser via CloudFolderView's template binding (D-12 GREEN)
- setBrowseState in mock now updates _mockFolderFreshness so cloud-health-banner appears
when API returns warning freshness (T-13-30 mitigated)
- Added testCloudConnection to API mock so D-13 no-probe assertion can verify it was not called
- beforeEach resets reactive refs for test isolation
- 11 rendered-flow tests pass; 70 total across health/store/view/rendered-flow suites
2026-06-22 23:56:13 +02:00
curo1305
60afb028bf
feat(13-10): store-backed health mapping, reconnect UX, no-probe-on-navigation, and Google Drive consent copy
...
- D-12: connectionHealth ref as single source for browser compact status and Settings diagnostics
- D-13: handleHealthFailure schedules pendingHealthRetest; navigation never triggers probe
- D-13: testConnection method in store (explicit action only, not navigation side-effect)
- D-14: markReconnecting preserves cached browseItems as stale; markReconnectRefreshPending flag
- D-15: degraded vs requires_reauth health states distinguished in store vocabulary
- D-17: Google Drive scope notice in SettingsCloudTab for all connect/reconnect paths
- StorageBrowser: cloud-health-banner (warning/stale) and requires-reauth prompt with reconnect action
- 59 tests passing: store, Settings, and CloudFolderView health/reconnect suites
2026-06-22 23:55:58 +02:00
curo1305
a77b7324aa
docs(13-09): complete move and delete mutation plan summary
2026-06-22 20:04:38 +02:00
curo1305
508d27643b
feat(13-09): move stale-guard, descendant safety, reconciliation, delete disclosure, and metadata-only auditing
...
Move endpoint (D-07, D-08, D-09, T-13-27, T-13-28, T-13-29):
- Descendant destination detection via cloud_items ancestor-chain walk (D-09)
- Stale provider result marks source folder non-fresh, returns typed stale body (D-07)
- Success: upsert_cloud_item with new parent_ref before returning
- Success: update_folder_state for both source and destination folders
- Success: write_audit_log 'cloud.item_moved' with metadata-only payload
Delete endpoint (D-10, D-11, T-13-29):
- Pre-fetch item kind for D-10 folder-vs-file disclosure
- Success: update_folder_state for parent folder before returning
- Success: write_audit_log 'cloud.item_deleted' with delete_kind metadata
- Response carries is_folder/item_kind for frontend disclosure
- Failed deletes never emit audit rows
Promote xfail markers in test_cloud_audit.py for move and delete audit rows
2026-06-22 20:02:09 +02:00
curo1305
af7d45f3c4
test(13-09): add failing RED tests for move stale-guard, reconciliation, and delete disclosure/audit
...
- Move: stale etag returns 409 + refreshes source folder state
- Move: descendant destination rejected (D-09)
- Move: success upserts cloud_item with new parent_ref (reconcile-before-return)
- Move: success marks source + destination folders non-fresh
- Move: success writes metadata-only 'cloud.item_moved' audit row
- Delete: success marks parent folder non-fresh
- Delete: folder disclosure stronger than file (is_folder=True, D-10)
- Delete: success writes metadata-only 'cloud.item_deleted' audit row
- Delete: failed delete must not write false audit event
2026-06-22 19:58:00 +02:00
curo1305
3e9355f42d
docs(13-08): complete create-folder and rename collision, stale guard, reconciliation plan summary
2026-06-22 19:53:24 +02:00
curo1305
aaa63c19e4
feat(13-08): implement create-folder and rename collision retry, stale guard, and reconciliation
...
- create_cloud_folder: bounded collision retry (up to 5 attempts) with keep_both_name counter suffix (D-05, D-06)
- create_cloud_folder: stale precondition marks parent folder non-fresh and returns typed stale result (D-07)
- rename_cloud_item: stale precondition marks parent folder non-fresh via folder state update (D-07)
- create_cloud_folder: reconcile-before-return upserts new folder in cloud_items and invalidates parent (T-13-26)
- rename_cloud_item: reconcile-before-return upserts renamed item and invalidates parent folder (T-13-26)
- Import upsert_cloud_item, update_folder_state, keep_both_name, CloudResource from service modules
2026-06-22 19:51:57 +02:00
curo1305
9ad99461bf
test(13-08): add RED tests for create-folder and rename collision retry, stale guard, and reconciliation
...
- Test 1: collision auto-retry with bounded window (D-05, D-06)
- Test 2: stale guard updates folder state and returns typed stale kind (D-07)
- Test 3: create-folder and rename success upserts CloudItem and invalidates parent folder
- Test 4: failed rename does not mutate CloudItem rows
2026-06-22 19:49:41 +02:00
curo1305
561a40908d
docs(13-07): complete cloud queue and preview plan summary
2026-06-22 19:45:55 +02:00
curo1305
3351e63458
feat(13-07): wire binary-only preview and authorized download through shared actions
...
- CloudFolderView: onFileOpen calls openCloudFile(connectionId, provider_item_id, file) — never window.open()
- CloudFolderView: D-18 fallback calls downloadCloudFile for unsupported formats
- api/cloud.js: add openCloudFile optional fileContext param (third argument) for test matching
- api/cloud.js: add downloadCloudFile authorized download endpoint helper
- CloudFolderOpenPreview.test.js: fix makeBrowserStub missing name (findComponent by name)
- All 8 preview suite tests pass — binary-only preview + authorized fallback download
2026-06-22 19:42:48 +02:00
curo1305
e7e62bbab8
feat(13-07): implement sequential cloud upload queue with typed pause/resume
...
- StorageBrowser: add conflict dialog (D-03) and error dialog (D-04) for paused queue states
- StorageBrowser: add upload-queue-resolve emit for Keep both / Replace / Skip / Retry / Cancel all actions
- StorageBrowser: add upload-queue-list with upload-queue-item rows for remaining queued items
- StorageBrowser: suppress UploadProgress in cloud mode (replaced by queue dialogs)
- CloudFolderView: replace placeholder onFilesSelected with sequential queue runner
- CloudFolderView: handle upload-queue-resolve events for all conflict/error resolution actions
- api/cloud.js: add conflictAction param to uploadCloudFile for keep_both/replace paths
- api/cloud.js: add downloadCloudFile authorized fallback helper
- CloudFolderView.test.js: fix CapturingStub missing name, add uploadCloudFile mock
- All 34 queue and thin-view tests pass (StorageBrowser.cloud-queue + CloudFolderView)
2026-06-22 19:42:29 +02:00
curo1305
fc28e032be
docs(13-06): complete upload follow-through plan
2026-06-22 19:31:38 +02:00
curo1305
d959e0cf42
feat(13-06): emit metadata-only audit rows on authoritative upload success
...
- Write cloud.file_uploaded audit row in same transaction as reconciliation
- Audit payload is metadata-only: filename, size_bytes, connection_id, provider_item_id, parent_ref
- No provider URLs, tokens, bytes, or document text in audit metadata (T-13-02)
- Non-success paths (conflict, offline, reauth_required) bypass audit write (T-13-21)
- Import get_client_ip from deps.utils and write_audit_log from services.audit
2026-06-22 19:29:46 +02:00
curo1305
33f0498503
test(13-06): add failing upload audit test (RED) — promote from xfail
...
- Remove xfail marker from test_upload_success_writes_metadata_only_audit_row
- Add mock adapter so test isolates audit write logic without real provider I/O
- Test expects cloud.file_uploaded audit row with metadata-only payload (T-13-20)
2026-06-22 19:28:11 +02:00
curo1305
7ecbec7df9
feat(13-06): route upload success through centralized reconciliation before returning
...
- Upsert uploaded item into cloud_items for stable row identity and navigation
- Invalidate parent folder state (warning/upload_mutated) so next browse re-fetches
- Reconcile-before-return: session committed before response returned
- Failed/conflict uploads bypass reconciliation path (T-13-19)
2026-06-22 19:26:41 +02:00
curo1305
4cd6499a96
test(13-06): add failing upload reconciliation tests (RED)
...
- test_upload_success_upserts_cloud_item_before_returning — verifies CloudItem row exists after success
- test_upload_success_marks_folder_freshness_stale — verifies folder state updated on success
- test_upload_failed_does_not_mutate_cloud_items — verifies failed uploads don't create phantom items
2026-06-22 19:25:47 +02:00
curo1305
cad5ef5de2
docs(13-05): complete upload mechanics plan
2026-06-22 19:22:40 +02:00
curo1305
3ddf4da6a8
feat(13-05): add typed upload route mechanics tests (Task 2)
...
- test_upload_success_returns_typed_uploaded_body: kind/provider_item_id/name/size
- test_upload_provider_retryable_error_returns_offline_kind: typed offline body
- test_upload_provider_conflict_returns_conflict_kind: provider-detected collision
- test_upload_reauth_result_is_typed_and_not_500: CONN-02 credential failure path
- test_upload_queue_control_semantics_are_backend_authored: all 4 queue fields
- test_upload_keep_both_name_format: route can use keep_both_name() from service
- test_upload_foreign_user_blocked: IDOR protection on upload route
- 7 new tests pass; full suite 741 passed
2026-06-22 19:20:18 +02:00
curo1305
e1ce4cbe14
feat(13-05): implement keep_both_name() for D-03/D-05 collision naming
...
- keep_both_name(filename, counter) inserts counter before first extension
- Handles compound extensions (archive.tar.gz → archive (1).tar.gz)
- Handles extensionless files (README → README (1))
- Lives in services/cloud_operations as shared upload-queue helper
- All 23 upload contract + keep-both naming tests pass
2026-06-22 19:17:59 +02:00
curo1305
f47e36d93d
test(13-05): add failing RED tests for upload conflict semantics and keep-both naming
...
- TestUploadConflictSemantics: typed upload results across all 4 providers
- TestKeepBothNaming: keep_both_name() helper with counter before extension
- Tests verify credentials never appear in upload results (T-13-17)
- Upload kind values must be MUT_KINDS constants
- 16/23 pass (providers already have upload_file); 7 fail (keep_both_name missing)
2026-06-22 19:17:13 +02:00
curo1305
86a4fe0847
docs(13-04): complete authorized cloud mutations plan
2026-06-22 19:12:20 +02:00
curo1305
94a0617b9b
feat(13-04): add authorized cloud content and mutation routes with typed bodies
...
- backend/api/cloud/operations.py: owner-scoped open, preview, download, create-folder,
rename, move, delete, upload routes with typed kind/reason response bodies (D-02, D-03,
D-05, D-07, D-08, D-09, D-10, D-11, D-18, T-13-01, T-13-14)
- backend/api/cloud/__init__.py: register operations_router on /api/cloud
- backend/api/cloud/connections.py: Google Drive OAuth scope broadened to 'drive' (D-17)
- backend/api/cloud/schemas.py: ConnectionHealthOut, ReconnectOut, ContentResultOut,
MutationResultOut, CreateFolderRequest, RenameItemRequest, MoveItemRequest typed schemas
- frontend/src/api/cloud.js: centralized helpers for all Phase 13 routes
- backend/tests/test_cloud_mutations.py: mock adapter + settings key fixture; 21 tests pass
- backend/tests/test_cloud_audit.py: mark 6 RED audit tests as xfail (audit writes are
T-13-05 scope for a later plan); update credential fixture to use settings key
2026-06-22 19:09:38 +02:00
curo1305
5c0bc2a3b4
feat(13-04): upgrade Google Drive scope to drive, add health/reconnect/content API helpers
...
- connections.py: Update Google Drive OAuth to broader `drive` scope (D-17)
instead of `drive.file` so authorized users can operate on all existing Drive
items, not just files created by this app. Both initiation and callback flows
updated to keep scopes consistent.
- schemas.py: Add Phase 13 typed response schemas — ConnectionHealthOut, ReconnectOut,
ContentResultOut, MutationResultOut, and request schemas CreateFolderRequest,
RenameItemRequest, MoveItemRequest. All credential-free (T-13-14, CONN-03).
- api/cloud.js: Add centralized frontend helpers for getConnectionHealth,
reconnectCloudConnection, testCloudConnection (D-12, D-13), plus authorized
cloud content and mutation helpers: openCloudFile, previewCloudFile,
createCloudFolder, renameCloudItem, moveCloudItem, deleteCloudItem, uploadCloudFile.
All reconnect/health/test tests pass (14/14). Security suite passes (19/19).
2026-06-22 18:49:47 +02:00
curo1305
7501036300
docs(13-03): complete cloud operations seam plan
2026-06-22 18:45:54 +02:00
curo1305
6784d3bdb7
feat(13-03): add cloud operations service and reconnect/health/test routes
...
- Create backend/services/cloud_operations.py as the single Phase 13 orchestration seam:
get_connection_health (D-12), test_connection (D-13), reconnect_connection (CONN-01/02/03,
D-14), disconnect_connection (D-16, explicit CloudItem cascade for SQLite compatibility)
- Add POST /connections/{id}/reconnect route (CONN-01/02/03, D-14)
- Add GET /connections/{id}/health route (D-12, T-13-02)
- Add POST /connections/{id}/test route (D-13, T-13-02)
- Update DELETE /connections/{id} to use service-layer disconnect with explicit
CloudItem deletion (D-16; covers FK-cascade-less environments like SQLite tests)
- Fix (Rule 2 - T-13-02): add _scrub_audit_metadata() to admin audit log API to
remove credential fields before returning audit rows to admin callers
- All 14 reconnect tests pass + 110 provider-contract tests pass
- Pre-existing failures in test_cloud_mutations and test_extractor are unrelated
2026-06-22 18:43:50 +02:00
curo1305
88a62da4c4
feat(13-03): extend cloud contract with mutable adapter and provider implementations
...
- Add MutableCloudResourceAdapter abstract class to cloud_base.py with Phase 13
mutable-operation vocabulary (MUT_KIND_* / MUT_REASON_* constants, PreviewSupport)
- Add abstract methods: create_folder, rename, move, delete, upload_file + _normalize_error
- Update GoogleDriveBackend to implement MutableCloudResourceAdapter with Drive-scope
methods; prefer trash() for delete (D-11); update SCOPES to drive (D-17)
- Update OneDriveBackend to implement MutableCloudResourceAdapter; use
PublicClientApplication for refresh_token flow; Graph DELETE is always permanent (D-11)
- Update WebDAVBackend to implement MutableCloudResourceAdapter; SSRF guard via __init__
(not per-call) for mutable methods; _validate_destination for MOVE SSRF (T-13-04)
- NextcloudBackend inherits all mutable methods from WebDAVBackend (no changes needed)
- Add build_mutable_cloud_adapter() to cloud_backend_factory.py
- All 184 tests pass (test_cloud_backends.py + test_cloud_provider_contract.py)
2026-06-22 18:31:53 +02:00
curo1305
f2411de85e
docs(13-02): complete red frontend test plan for cloud queue, health, and preview
2026-06-22 18:16:47 +02:00
curo1305
8923ed5b3c
test(13-02): add red store, health-flow, reconnect, and no-probe tests
...
- SettingsCloudTab.health.test.js: Test/Reconnect/Disconnect per-connection actions,
explicit confirmation before credential removal, Google Drive broader scope consent
copy (D-12/D-13/D-15/D-16/D-17/T-13-09)
- cloudConnections.test.js: connectionHealth state map, setConnectionHealth translation,
degraded vs requires_reauth distinction, pendingHealthRetest after failure, reconnect
preserves cached items, auto-test after connect, no-probe-on-navigation (D-12..D-15)
- CloudFolderRenderedFlow.test.js: warning+reconnect banner alongside cached items,
requires_reauth renders actionable prompt, folder-navigate never triggers health probe
(D-12/D-13/D-14/CONN-02/T-13-06)
2026-06-22 18:13:39 +02:00
curo1305
514925bd4c
test(13-02): add red shared-browser queue/preview and thin-view tests
...
- StorageBrowser.cloud-queue.test.js: sequential upload queue, paused_conflict
dialog (Keep both/Replace/Skip/Cancel all), paused_error dialog (Retry/Skip/
Cancel all), backend-typed conflict/error bodies, no window.open() (D-01/D-03/D-04)
- CloudFolderOpenPreview.test.js: authorized file-open via API, no raw provider
URLs, Office/Workspace authorized download fallback, no anchor-click download
hack, no re-emitted file-open to router (D-02/D-18/T-13-07)
- CloudFolderView.test.js: extends thin-view invariants for Phase 13 queue prop
forwarding and upload-event queue semantics (D-01/D-04)
2026-06-22 18:10:16 +02:00
curo1305
451d30208c
docs(13-01): complete red contract suite plan
2026-06-22 18:03:09 +02:00
curo1305
fd6b561899
test(13-01): extend provider contract suites for four-provider mutable-operation parity
...
- Add Phase 13 mutable-operation RED tests to test_cloud_backends.py:
TestGoogleDriveMutableContract (D-17 scope, create/rename/move/delete/upload),
TestOneDriveMutableContract (CONN-02 token handoff, permanent-delete disclosure,
nextLink SSRF guard), TestNextcloudMutableContract (create-folder SSRF, delete
normalization), TestWebDAVMutableContract (permanent-delete, move SSRF, no
cloud_items imports)
- Add Phase 13 mutable-operation RED tests to test_cloud_provider_contract.py:
TestMutableAdapterContract (method existence, async contract, canonical signatures
for all four providers), TestMutableAdapterResultNormalization (normalized kind/reason
return types, conflict normalization documentation, unsupported-capability disclosure)
- All new tests fail against the current codebase — mutable adapter methods do not
exist yet (expected RED); all prior Phase 12 tests remain green
2026-06-22 18:01:15 +02:00
curo1305
efb596433c
test(13-01): add red API and audit contracts for reconnect, content, and mutation flows
...
- Create test_cloud_mutations.py: IDOR, admin block, credential secrecy, and typed
kind/reason body coverage for open, preview, upload, create-folder, rename, move,
and delete endpoint contracts (D-02 through D-11, D-18)
- Create test_cloud_reconnect.py: reconnect patch-in-place (CONN-01), encrypted credential
persistence (CONN-02), response secrecy (CONN-03), health endpoint, test action,
cache-preservation on reconnect (D-14), transient-outage data preservation (D-15),
and disconnect metadata cleanup (D-16)
- Create test_cloud_audit.py: metadata-only audit rows for every successful cloud operation,
false-overwrite prevention (T-13-05), admin audit log credential exclusion (T-13-02)
- All tests fail against current codebase — Phase 13 routes do not exist yet (expected RED)
2026-06-22 17:57:55 +02:00
curo1305
f01bb181c1
docs(state): record phase 13 context session
2026-06-22 15:46:17 +02:00
curo1305
c7688a52f3
docs(13): capture phase context
2026-06-22 15:46:05 +02:00
curo1305
38900e0ee7
test(12.1): complete UAT - 5 passed, 1 issue (missing modified timestamps), 1 skipped
2026-06-22 14:49:01 +02:00
curo1305
64ddb50cd6
fix(cloud): show provider root items in browser
2026-06-22 13:55:07 +02:00
curo1305
d452dee3f7
docs(phase-12.1): update validation strategy
2026-06-22 12:03:16 +02:00
curo1305
b00218e5c5
test(phase-12.1): repair live browse validation guard
2026-06-22 12:03:06 +02:00
curo1305
d02d5db7c3
docs(phase-12.1): audit Nyquist validation coverage
2026-06-22 11:55:31 +02:00
curo1305
66a7937bd1
docs(phase-12.1): add security threat verification
2026-06-22 10:00:09 +02:00
curo1305
aa1d626187
docs(12.1-04): complete plan 04 summary and state updates
2026-06-22 09:48:33 +02:00
curo1305
46b7ea6c12
test(12.1): verify live cloud browse integration
...
Phase 12.1 close — docs, version, and security evidence:
- Bump version 0.2.5 → 0.2.6 in backend/main.py, frontend/package.json
- CLAUDE.md: update current state to Phase 12.1 complete v0.2.6
- README.md: add Phase 12.1 corrections, live smoke variable names, Phase 13/14 exclusions
- RUNBOOK.md: add live smoke invocation, warning semantics table, fixture reconciliation procedure
- SECURITY.md: add Phase 12.1 Plan 04 threat table (T-12.1-16..20, T-12.1-SC) and gate evidence
- 12.1-VALIDATION.md: mark Plan 04 complete with final gate evidence
2026-06-22 09:46:25 +02:00
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
curo1305
1ec5158c65
test(12.1): owner-confirmed expected root manifest
...
- Create backend/tests/fixtures/cloud/nextcloud_expected_root.json with
owner_confirmed: true and corrected 10-item name/kind manifest
- Add test_nextcloud_expected_root_manifest: exact set and kind equality
against fixture (T-12.1-19 — count-only acceptance blocked)
- Update 12.1-VALIDATION.md: manifest status OWNER CONFIRMED, add
exact-acceptance row to Nyquist matrix
2026-06-22 09:35:36 +02:00
curo1305
779b05086b
test(12.1-04): add opt-in live Nextcloud smoke test suite
...
- backend/tests/test_nextcloud_live.py: three read-only live tests behind
live_nextcloud marker (adapter root metadata, sanitized diagnostic, connection-ID
browse as testuser@docuvault.example with IDOR/admin negatives)
- backend/pytest.ini: register live_nextcloud marker; addopts excludes it from
ordinary runs so CI never contacts Nextcloud without explicit selection
- 12.1-VALIDATION.md: live test contract, commands, skip behaviour, sanitized
7-of-10 probe result, and threat references T-12.1-16 through T-12.1-20
- Manifest status: unconfirmed — Task 2 exact-name gate pending owner decision
2026-06-22 09:02:42 +02:00
curo1305
9ef7f81b3f
docs(12.1-03): complete plan 03 summary and state updates
2026-06-22 08:55:02 +02:00
curo1305
7bb046ac41
fix(12.1): align cloud browser contract — kind, provider_item_id, server freshness
...
Normalized cloud frontend for DocuVault v0.2.5:
- Cloud UI classifies items by kind=folder/file (is_dir removed from all active paths)
- Folder navigation uses provider_item_id (opaque provider ref) — DocuVault id kept for row identity
- Server freshness (refresh_state, last_refreshed_at) mapped verbatim — no browser-clock evidence
- Breadcrumb lineage built from explicit visited nodes — never split(provider_item_id)
- CloudFolderTreeItem: expandable/icon/navigate/loadChildren all use kind and provider_item_id
- Version bump 0.2.4 → 0.2.5
- SECURITY.md: T-12.1-11 through T-12.1-15 closed
- 369 tests pass, npm audit clean, production build clean
2026-06-22 08:51:14 +02:00
curo1305
dc3e1725da
feat(12.1-03): align cloud browser contract — kind, provider_item_id, server freshness
...
- CloudFolderView: folders/files classified by kind=folder/file (remove is_dir)
- CloudFolderView: navigateTo uses item.provider_item_id for route param (not item.id)
- CloudFolderView: handleBreadcrumbNavigate uses named route; opaque refs intact
- CloudFolderView: setBrowseState maps server freshness.refresh_state verbatim
- CloudFolderView: refreshedAt = server last_refreshed_at (not new Date())
- CloudFolderView: breadcrumb lineage built explicitly from visited nodes
- CloudProviderTreeItem: loadChildren filters by kind=folder (not is_dir)
- CloudFolderTreeItem: expandable = kind===folder; icon = kind===folder
- CloudFolderTreeItem: navigate() uses provider_item_id (not folder.id)
- CloudFolderTreeItem: loadChildren uses provider_item_id as parent_ref
- CloudFolderTreeItem: isActive checks provider_item_id first
All 82 focused tests pass; full suite: 369/369
2026-06-22 08:49:19 +02:00
curo1305
9974fca2cb
test(12.1-03): add RED tests for server freshness mapping
...
- cloudConnections: setBrowseState warning/refreshing/fresh states
- cloudConnections: cached items remain during warning
- cloudConnections: selectConnection clears browse state
- cloudConnections: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: maps_server_warning_and_last_success
- CloudFolderView: http_200_does_not_imply_fresh
- CloudFolderView: does_not_use_browser_clock_as_refresh_evidence
- CloudFolderView: cached_items_remain_visible_during_warning
3 new failures against unconditional fresh/new Date() behavior
2026-06-22 08:45:50 +02:00
curo1305
ba7f652cde
test(12.1-03): add RED tests for kind/provider_item_id/freshness regressions
...
- CloudFolderView: renders_kind_folder_and_file_in_shared_browser (is_dir → kind)
- CloudFolderView: folder_click_uses_provider_item_id_not_id
- CloudFolderView: stable_docuvault_id_remains_row_key
- CloudFolderView: opaque_reference_round_trip (reserved chars)
- CloudFolderTreeItem: nested_tree_uses_provider_item_id (navigation + loadChildren)
- CloudFolderTreeItem: expandable based on kind=folder, not is_dir
- CloudFolderTreeItem: opaque OneDrive ref used intact
- CloudProviderTreeItem: tree_expansion_filters_kind_folder
- StorageBrowser: cloud folder/file rendering with normalized items
- CloudBreadcrumbNavigation: explicit lineage tests (pass against current code)
9 tests fail against is_dir/item.id behavior as expected
2026-06-22 08:44:27 +02:00
curo1305
792a25fad7
docs(12.1-02): complete plan 02 summary and state updates
2026-06-22 08:38:18 +02:00
curo1305
70a543a8c1
fix(12.1): make cloud freshness authoritative — plan 02 documentation and version
...
- Version bump 0.2.3 → 0.2.4 (user-visible sync status corrected)
- CLAUDE.md: update current state; add apply_listing_and_finalize to module map; add no-independent-fresh rule
- README.md: bump version
- RUNBOOK.md: update freshness state docs; explain complete=True gate and last_refreshed_at behavior
- SECURITY.md: add T-12.1-06..10 threat closure evidence for Plan 02
2026-06-22 08:34:51 +02:00
curo1305
bfa4dc502a
feat(12.1-02): centralize listing freshness gate — apply_listing_and_finalize
...
- Add ListingResult dataclass to cloud_items.py
- Add apply_listing_and_finalize() — single shared gate for complete/incomplete semantics
- complete=True: upserts, soft-deletes unseen children, marks fresh, advances last_refreshed_at
- complete=False: upserts seen items only, never deletes unseen, preserves prior timestamp, warns
- browse.py: replace unconditional update_folder_state('fresh') with apply_listing_and_finalize
- cloud_tasks.py: replace unconditional fresh transition with apply_listing_and_finalize
- Celery task returns structured warning status on incomplete (no credentials/provider item names)
- Fix timezone naive/aware comparison in test (SQLite strips tzinfo)
2026-06-22 08:29:41 +02:00
curo1305
fe08afd740
test(12.1-02): add failing tests for truthful freshness gate (RED)
...
- test_incomplete_listing_never_marks_folder_fresh
- test_incomplete_listing_retains_cached_rows_and_last_success
- test_complete_empty_listing_is_authoritative_and_fresh
- test_partial_items_upsert_without_deleting_unseen_children
- test_apply_listing_returns_warning_for_complete_false
- test_sync_browse_returns_warning_for_complete_false
- test_worker_returns_warning_for_complete_false
- security: browse_complete_false_never_sets_fresh, no_raw_provider_error, owner_scoped_on_incomplete
2026-06-22 08:26:35 +02:00
curo1305
a6e8a597e7
docs(12.1-01): complete Plan 01 summary and state updates
2026-06-22 08:20:06 +02:00
curo1305
62128730e8
fix(12.1-01): restore asyncio import, bump version to 0.2.3, update docs
...
- Restore asyncio import removed when legacy list_folder was deleted (health_check
still uses asyncio.to_thread); fixes test_nextcloud_connect_persists regression
- Bump backend/main.py and frontend/package.json version to 0.2.3
- Update CLAUDE.md: note Phase 12.1 Plan 01 complete, add normalize_nextcloud_url
to shared module map, add NextcloudBackend no-override rule
- Update README.md: version 0.2.3, note canonical Nextcloud URL normalization and
OneDrive nextLink origin guard
- Full backend suite: 585 passed, 1 pre-existing failure (missing python-docx module)
2026-06-22 08:18:23 +02:00
curo1305
805fe44bfb
feat(12.1-01): add cross-origin nextLink guard and Drive/OneDrive contract tests
...
- Validate @odata.nextLink hostname against graph.microsoft.com before following
(T-12.1-03); cross-origin nextLink returns complete=False with prior items retained
- Add TestOneDriveCrossOriginNextLink: cross-origin rejection, same-origin follows,
page failure retains prior items
- Add TestGoogleDriveAuthFailureControl: 401 returns complete=False, page1+page2
error retains page1 items
- All 163 four-provider contract tests pass
2026-06-22 08:12:39 +02:00
curo1305
2b46f74329
feat(12.1-01): repair Nextcloud adapter contract and add URL normalization
...
- Remove incompatible NextcloudBackend.list_folder(folder_path="") override
so Nextcloud inherits canonical WebDAVBackend.list_folder(connection_id,
user_id, parent_ref=None, page_token=None) -> CloudListing
- Add normalize_nextcloud_url() to cloud_utils.py: idempotent canonical DAV
root derivation, username percent-encoding, https-only, rejects userinfo/
query/fragment, validates via SSRF guard before return
- Use normalize_nextcloud_url in cloud_backend_factory for nextcloud provider
- Add TestNextcloudBackendNoListFolderOverride and TestNextcloudUrlNormalization
to test_webdav_backend.py
- All 9 Nextcloud contract failures now pass; full focused suite: 158 passed
2026-06-22 08:11:06 +02:00
curo1305
eb68facd6c
test(12.1-01): add failing four-provider contract suite and fixtures
...
- Create test_cloud_provider_contract.py with parametrized suite for
Nextcloud, WebDAV, Google Drive, OneDrive
- Assert canonical (connection_id, user_id, parent_ref=None, page_token=None)
signature, CloudListing return type, trusted caller identity propagation,
metadata normalization, pagination completeness, and forbidden-operation spies
- Add synthetic credential-free fixtures: nextcloud_root.xml, webdav_root.xml,
google_drive_pages.json, onedrive_pages.json
- 9 tests fail for nextcloud (expected RED state — incompatible list_folder override)
- All webdav, google_drive, onedrive contract tests pass
2026-06-22 08:09:00 +02:00
curo1305
692600c755
test(12): close Nyquist validation gap
2026-06-22 06:44:33 +02:00
curo1305
e64980af5f
docs(phase-12): add security threat verification — 26/26 closed
2026-06-22 01:39:24 +02:00
curo1305 and Claude Sonnet 4.6
c283623903
docs(phase-12): resolve UAT gaps and close phase after 12-06 gap closure
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-21 22:38:23 +02:00
curo1305
bd5e8f4192
docs(12): add code review report for phase 12-06 gap closure
2026-06-21 22:35:01 +02:00
curo1305
4a910549ac
docs(12-06): add plan 06 SUMMARY — UUID-only navigation, multi-account, credential-update
2026-06-21 22:30:51 +02:00
curo1305
c85e4abd91
chore(12-06): bump version 0.2.1 → 0.2.2
2026-06-21 22:30:11 +02:00
curo1305
057b4999fd
feat(12-06): UUID-only cloud navigation, breadcrumb hierarchy, route-aware sidebar
...
- CloudProviderTreeItem: getCloudFoldersByConnectionId(connection.id) + /cloud/{uuid}/root
- CloudFolderTreeItem: connectionId prop replaces provider slug in browse + route
- AppSidebar: Cloud Storage active only on exact /cloud; connection nodes use per-connection isActive
- New tests: CloudProviderTreeItem, CloudFolderTreeItem, AppSidebar cloud active-state
2026-06-21 22:30:05 +02:00
curo1305
731b65ecdd
feat(12-06): connection-ID native lifecycle — always INSERT, PUT credentials, connectionsFor multi-account
...
- Replace _upsert_cloud_connection with _insert_cloud_connection (always inserts new UUID row)
- Add PUT /connections/{id}/credentials endpoint (owner-scoped, SSRF + health-check, password-preserve)
- SettingsCloudTab: connectionsFor() renders all same-provider connections with Add account row
- CloudCredentialModal.submit: calls updateWebDavCredentials on edit, connectWebDav on create
- utils.js: FastAPI validation arrays normalised to concise field messages (Rule 2)
- Backend tests: same-provider independence + IDOR negative test for credential update
2026-06-21 22:29:59 +02:00
curo1305
97c30c3a15
docs(12): plan cloud UAT gap fixes
2026-06-21 22:21:05 +02:00
curo1305
70ed1219a9
test(12): pause UAT - 1 passed, 2 issues, 3 blocked
2026-06-21 22:18:14 +02:00
curo1305
8c80607df9
fix(dev-env): complete local startup configuration
2026-06-21 20:43:45 +02:00
curo1305
461b56892c
docs(12-05): mark VERIFICATION.md passed — all 5 truths verified
2026-06-21 20:33:37 +02:00
curo1305 and Claude Sonnet 4.6
206f564248
test(12-05): fix test_nextcloud_connect_persists + compose migration test path
...
- test_nextcloud_connect_persists: provider=nextcloud routes to NextcloudBackend
(not WebDAVBackend) — add storage.nextcloud_backend.validate_cloud_url patch
and use AsyncMock for asyncio.to_thread (plain return_value=True is not
awaitable, swallowed by except → False). Test now passes HTTP 201.
- test_compose_migrations: skip module when docker-compose.yml is not found at
the expected repo-root path (file is not mounted inside the backend container).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-06-20 12:35:35 +02:00