Folders, Sharing, Quotas & Document UX — plans verified (0 blockers, 2 non-blocking warnings). Covers FOLD-01..05, SHARE-01..05, SEC-08/09, ADMIN-06, DOC-01/02. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
12 KiB
12 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 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 04-folders-sharing-quotas-document-ux | 01 | execute | 1 |
|
true |
|
|
Purpose: Establish the Nyquist test gate before any backend code is written. Output: Five test files (three new, two extended) with named xfail stubs for all 22 planned tests.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/04-folders-sharing-quotas-document-ux/04-CONTEXT.md @.planning/phases/04-folders-sharing-quotas-document-ux/04-VALIDATION.md @backend/tests/conftest.py @backend/tests/test_documents.py @backend/tests/test_security.py Task 1: Create test_folders.py and test_shares.py stubs backend/tests/test_folders.py, backend/tests/test_shares.py backend/tests/conftest.py — read the entire file to understand available fixtures (auth_user, admin_user, async_client, db_session) and how they are declared; extract fixture names and signatures before writing any test backend/tests/test_documents.py — read lines 1-50 for established import and fixture-injection patterns - test_create_folder: POST /api/folders creates folder, returns 201 - test_create_folder_duplicate_name: POST /api/folders with same name under same parent returns 409 - test_rename_folder: PATCH /api/folders/{id} changes name, returns 200 - test_rename_folder_wrong_owner: PATCH /api/folders/{id} by non-owner returns 404 - test_delete_empty_folder: DELETE /api/folders/{id} on empty folder returns 204 - test_delete_folder_cascade: DELETE /api/folders/{id} on non-empty folder deletes all docs + decrements quota - test_delete_folder_wrong_owner: DELETE /api/folders/{id} by non-owner returns 404 - test_move_document: PATCH /api/documents/{id}/folder moves doc to target folder, returns 200 - test_move_wrong_owner_404: PATCH /api/documents/{id}/folder where doc or target folder belongs to other user returns 404 - test_breadcrumb_path: GET /api/folders/{id} returns breadcrumb array of {id, name} from root to current - test_document_sort: GET /api/documents?sort=name|date|size returns correctly ordered results - test_fts_search: GET /api/documents?q=term returns matching docs only; marked with pytest.mark.skipif for non-PostgreSQL - test_fts_search_scoped_to_owner: GET /api/documents?q=term does not return other user's matching docs - test_share_success: POST /api/shares grants share, recipient can see doc via GET /api/shares/received - test_share_handle_not_found: POST /api/shares with unknown handle returns 404 - test_shared_with_me: GET /api/shares/received lists docs shared with current user - test_share_no_quota_impact: share does not increment recipient's quota used_bytes - test_revoke_share: DELETE /api/shares/{id} removes share; GET /api/shares/received no longer lists the doc - test_share_revoke_wrong_owner_404: DELETE /api/shares/{id} by non-owner returns 404 - test_share_duplicate: POST /api/shares same doc+recipient twice returns 409 Create backend/tests/test_folders.py. Header imports: `import pytest` and `pytest.mark.xfail(strict=False)`. Import `pytest_asyncio` and any fixtures from conftest using injection (no direct import — pytest injects by name). Every test function body is `pytest.xfail("not implemented yet")` as the first line — no other code. Name stubs exactly as listed in the behavior block (test_create_folder, test_create_folder_duplicate_name, etc.). Mark test_fts_search and test_fts_search_scoped_to_owner with both `@pytest.mark.xfail(strict=False)` and a `pytest.mark.skipif` checking for the INTEGRATION env var — pattern: `pytest.mark.skipif(not os.environ.get("INTEGRATION"), reason="requires PostgreSQL")`.Create backend/tests/test_shares.py with the same xfail stub pattern.
Stubs: test_share_success, test_share_handle_not_found, test_shared_with_me, test_share_no_quota_impact, test_revoke_share, test_share_revoke_wrong_owner_404, test_share_duplicate.
Do NOT write any assertion code in stub bodies. One line only: `pytest.xfail("not implemented yet")`.
New test_audit.py:
- test_audit_log_viewer: GET /api/admin/audit-log returns paginated entries
- test_audit_log_no_doc_content: audit log entries contain no "filename", "extracted_text" keys in metadata_
- test_audit_log_regular_user_403: GET /api/admin/audit-log with regular user token returns 403
- test_audit_log_export_csv: GET /api/admin/audit-log/export?format=csv returns CSV content-type
Additions to test_security.py:
- test_credentials_enc_not_in_response: no API response for current user includes credentials_enc field
- test_delete_user_cleans_files: admin DELETE /api/admin/users/{id} triggers MinIO object deletion before DB removal
Create backend/tests/test_audit.py from scratch with the four stubs plus necessary imports (pytest, pytest_asyncio pattern from conftest — no direct imports, fixture injection only).
For test_security.py: read the existing file first. Append the two new stubs ONLY if they do not already exist (check for test_credentials_enc_not_in_response and test_delete_user_cleans_files). If test_security.py does not exist, create it with both stubs.
All new stubs: `@pytest.mark.xfail(strict=False)`, body `pytest.xfail("not implemented yet")`.
<threat_model>
Trust Boundaries
| Boundary | Description |
|---|---|
| Test code → conftest fixtures | Test stubs must not import production secrets or live services |
STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|---|---|---|---|---|
| T-04-00-01 | Tampering | test stub files | mitigate | xfail(strict=False) ensures stubs cannot falsely pass and mask missing implementation |
| T-04-00-02 | Information Disclosure | test fixture reuse | accept | Phase 3 conftest fixtures already use ephemeral DB + mock MinIO; no real credentials in tests |
| T-04-SC | Tampering | npm/pip/cargo installs | accept | No new packages installed in this plan |
| </threat_model> |
Expected: zero FAILED, zero ERROR. All new stubs appear as xfail (x) in summary.
<success_criteria>
- Five test files collectively contain all 23 Phase 4 test stubs
pytest -vexits 0 (green)- No existing passing tests regress
- All stubs are properly named (exact names matching 04-VALIDATION.md Per-Task Verification Map) </success_criteria>