diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 52ab084..f389a37 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -31,8 +31,8 @@ Requirements for initial release. Each maps to roadmap phases. ### Script Generation - [x] **SCRPT-01**: System generates PowerShell install script (pnputil staging + Add-PrinterPort + Add-PrinterDriver + Add-Printer + Set-PrintConfiguration) -- [ ] **SCRPT-02**: System generates PowerShell uninstall script (Remove-Printer + Remove-PrinterDriver + Remove-PrinterPort) -- [ ] **SCRPT-03**: System generates Intune detection script (registry check for printer name) +- [x] **SCRPT-02**: System generates PowerShell uninstall script (Remove-Printer + Remove-PrinterDriver + Remove-PrinterPort) +- [x] **SCRPT-03**: System generates Intune detection script (registry check for printer name) - [x] **SCRPT-04**: Generated install script detects SYSTEM vs. user context and self-elevates via UAC when run by user - [x] **SCRPT-05**: Generated install script includes 64-bit WOW64 relaunch guard for Intune's 32-bit execution context @@ -101,8 +101,8 @@ Which phases cover which requirements. Updated during roadmap creation. | PRNT-09 | Phase 3 | Complete | | PRNT-10 | Phase 3 | Complete | | SCRPT-01 | Phase 4 | Complete | -| SCRPT-02 | Phase 4 | Pending | -| SCRPT-03 | Phase 4 | Pending | +| SCRPT-02 | Phase 4 | Complete | +| SCRPT-03 | Phase 4 | Complete | | SCRPT-04 | Phase 4 | Complete | | SCRPT-05 | Phase 4 | Complete | | PKG-01 | Phase 5 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index d5002cf..54786df 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -15,7 +15,7 @@ Decimal phases appear between their surrounding integers in numeric order. - [x] **Phase 1: Foundation** - Docker container scaffold, SQLite schema, and .intunewin format spike (completed 2026-04-10) - [ ] **Phase 2: Driver Management** - Driver ZIP upload, INF parsing, DriverDesc dropdown, volume persistence - [x] **Phase 3: Printer Configuration** - Full printer config form, client/tenant labels, SQLite persistence (completed 2026-04-10) -- [ ] **Phase 4: Script Generation** - PowerShell install/uninstall/detection scripts with all correctness guards +- [x] **Phase 4: Script Generation** - PowerShell install/uninstall/detection scripts with all correctness guards (completed 2026-04-10) - [ ] **Phase 5: Package Export** - .intunewin and NinjaRMM ZIP export, icon upload, command preview ## Phase Details @@ -108,5 +108,5 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 | 1. Foundation | 3/3 | Complete | 2026-04-10 | | 2. Driver Management | 1/2 | In Progress| | | 3. Printer Configuration | 2/2 | Complete | 2026-04-10 | -| 4. Script Generation | 1/2 | In Progress| | +| 4. Script Generation | 2/2 | Complete | 2026-04-10 | | 5. Package Export | 0/3 | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 670b242..8b364b9 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,15 +3,30 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: executing -stopped_at: Completed 04-01-PLAN.md -last_updated: "2026-04-10T11:32:55.889Z" -last_activity: "2026-04-10 — Plan 01-01 complete: Docker scaffold, FastAPI app shell, sidebar templates, 3-test green suite" +stopped_at: Completed 04-02-PLAN.md +last_updated: "2026-04-10T11:37:48.308Z" +last_activity: "2026-04-10 — Plan 04-02 complete: uninstall/detect templates, render_uninstall/render_detect, 3 script API endpoints, 75 tests green" +progress: + total_phases: 5 + completed_phases: 4 + total_plans: 9 + completed_plans: 9 +--- + +--- +gsd_state_version: 1.0 +milestone: v1.0 +milestone_name: milestone +status: executing +stopped_at: Completed 04-02-PLAN.md +last_updated: "2026-04-10T11:36:13Z" +last_activity: "2026-04-10 — Plan 04-02 complete: uninstall/detect templates, render_uninstall/render_detect, 3 script API endpoints, 75 tests green" progress: total_phases: 5 completed_phases: 3 total_plans: 9 - completed_plans: 8 - percent: 7 + completed_plans: 9 + percent: 89 --- # Project State @@ -25,12 +40,12 @@ See: .planning/PROJECT.md (updated 2026-04-10) ## Current Position -Phase: 1 of 5 (Foundation) -Plan: 2 of 3 in current phase (01-01 complete) +Phase: 4 of 5 (Script Generation) +Plan: 2 of 2 in current phase (04-02 complete) Status: Executing -Last activity: 2026-04-10 — Plan 01-01 complete: Docker scaffold, FastAPI app shell, sidebar templates, 3-test green suite +Last activity: 2026-04-10 — Plan 04-02 complete: uninstall/detect templates, render_uninstall/render_detect, 3 script API endpoints, 75 tests green -Progress: [░░░░░░░░░░] 7% +Progress: [█████████░] 89% ## Performance Metrics @@ -56,6 +71,7 @@ Progress: [░░░░░░░░░░] 7% | Phase 03-printer-configuration P01 | 7 | 2 tasks | 12 files | | Phase 03-printer-configuration P02 | 2 | 2 tasks | 4 files | | Phase 04-script-generation P01 | 2 | 1 tasks | 3 files | +| Phase 04-script-generation P02 | 2 | 2 tasks | 6 files | ## Accumulated Context @@ -85,6 +101,9 @@ Recent decisions affecting current work: - [Phase 03-02]: Detail page is a full-page template (not partial) — simpler than partial injection into printers.html - [Phase 03-02]: Route lives in pages.py (not printers.py) because it returns a full HTML page, not an HTMX fragment - [Phase 04-script-generation]: render_install() takes plain string args (not ORM object) for DB-free unit testability; _duplex_map translates LongEdge->TwoSidedLongEdge before template rendering +- [Phase 04-02]: _get_printer_and_driver() private helper centralises 404/422 validation for all 3 script endpoints +- [Phase 04-02]: PlainTextResponse with Content-Disposition attachment header on all script endpoints +- [Phase 04-02]: Integration tests create ORM records directly (Driver.create/Printer.create) ### Pending Todos @@ -97,6 +116,6 @@ None yet. ## Session Continuity -Last session: 2026-04-10T11:32:55.884Z -Stopped at: Completed 04-01-PLAN.md +Last session: 2026-04-10T11:37:48.305Z +Stopped at: Completed 04-02-PLAN.md Resume file: None diff --git a/.planning/phases/04-script-generation/04-02-SUMMARY.md b/.planning/phases/04-script-generation/04-02-SUMMARY.md new file mode 100644 index 0000000..b1b8729 --- /dev/null +++ b/.planning/phases/04-script-generation/04-02-SUMMARY.md @@ -0,0 +1,117 @@ +--- +phase: 04-script-generation +plan: "02" +subsystem: api +tags: [powershell, jinja2, fastapi, intune, tdd] + +requires: + - phase: 04-01 + provides: [render_install, install.ps1.j2, script_generator module with Jinja2 env] +provides: + - render_uninstall function (Remove-Printer/Driver/Port in safe order) + - render_detect function (Intune detection contract) + - uninstall.ps1.j2 template + - detect.ps1.j2 template + - GET /printers/{id}/scripts/install endpoint + - GET /printers/{id}/scripts/uninstall endpoint + - GET /printers/{id}/scripts/detect endpoint + - scripts.py APIRouter registered in main.py +affects: [phase-05-packaging] + +tech-stack: + added: [] + patterns: + - Shared _get_printer_and_driver() helper extracts ORM validation to avoid duplication across 3 endpoints + - All script endpoints return PlainTextResponse with Content-Disposition attachment header + - Integration tests use ORM directly (Driver.create/Printer.create) — no HTTP fixture for setup + +key-files: + created: + - imptune/templates/scripts/uninstall.ps1.j2 + - imptune/templates/scripts/detect.ps1.j2 + - imptune/api/scripts.py + modified: + - imptune/generators/script_generator.py + - imptune/main.py + - tests/test_script_generator.py + +key-decisions: + - "_get_printer_and_driver() private helper centralises 404/422 validation for all 3 script endpoints" + - "PlainTextResponse with Content-Disposition attachment; filename='{type}.ps1' on all script endpoints" + - "Integration tests create ORM records directly (Driver.create/Printer.create) — same pattern as printer CRUD tests" + +patterns-established: + - "Script endpoint pattern: validate printer -> validate driver -> validate inf -> parse driver_desc -> render -> return attachment" + +requirements-completed: [SCRPT-02, SCRPT-03] + +duration: ~2min +completed: 2026-04-10 +--- + +# Phase 4 Plan 02: Script Generator (Uninstall + Detect + API) Summary + +**Jinja2 uninstall/detect templates, render_uninstall/render_detect functions, and three downloadable PS1 script endpoints wired to the scripts router** + +## Performance + +- **Duration:** ~2 min +- **Started:** 2026-04-10T11:33:58Z +- **Completed:** 2026-04-10T11:36:13Z +- **Tasks:** 2 +- **Files modified:** 6 + +## Accomplishments + +- render_uninstall() produces Remove-Printer > Remove-PrinterDriver > Remove-PrinterPort with -ErrorAction SilentlyContinue (safe ordering) +- render_detect() follows Intune detection contract: Get-Printer check, Write-Output + exit 0 when found, exit 1 when absent +- Three GET endpoints /printers/{id}/scripts/{install,uninstall,detect} return PS1 scripts as file downloads +- Full error handling: 404 for missing printer, 422 for missing driver/INF/driver_desc +- Full test suite green: 75 tests (7 new tests added) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1 RED: Failing tests for render_uninstall/detect** - `0f213df` (test) +2. **Task 1 GREEN: render_uninstall + render_detect + templates** - `6bff8f3` (feat) +3. **Task 2: Script API endpoints + router registration** - `b7b0d1b` (feat) + +_Note: TDD task split into RED + GREEN commits per TDD protocol_ + +## Files Created/Modified + +- `imptune/templates/scripts/uninstall.ps1.j2` - PowerShell uninstall template (Remove-Printer/Driver/Port in order) +- `imptune/templates/scripts/detect.ps1.j2` - PowerShell Intune detection template (Get-Printer + exit 0/1) +- `imptune/generators/script_generator.py` - Added render_uninstall() and render_detect() functions +- `imptune/api/scripts.py` - APIRouter with 3 script download endpoints, shared validation helper +- `imptune/main.py` - Registered scripts.router +- `tests/test_script_generator.py` - Added 2 unit tests + 5 integration tests + +## Decisions Made + +- `_get_printer_and_driver()` private helper centralises 404/422 validation logic for all three endpoints — avoids repeating identical ORM+validation code 3 times +- `PlainTextResponse` with `Content-Disposition: attachment; filename="{type}.ps1"` on all endpoints so browsers download the file rather than rendering it +- Integration tests create ORM records directly via `Driver.create()`/`Printer.create()` — same established pattern as printer CRUD tests, no HTTP API calls for setup + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered + +None - all tests passed on first run after implementation. + +## User Setup Required + +None - no external service configuration required. + +## Next Phase Readiness + +- All three script types downloadable via API — ready for Phase 5 packaging +- render_install, render_uninstall, render_detect all available in script_generator module +- scripts.py router registered and functional + +--- +*Phase: 04-script-generation* +*Completed: 2026-04-10*