7.2 KiB
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— Full security review with 4 BLOCKERsdocs/sprint-12/SPRINT-12-SUMMARY.md— Sprint 12 outcome (test infra delivered).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 triggers on push to main and:
- ✅ Checks out the commit
- ✅ Builds Docker images
- ✅ Deploys with
docker compose up -d - ✅ Checks backend health (actuator)
- ⚠️ Frontend check is non-blocking (doesn't fail the job)
- ❌ 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:
- Security fixes (unblocks production) — ~2 hours
- CI test gate (prevents future regressions) — ~2 hours
- Backend test expansion (confidence for the security fixes themselves) — ~4 hours
- Repo cleanup + CORS + rate limiting (polish) — ~2 hours
7. Open Questions
- Should CORS allowed origins come from
application.propertiesor 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)