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
14 KiB
14 KiB
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)
F001implemented 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)
getAuthorizationBundleDraftEditorActioncurrently requires only read permission but callsensureDraftBundleRevision(...), which creates draft state as a side effect. - (2026-04-22)
upsertBundleRule(...)anddeleteBundleRule(...)are currently not scoped tightly enough to the active draft revision, which weakens draft/publish isolation. - (2026-04-22) Runtime relationship evaluation for
selected_clientsandselected_boardsdepends 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_entrywhile selected time/delegation kernel calls currently usetimesheet. - (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)
serverpackage tests run directly viacd server && npx vitest run ...; rootnpm run test:local -- ...currently fails because itsdotenvinvocation expects a different CLI syntax. - (2026-04-22) Control-plane schema allows
authorization_bundle_rules.bundle_idto drift from the referenced revision’sbundle_idbecause rule rows currently only foreign-key revision by(tenant, revision_id). - (2026-04-22) Runtime rule mapping loaded
constraints/redactedFieldsfrom rule config but did not loadselectedClientIdsorselectedBoardIds, so selected template rules could evaluate against missing IDs. - (2026-04-22)
seedStarterAuthorizationBundlesActioncreated 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
timesheetfor bundle evaluation while the bundle editor/catalog and starter rules targettime_entry. - (2026-04-22) Simulator billing record lookup/listing used
invoices, but migrated billing API authorization evaluatesbillingover 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_idand 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.tsee/server/src/lib/actions/auth/authorizationBundleActions.tsserver/src/lib/authorization/kernel/providers/bundleProvider.tspackages/scheduling/src/actions/timeEntryDelegationAuth.tsserver/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.mdee/docs/plans/2026-04-21-premium-abac-authorization-kernel/features.jsonee/docs/plans/2026-04-21-premium-abac-authorization-kernel/tests.jsonee/docs/plans/2026-04-21-premium-abac-authorization-kernel/SCRATCHPAD.md
- Key implementation files:
server/src/lib/authorization/bundles/service.tsserver/src/lib/authorization/kernel/providers/bundleProvider.tsserver/src/lib/authorization/kernel/relationships.tsee/server/src/lib/actions/auth/authorizationBundleActions.tspackages/scheduling/src/actions/timeEntryDelegationAuth.tsserver/src/lib/api/controllers/authorizationKernel.tsserver/src/lib/api/controllers/ApiTicketController.tsserver/src/lib/api/controllers/ApiProjectController.tsserver/src/lib/api/controllers/ApiQuoteController.tsserver/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 Mappingsection inPRD.mdthat 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.
- Added a new
- (2026-04-22) Completed
F002:- Updated
getAuthorizationBundleDraftEditorActionto checksystem_settings:writecapability. - 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.
- Updated
- (2026-04-22) Completed
F003:- Hardened
upsertBundleRuleto require a draft revision scoped bytenant + bundle + revision. - Rule updates now also require
tenant + bundle + revision + rulematch and fail closed when no matching draft rule exists.
- Hardened
- (2026-04-22) Completed
F004:- Hardened
deleteBundleRuleto requiretenant + bundle + revision + rulematch. - Delete now fails closed when the rule is not in the expected draft revision scope.
- Hardened
- (2026-04-22) Verification for
F002-F004:- Command:
cd server && npx vitest run src/test/unit/authorization/bundleManagementPermissions.test.ts - Result: pass.
- Command:
- (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.
- Added migration
- (2026-04-22) Verification for
F005:- Command:
cd server && npx vitest run src/test/unit/migrations/authorizationBundleControlPlaneMigration.test.ts - Result: pass.
- Command:
- (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_clientsandselected_boardsuse rule-scoped configured IDs during decisioning instead of relying on ad hoc caller input.
- Extended bundle-provider rule type with
- (2026-04-22) Verification for
F006-F008:- Command:
cd server && npx vitest run src/test/unit/authorization/bundle.provider.test.ts - Result: pass.
- Command:
- (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
publishBundleRevisionto acceptKnex | 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).
- Command:
- (2026-04-22) Completed
F010:- Updated time delegation/approval kernel evaluations in
timeEntryDelegationAuth.tsto use resource typetime_entryfor bundle decisions. - Updated scheduling authorization regression test bundle-rule fixtures to match
time_entry.
- Updated time delegation/approval kernel evaluations in
- (2026-04-22) Verification for
F010:- Command:
cd server && npx vitest run ../packages/scheduling/tests/timeEntryDelegationAuth.authorization.test.ts - Result: pass.
- Command:
- (2026-04-22) Completed
F011:- Updated simulator billing record reference data and persisted-record loading from
invoicestoquotes. - Updated authorization-record normalization to include
quote_id.
- Updated simulator billing record reference data and persisted-record loading from
- (2026-04-22) Completed
F012:- Added simulator parity for mutation-guard invariants on
approveactions by usingauthorizeMutationwith not-self-approver guards forbillingandtime_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.
- Added simulator parity for mutation-guard invariants on
- (2026-04-22) Completed
F013:- Added explicit simulator support gating: only
read/approveactions 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.
- Added explicit simulator support gating: only
- (2026-04-22) Verification for
F011-F013andF023:- Command:
cd server && npx vitest run src/test/unit/authorization/bundleSimulatorAction.test.ts - Result: pass.
- Command:
- (2026-04-22) Completed
T009,T010andF023:- Extended
bundleSimulatorAction.test.tsto 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.
- Extended
- (2026-04-22) Completed
F014:- Extended API authorization subject normalization to support
client_id/clientIdandportfolio_client_ids/portfolioClientIds. - Subject shaping now preserves client/portfolio scope IDs across API user payload variants.
- Extended API authorization subject normalization to support
- (2026-04-22) Completed
F015,F016,F017,F018:- Added
authorizationAwarePaginationhelper that scans source pages, applies authorization first, and paginates authorized rows afterward. - Updated
ApiTicketController,ApiProjectController, andApiQuoteControllerlist paths to use authorization-aware pagination totals. - Remediation remains fail-closed: only authorized rows contribute to response data/totals.
- Added
- (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,T014andF024:- Added
authorizationAwarePagination.test.tswith ticket/project/quote scenarios proving no authorized rows are stranded behind filtered source pages. - Coverage asserts coherent authorized totals after narrowing.
- Added
- (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.
- Command:
- (2026-04-22) Completed
T001,T002,T003andF019:- Verified bundle-management permission and draft-revision scoping regressions remain covered in
bundleManagementPermissions.test.ts.
- Verified bundle-management permission and draft-revision scoping regressions remain covered in
- (2026-04-22) Completed
T004:- Verified migration-level revision/bundle integrity constraints in
authorizationBundleControlPlaneMigration.test.ts.
- Verified migration-level revision/bundle integrity constraints in
- (2026-04-22) Completed
T005,T006andF020:- Verified runtime selected-client and selected-board evaluation coverage in
bundle.provider.test.ts.
- Verified runtime selected-client and selected-board evaluation coverage in
- (2026-04-22) Completed
T007andF021:- Verified starter-bundle publish-backed enforceability in
starterBundles.test.ts.
- Verified starter-bundle publish-backed enforceability in
- (2026-04-22) Completed
T008andF022:- Verified time delegation authorization path alignment to
time_entryintimeEntryDelegationAuth.authorization.test.ts.
- Verified time delegation authorization path alignment to
- (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.
- Command: