Commit Graph

5 Commits

Author SHA1 Message Date
Hartmut c0c5f762b8 security: bound JSONB inputs + whitelist batchUpdateCustomFields keys (#48)
batchUpdateCustomFields used $executeRaw to merge a manager-supplied
record straight into Resource.dynamicFields with no key whitelist —
so a manager could pollute the JSONB namespace with arbitrary keys
(e.g. ones admin tools later interpret). Separately, several user-facing
JSONB fields (allocation/demand metadata, dynamicFields) were typed as
unbounded z.record(z.string(), z.unknown()), letting clients ship
multi-MB payloads that flow into DB writes, audit logs, and SSE frames.

- Add BoundedJsonRecord helper (shared) — 64 keys / depth 4 /
  8 KB strings / 32 KB serialized total. Conservative defaults; call
  sites needing more should use a strict object schema.
- Apply BoundedJsonRecord to the highest-traffic untrusted JSONB inputs:
  allocation metadata (Create/CreateDemandRequirement/CreateAssignment),
  resource & project dynamicFields, and the createDemand router input.
- batchUpdateCustomFields:
    * Tighten input schema (key length, value bounds, max 100 keys).
    * Fetch each target resource and verify all input keys are in the
      union of (specific blueprint defs) ∪ (active global RESOURCE
      blueprint defs) for that resource. Empty whitelist → reject all
      keys (stricter than create/update, but appropriate for a bulk
      escape-hatch endpoint).
    * Run the existing per-key value validator afterwards.
    * 404 if any requested id does not exist (was silently skipped).
- New helper getAllowedDynamicFieldKeys() in blueprint-validation.
- 7 new BoundedJsonRecord tests, 2 new batchUpdateCustomFields tests
  covering the whitelist-rejection and not-found paths.

Covers EAPPS 3.2.7 (input bounds) / OWASP A03 (injection / mass assignment).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 08:44:11 +02:00
Hartmut 4a49ec4f05 fix(sanity): resolve 15 gaps from sanity check audit (G-01 through G-15)
- G-01: ProjectWizard renders blueprint fieldDefs with DynamicFieldInput component
- G-02: Blueprint rolePresets validated via RolePresetsSchema in wizard; API keeps loose schema
- G-03: ProjectWizard step 2/3 validation (role, hoursPerDay, headcount required)
- G-04: EstimateWizard validates baseCurrency and demand line cost rates
- G-05: Project lifecycle transition guards with ALLOWED_TRANSITIONS map
- G-06: Blueprint validator extended for minLength/maxLength/pattern and DATE range checks
- G-07: assertBlueprintDynamicFields merges global blueprint fieldDefs into validation
- G-08: (tracked — chapter managed dropdown; deferred to backend ticket)
- G-09: JSDoc added to lcrCents/ucrCents clarifying LCR/UCR terminology
- G-10: Dispo route redirect already in place — closed as done
- G-11: packages/ui empty by design — closed as documented
- G-12: @deprecated JSDoc added to CreateAllocationSchema and UpdateAllocationSchema
- G-13: ProjectWizard review step enhanced with blueprint name, field values, skills, assignments
- G-14: ProjectWizard handleSubmit collects per-item warnings instead of silent swallowing
- G-15: Vacation cancel reverses usedDays entitlement for APPROVED ANNUAL/OTHER vacations

Tests: all 1575 passing (1 pre-existing failure in insights-summary unrelated to these changes)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 00:11:12 +02:00
Hartmut cd78f72f33 chore: full technical rename planarchy → capakraken
Complete rename of all technical identifiers across the codebase:

Package names (11 packages):
- @planarchy/* → @capakraken/* in all package.json, tsconfig, imports

Import statements: 277 files, 548 occurrences replaced

Database & Docker:
- PostgreSQL user/db: planarchy → capakraken
- Docker volumes: planarchy_pgdata → capakraken_pgdata
- Connection strings updated in docker-compose, .env, CI

CI/CD:
- GitHub Actions workflow: all filter commands updated
- Test database credentials updated

Infrastructure:
- Redis channel: planarchy:sse → capakraken:sse
- Logger service name: planarchy-api → capakraken-api
- Anonymization seed updated
- Start/stop/restart scripts updated

Test data:
- Seed emails: @planarchy.dev → @capakraken.dev
- E2E test credentials: all 11 spec files updated
- Email defaults: @planarchy.app → @capakraken.app
- localStorage keys: planarchy_* → capakraken_*

Documentation: 30+ .md files updated

Verification:
- pnpm install: workspace resolution works
- TypeScript: only pre-existing TS2589 (no new errors)
- Engine: 310/310 tests pass
- Staffing: 37/37 tests pass

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-27 13:18:09 +01:00
Hartmut ad0855902b refactor: complete v2 refactoring plan (Phases 1-5)
Phase 1 — Quick Wins: centralize formatMoney/formatCents, extract
findUniqueOrThrow helper (19 routers), shared Prisma select constants,
useInvalidatePlanningViews hook, status badge consolidation, composite
DB indexes.

Phase 2 — Timeline Split: extract TimelineContext, TimelineResourcePanel,
TimelineProjectPanel; split 28-dep useMemo into 3 focused memos.
TimelineView.tsx reduced from 1,903 to 538 lines.

Phase 3 — Query Performance: server-side filtering for getEntriesView,
remove availability from timeline resource select, SSE event debouncing
(50ms batch window).

Phase 4 — Estimate Workspace: extract 7 tab components and 3 editor
components. EstimateWorkspaceClient 1,298→306 lines,
EstimateWorkspaceDraftEditor 1,205→581 lines.

Phase 5 — Package Cleanup: split commit-dispo-import-batch (1,112→573
lines), extract shared pagination helper with 11 tests.

All tests pass: 209 API, 254 engine, 67 application.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-14 23:03:42 +01:00
Hartmut dd55d0e78b chore(repo): initialize planarchy workspace 2026-03-14 14:31:09 +01:00