diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 544f791..72da4af 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -294,7 +294,7 @@ Decimal phases appear between their surrounding integers in numeric order. 5. Password-protected PFX/PKCS12 files can be opened (password prompt) and created (password input) 6. Module appears in the module registry with slug `cert-manager` -**Plans**: 3/6 plans executed +**Plans**: 4/6 plans executed Plans: **Wave 1** @@ -308,7 +308,7 @@ Plans: **Wave 3** *(blocked on Wave 2 completion)* -- [ ] 09-04-PLAN.md — Split slice: splitCerts (fullchain/P7B) + POST /split + Split tab download list (CERT-02) +- [x] 09-04-PLAN.md — Split slice: splitCerts (fullchain/P7B) + POST /split + Split tab download list (CERT-02) **Wave 4** *(blocked on Wave 3 completion)* @@ -335,4 +335,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 | 6. Desktop Client & CI/CD | 2/3 | In Progress| | | 7. DKV Fleet Module | 6/6 | Complete | 2026-06-27 | | 8. Dashboard Widgets Vollimplementierung | 4/4 | Complete | 2026-07-01 | -| 9. Cert Manager Module | 3/6 | In Progress| | +| 9. Cert Manager Module | 4/6 | In Progress| | diff --git a/.planning/STATE.md b/.planning/STATE.md index 448783b..39f151e 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -6,14 +6,14 @@ current_phase: 9 current_phase_name: cert-manager-module status: executing stopped_at: context exhaustion at 75% (2026-07-01) -last_updated: "2026-07-01T21:57:48.774Z" +last_updated: "2026-07-02T05:17:41.739Z" last_activity: 2026-07-01 last_activity_desc: Phase 9 execution started progress: total_phases: 9 completed_phases: 7 total_plans: 40 - completed_plans: 36 + completed_plans: 37 percent: 78 --- @@ -29,7 +29,7 @@ See: .planning/PROJECT.md (updated 2026-06-18) ## Current Position Phase: 9 (cert-manager-module) — EXECUTING -Plan: 2 of 6 +Plan: 3 of 6 Status: Ready to execute Last activity: 2026-07-01 — Phase 9 execution started @@ -68,6 +68,7 @@ Progress: [█████████░] 93% | Phase 07-dkv-fleet-module P05 | 8min | 3 tasks | 11 files | | Phase 07-dkv-fleet-module P06 | 5min | 2 tasks | 7 files | | Phase 09 P03 | 17 | 3 tasks | 6 files | +| Phase 09-cert-manager-module P04 | 4 | 3 tasks | 5 files | ## Accumulated Context @@ -127,6 +128,8 @@ Recent decisions affecting current work: - [Phase ?]: 09-03 - [Phase ?]: 09-03 - [Phase ?]: 09-03 +- [Phase ?]: splitCerts PEM path reuses parsePemChain; P7B sniffs first bytes +- [Phase ?]: splitCerts format crt comparison removed — detectFormat returns pem|der|pfx|p7b only ### Pending Todos @@ -153,6 +156,6 @@ Items acknowledged and carried forward from previous milestone close: ## Session Continuity -Last session: 2026-07-01T21:57:19.815Z +Last session: 2026-07-02T05:17:32.493Z Stopped at: context exhaustion at 75% (2026-07-01) Resume file: .planning/phases/08-dashboard-widgets-vollimplementierung/08-CONTEXT.md diff --git a/.planning/phases/09-cert-manager-module/09-04-SUMMARY.md b/.planning/phases/09-cert-manager-module/09-04-SUMMARY.md new file mode 100644 index 0000000..6de5d61 --- /dev/null +++ b/.planning/phases/09-cert-manager-module/09-04-SUMMARY.md @@ -0,0 +1,160 @@ +--- +phase: 09-cert-manager-module +plan: "04" +subsystem: api+frontend +tags: [cert-manager, splitCerts, node-forge, pkcs7, split-tab, tdd, vitest] +dependency_graph: + requires: [09-01, 09-02, 09-03] + provides: [cert-manager-split-endpoint, split-response-interface, split-tab-ui] + affects: + - apps/api/src/cert-manager/cert-manager.service.ts + - apps/api/src/cert-manager/cert-manager.service.spec.ts + - apps/web/src/app/(portal)/modules/cert-manager/actions.ts + - apps/web/src/app/(portal)/modules/cert-manager/components/SplitTab.tsx + - apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx +tech_stack: + added: [] + patterns: [tdd-red-green, node-forge-pkcs7-split, parsePemChain-reuse, downloadBase64-pattern, vi.spyOn-mock] +key_files: + created: [] + modified: + - apps/api/src/cert-manager/cert-manager.service.ts + - apps/api/src/cert-manager/cert-manager.service.spec.ts + - apps/web/src/app/(portal)/modules/cert-manager/actions.ts + - apps/web/src/app/(portal)/modules/cert-manager/components/SplitTab.tsx + - apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx +decisions: + - "splitCerts PEM path reuses parsePemChain helper (no duplication); P7B path sniffs first bytes for PEM vs DER" + - "format === 'crt' comparison removed — detectFormat only returns 'pem'|'der'|'pfx'|'p7b' (Rule 1 auto-fix, TS2367)" + - "SplitTab error classification: 'format'/'invalid'/'unknown' in message -> unknownFormat, else -> generic (mirrors InspectTab)" + - "splitCertsAction accepts File directly (not FormData) — caller is always browser File object; postForm wraps it" +metrics: + duration: "~4 minutes" + completed: "2026-07-02T05:19:00Z" + tasks_completed: 3 + files_created: 0 + files_modified: 5 +requirements: [CERT-02] +status: complete +--- + +# Phase 09 Plan 04: Split Vertical Slice Summary + +**One-liner:** splitCerts splits fullchain PEM chains and P7B PKCS7 bundles into individually downloadable base64 PEM certs; POST /split wired; SplitTab renders per-cert download list with subject CN and expiry. + +## Objective + +Second functional vertical slice: certificate chain/bundle splitting. Delivers CERT-02 (upload fullchain.pem or P7B, download each cert separately). Reuses parsePemChain + downloadBase64 patterns from Plan 03. + +## Tasks Completed + +| # | Name | Type | Commit | Status | +|---|------|------|--------|--------| +| 1 | RED — failing splitCerts spec | test | eec6631 | done | +| 2 | GREEN — implement splitCerts + wire POST /split | feat | 2c4ada3 | done | +| 3 | Split tab UI + splitCertsAction + render test | feat | 33b1bc3 | done | + +## What Was Built + +### Task 1: RED — failing splitCerts spec + +Added 3 new splitCerts tests to `cert-manager.service.spec.ts`: + +- **Fullchain PEM test:** builds two RSA-1024 self-signed certs, concatenates PEMs, calls splitCerts, asserts count=2, each cert content is base64 of single PEM block, both CNs present, ISO notAfter format +- **P7B bundle test:** builds a P7B PEM via `forge.pkcs7.createSignedData()` + `forge.pem.encode({ type:'PKCS7', body:... })`, calls splitCerts on a .p7b file, asserts at least 1 cert returned +- **Malformed input test:** garbage bytes with .pem extension → expects BadRequestException + +All 3 tests FAIL against the NotImplementedException stub (RED confirmed). 16 prior tests remain green. + +### Task 2: GREEN — splitCerts implementation + +**`cert-manager.service.ts`:** +- Exported `SplitEntry` interface: `{ index, filename, content (base64 PEM), subject.cn, validity.notAfter }` +- Exported `SplitResponse` interface: `{ count, certs: SplitEntry[] }` +- Implemented `splitCerts({ file }): Promise`: + - PEM path: `parsePemChain(buffer.toString('utf-8'))` → array of forge certs + - P7B path: sniff first 27 bytes for `-----BEGIN` → `messageFromPem` (PEM-wrapped) or `asn1.fromDer` + `messageFromAsn1` (binary DER) + - Unsupported format (pfx/der) → explicit BadRequestException + - Each cert: `certificateToPem(cert)` → base64 → SplitEntry with index, filename `cert-N.pem`, subject.cn, notAfter + - Outer try/catch → BadRequestException on malformed input (T-09-01) +- POST /split controller route was already fully wired from Plan 01 (FileInterceptor, 5MB limit, T-09-03, T-09-04) + +**Result: all 19 API tests pass (16 prior + 3 new splitCerts).** + +### Task 3: SplitTab UI + splitCertsAction + render tests + +**`actions.ts`:** +- Added `SplitEntry` + `SplitResponse` interfaces (mirrors API response) +- Added `splitCertsAction(file: File): Promise` — builds FormData, delegates to `postForm('split', form)` + +**`components/SplitTab.tsx`:** +- `'use client'` component with `useState` for loading/result/error +- Aufteilen button: disabled when no file or loading; label swaps to `t('actions.processing')` +- Empty state when no result and no error +- Per-cert `