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
This commit is contained in:
+48
@@ -734,6 +734,54 @@ WHERE cc.id IS NULL;
|
||||
- **Credential fields:** `credentials_enc` is never included in browse API responses. Verify with: `grep -r "credentials_enc" backend/api/cloud/` — must only appear in connection create/update service code, never in response schemas.
|
||||
- **SSRF guard:** `storage/cloud_utils.validate_cloud_url` blocks RFC1918, link-local, file://, and cloud metadata IPs. All WebDAV/Nextcloud URLs pass through this guard before any connection is established.
|
||||
|
||||
### Phase 12.1 Live Smoke Tests (Opt-In, Read-Only)
|
||||
|
||||
The `live_nextcloud` pytest marker selects opt-in tests that use real Nextcloud credentials. These tests are **excluded from ordinary CI runs** (`addopts = -m "not live_nextcloud"` in `pytest.ini`).
|
||||
|
||||
**Running the live smoke:**
|
||||
```bash
|
||||
# Set in .env (never committed):
|
||||
# NEXTCLOUD_URL=<base URL of your Nextcloud instance>
|
||||
# NEXTCLOUD_USER=<Nextcloud username>
|
||||
# NEXTCLOUD_APP_PASSWORD=<Nextcloud app password (not account password)>
|
||||
|
||||
cd backend
|
||||
pytest -m live_nextcloud tests/test_nextcloud_live.py
|
||||
```
|
||||
|
||||
**What the live tests do:**
|
||||
- `test_nextcloud_adapter_read_only_root_metadata` — invokes production adapter directly via `PROPFIND`; asserts no byte/mutation method exists; verifies item ownership identity
|
||||
- `test_nextcloud_root_diagnostic` — sanitized count/kind diagnostic; prints total, expected-match count, missing expected names, unexpected count (names withheld); exits successfully even if candidate manifest has drift
|
||||
- `test_nextcloud_connection_id_browse_as_designated_user` — end-to-end browse via `GET /api/cloud/connections/{id}/items` in isolated test DB; asserts foreign-user 403/404 and admin 403/404
|
||||
- `test_nextcloud_expected_root_manifest` — exact set and kind equality against owner-confirmed fixture (requires `-k expected_root_manifest` or running all live tests)
|
||||
|
||||
**What they do NOT do:**
|
||||
- Never download file bytes
|
||||
- Never issue PUT/POST/PATCH/DELETE/MKCOL/MOVE/COPY
|
||||
- Never print credential values, full URLs, or unexpected provider names
|
||||
- Never change MinIO objects, quota, or provider content
|
||||
- Missing credentials produce a descriptive skip, not a failure
|
||||
|
||||
**Fixture reconciliation procedure:**
|
||||
If the expected root manifest (`backend/tests/fixtures/cloud/nextcloud_expected_root.json`) drifts:
|
||||
1. Run `pytest -m live_nextcloud -k root_diagnostic` and read the sanitized output (missing expected names only)
|
||||
2. Compare the missing names with the Nextcloud web UI (do not print the unexpected names)
|
||||
3. Update the fixture with the owner-confirmed correct names and set `owner_confirmed: true`
|
||||
4. Never record unexpected live names in any committed artifact
|
||||
|
||||
### Phase 12 / 12.1 Warning Semantics
|
||||
|
||||
A `warning` freshness state in the browse response means the last reconciliation was incomplete or failed. **The UI shows a warning indicator; cached rows remain visible.** This is not an error — it is honest state:
|
||||
|
||||
| State | Meaning | UI behavior |
|
||||
|-------|---------|-------------|
|
||||
| `fresh` | Last `complete=True` listing succeeded | Green freshness indicator |
|
||||
| `refreshing` | Background refresh in progress | Spinner |
|
||||
| `warning` | Last listing was incomplete or failed | Warning banner; cached rows visible |
|
||||
| `stale` | Transport error during load | Error message; no freshness indicator |
|
||||
|
||||
`complete=False` from any provider ALWAYS produces `warning`, never `fresh`. `last_refreshed_at` is not advanced for incomplete listings.
|
||||
|
||||
### Phase 12 Deferred Items
|
||||
|
||||
| Item | Current state | Future path |
|
||||
|
||||
Reference in New Issue
Block a user