140 lines
7.2 KiB
Markdown
140 lines
7.2 KiB
Markdown
# 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)
|