Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

174 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scratchpad — Premium ABAC Follow-up Remediation
- Plan slug: `premium-abac-remediation`
- Created: `2026-04-22`
## What This Is
Keep a lightweight, continuously-updated log of discoveries and decisions made while implementing this plan.
Prefer short bullets. Append new entries as you learn things, and also *update earlier notes* when a decision changes or an open question is resolved.
## Decisions
- (2026-04-22) This is a **follow-up remediation plan** for `ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/`, not a replacement for it.
- (2026-04-22) Scope is limited to defects identified during review of the first implementation session.
- (2026-04-22) Remediation should be **surgical** where possible and should preserve the architecture and product decisions from the original plan.
- (2026-04-22) The most urgent fixes are draft/publish integrity, selected-rule fidelity, starter-bundle publish behavior, time resource-key alignment, simulator fidelity, and API pagination semantics.
- (2026-04-22) `F001` implemented by adding explicit remediation-to-original feature/test mapping to this plan PRD; this follow-up now has auditable traceability to original plan IDs.
## Discoveries / Constraints
- (2026-04-22) `getAuthorizationBundleDraftEditorAction` currently requires only read permission but calls `ensureDraftBundleRevision(...)`, which creates draft state as a side effect.
- (2026-04-22) `upsertBundleRule(...)` and `deleteBundleRule(...)` are currently not scoped tightly enough to the active draft revision, which weakens draft/publish isolation.
- (2026-04-22) Runtime relationship evaluation for `selected_clients` and `selected_boards` depends on evaluation input fields, but the stored rule config is not fully propagated into bundle-rule evaluation objects.
- (2026-04-22) Starter bundle seeding currently creates bundle rules without publishing the initial revision, leaving seeded bundles inert.
- (2026-04-22) Migrated Time UI/catalog uses `time_entry` while selected time/delegation kernel calls currently use `timesheet`.
- (2026-04-22) API list controllers for tickets, projects, and quotes paginate in the service layer first, then narrow in memory, then report filtered-page counts as totals.
- (2026-04-22) Simulator fidelity is weakened by billing-record mismatch and by simulator kernel construction that does not mirror all builtin resource-specific invariants used in real runtime paths.
- (2026-04-22) `server` package tests run directly via `cd server && npx vitest run ...`; root `npm run test:local -- ...` currently fails because its `dotenv` invocation expects a different CLI syntax.
- (2026-04-22) Control-plane schema allows `authorization_bundle_rules.bundle_id` to drift from the referenced revisions `bundle_id` because rule rows currently only foreign-key revision by `(tenant, revision_id)`.
- (2026-04-22) Runtime rule mapping loaded `constraints`/`redactedFields` from rule config but did not load `selectedClientIds` or `selectedBoardIds`, so selected template rules could evaluate against missing IDs.
- (2026-04-22) `seedStarterAuthorizationBundlesAction` created starter bundle draft revisions/rules but never published them, so seeded bundles were assignable yet inert.
- (2026-04-22) Time delegation/approval kernelization used resource type `timesheet` for bundle evaluation while the bundle editor/catalog and starter rules target `time_entry`.
- (2026-04-22) Simulator billing record lookup/listing used `invoices`, but migrated billing API authorization evaluates `billing` over quote records (`quotes`).
- (2026-04-22) Simulator previously evaluated all actions via `authorizeResource`, so approve-path mutation guards (for billing/time self-approval) were not represented.
- (2026-04-22) Simulator previously allowed non-read action modes (`create/update/delete`) without mutation context, which could imply unsupported fidelity.
- (2026-04-22) API authorization subject shaping only mapped `client_id` and ignored camelCase client ID payloads and portfolio client ID arrays.
- (2026-04-22) Ticket/project/quote API list controllers paginated service results before authorization narrowing, which stranded authorized records and reported filtered-page counts as totals.
## Commands / Runbooks
- (2026-04-22) Inspect original plan scratchpad and feature/test references:
`read ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/SCRATCHPAD.md`
- (2026-04-22) Review committed implementation history on this branch:
`git log --oneline --decorate --reverse --ancestry-path $(git merge-base HEAD origin/main)..HEAD`
- (2026-04-22) Review changed files in the premium-ABAC rollout:
`git diff --stat $(git merge-base HEAD origin/main)..HEAD`
- (2026-04-22) Spot-check known hot files:
- `server/src/lib/authorization/bundles/service.ts`
- `ee/server/src/lib/actions/auth/authorizationBundleActions.ts`
- `server/src/lib/authorization/kernel/providers/bundleProvider.ts`
- `packages/scheduling/src/actions/timeEntryDelegationAuth.ts`
- `server/src/lib/api/controllers/Api{Ticket,Project,Quote}Controller.ts`
## Links / References
- Original plan:
- `ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/PRD.md`
- `ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/features.json`
- `ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/tests.json`
- `ee/docs/plans/2026-04-21-premium-abac-authorization-kernel/SCRATCHPAD.md`
- Key implementation files:
- `server/src/lib/authorization/bundles/service.ts`
- `server/src/lib/authorization/kernel/providers/bundleProvider.ts`
- `server/src/lib/authorization/kernel/relationships.ts`
- `ee/server/src/lib/actions/auth/authorizationBundleActions.ts`
- `packages/scheduling/src/actions/timeEntryDelegationAuth.ts`
- `server/src/lib/api/controllers/authorizationKernel.ts`
- `server/src/lib/api/controllers/ApiTicketController.ts`
- `server/src/lib/api/controllers/ApiProjectController.ts`
- `server/src/lib/api/controllers/ApiQuoteController.ts`
- `server/migrations/20260421190000_create_authorization_bundle_control_plane.cjs`
## Open Questions
- Should this follow-up fully solve post-authorization pagination totals, or only make pagination semantics honest and fail-safe for now?
- Should simulator fidelity in this follow-up be broadened by modeling builtin resource rules per resource family, or narrowed by explicitly refusing unsupported scenario types?
## Progress Log
- (2026-04-22) Completed `F001`:
- Added a new `Traceability Mapping` section in `PRD.md` that maps each remediation feature cluster to original-plan feature/test IDs.
- Purpose: satisfy follow-up-plan auditability and make remediation-to-original linkage explicit in the source-of-truth artifact.
- (2026-04-22) Completed `F002`:
- Updated `getAuthorizationBundleDraftEditorAction` to check `system_settings:write` capability.
- Write-capable users keep existing behavior (`ensureDraftBundleRevision`), while read-only users load an existing draft or published revision without creating draft state.
- Added explicit summary text for read-only fallback when no active draft exists.
- (2026-04-22) Completed `F003`:
- Hardened `upsertBundleRule` to require a draft revision scoped by `tenant + bundle + revision`.
- Rule updates now also require `tenant + bundle + revision + rule` match and fail closed when no matching draft rule exists.
- (2026-04-22) Completed `F004`:
- Hardened `deleteBundleRule` to require `tenant + bundle + revision + rule` match.
- Delete now fails closed when the rule is not in the expected draft revision scope.
- (2026-04-22) Verification for `F002-F004`:
- Command: `cd server && npx vitest run src/test/unit/authorization/bundleManagementPermissions.test.ts`
- Result: pass.
- (2026-04-22) Completed `F005`:
- Added migration `server/migrations/20260422113000_enforce_authorization_rule_revision_bundle_integrity.cjs`.
- Enforced unique key on `authorization_bundle_revisions (tenant, bundle_id, revision_id)` and moved rules FK to `(tenant, bundle_id, revision_id)`.
- Result: a rule can no longer reference a revision from a different bundle.
- (2026-04-22) Verification for `F005`:
- Command: `cd server && npx vitest run src/test/unit/migrations/authorizationBundleControlPlaneMigration.test.ts`
- Result: pass.
- (2026-04-22) Completed `F006`:
- Added selected-client ID normalization/loading from rule config in runtime rule resolution and simulator rule normalization.
- Supports both camelCase (`selectedClientIds`) and snake_case (`selected_client_ids`) config keys.
- (2026-04-22) Completed `F007`:
- Added selected-board ID normalization/loading from rule config in runtime rule resolution and simulator rule normalization.
- Supports both camelCase (`selectedBoardIds`) and snake_case (`selected_board_ids`) config keys.
- (2026-04-22) Completed `F008`:
- Extended bundle-provider rule type with `selectedClientIds`/`selectedBoardIds`.
- Updated template evaluation so `selected_clients` and `selected_boards` use rule-scoped configured IDs during decisioning instead of relying on ad hoc caller input.
- (2026-04-22) Verification for `F006-F008`:
- Command: `cd server && npx vitest run src/test/unit/authorization/bundle.provider.test.ts`
- Result: pass.
- (2026-04-22) Completed `F009`:
- Starter seeding now publishes each created starter bundle revision immediately after inserting starter rules.
- Kept publish inside the existing transaction flow by widening `publishBundleRevision` to accept `Knex | Knex.Transaction`.
- (2026-04-22) Verification for `F009`:
- Command: `cd server && npx vitest run src/test/unit/authorization/starterBundles.test.ts`
- Result: pass.
- Command: `cd server && npx vitest run src/test/unit/authorization/bundleManagementPermissions.test.ts`
- Result: test pass but process ended with coverage cleanup error (`ENOENT .../coverage/.tmp`).
- (2026-04-22) Completed `F010`:
- Updated time delegation/approval kernel evaluations in `timeEntryDelegationAuth.ts` to use resource type `time_entry` for bundle decisions.
- Updated scheduling authorization regression test bundle-rule fixtures to match `time_entry`.
- (2026-04-22) Verification for `F010`:
- Command: `cd server && npx vitest run ../packages/scheduling/tests/timeEntryDelegationAuth.authorization.test.ts`
- Result: pass.
- (2026-04-22) Completed `F011`:
- Updated simulator billing record reference data and persisted-record loading from `invoices` to `quotes`.
- Updated authorization-record normalization to include `quote_id`.
- (2026-04-22) Completed `F012`:
- Added simulator parity for mutation-guard invariants on `approve` actions by using `authorizeMutation` with not-self-approver guards for `billing` and `time_entry`.
- Added simulator-side document client-visibility narrowing for client principals to mirror runtime deny behavior.
- Added managed-user lookup to simulation subject shaping for closer runtime parity.
- (2026-04-22) Completed `F013`:
- Added explicit simulator support gating: only `read/approve` actions are allowed in this follow-up; unsupported modes fail closed with clear errors.
- Added explicit refusal for ticket simulation with client principals until board-visibility builtin invariants are modeled.
- (2026-04-22) Verification for `F011-F013` and `F023`:
- Command: `cd server && npx vitest run src/test/unit/authorization/bundleSimulatorAction.test.ts`
- Result: pass.
- (2026-04-22) Completed `T009`, `T010` and `F023`:
- Extended `bundleSimulatorAction.test.ts` to verify quote-backed billing simulation records and approve self-approval guard behavior.
- Added regression coverage for supported-mode fidelity and explicit unsupported-mode rejection semantics.
- (2026-04-22) Completed `F014`:
- Extended API authorization subject normalization to support `client_id`/`clientId` and `portfolio_client_ids`/`portfolioClientIds`.
- Subject shaping now preserves client/portfolio scope IDs across API user payload variants.
- (2026-04-22) Completed `F015`, `F016`, `F017`, `F018`:
- Added `authorizationAwarePagination` helper that scans source pages, applies authorization first, and paginates authorized rows afterward.
- Updated `ApiTicketController`, `ApiProjectController`, and `ApiQuoteController` list paths to use authorization-aware pagination totals.
- Remediation remains fail-closed: only authorized rows contribute to response data/totals.
- (2026-04-22) Completed `T011`:
- Added API authorization subject unit coverage for snake_case and camelCase client/portfolio identifiers.
- (2026-04-22) Completed `T012`, `T013`, `T014` and `F024`:
- Added `authorizationAwarePagination.test.ts` with ticket/project/quote scenarios proving no authorized rows are stranded behind filtered source pages.
- Coverage asserts coherent authorized totals after narrowing.
- (2026-04-22) Verification for `F014-F018`, `T011-T014`:
- Command: `cd server && npx vitest run src/test/unit/authorization/bundleSimulatorAction.test.ts src/test/unit/api/authorizationKernel.test.ts src/test/unit/api/authorizationAwarePagination.test.ts`
- Result: pass.
- (2026-04-22) Completed `T001`, `T002`, `T003` and `F019`:
- Verified bundle-management permission and draft-revision scoping regressions remain covered in `bundleManagementPermissions.test.ts`.
- (2026-04-22) Completed `T004`:
- Verified migration-level revision/bundle integrity constraints in `authorizationBundleControlPlaneMigration.test.ts`.
- (2026-04-22) Completed `T005`, `T006` and `F020`:
- Verified runtime selected-client and selected-board evaluation coverage in `bundle.provider.test.ts`.
- (2026-04-22) Completed `T007` and `F021`:
- Verified starter-bundle publish-backed enforceability in `starterBundles.test.ts`.
- (2026-04-22) Completed `T008` and `F022`:
- Verified time delegation authorization path alignment to `time_entry` in `timeEntryDelegationAuth.authorization.test.ts`.
- (2026-04-22) Verification for `T001-T008`, `F019-F022`:
- Command: `cd server && npx vitest run src/test/unit/authorization/bundleManagementPermissions.test.ts src/test/unit/migrations/authorizationBundleControlPlaneMigration.test.ts src/test/unit/authorization/bundle.provider.test.ts src/test/unit/authorization/starterBundles.test.ts ../packages/scheduling/tests/timeEntryDelegationAuth.authorization.test.ts`
- Result: pass.