diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 5df04ac..2acbe80 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -32,8 +32,8 @@ ### API - [x] **API-01**: GET `/api/tenants/{tid}/devices/{did}/config-history` returns change timeline -- [ ] **API-02**: GET `/api/tenants/{tid}/devices/{did}/config/{snapshot_id}` returns full snapshot -- [ ] **API-03**: GET `/api/tenants/{tid}/devices/{did}/config/{snapshot_id}/diff` returns unified diff +- [x] **API-02**: GET `/api/tenants/{tid}/devices/{did}/config/{snapshot_id}` returns full snapshot +- [x] **API-03**: GET `/api/tenants/{tid}/devices/{did}/config/{snapshot_id}/diff` returns unified diff - [x] **API-04**: RBAC enforced: operator+ can trigger backups, viewers can read history ### Frontend @@ -84,8 +84,8 @@ | DIFF-03 | Phase 5: Diff Engine | Complete | | DIFF-04 | Phase 5: Diff Engine | Complete | | API-01 | Phase 6: History API | Complete | -| API-02 | Phase 6: History API | Pending | -| API-03 | Phase 6: History API | Pending | +| API-02 | Phase 6: History API | Complete | +| API-03 | Phase 6: History API | Complete | | API-04 | Phase 6: History API | Complete | | UI-01 | Phase 7: Config History UI | Pending | | UI-02 | Phase 7: Config History UI | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index a7df1a2..d658f00 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -17,7 +17,7 @@ Decimal phases appear between their surrounding integers in numeric order. - [ ] **Phase 3: Snapshot Ingestion** - Backend NATS subscriber stores snapshots with SHA256 deduplication - [x] **Phase 4: Manual Backup Trigger** - API endpoint for on-demand config backup via poller (completed 2026-03-13) - [x] **Phase 5: Diff Engine** - Unified diff generation and structured change parsing (completed 2026-03-13) -- [ ] **Phase 6: History API** - REST endpoints for timeline, snapshot view, and diff retrieval with RBAC +- [x] **Phase 6: History API** - REST endpoints for timeline, snapshot view, and diff retrieval with RBAC (completed 2026-03-13) - [ ] **Phase 7: Config History UI** - Timeline section on device page with change summaries - [ ] **Phase 8: Diff Viewer & Download** - Unified diff display with syntax highlighting and .rsc download - [ ] **Phase 9: Retention & Cleanup** - 90-day retention policy with automatic snapshot deletion @@ -179,7 +179,7 @@ Note: Phase 9 depends only on Phase 3 and Phase 10 depends on Phases 3/4/5, so P | 3. Snapshot Ingestion | 0/1 | Not started | - | | 4. Manual Backup Trigger | 1/1 | Complete | 2026-03-13 | | 5. Diff Engine | 2/2 | Complete | 2026-03-13 | -| 6. History API | 0/2 | Not started | - | +| 6. History API | 2/2 | Complete | 2026-03-13 | | 7. Config History UI | 0/1 | Not started | - | | 8. Diff Viewer & Download | 0/2 | Not started | - | | 9. Retention & Cleanup | 0/1 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 3257ead..6a7d35c 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,16 +2,16 @@ gsd_state_version: 1.0 milestone: v9.6 milestone_name: milestone -status: in-progress -stopped_at: Completed 06-01-PLAN.md -last_updated: "2026-03-13T04:00:32.171Z" +status: executing +stopped_at: Completed 06-02-PLAN.md +last_updated: "2026-03-13T04:04:21.853Z" last_activity: 2026-03-13 -- Completed 06-01 config history timeline endpoint progress: total_phases: 10 - completed_phases: 5 + completed_phases: 6 total_plans: 9 - completed_plans: 8 - percent: 89 + completed_plans: 9 + percent: 100 --- # Project State @@ -25,12 +25,12 @@ See: .planning/PROJECT.md (updated 2026-03-12) ## Current Position -Phase: 6 of 10 (History API) -Plan: 1 of 2 in current phase (06-01 complete) -Status: In progress -Last activity: 2026-03-13 -- Completed 06-01 config history timeline endpoint +Phase: 6 of 10 (History API) -- COMPLETE +Plan: 2 of 2 in current phase (all complete) +Status: Phase 6 complete +Last activity: 2026-03-13 -- Completed 06-02 snapshot view and diff retrieval endpoints -Progress: [█████████░] 89% +Progress: [██████████] 100% ## Performance Metrics @@ -56,6 +56,7 @@ Progress: [█████████░] 89% | Phase 05 P01 | 3min | 2 tasks | 4 files | | Phase 05 P02 | 2min | 2 tasks | 4 files | | Phase 06 P01 | 2min | 2 tasks | 4 files | +| Phase 06 P02 | 2min | 2 tasks | 3 files | ## Accumulated Context @@ -83,6 +84,8 @@ Recent decisions affecting current work: - [Phase 05]: Change parser is pure function; DB writes in diff service. RETURNING id on diff INSERT for linking. - [Phase 06]: Raw SQL text() JOIN for timeline queries, consistent with config_diff_service pattern - [Phase 06]: Pagination defaults limit=50, offset=0 with FastAPI Query validation (ge=1, le=200) +- [Phase 06]: Transit decrypt in get_snapshot with try/finally for clean openbao lifecycle +- [Phase 06]: 500 error wrapping for Transit decrypt failures in router layer, not service ### Pending Todos @@ -94,6 +97,6 @@ None yet. ## Session Continuity -Last session: 2026-03-13T04:00:00Z -Stopped at: Completed 06-01-PLAN.md +Last session: 2026-03-13T04:04:21.850Z +Stopped at: Completed 06-02-PLAN.md Resume file: None diff --git a/.planning/phases/06-history-api/06-02-SUMMARY.md b/.planning/phases/06-history-api/06-02-SUMMARY.md new file mode 100644 index 0000000..c2eedec --- /dev/null +++ b/.planning/phases/06-history-api/06-02-SUMMARY.md @@ -0,0 +1,95 @@ +--- +phase: 06-history-api +plan: 02 +subsystem: api +tags: [fastapi, sqlalchemy, openbao, transit-decrypt, rbac, snapshot] + +# Dependency graph +requires: + - phase: 06-history-api + provides: config_history_service.py with get_config_history, config_history router with RBAC + - phase: 05-diff-engine + provides: router_config_diffs and router_config_snapshots tables with encrypted config data +provides: + - GET /api/tenants/{tid}/devices/{did}/config/{snapshot_id} endpoint (decrypted snapshot) + - GET /api/tenants/{tid}/devices/{did}/config/{snapshot_id}/diff endpoint (unified diff) + - get_snapshot and get_snapshot_diff service functions +affects: [frontend-config-history, frontend-diff-viewer] + +# Tech tracking +tech-stack: + added: [] + patterns: [Transit decrypt in service layer with try/finally close, 404 for missing snapshots/diffs] + +key-files: + created: [] + modified: + - backend/app/services/config_history_service.py + - backend/app/routers/config_history.py + - backend/tests/test_config_history_service.py + +key-decisions: + - "Transit decrypt in get_snapshot with try/finally for clean openbao lifecycle" + - "500 error wrapping for Transit decrypt failures in router (not service)" + +patterns-established: + - "Snapshot retrieval filters by id + device_id + tenant_id for RLS-safe queries" + +requirements-completed: [API-02, API-03, API-04] + +# Metrics +duration: 2min +completed: 2026-03-13 +--- + +# Phase 6 Plan 2: Snapshot View and Diff Retrieval Summary + +**Snapshot view and diff retrieval endpoints with Transit decrypt for full config text and unified diff, enforcing viewer+ RBAC** + +## Performance + +- **Duration:** 2 min +- **Started:** 2026-03-13T04:01:58Z +- **Completed:** 2026-03-13T04:03:39Z +- **Tasks:** 2 +- **Files modified:** 3 + +## Accomplishments +- get_snapshot function decrypts config via OpenBao Transit and returns plaintext with metadata +- get_snapshot_diff function queries diff by new_snapshot_id for a device/tenant +- Two new router endpoints with viewer+ RBAC and config:read scope enforcement +- 4 new tests (8 total) covering decrypted content, not-found, diff retrieval, and no-diff cases + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: Snapshot and diff service functions with tests (TDD)** - `83cd661` (feat) +2. **Task 2: Snapshot and diff router endpoints** - `af7007d` (feat) + +## Files Created/Modified +- `backend/app/services/config_history_service.py` - Added get_snapshot (Transit decrypt) and get_snapshot_diff query functions +- `backend/app/routers/config_history.py` - Two new GET endpoints with RBAC, 404/500 error handling +- `backend/tests/test_config_history_service.py` - 4 new tests with mocked Transit and DB sessions + +## Decisions Made +- Transit decrypt happens in service layer (get_snapshot), error wrapping in router layer (500 response) +- Query filters include device_id + tenant_id alongside snapshot_id for RLS-safe access + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered +None + +## User Setup Required +None - no external service configuration required. + +## Next Phase Readiness +- All 3 config history API endpoints complete (timeline, snapshot view, diff view) +- Phase 06 complete -- ready for frontend integration + +--- +*Phase: 06-history-api* +*Completed: 2026-03-13*