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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
174 lines
14 KiB
Markdown
174 lines
14 KiB
Markdown
# 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 revision’s `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.
|