# Analysis: Sprint 13 — Production Hardening **Date:** 2026-06-18 **Author:** Patrick Plate / Lumen (Planner) **Status:** v1 **Sprint Theme:** Production Hardening & Housekeeping --- ## 1. Problem Analysis CannaManage has completed 12 sprints of feature development and is functionally complete for MVP. However, a comprehensive security review (2026-06-15) identified **4 production-blocking vulnerabilities** that prevent deployment. Additionally, backend test coverage sits at ~12% (20 tests for 29K LOC), the CI/CD pipeline deploys without running tests, and various repo hygiene issues remain unaddressed. Sprint 13 is a **hardening sprint** — no new features, purely focused on making the existing codebase production-ready. ### Source Documents - [`docs/security-code-review-final.md`](docs/security-code-review-final.md) — Full security review with 4 BLOCKERs - [`docs/sprint-12/SPRINT-12-SUMMARY.md`](docs/sprint-12/SPRINT-12-SUMMARY.md) — Sprint 12 outcome (test infra delivered) - [`.gitea/workflows/deploy.yml`](.gitea/workflows/deploy.yml) — Current CI/CD pipeline (no tests) --- ## 2. Affected Components | Component | Path | Issue | |-----------|------|-------| | DocumentController | `cannamanage-api/src/main/java/de/cannamanage/api/controller/DocumentController.java` | IDOR — no tenant check on download/delete | | DocumentService | `cannamanage-service/src/main/java/de/cannamanage/service/DocumentService.java` | Path traversal via unsanitized filename | | SecurityConfig | `cannamanage-api/src/main/java/de/cannamanage/api/security/SecurityConfig.java` | Missing `/api/v1/documents/**` matchers, CORS hardcoded | | deploy.yml | `.gitea/workflows/deploy.yml` | Deploys without running tests | | package.json | `cannamanage-frontend/package.json` | Wrong project name ("shadboard-nextjs-starter-kit") | | cannamanage-domain | `cannamanage-domain/src/` | 0 unit tests | | cannamanage-service | `cannamanage-service/src/` | Low test coverage on service layer | --- ## 3. Current State (Ist-Zustand) ### Security Posture The security review gave a **CONDITIONAL PASS** — architecture is solid (multi-tenant via `AbstractTenantEntity`, BCrypt+SHA-256, RFC 9457 errors, GoBD append-only audit) but 4 specific issues block go-live: | # | Blocker | Severity | Status Since | |---|---------|----------|-------------| | 1 | IDOR in DocumentController (download by raw UUID, no tenant verify) | HIGH | Sprint 9 (unfixed) | | 2 | Path traversal in DocumentService (`file.getOriginalFilename()` unsanitized) | HIGH | Sprint 9 (unfixed) | | 3 | JWT dev-secret fallback | HIGH | **FIXED** — `application.properties` now uses fail-on-startup marker | | 4 | `/api/v1/documents/**` missing from SecurityConfig matchers | HIGH | Sprint 9 (unfixed) | **Note:** Blocker #3 is already resolved. The current `application.properties:13` reads: ``` cannamanage.security.jwt.secret=${CANNAMANAGE_SECURITY_JWT_SECRET:CHANGE_ME_IN_PRODUCTION_THIS_WILL_FAIL_ON_STARTUP} ``` The `JwtService.validateSecret()` detects this marker and refuses startup. This leaves **3 active blockers**. ### CI/CD Pipeline The current [`.gitea/workflows/deploy.yml`](.gitea/workflows/deploy.yml:17) triggers on push to `main` and: 1. ✅ Checks out the commit 2. ✅ Builds Docker images 3. ✅ Deploys with `docker compose up -d` 4. ✅ Checks backend health (actuator) 5. ⚠️ Frontend check is non-blocking (doesn't fail the job) 6. ❌ **No tests run at all** — neither backend (Maven) nor frontend (Vitest/Playwright) ### Test Coverage - **Backend:** ~20 tests across cannamanage-api (GlobalExceptionHandlerTest, some controller tests). cannamanage-domain and cannamanage-service have minimal or zero coverage. - **Frontend:** Playwright integration specs (70+ tests) exist but are never run in CI. No Vitest unit tests in CI either. - **Sprint 12** delivered the Docker Compose test infrastructure (`docker-compose.test.yml`) — it's ready to be wired into CI. ### Repo Hygiene | Issue | Location | Impact | |-------|----------|--------| | Wrong project name | `cannamanage-frontend/package.json` → `"name": "shadboard-nextjs-starter-kit"` | Confusing, unprofessional | | Dead `.github/` folder | `.github/modernize/` | GitHub-specific, project uses Gitea | | No root README | `.` | No project documentation for new contributors | | Leftover screenshot scripts | `cannamanage-frontend/*.mjs` | Dev clutter (gitignored PNGs, but scripts committed) | | SonarQube findings | 7 MAJOR/MINOR issues | Dead fields, generic exceptions, string duplication | --- ## 4. Risk Assessment | Risk | Probability | Impact | Mitigation | |------|-------------|--------|------------| | Document data leak via IDOR | High (any authenticated user) | Critical (DSGVO breach, multi-tenant violation) | Fix #1: Add tenant verification to DocumentController | | Arbitrary file write via path traversal | Medium (requires auth + upload permission) | High (server compromise) | Fix #2: Sanitize with `FilenameUtils.getName()` | | Broken deployment from untested code | Medium (no test gate) | High (production outage) | Add test step to deploy.yml | | Low test confidence for future changes | Ongoing | Medium (regression risk) | Expand backend test suite | --- ## 5. Solution Options ### Option A: Minimal Security Fix Only (2-3 hours) - Fix 3 remaining security blockers - No CI/CD changes, no test expansion, no cleanup - **Pro:** Fastest path to unblock deployment - **Con:** Leaves test debt and CI risk intact; next feature sprint can introduce regressions ### Option B: Security + CI Quality Gate (4-6 hours) - Fix 3 security blockers - Add Maven test + Playwright test steps to CI - Basic repo cleanup (package.json, README) - **Pro:** Production-safe deployment pipeline, reasonable effort - **Con:** Test coverage still low for service/domain layer ### Option C: Full Hardening Sprint (8-12 hours) ⬅️ RECOMMENDED - Fix 3 security blockers - Expand backend test suite (target: DocumentService, AuthService, key service methods) - Wire tests into CI/CD pipeline (fail-fast on test failure) - CORS configuration externalization - Login rate limiting - Complete repo cleanup (README, package.json, dead files, SonarQube fixes) - **Pro:** Production-ready with confidence, clean repo, future-proof - **Con:** Full sprint investment (no new features) --- ## 6. Recommendation **Option C** — This is the right time for a full hardening sprint. The project is feature-complete for MVP, Sprint 12 already built the test infrastructure, and the security blockers have been unfixed since Sprint 9. A half-measure (Option A/B) would leave known technical debt that compounds with every future sprint. Priority ordering: 1. **Security fixes** (unblocks production) — ~2 hours 2. **CI test gate** (prevents future regressions) — ~2 hours 3. **Backend test expansion** (confidence for the security fixes themselves) — ~4 hours 4. **Repo cleanup + CORS + rate limiting** (polish) — ~2 hours --- ## 7. Open Questions - [ ] Should CORS allowed origins come from `application.properties` or environment variables? - [ ] Login rate limiting: Bucket4j (Spring-native) or custom filter with in-memory counter? - [ ] Target test coverage % for this sprint? (Suggest: cover all security-critical paths = DocumentService, AuthService, TenantFilterAspect)