@wildo-ai/saas-backend-lib 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts +14 -3
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js +115 -22
- package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts +3 -1
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js +8 -3
- package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts +11 -0
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js +11 -2
- package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts +1 -0
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js +6 -1
- package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js +16 -0
- package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts +20 -6
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js +88 -32
- package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.d.ts +3 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.js +32 -7
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts +8 -5
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +31 -0
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +127 -5
- package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts +71 -1
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js +62 -2
- package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +21 -0
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +126 -4
- package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts +3 -26
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.js +3 -68
- package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.js.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +4 -2
- package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +6 -6
- package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +38 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js +40 -0
- package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +20 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +28 -0
- package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts +12 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js +118 -0
- package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js.map +1 -0
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js +8 -5
- package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js +14 -0
- package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js.map +1 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.js +7 -1
- package/dist/esm/config/custom/application-config-controller.backend.service.js.map +1 -1
- package/dist/esm/config/models/app-config.backend.schemas.d.ts +4 -0
- package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts +10 -1
- package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -1
- package/dist/esm/config/services/app-configuration.backend.utils.js +13 -2
- package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -1
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.d.ts +2 -2
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js +2 -2
- package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js.map +1 -1
- package/dist/esm/databases/models/filter.backend.schemas.js +2 -2
- package/dist/esm/databases/models/filter.backend.schemas.js.map +1 -1
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts.map +1 -1
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js +20 -1
- package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js.map +1 -1
- package/dist/esm/databases/services/redis.service.d.ts +27 -0
- package/dist/esm/databases/services/redis.service.d.ts.map +1 -1
- package/dist/esm/databases/services/redis.service.js +29 -0
- package/dist/esm/databases/services/redis.service.js.map +1 -1
- package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/errors/services/error-handler.backend.service.js +5 -0
- package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -1
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts +41 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js +40 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts +64 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts.map +1 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js +193 -0
- package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js.map +1 -0
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts +13 -2
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.js +8 -2
- package/dist/esm/external-data/external-data-pipeline-run.backend.service.js.map +1 -1
- package/dist/esm/external-data/external-data-transform.backend.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-transform.backend.js +7 -1
- package/dist/esm/external-data/external-data-transform.backend.js.map +1 -1
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts +2 -0
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts.map +1 -1
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js +13 -0
- package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +14 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +6 -0
- package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
- package/dist/esm/files/controllers/file.controller.d.ts +24 -1
- package/dist/esm/files/controllers/file.controller.d.ts.map +1 -1
- package/dist/esm/files/controllers/file.controller.js +66 -2
- package/dist/esm/files/controllers/file.controller.js.map +1 -1
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts +17 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts.map +1 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js +1 -0
- package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js.map +1 -0
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +5 -1
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +42 -3
- package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts +18 -0
- package/dist/esm/files/services/file-operation-handler.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/file-operation-handler.backend.service.js +36 -28
- package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -1
- package/dist/esm/files/services/file-upload-grant.backend.service.d.ts +163 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.d.ts.map +1 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.js +442 -0
- package/dist/esm/files/services/file-upload-grant.backend.service.js.map +1 -0
- package/dist/esm/files/services/files.backend.service.d.ts +19 -0
- package/dist/esm/files/services/files.backend.service.d.ts.map +1 -1
- package/dist/esm/files/services/files.backend.service.js +78 -15
- package/dist/esm/files/services/files.backend.service.js.map +1 -1
- package/dist/esm/files/utils/file-uploader.utils.d.ts.map +1 -1
- package/dist/esm/files/utils/file-uploader.utils.js +12 -0
- package/dist/esm/files/utils/file-uploader.utils.js.map +1 -1
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js +5 -5
- package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts +79 -0
- package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
- package/dist/esm/flows-actors/services/agents.backend.service.js +319 -42
- package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +151 -41
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +300 -139
- package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +14 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inject/models/container.d.ts.map +1 -1
- package/dist/esm/inject/models/container.js +4 -0
- package/dist/esm/inject/models/container.js.map +1 -1
- package/dist/esm/inject/models/service-types.d.ts +3 -0
- package/dist/esm/inject/models/service-types.d.ts.map +1 -1
- package/dist/esm/inject/models/service-types.js +2 -0
- package/dist/esm/inject/models/service-types.js.map +1 -1
- package/dist/esm/mcp/controllers/mcp.controller.d.ts.map +1 -1
- package/dist/esm/mcp/controllers/mcp.controller.js +12 -4
- package/dist/esm/mcp/controllers/mcp.controller.js.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts +34 -0
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts.map +1 -1
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.js +42 -0
- package/dist/esm/mcp/models/mcp-tool.backend.schemas.js.map +1 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.d.ts +29 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.d.ts.map +1 -1
- package/dist/esm/mcp/services/mcp-server.backend.service.js +131 -3
- package/dist/esm/mcp/services/mcp-server.backend.service.js.map +1 -1
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts +64 -2
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts.map +1 -1
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js +130 -6
- package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +9 -0
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +11 -36
- package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js +9 -7
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts +5 -5
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js +14 -13
- package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts +2 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js +2 -2
- package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.d.ts.map +1 -1
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js +9 -7
- package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js.map +1 -1
- package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.d.ts.map +1 -1
- package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.js +4 -1
- package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.js.map +1 -1
- package/dist/esm/requests/service/websocket.service.d.ts.map +1 -1
- package/dist/esm/requests/service/websocket.service.js +56 -7
- package/dist/esm/requests/service/websocket.service.js.map +1 -1
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -1
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +2 -0
- package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -1
- package/dist/esm/resources/services/resource-id.backend.service.js +3 -3
- package/dist/esm/resources/services/resource-id.backend.service.js.map +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.js +1 -1
- package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js +13 -7
- package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.d.ts +28 -0
- package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -1
- package/dist/esm/runtime/services/start-application.backend.service.js +82 -0
- package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts +3 -23
- package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js +20 -45
- package/dist/esm/security/authentications/models/jwt.backend.schemas.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts +9 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js +9 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js +5 -3
- package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js.map +1 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +25 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js +55 -4
- package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.d.ts.map +1 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js +24 -1
- package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js.map +1 -1
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts +117 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts.map +1 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js +104 -0
- package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js.map +1 -0
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +101 -6
- package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -1
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js +210 -30
- package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts +18 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js +110 -74
- package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js.map +1 -1
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts +22 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts.map +1 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js +22 -0
- package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js.map +1 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts +17 -3
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js +12 -0
- package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +20 -0
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -1
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js +58 -5
- package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -1
- package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -1
- package/dist/esm/security/jwt/services/jwt.backend.service.js +1 -18
- package/dist/esm/security/jwt/services/jwt.backend.service.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +15 -9
- package/dist/esm/.builder.pid +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorizations.backend.service.js","sourceRoot":"","sources":["../../../../../../src/security/authorizations/services/authorizations.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthExecutionContextFactoryBackendService } from '~wildo-backend-lib/security/authentications/services/auth-execution-context-factory.backend.service';\nimport { inject, injectable, optional } from \"inversify\";\nimport type { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport {\n anyOrganizationUnitGrantInheritsDownward,\n CORE_APP_ROLES,\n expandOrganizationUnitGrantThroughInheritance,\n isOrganizationWideRoleInfo,\n OrganizationUnitNarrowingDecisionKind,\n resolveOrganizationUnitNarrowingDecision,\n isWildoBackendError,\n} from \"@wildo-ai/saas-models\";\nimport type {\n OrganizationUnitGrantExpansion,\n OrganizationUnitInheritanceNode,\n OrganizationUnitNarrowingStamp,\n} from \"@wildo-ai/saas-models\";\nimport type { ResourcesRegistryBackendService } from \"~wildo-backend-lib/resources/services/resources-registry.backend.service\";\nimport { SAAS_SERVICE_TYPES } from \"~wildo-backend-lib/inject/models/service-types\";\nimport { LoggerService } from \"~wildo-backend-lib/monitoring/logger/services/logger.service\";\nimport { ErrorBuilderBackendService } from \"~wildo-backend-lib/errors/services/error-builder.backend.service\";\nimport { describeCaughtError, projectCaughtErrorLogFields } from \"~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils\";\nimport { RepositoriesRegistryHandlerBackendService } from \"~wildo-backend-lib/base-classes/services/repositories/repositories-registry-handler.backend.service\";\nimport { IdOrIdsOrFilterType } from \"~wildo-backend-lib/base-classes/models/repositories.backend.schemas\";\nimport {\n ResourceConfiguration_Operation,\n CoreResourceType,\n coreResourceShared_FieldIdentifier,\n PlatformAccessGrantStatus,\n PlatformAccessGrants_Operations,\n ResourceOperationVariantType,\n ResourcePrimaryScope,\n isPlatformAccessGrantUsable,\n PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE,\n ResourcesConfig_OperationPathUtils,\n ErrorType,\n ErrorCustomMessageReference,\n RolesConfiguration,\n RoleDefinition,\n DEFAULT_APP_ROLE_CONFIGURATION,\n DEFAULT_ORGANIZATION_ROLES,\n Roles,\n AppRoles,\n OrgRoles,\n CoreResourceOperation,\n ExecutionContext_ExecutionType,\n ResourceOperationDenialReason,\n ResourceOperationRiskLevel\n} from \"@wildo-ai/saas-models\";\nimport type { AuditLogsBackendService } from \"~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service\";\nimport type { RedisService } from \"~wildo-backend-lib/databases/services/redis.service\";\nimport type { Container } from \"inversify\";\nimport { classifyAuthorizationDenial, resolveDenialAuditEmissionDecision } from \"~wildo-backend-lib/security/authorizations/authorization-denial-audit.backend.utils\";\nimport { isOwnScopeRootResource } from \"~wildo-backend-lib/security/authorizations/scope-root-collection-confinement.backend\";\nimport { ExecutionContext } from \"~wildo-backend-lib/runtime/models/execution-context.backend.schemas\";\nimport { ResourceConfiguration_OperationRepositoryPath } from \"@wildo-ai/saas-models\";\n\n@injectable()\nexport class AuthorizationsBackendService {\n\n\n private readonly logDebug: (message: string, context?: Record<string, unknown>) => void;\n\n // Role configuration management\n private appRoles: RolesConfiguration;\n private orgRoles: RolesConfiguration;\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService) private readonly errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService) private readonly repositoriesRegistry: RepositoriesRegistryHandlerBackendService,\n /**\n * Source of the organization-unit narrowing registry (WS-C). Added LAST so existing positional\n * construction keeps working; when absent the narrowing lookup resolves to \"no resource is\n * narrowed\", which is the fail-CLOSED direction here rather than the fail-open one: the\n * repositories read the same registry independently, so a resource they see as narrowed and this\n * gate does not ends up with NO stamp — and an unstamped narrowed resource yields no rows.\n */\n @inject(SAAS_SERVICE_TYPES.ResourceRegistryService) @optional() private readonly resourcesRegistry?: ResourcesRegistryBackendService,\n /**\n * Counter store backing the denial-audit escalation ladder. Optional: with no Redis bound the\n * dedup degrades to always-emit, which is the fail-OPEN direction and the correct one — a\n * fail-closed cooldown would let an attacker blind the trail by taking Redis down.\n */\n @inject(SAAS_SERVICE_TYPES.RedisService) @optional() private readonly redisService?: RedisService,\n /**\n * Lazy resolver for {@link AuditLogsBackendService} — the sink for `RESOURCE_OPERATION_DENIED`\n * (the record half of \"record access decisions\"). Deliberately NOT constructor-injected:\n * `AuditLogsBackendService` → `AuditEventDispatcherBackendService` → `QueueBackendService` →\n * `AuthorizationsBackendService` (via `authorizeInController`, which `QueueBackendService` calls\n * on its own enqueue paths) is an existing edge, so a direct constructor inject here would close\n * that chain into an InversifyJS circular-dependency plan failure at boot. Resolved on demand via\n * {@link resolveAuditLogsService} instead — the same lazy-container pattern `WebSocketService`\n * uses to break its own cycle with `NotificationBadgeService`/`ConversationalExecutionBackendService`.\n * Optional and positioned LAST so existing positional construction (and every partial-container\n * test) keeps working; when absent, or when `AuditLogsService` is unbound, the refusal is still\n * enforced, it simply leaves no audit row.\n *\n * Emission is deliberately BEST-EFFORT and can never alter the authorization outcome: the caller\n * has already been refused by the time this is consulted, so letting an audit-store problem turn\n * a correct 403 into a 500 would degrade the system to protect a log. Detection of that gap is\n * the audit pipeline's own control (`audit_store_failure_total`), not this gate's.\n *\n * assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n */\n @inject('Container') @optional() private readonly container?: Container,\n ) {\n\n this.logDebug = this.logger.debugByType('AuthorizationsBackendService');\n this.logger.setDebugTypeLogging('AuthorizationsBackendService', false);\n\n // Initialize default role configurations\n this.initializeRoles();\n }\n\n /**\n * Initialize roles with default configurations and optional custom roles\n */\n private initializeRoles(customRoles?: RolesConfiguration): void {\n // Start with default configurations\n this.appRoles = { ...DEFAULT_APP_ROLE_CONFIGURATION };\n this.orgRoles = { ...DEFAULT_ORGANIZATION_ROLES };\n\n // Add custom roles if provided, filtering by scope\n if (customRoles) {\n this.addCustomRoles(customRoles);\n }\n\n this.logDebug('Role configurations initialized', { appRolesCount: Object.keys(this.appRoles).length, orgRolesCount: Object.keys(this.orgRoles).length, hasCustomRoles: !!customRoles });\n }\n\n /**\n * Initialize roles with custom roles configuration\n */\n public initializeRolesWithCustom(customRoles: RolesConfiguration): void {\n this.initializeRoles(customRoles);\n }\n\n /**\n * Add custom roles, filtering them by relatedPrimaryScope to place them in the correct configuration\n */\n private addCustomRoles(customRoles: RolesConfiguration): void {\n let appRolesAdded = 0;\n let orgRolesAdded = 0;\n const invalidRoles: string[] = [];\n\n for (const [roleKey, roleDefinition] of Object.entries(customRoles)) {\n try {\n // Type cast to RoleDefinition since we know the structure from RolesConfiguration\n const typedRoleDefinition = roleDefinition as RoleDefinition;\n\n switch (typedRoleDefinition.relatedPrimaryScope) {\n case ResourcePrimaryScope.APPLICATION:\n this.appRoles[roleKey] = { ...typedRoleDefinition };\n appRolesAdded++;\n this.logDebug('Custom app role added', { roleKey, role: typedRoleDefinition.role, inheritFrom: typedRoleDefinition.inheritFrom, isSystemRole: typedRoleDefinition.isSystemRole });\n break;\n\n case ResourcePrimaryScope.ORGANIZATIONS:\n this.orgRoles[roleKey] = { ...typedRoleDefinition };\n orgRolesAdded++;\n this.logDebug('Custom org role added', { roleKey, role: typedRoleDefinition.role, inheritFrom: typedRoleDefinition.inheritFrom, isSystemRole: typedRoleDefinition.isSystemRole });\n break;\n\n case ResourcePrimaryScope.USER_SELF:\n // This scope doesn't have dedicated role configurations\n // Log a warning but don't add them\n this.logger.warn('Custom role with unsupported scope ignored', { roleKey, scope: typedRoleDefinition.relatedPrimaryScope, message: 'USER_SELF scope does not support custom roles' });\n invalidRoles.push(roleKey);\n break;\n\n default:\n this.logger.warn('Custom role with unknown scope ignored', { roleKey, scope: typedRoleDefinition.relatedPrimaryScope });\n invalidRoles.push(roleKey);\n break;\n }\n } catch (error) {\n this.logger.error('Failed to add custom role', { roleKey, ...projectCaughtErrorLogFields(error), roleDefinition });\n invalidRoles.push(roleKey);\n }\n }\n\n this.logDebug('Custom roles processing completed', { totalCustomRoles: Object.keys(customRoles).length, appRolesAdded, orgRolesAdded, invalidRoles: invalidRoles.length, invalidRoleKeys: invalidRoles });\n }\n\n public addMultipleCustomRoles(customRoles: RolesConfiguration): void {\n this.addCustomRoles(customRoles);\n }\n\n public addAppRole(roleKey: AppRoles, roleDefinition: RoleDefinition): void {\n // Validate that the role definition has APPLICATION scope\n if (roleDefinition.relatedPrimaryScope !== ResourcePrimaryScope.APPLICATION) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { roleScope: roleDefinition.relatedPrimaryScope, currentRoleScope: ResourcePrimaryScope.APPLICATION, roleKey , roleDefinition } });\n }\n\n this.appRoles[roleKey] = { ...roleDefinition };\n\n this.logDebug('App role added/updated', { roleKey, roleDefinition });\n }\n\n public addOrgRole(roleKey: OrgRoles, roleDefinition: RoleDefinition): void {\n // Validate that the role definition has ORGANIZATIONS scope\n if (roleDefinition.relatedPrimaryScope !== ResourcePrimaryScope.ORGANIZATIONS) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { roleScope: roleDefinition.relatedPrimaryScope, currentRoleScope: ResourcePrimaryScope.ORGANIZATIONS, roleKey , roleDefinition } });\n }\n\n this.orgRoles[roleKey] = { ...roleDefinition };\n\n this.logDebug('Org role added/updated', { roleKey, roleDefinition });\n }\n\n public getAppRole(roleKey: AppRoles): RoleDefinition | undefined {\n return this.appRoles[roleKey];\n }\n\n public getOrgRole(roleKey: OrgRoles): RoleDefinition | undefined {\n return this.orgRoles[roleKey];\n }\n\n public getAppRoles(): RolesConfiguration {\n return { ...this.appRoles };\n }\n\n public getOrgRoles(): RolesConfiguration {\n return { ...this.orgRoles };\n }\n\n public hasAppRole(roleKey: AppRoles): boolean {\n return roleKey in this.appRoles;\n }\n\n public hasOrgRole(roleKey: OrgRoles): boolean {\n return roleKey in this.orgRoles;\n }\n\n public getRoleHierarchy(roleKey: Roles, scope: ResourcePrimaryScope): string[] {\n const rolesConfig = scope === ResourcePrimaryScope.APPLICATION ? this.appRoles : this.orgRoles;\n const roleHierarchy: string[] = [];\n let currentRoleKey: string | undefined = roleKey;\n\n while (currentRoleKey && rolesConfig[currentRoleKey]) {\n roleHierarchy.push(currentRoleKey);\n currentRoleKey = rolesConfig[currentRoleKey].inheritFrom;\n }\n\n return roleHierarchy;\n }\n\n public resetRolesToDefaults(): void {\n this.initializeRoles();\n this.logDebug('Roles reset to default configurations');\n }\n\n /**\n * Reset roles to default configurations with custom roles\n */\n public resetRolesToDefaultsWithCustom(customRoles: RolesConfiguration): void {\n this.initializeRoles(customRoles);\n this.logger.info('Roles reset to default configurations with custom roles');\n }\n\n /**\n * Evaluate the organization-unit narrowing decision for this request and STAMP it on the context.\n *\n * assurance-control: WILDO.ACCESS.SCOPE_CONFINEMENT — the stamp is the conferring-grant\n * record: it names WHY this principal reached this resource, which is the input an access review\n * needs in order to answer that question without reconstructing it from role tables.\n *\n * ## Why here and nowhere else (plan decision D-C6)\n *\n * This is the only place holding all three inputs at once: the operation, its declared roles, and\n * `getRoleHierarchy`. The repository layer — which needs the ANSWER — cannot reach a role-hierarchy\n * resolver without injecting this service, and this service already depends on the repositories\n * registry, so that would invert the dependency direction. Evaluating once and carrying the result\n * also removes the possibility that the gate and the filter disagree: two evaluations of the same\n * inputs can drift, one stamped decision cannot.\n *\n * ## Both halves must land together\n *\n * Admitting a unit grant here without the repository narrowing rows would turn one unit's grant\n * into tenant-wide access — the escalation the whole model exists to prevent. The repository's\n * fail-closed default (an unstamped narrowable resource yields no rows) is what protects the window\n * between them.\n */\n /**\n * PUBLIC seam so a caller that must READ before authorization can stamp first.\n *\n * The controller's context-addressed probes (`resolveContextAddressedSingletonOperationAuthorizationId`\n * and its association twin) resolve WHICH row an id-less operation is about by running a real,\n * narrowed repository read — necessarily BEFORE `authorizeInController`, because the id they produce\n * is the thing being authorized. On a narrowed resource that read would otherwise run against no\n * stamp, fail closed, resolve nothing, and answer NOT_FOUND before authorization ever ran: the same\n * defect this class fixed for `authorizeInRepositoryAndService`, one boundary out.\n *\n * Stamping here rather than exempting the probe is the deliberate half. A probe that skips narrowing\n * would resolve a singleton belonging to a unit the caller does not hold, and the confinement would\n * then depend entirely on a later check noticing — fail-open by default. Stamped, the probe simply\n * does not find it, which is the same answer the row filter gives everywhere else.\n *\n * Safe to call more than once per request: `mergeOrganizationUnitNarrowingStamps` only ever tightens,\n * so a later evaluation can restrict further and never widen.\n */\n public async stampOrganizationUnitNarrowingForOperation(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<void> {\n await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n }\n\n private async resolveAndStampOrganizationUnitNarrowing(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<OrganizationUnitNarrowingStamp> {\n const { resourceIdentifier, operationIdentifier, roles: operationRoles } = operation;\n\n const decision = resolveOrganizationUnitNarrowingDecision({\n resourceType: resourceIdentifier,\n requiredRoles: operationRoles ?? [],\n initiatorRoles: executionContext.initiatorRoles,\n narrowingRegistry: this.resourcesRegistry?.getResourcesRegistry()?.organizationUnitNarrowing ?? {},\n roleHierarchyResolver: (role, scope) => this.getRoleHierarchy(role as Roles, scope),\n });\n\n // Downward inheritance (D-C2): a grant at a unit declaring INHERIT_DOWN also reaches that unit's\n // descendants. Expanding HERE rather than in the repository keeps D-C6's one-evaluation rule\n // intact — the effective unit set travels in the stamp, so the row filter and the write guard\n // cannot end up with different ideas of how far the same grant reaches.\n const expansion =\n decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? await this.expandOrganizationUnitGrant(decision.organizationUnitIds, executionContext)\n : undefined;\n\n const effectiveDecision =\n expansion && decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? { ...decision, organizationUnitIds: expansion.effectiveOrganizationUnitIds }\n : decision;\n\n const stamp: OrganizationUnitNarrowingStamp = {\n resourceType: resourceIdentifier,\n operationIdentifier: String(operationIdentifier),\n requiredRoles: operationRoles ?? [],\n decision: effectiveDecision,\n inheritedOrganizationUnitIds: expansion?.inheritedOrganizationUnitIds,\n };\n\n executionContext.stampOrganizationUnitNarrowingDecision(stamp);\n\n if (effectiveDecision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED) {\n // The conferring grant, recorded at INFO: this is an access decision a reviewer must be able to\n // reconstruct, not a debug detail. Organization-wide decisions are the unchanged norm and stay\n // on the debug channel.\n //\n // Directly-held and inherited units are reported SEPARATELY: with downward inheritance a grant\n // at a root unit reaches the whole chart, and an access review must be able to see that rather\n // than read one effective list that looks narrow (D-C4 watch item 4).\n this.logger.info('Organization-unit narrowed access granted', {\n resourceType: resourceIdentifier,\n operationIdentifier: stamp.operationIdentifier,\n requiredRoles: stamp.requiredRoles,\n conferringOrganizationUnitIds: decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? decision.organizationUnitIds\n : [],\n inheritedOrganizationUnitIds: stamp.inheritedOrganizationUnitIds ?? [],\n effectiveOrganizationUnitIds: effectiveDecision.organizationUnitIds,\n userId: executionContext.userId,\n organizationId: executionContext.organizationId,\n });\n } else {\n this.logDebug('Organization-unit narrowing decision', { resourceIdentifier, decisionKind: effectiveDecision.kind });\n }\n\n return stamp;\n }\n\n /**\n * Expand directly-held unit grants across the organization tree, per each unit's `inheritanceType`.\n *\n * assurance-control: WILDO.ACCESS.SCOPE_CONFINEMENT — a grant reaches exactly the subtree its unit\n * declares.\n *\n * ## Cost, and the pre-check that keeps it honest\n *\n * Two reads at most, and usually one: the granted units are fetched by id (an indexed `$in` over a\n * handful of ids), and the organization's unit set is fetched ONLY when at least one of them\n * actually declares downward inheritance. An organization whose units are all `NO_INHERITANCE`\n * therefore pays a single small lookup. The subtree test itself is a `path` PREFIX comparison in\n * memory — never a recursive walk, which is the entire reason `path` is materialized (D-C5).\n *\n * ## Failure posture: PROPAGATE, matching the emission phase\n *\n * A read failure is NOT swallowed into \"no inheritance\". Silently returning the unexpanded set\n * gives the principal a grant narrower than the one they hold, which surfaces as missing rows\n * rather than as an error — presenting a failure as data, the exact degradation the execution-context\n * builder refused when it chose to propagate. An UNREGISTERED repository is different and is treated\n * as such: an application with no unit tree has no descendants to find, which is an accurate answer.\n */\n /**\n * The context for reading ORGANIZATION_UNITS from inside authorization.\n *\n * NOT the caller's. This runs on the authorization path for ANY resource operation that opted into\n * unit narrowing, so `executionContext` is keyed to whatever resource the request addressed — a\n * nested route contributes that resource's own FK (`todoId`, `organizationMemberId`, …). The\n * repository's contextual filter is fail-closed on a field the target does not model: it THROWS\n * `CONFIGURATION` / `context_filter` rather than ignoring it, so a unit-narrowed grant on a nested\n * resource would 500 the authorization decision itself. `createForSubCall` narrows the inherited\n * context to what ORGANIZATION_UNITS actually models, which keeps `organizationId` — the scoping\n * this read depends on — and drops the rest.\n *\n * Resolved LAZILY from the container, mirroring how the execution-context creator resolves its own\n * late collaborators: authorization is constructed early in backend startup and a hard constructor\n * dependency here risks a DI cycle. When the container or the creator is unavailable (minimal test\n * containers), fall back to the caller's context — the pre-existing behaviour — rather than failing\n * an authorization decision over a read-context refinement.\n */\n private async createOrganizationUnitReadContext(\n executionContext: ExecutionContext<any>,\n ): Promise<ExecutionContext<any>> {\n try {\n const executionContextCreator = this.container?.get<ExecutionContextCreatorBackendService>(\n SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService,\n );\n if (!executionContextCreator) return executionContext;\n return await executionContextCreator.createForSubCall(\n executionContext,\n CoreResourceType.ORGANIZATION_UNITS,\n CoreResourceOperation.LIST,\n );\n } catch {\n return executionContext;\n }\n }\n\n private async expandOrganizationUnitGrant(\n grantedOrganizationUnitIds: readonly string[],\n executionContext: ExecutionContext<any>,\n ): Promise<OrganizationUnitGrantExpansion> {\n const unexpanded: OrganizationUnitGrantExpansion = {\n effectiveOrganizationUnitIds: [...grantedOrganizationUnitIds],\n inheritedOrganizationUnitIds: [],\n };\n if (grantedOrganizationUnitIds.length === 0) return unexpanded;\n\n const unitRepository = this.repositoriesRegistry.getRepository(CoreResourceType.ORGANIZATION_UNITS);\n if (!unitRepository) return unexpanded;\n\n const unitReadContext = await this.createOrganizationUnitReadContext(executionContext);\n\n const grantedUnits = await unitRepository.list<OrganizationUnitInheritanceNode>(unitReadContext, {\n _id: { $in: [...grantedOrganizationUnitIds] },\n }) ?? [];\n\n if (!anyOrganizationUnitGrantInheritsDownward(grantedUnits)) return unexpanded;\n\n // Scoped to the organization the request is acting in. Org charts are small and bounded, and the\n // alternative — a `path`-prefix query per granted unit — would need a per-adapter `startsWith`\n // operator the portable filter contract does not carry.\n const organizationUnits = await unitRepository.list<OrganizationUnitInheritanceNode>(unitReadContext, {\n organizationId: executionContext.organizationId,\n }) ?? [];\n\n return expandOrganizationUnitGrantThroughInheritance(grantedUnits, organizationUnits);\n }\n\n /**\n * Does a stamped decision ADMIT this caller on the strength of a unit grant alone?\n *\n * Consulted only after the organization-wide role check has already failed. `UNIT_NARROWED` means\n * the decision authority found a unit grant that satisfies the operation on a resource that opted\n * in, so admitting is exactly the ADDITIVE rule (D-C3b): a unit grant widens reach for a principal\n * who would otherwise be denied, and the repository then confines them to those units.\n */\n private isAdmittedByUnitScopedGrant(executionContext: ExecutionContext<any>, resourceIdentifier: string): boolean {\n const stamp = executionContext.getOrganizationUnitNarrowingStamp(resourceIdentifier);\n return stamp?.decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED;\n }\n\n /**\n * Does this operation declare `APP_PUBLIC` — i.e. is it callable with no credential at all?\n *\n * Read from the OPERATION rather than inferred from the context, so the public carve-out above\n * cannot be satisfied by the caller's side of the request alone.\n */\n private operationDeclaresPublicAccess(operation: ResourceConfiguration_Operation<any, any, any>): boolean {\n const roles = (operation as { roles?: unknown }).roles;\n return Array.isArray(roles) && roles.includes(CORE_APP_ROLES.APP_PUBLIC);\n }\n\n public async authorizeInRepositoryAndService(id_or_ids : IdOrIdsOrFilterType, operation: ResourceConfiguration_Operation<any, any, any>, executionContext: ExecutionContext<any>): Promise<void> {\n const { resourceIdentifier, operationIdentifier, variantType, resourcePrimaryScope, roles: operationRoles } = operation;\n\n this.logDebug('Starting authorization check', {\n resourceIdentifier,\n operationIdentifier,\n variantType,\n resourcePrimaryScope,\n operationRoles,\n idOrIds: id_or_ids,\n initiatorIds: executionContext.initiatorIds,\n initiatorRoles: executionContext.initiatorRoles?.map(r => ({ roles: r.roles, scope: r.relatedPrimaryScope }))\n });\n\n // Webhook callbacks are trusted after signature verification — scope filtering via\n // repository is enough, no role-based authorization needed.\n if (executionContext.isWebhookExecution()) {\n this.logDebug('Webhook execution — skipping role-based authorization (scope filtering is applied by repository)');\n return;\n }\n\n /*\n * A PUBLIC operation reached by a PUBLIC caller has no principal to authorize, and that is the\n * declaration rather than a gap.\n *\n * `createForPublicOperation` sets `initiatorIds: null` deliberately — a caller who presented no\n * credential has no identity — so the guard immediately below denies every ADDRESSED public\n * operation with MISSING_INITIATOR. Collection operations never hit it (`authorizeCollectionOperation`\n * is a different path with no pre-fetch), which is why `APP_PUBLIC` looked complete: LIST answered\n * 200 while READ on the same resource, with the same declared role, answered 403.\n *\n * This is the same trade the webhook carve-out above makes, for the same reason: there is no\n * principal whose roles could be checked, the operation itself declares who may call it, and the\n * repository's contextual filter still runs underneath. It is NOT a widening — an operation that\n * does not declare `APP_PUBLIC` cannot reach here, because `ExecutionContextCreator` only mints a\n * public context for an operation that does.\n *\n * BOTH conditions are required on purpose. Keying on the context alone would let any future\n * public-context path reach a non-public operation; keying on the operation alone would admit a\n * credentialed-but-unauthorized caller to a public operation's addressed form without their roles\n * being examined. Together they say exactly one thing: nobody claimed an identity, and none was\n * required.\n */\n if (executionContext.isPublicExecution() && this.operationDeclaresPublicAccess(operation)) {\n this.logDebug('Public execution of a publicly-declared operation — no principal to authorize; '\n + 'the repository contextual filter still applies');\n return;\n }\n\n // Ensure we have initiator information for authorization\n if (!executionContext.initiatorIds || !executionContext.initiatorRoles) {\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.MISSING_INITIATOR, operation, executionContext,\n );\n throw this.errorBuilder.buildError( ErrorType.AUTHORIZATION, executionContext,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_MISSING_INITIATOR,\n context: { initiatorIds: executionContext.initiatorIds, initiatorRoles: executionContext.initiatorRoles} } );\n }\n\n // WS-C: evaluate the unit-narrowing decision and STAMP it HERE — before the authorization\n // pre-fetch below, not just before the role gate.\n //\n // ## Why this position is load-bearing (it was three phases later, and that broke every\n // ## id-addressed operation on a narrowed resource)\n //\n // The pre-fetch a few lines down reads the target row through `doByPath(READ, …)`, which applies\n // `buildContextualFilter` — and that filter fails CLOSED on a narrowable resource carrying no\n // stamp, because \"no decision\" must never be read as \"no restriction\". With the stamp written\n // later, the authorizer's own read was the unstamped request: it matched nothing, the count check\n // threw NOT_FOUND, and the stamping line was never reached. Effect: for EVERY caller including an\n // organization-wide admin, a narrowed resource answered 404 on READ / UPDATE / DELETE by id and\n // was reachable only through the collection verbs — which pass through\n // `authorizeCollectionOperation`, a path with no pre-fetch, and therefore looked healthy.\n //\n // Nothing here depends on the row: the decision is a question about the CALLER (their unit role\n // grants) and the OPERATION (its declared roles). `initiatorRoles` is asserted present directly\n // above, so every input is already in hand.\n //\n // Stamping first is also strictly better than merely correct. It makes the pre-fetch ITSELF\n // narrowed, so a caller naming a row in a unit they do not hold cannot even load it for the\n // authorization phases that follow — the cross-unit refusal happens at the read rather than\n // depending on a later check to notice.\n //\n // Placed before the id extraction so the `FilterQuery` early-return below is covered too. That\n // path deliberately skips the rest of authorization, and letting it skip the stamp as well would\n // leave the repository to fail closed on a request the gate had decided not to examine.\n const narrowingStamp = await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n\n // A DENIED narrowing decision is a statement about the CALLER, so it must surface as one.\n //\n // Stamping before the pre-fetch (above) is what makes the id-addressed path work at all, but it\n // has a consequence that has to be handled HERE rather than left to fall out: a DENIED decision\n // stamps DENY_ALL, the pre-fetch below then reads through a match-nothing predicate, resolves no\n // row, and the count check answers **404 NOT_FOUND**. The caller lacks the role, and we would be\n // telling them the record does not exist.\n //\n // That is wrong in three ways, none of them a leak: a narrowed resource would answer a role denial\n // differently from every other resource in the application; an operator debugging a\n // misconfiguration would hunt for a missing row that is sitting right there; and the module's own\n // contract calls `DECISION_DENIED` a belt-and-braces case that \"would already have thrown\",\n // which stopped being true the moment the stamp preceded the fetch.\n //\n // Running the role gate NOW rather than inventing an error here is deliberate — it is the same\n // gate, the same `AUTHORIZATIONS_ACCESS_DENIED`, and the same `INSUFFICIENT_ROLES` audit reason\n // the caller would have received a few phases later. And it provably refuses: `DENIED` is returned\n // only when no organization-wide grant satisfies the operation (the identical hierarchy\n // computation `validateOperationRoles` performs) AND no unit grant does either (so the\n // `isAdmittedByUnitScopedGrant` rescue cannot fire). No later phase can add authority that the\n // decision did not already consider, so this changes WHICH error surfaces and when — never\n // WHETHER the caller is admitted, and never what data they can reach.\n //\n // The confined-caller case is untouched and still answers 404: a caller who HOLDS a grant but\n // names a row in another unit is `CONFINED_TO_UNITS`, not `DENIED`, so it falls through to the\n // pre-fetch and is deliberately indistinguishable from a row that does not exist (D-1) — that\n // one is about REACH, and must not become an existence oracle.\n // (The refusal itself is raised just below, AFTER the ids are extracted — see there for why.)\n\n // Extract actual IDs from IdOrIdsOrFilterType for processing\n let idsArray: string[] = [];\n\n if (typeof id_or_ids === 'string') {\n idsArray = [id_or_ids];\n } else if (Array.isArray(id_or_ids)) {\n idsArray = id_or_ids;\n } else if (typeof id_or_ids === 'object' && id_or_ids && 'id_or_ids' in id_or_ids) {\n // Extract IDs from combined object\n const { id_or_ids: ids } = id_or_ids;\n if (typeof ids === 'string') {\n idsArray = [ids];\n } else if (Array.isArray(ids)) {\n idsArray = ids;\n }\n } else if (typeof id_or_ids === 'object' && id_or_ids) {\n // For FilterQuery objects, we can't extract specific IDs - skip authorization or use context\n this.logDebug('Authorization called with FilterQuery - unable to extract specific IDs for authorization');\n return; // Skip authorization for filter-based operations\n }\n\n // Raise the DENIED refusal HERE — after the ids are known, and still before the pre-fetch below.\n //\n // The position is a compromise between two constraints that pull opposite ways. It must precede\n // the pre-fetch, or the DENY_ALL stamp turns a role denial into a 404 (the whole point). But an\n // earlier revision raised it before the id extraction and therefore reported the denial with an\n // EMPTY attempted-id list — so `RESOURCE_OPERATION_DENIED` on a narrowed resource recorded no\n // attempted id, while the identical denial on every other resource (raised by the later phase\n // with `idsArray`) recorded one. An access-decision record that silently loses its subject on\n // exactly the resources an application opted in to CONFINE is the wrong half to degrade.\n //\n // The `FilterQuery` early-return above is deliberately NOT covered: that path skips authorization\n // by design and has no ids to report, and the stamp it carries still makes the repository fail\n // closed.\n if (narrowingStamp.decision.kind === OrganizationUnitNarrowingDecisionKind.DENIED) {\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext, idsArray,\n );\n }\n\n // Get repository for the resource to fetch data\n const repository = this.repositoriesRegistry.getRepositoryOrThrow(resourceIdentifier, executionContext);\n\n // Fetch the related elements using the repository\n let resourceObjects: any[] = [];\n\n const operationRepositoryPath: ResourceConfiguration_OperationRepositoryPath = { resourceIdentifier, operationIdentifier: CoreResourceOperation.READ };\n // A cross-tenant-admitted operation (a per-VARIANT opt-in, e.g. `organizations.restore` /\n // `activate` — the RECUPERATIVE platform-operator doors) must read its target UNSCOPED here.\n //\n // ## Why the scoped pre-fetch is wrong for exactly these operations\n //\n // The pre-fetch below reads through `buildContextualFilter`, which scopes to the CALLER's tenant.\n // But these operations run on tenants the caller is deliberately NOT scoped into: a marked tenant\n // confers no authority to its own admins (recovery is out-of-tenant by design — see\n // `.claude/rules/administrative-continuity-floors.md`), so a platform super-administrator restoring\n // it holds no organization-scope entry for it and the scoped read resolves NOTHING → the count\n // check answers 404. The result: `restore` / `activate` — the doors whose entire purpose is to act\n // on a no-authority-status tenant — are structurally unreachable through this path.\n //\n // Reading UNSCOPED here makes this pre-fetch consistent with the crossing that `authorizeOrganizations`\n // already ADMITS at its gate for the same variant, and it mirrors the WRITE side exactly:\n // `assertOrganizationUnitBelongsToCallerTenant` reads `excludeContextualFilter: true` and then makes\n // the tenant decision explicitly. Safe because (a) it is gated on the per-variant opt-in, not global;\n // (b) the row is used ONLY for the authorization decision, never disclosed to the caller; and (c) the\n // operation's role gate (`validateOperationRoles` → APP_ADMIN_SUPER_ADMIN) still runs below and denies\n // any non-operator, so a non-super-admin never reaches the operation regardless of what was read. The\n // crossing itself is audited by `authorizeOrganizations` (`CROSS_TENANT_ADMINISTRATIVE_ACCESS`).\n // Read the flag from BOTH the resolved `operation` param AND `executionContext.operation`. The\n // per-variant opt-in is flattened onto `executionContext.operation` (which is why the sibling\n // predicate `admitsCrossTenantPlatformAdministration()` reads it there, and why the crossing is\n // admitted at `authorizeOrganizations`); the `operation` param can still be the pre-variant\n // object on some dispatch paths. Checking both makes the unscoping consistent with the gate that\n // will admit the crossing a few lines below, regardless of which object carried the variant.\n const crossTenantAdmitted =\n (operation as { admitsCrossTenantPlatformAdministration?: boolean }).admitsCrossTenantPlatformAdministration === true\n || (executionContext.operation as { admitsCrossTenantPlatformAdministration?: boolean } | undefined)\n ?.admitsCrossTenantPlatformAdministration === true;\n try {\n // Use repository read operation to get objects\n\n const obj_s = await repository.doByPath(\n operationRepositoryPath,\n executionContext,\n (idsArray.length === 1) ? idsArray[0] : idsArray,\n undefined,\n crossTenantAdmitted ? { excludeContextualFilter: true } : undefined,\n );\n resourceObjects = (idsArray.length === 1)? [obj_s] : obj_s;\n\n } catch (error) {\n const authError = this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: {\n message: `Failed to fetch resource objects for authorization: ${describeCaughtError(error)}`,\n /**\n * The inner error's own CONTEXT, which this wrapper used to discard.\n *\n * `describeCaughtError` on a `WildoBackendError` yields its message REFERENCE and nothing\n * else, so a structural failure that carefully recorded which operation key was missing\n * arrived here as the bare string `repository_resource_operation_failed`. Every\n * investigation then had to re-run with a temporary log to learn a fact the error already\n * knew — the second time in one session that a swallowed cause cost a debugging cycle.\n *\n * Only the context is lifted, not the whole error: the OUTER shape stays a 404 with no\n * detail for the client (`sanitizeErrorForClient` strips `context`), so this is\n * diagnosability for the log, not disclosure to the caller.\n */\n cause: isWildoBackendError(error) ? error.context : undefined,\n }\n }\n );\n throw authError;\n }\n\n // 🔒 SECURITY / fail-closed: a resource-specific repository READ resolves to\n // `null` when the target row does not exist OR is invisible to the caller's\n // scope. The READ applies a contextual scope/ownership filter, so a\n // cross-scope id (e.g. another organization's todo) also comes back as `null`\n // rather than throwing — the try/catch above never fires for that case. Drop\n // every `null`/`undefined` entry BEFORE the count check so a missing /\n // scope-invisible target fails closed with a clean NOT_FOUND (404), which also\n // avoids leaking the existence of out-of-scope resources.\n //\n // Without this filter the single-id path produced `[null]` (array length 1),\n // which silently passed the length-based count check below\n // (`1 === idsArray.length`) and flowed into performPrimaryScopeAuthorization(),\n // where each per-scope authorizer dereferences `resourceObject.<scopeField>`\n // (e.g. `resourceObject['organizationId']`). That threw a raw `TypeError`\n // (\"Cannot read properties of null\"), which the error pipeline classifies as\n // ErrorType.INTERNAL (CRITICAL) → `logger.fatal()` + HTTP 500 — destabilizing\n // the backend under client retry/poll instead of returning a 404. Filtering at\n // this single choke point fixes it for ALL primary scopes at once, rather than\n // adding a defensive null-check inside every authorize* method.\n resourceObjects = (Array.isArray(resourceObjects) ? resourceObjects : []).filter(\n (resourceObject) => resourceObject !== null && resourceObject !== undefined,\n );\n\n // Check that we found all expected resources\n if (resourceObjects.length !== idsArray.length) {\n // A REFUSAL, recorded as one — even though it surfaces to the caller as 404. This is the\n // cross-tenant probe path: the row is absent OR invisible to this caller, and the two are\n // deliberately indistinguishable in the response so it cannot be used as an existence oracle.\n // The audit row is where the refusal becomes visible to a reviewer; the HTTP response is\n // unchanged. See ResourceOperationDenialReason.SUBJECT_NOT_RESOLVABLE for why a single such\n // row proves nothing and the aggregate is the signal.\n // assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.SUBJECT_NOT_RESOLVABLE, operation, executionContext, idsArray,\n );\n const error = this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n }\n );\n throw error;\n }\n\n // Validate FK relationship access (e.g., /assigned-to-users/{userId}/todos/{todoId})\n // This ensures users can only access resources via FK paths they own\n await this.runAuthorizationPhase(\n () => this.validateFKRelationshipAccess(executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.FK_RELATIONSHIP_DENIED),\n operation, executionContext, idsArray,\n );\n\n // Perform authorization checks based on primary scope\n await this.runAuthorizationPhase(\n () => this.performPrimaryScopeAuthorization(resourceObjects, operation, executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.SCOPE_MISMATCH),\n operation, executionContext, idsArray,\n );\n\n // (The unit-narrowing decision was stamped at the TOP of this method — it must precede the\n // authorization pre-fetch, not merely the role gate below. See the comment there.)\n\n // Check that user has required roles to perform the operation\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext, idsArray,\n );\n\n this.logDebug('Authorization check completed successfully');\n }\n\n /**\n * Resolve the effective scope at runtime.\n * For isAnonymizable resources (primaryScope: USER_SELF), the effective scope\n * switches to ANONYMOUS when the caller is an anonymous session.\n */\n private resolveEffectiveScope(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): ResourcePrimaryScope {\n if (operation.resourcePrimaryScope === ResourcePrimaryScope.USER_SELF && executionContext.isAnonymousExecution()) {\n return ResourcePrimaryScope.ANONYMOUS;\n }\n return operation.resourcePrimaryScope;\n }\n\n /**\n * Perform authorization checks based on primary scope\n */\n private async performPrimaryScopeAuthorization(\n resourceObjects: any[],\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { resourceIdentifier } = operation;\n const { initiatorIds } = executionContext;\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n\n for (const resourceObject of resourceObjects) {\n switch (effectiveScope) {\n case ResourcePrimaryScope.USER_SELF:\n await this.authorizeUserSelf(resourceObject, resourceIdentifier, initiatorIds!, executionContext, operation);\n break;\n\n case ResourcePrimaryScope.ORGANIZATIONS:\n await this.authorizeOrganizations(resourceObject, resourceIdentifier, initiatorIds!, executionContext);\n break;\n\n case ResourcePrimaryScope.APPLICATION:\n await this.authorizeApplication(resourceObject, resourceIdentifier, initiatorIds!, executionContext);\n break;\n\n case ResourcePrimaryScope.ANONYMOUS:\n await this.authorizeAnonymous(resourceObject, executionContext);\n break;\n\n default:\n const error = this.errorBuilder.buildError(\n ErrorType.INTERNAL,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { message: `Unsupported primary scope: ${effectiveScope}` }\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize USER_SELF scope — the addressed row must belong to the caller, unless the operation\n * variant is explicitly admitted to administer another person.\n *\n * ## Why the admission exists\n *\n * `USERS` is a self-anchor scope root, so its `resourcePrimaryScope` IS `USER_SELF` and every\n * USERS operation lands here. Without an admission this check made the whole administrative\n * surface self-only: `assign_roles`, `revoke_roles`, `suspend_user`, `unsuspend_user`,\n * `force_password_reset`, the admin READ and the core UPDATE/DELETE all refused against another\n * user, contradicting both the resource specification and the admin UI that surfaces them as\n * per-row actions.\n *\n * ## Why it is per-VARIANT, and why that is not a technicality\n *\n * The two `users | read` variants need opposite answers: the DEFAULT is gated `APP_USER`, so\n * admitting it would let any authenticated user read any other user's row; the `admin` variant is\n * gated `APP_ADMIN_VIEWER` and is exactly the surface that should. A resource-level switch cannot\n * express that, and using one would have opened the wider hole while fixing the narrower one.\n *\n * The admission relaxes WHOSE row may be addressed, never WHO may call — the operation's `roles`\n * gate runs separately and unchanged. Mirrors {@link admitsCrossTenantPlatformAdministration}: an\n * explicit, enumerable, empty-by-default opt-in rather than a privilege-based bypass.\n */\n private async authorizeUserSelf(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>,\n operation?: { admitsCrossSubjectUserAdministration?: boolean; operationIdentifier?: unknown },\n ): Promise<void> {\n // Checked BEFORE either branch: the admission is a property of the OPERATION (\"this verb\n // administers another person\"), not of the shape of the row it happens to address, so it applies\n // equally to the user row itself and to a user-owned child resource.\n if (operation?.admitsCrossSubjectUserAdministration === true) {\n this.logDebug('Cross-subject user administration admitted', {\n operationIdentifier: String(operation.operationIdentifier),\n resourceIdentifier,\n });\n return;\n }\n\n if (resourceIdentifier === CoreResourceType.USERS || resourceIdentifier === CoreResourceType.USER_SELF) {\n // For user resources, check that the resource _id matches the initiator userId\n if (resourceObject._id !== initiatorIds.userId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n } else {\n // For other resources, check the related user field identifier\n const userFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.USERS];\n const userSelfFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.USER_SELF];\n\n const userIdFromResource = resourceObject[userFieldIdentifier] || resourceObject[userSelfFieldIdentifier];\n\n if (!userIdFromResource) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n\n if (userIdFromResource !== initiatorIds.userId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize ORGANIZATIONS scope\n */\n /**\n * Does this request carry a sanctioned platform-tier crossing of the tenant boundary?\n *\n * ## Why this is ONE method and not two checks\n *\n * Tenant isolation on an ORGANIZATIONS-scoped request is enforced at TWO independent gates that\n * run in different phases and read different inputs:\n *\n * - `validateParentScopeAccess` — does the caller hold an organization-WIDE role entry naming\n * this organization? (a ROLES question, asked before the row is fetched)\n * - `authorizeOrganizations` — does the fetched row actually belong to the caller's organization?\n * (a DATA question, asked after)\n *\n * A crossing has to be admitted at BOTH or it is admitted at neither, and the first version of\n * this feature (2026-08-05) opened only the first. One method, two call sites, so they cannot\n * drift.\n *\n * ## What this predicate does NOT buy you (measured over real HTTP, 2026-08-05)\n *\n * Per-instance org-scoped reach for a non-member platform super-administrator **already exists**\n * without any opt-in. `validateOperationRoles` deliberately skips ORGANIZATIONS-scope resources,\n * `validateParentScopeAccess` runs only on collection calls, and `authorizeOrganizations` compares\n * the fetched row's organization against a scope the SAME REQUEST supplied through its URL — so\n * the comparison is close to tautological on a resource route. What the flag genuinely adds is the\n * COLLECTION path (which does refuse today) plus an enumerable, audited declaration of intent.\n *\n * Do not read this predicate as the boundary. Whether a platform operator SHOULD be able to\n * administer any tenant is an open product decision; see\n * `.claude/rules/administrative-continuity-floors.md` and\n * `examples/wonder-todos/e2e/organization-ownership-grant-hostile.e2e.ts` probe F-1.\n *\n * Two conditions, both load-bearing: the OPERATION VARIANT must have opted in (never a blanket\n * super-admin bypass — that would dissolve tenant isolation for every operation a super-admin's\n * role chain satisfies), and the caller must hold `APP_ADMIN_SUPER_ADMIN` at APPLICATION scope\n * specifically.\n *\n * The APPLICATION-scope qualifier is DEFENCE IN DEPTH, not the first line, and the honest version\n * is worth stating: membership `roles` is a free-form string (`OrgRolesSchema` admits any string),\n * so a tenant admin CAN type `APP_ADMIN_SUPER_ADMIN` into their own row. What stops them today is\n * the independent operation-ROLES gate, which resolves an ORGANIZATIONS-scope entry against the\n * organization role table and finds no such key. Verified by mutation: deleting the qualifier\n * changes no current outcome. It stays because it is the only check that still holds if the two\n * role tables ever share a key, or if a future path reaches a gate without the roles gate running.\n *\n * assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — sanctioned, per-operation,\n * platform-tier crossing of a tenant boundary.\n */\n private async admitsCrossTenantPlatformAdministration(\n executionContext: ExecutionContext<any>,\n targetOrganizationId: string,\n ): Promise<boolean> {\n const operation = executionContext.operation as {\n admitsCrossTenantPlatformAdministration?: boolean;\n operationIdentifier?: unknown;\n } | undefined;\n if (operation?.admitsCrossTenantPlatformAdministration !== true) return false;\n\n const holdsPlatformAuthority = (executionContext.initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .filter(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.APPLICATION)\n .some(roleInfo => roleInfo.roles.some(\n heldRole => this.getRoleHierarchy(heldRole as Roles, ResourcePrimaryScope.APPLICATION)\n .includes(CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN),\n ));\n if (!holdsPlatformAuthority) return false;\n\n // ── The bootstrap exemption ────────────────────────────────────────────────────────────────\n // `requestAccess` is how an elevation comes into existence, so gating it on holding one would be\n // circular: an operator would need a grant in order to ask for a grant, and the mechanism could\n // never start. Narrow by construction — the verb writes one grant row in the target tenant and\n // touches nothing else, so the blast radius of an abused request is a notification, an audit row\n // naming the operator, and a decision the tenant can refuse.\n // `PlatformAccessGrants_Operations` deliberately lives in the grants VOCABULARY module, not its\n // resources-config module. Importing it from the config here pulled resource-configuration\n // evaluation into this file's module graph and broke decorator metadata elsewhere — see the note\n // on the enum. Do not \"tidy\" this import back to the config.\n if (String(operation.operationIdentifier ?? '') === PlatformAccessGrants_Operations.REQUEST_ACCESS) {\n return true;\n }\n\n // ── Zero standing privilege ───────────────────────────────────────────────────────────────\n // Holding `APP_ADMIN_SUPER_ADMIN` is no longer sufficient. Declaring the crossing per variant\n // removed AMBIENT authority; requiring a usable grant removes STANDING authority — the operator\n // must have asked for this tenant, been granted a window, and still be inside it. That is what\n // NIST SP 800-53 AC-2 / AC-6(1) and every zero-standing-privilege programme ask for, and what\n // Microsoft's JIT/JEA model implements internally.\n const usableGrant = await this.hasUsablePlatformAccessGrant(executionContext, targetOrganizationId);\n if (typeof usableGrant === 'string' && usableGrant) {\n // Stashed on the CONTEXT, not on the service: the authorizer is a singleton and a field here\n // would leak one request's grant onto another's audit row under concurrency.\n (executionContext as { authorizingPlatformAccessGrantId?: string }).authorizingPlatformAccessGrantId = usableGrant;\n }\n return Boolean(usableGrant);\n }\n\n /**\n * Is there a live elevation for this operator into this tenant?\n *\n * Read on a system context, because the caller is by definition not a member of the tenant whose\n * grants are being read — the resource's `systemAccessPolicy` allows exactly this and nothing else.\n *\n * **Fails CLOSED.** A read error, an unbound repository, a missing resource — every one answers\n * \"no elevation\". The alternative would let an operator restore standing access by breaking the\n * grant store, which is precisely the failure mode a fail-open control is criticised for.\n */\n /**\n * A system execution context for reading grants across tenant boundaries.\n *\n * Lazily resolved from the container, mirroring {@link resolveAuditLogsService}: this service is\n * constructed in contexts (unit suites, partial bindings) where the auth factory is not bound, and\n * a hard constructor dependency would make the authorizer unconstructible there. Returning\n * `undefined` fails the caller CLOSED, which is the correct direction for an admission check.\n */\n private async resolveSystemReadExecutionContext(): Promise<ExecutionContext<any> | undefined> {\n if (!this.container?.isBound?.(SAAS_SERVICE_TYPES.AuthExecutionContextFactory)) return undefined;\n const authEcFactory = this.container.get<AuthExecutionContextFactoryBackendService>(\n SAAS_SERVICE_TYPES.AuthExecutionContextFactory,\n );\n if (typeof authEcFactory?.createForSystemAuthOperation !== 'function') return undefined;\n return await authEcFactory.createForSystemAuthOperation(authEcFactory.getUsersReadOperationPath());\n }\n\n private async hasUsablePlatformAccessGrant(\n executionContext: ExecutionContext<any>,\n targetOrganizationId: string,\n ): Promise<string | boolean> {\n const operatorUserId = executionContext.initiatorIds?.userId;\n if (!operatorUserId || !targetOrganizationId) return false;\n // Returns the GRANT ID (truthy) rather than a bare `true` so the crossing event can name which\n // elevation authorised it. `true` remains possible only for a grant with no `_id`, which the\n // repository does not produce — the union keeps the caller's truthiness check honest either way.\n\n try {\n // `getRepository`, matching how the owner floor reaches its own collections. An earlier\n // revision called a method that does not exist and, because the call was optional-chained,\n // answered \"no grant\" for EVERY caller — a fail-closed bug that looks identical to correct\n // enforcement from the outside. If this ever refuses everything, check the accessor first.\n const repository = this.repositoriesRegistry?.getRepository?.(CoreResourceType.PLATFORM_ACCESS_GRANTS);\n if (!repository?.list) return false;\n\n // A SYSTEM context, not the caller's. The caller is by definition not a member of the tenant\n // whose grants are being read, so the repository's contextual filter would scope the query to\n // the OPERATOR's own organization and find nothing — the elevation would exist, be ACTIVE, and\n // never be seen. Caught by the e2e lane: the grant landed in the database and the crossing was\n // still refused. An earlier revision of this method documented the system context and then\n // passed `executionContext` anyway.\n const systemExecutionContext = await this.resolveSystemReadExecutionContext();\n if (!systemExecutionContext) return false;\n\n const grants = await repository.list<{ status: string; expiresAt: Date }>(systemExecutionContext, {\n organizationId: targetOrganizationId,\n operatorUserId,\n status: PlatformAccessGrantStatus.ACTIVE,\n } as never);\n\n // `isPlatformAccessGrantUsable` re-checks `expiresAt` rather than trusting the ACTIVE filter\n // above. The status is bookkeeping a sweeper maintains; the window is the control, and a grant\n // whose window elapsed must stop working whether or not anything has relabelled it yet.\n const now = new Date();\n const usable = (grants ?? []).find((grant) => isPlatformAccessGrantUsable(grant as never, now));\n return usable ? String((usable as { _id?: unknown })._id ?? '') || true : false;\n } catch {\n return false;\n }\n }\n\n /**\n * Does the caller hold an ORGANIZATION-WIDE role entry naming this exact organization?\n *\n * This is the \"is the caller actually in this tenant?\" question, and it is deliberately asked of\n * the caller's ROLE ENTRIES rather than of `initiatorIds`. On a resource route the URL segment\n * supplies `initiatorIds.organizationId`, so comparing a row against it compares the request with\n * itself. Role entries are the one input a request cannot author for itself.\n *\n * Organization-WIDE only. A unit-narrowed grant confers authority over a unit, not the tenant, and\n * every org-wide gate in this service filters it out — accepting one here would let a unit member\n * pass a tenant-level check.\n */\n private holdsOrganizationWideEntryFor(executionContext: ExecutionContext<any>, organizationId: string): boolean {\n return (executionContext.initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .some(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS\n && String(roleInfo.relatedResourceId ?? '') === organizationId);\n }\n\n /** The tenant a row belongs to: its own id for ORGANIZATIONS, its organization FK otherwise. */\n private resolveRowOrganizationId(resourceObject: any, resourceIdentifier: string): string {\n return resourceIdentifier === CoreResourceType.ORGANIZATIONS\n ? String(resourceObject?._id ?? '')\n : String(resourceObject?.[coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS]] ?? '');\n }\n\n /**\n * Emit {@link CoreAuditableEventType.CROSS_TENANT_ADMINISTRATIVE_ACCESS} when the caller holds no\n * organization-wide role entry for the row's tenant.\n *\n * ## Why membership is measured from role entries\n *\n * `authorizeOrganizations` compares the fetched row's organization against `initiatorIds`, and on\n * a resource route BOTH sides derive from the same request — the URL segment supplies the scope, so\n * the check is close to tautological and a non-member operator passes it in silence. Role entries\n * are the one input the request cannot author for itself, so they are what \"is this caller\n * actually in this tenant?\" has to be asked against.\n *\n * Only ORGANIZATION-WIDE entries count. A unit-narrowed grant confers authority over a unit, not\n * the tenant, and every org-wide gate filters it out — counting one here would classify a genuine\n * cross-tenant reach as ordinary membership and silence the event.\n *\n * Fire-and-forget by construction: no `await`, and the promise's rejection is swallowed. An\n * operator's request must not fail because the audit sink is down, and a fail-closed variant would\n * hand anyone a way to disable operator support by breaking the sink.\n *\n * assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION\n */\n private recordCrossTenantAdministrativeAccess(\n resourceObject: any,\n resourceIdentifier: string,\n executionContext: ExecutionContext<any>,\n ): void {\n const operation = executionContext.operation as {\n operationIdentifier?: unknown;\n variantType?: ResourceOperationVariantType;\n variantKey?: string;\n admitsCrossTenantPlatformAdministration?: boolean;\n } | undefined;\n if (!operation) return;\n\n const rowOrganizationId = this.resolveRowOrganizationId(resourceObject, resourceIdentifier);\n if (!rowOrganizationId) return;\n\n const initiatorRoles = executionContext.initiatorRoles ?? [];\n if (this.holdsOrganizationWideEntryFor(executionContext, rowOrganizationId)) return;\n\n const auditLogsService = this.resolveAuditLogsService();\n // Feature-DETECTED, not merely null-checked. Adding a `log*` method to `AuditLogsBackendService`\n // is a known way to break every partially-mocked test double in this repo: the property is\n // absent, so the CALL throws a TypeError synchronously — before any `.catch()` can make it\n // fire-and-forget. It is not a test-only concern either; a host binding an older audit service\n // takes the same throw. An observer must never be able to fail the request it observes.\n if (typeof auditLogsService?.logCrossTenantAdministrativeAccess !== 'function') return;\n\n try {\n void auditLogsService.logCrossTenantAdministrativeAccess({\n operatorUserId: executionContext.initiatorIds?.userId,\n targetOrganizationId: rowOrganizationId,\n resourceType: resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier ?? ''),\n variantType: operation.variantType as ResourceOperationVariantType,\n variantKey: operation.variantKey,\n targetResourceIds: resourceObject?._id ? [String(resourceObject._id)] : undefined,\n authorizingGrantId: (executionContext as { authorizingPlatformAccessGrantId?: string }).authorizingPlatformAccessGrantId,\n admissionDeclared: operation.admitsCrossTenantPlatformAdministration === true,\n initiatorRoles: initiatorRoles.flatMap(roleInfo => roleInfo.roles ?? []),\n executionType: executionContext.executionType,\n })?.catch?.(() => undefined);\n } catch {\n // Deliberately swallowed — see the feature-detection note above.\n }\n }\n\n /**\n * Refuse a per-instance tenant-boundary denial in a way that is INDISTINGUISHABLE from a row that\n * does not exist.\n *\n * ## Why 404 and not 403 (RFC 9110 §15.5.4, and an internal inconsistency)\n *\n * Every branch below is reached only AFTER the authorization pre-fetch resolved a row — so answering\n * 403 here while a missing row answers 404 turns the STATUS into an existence oracle: an admin of any\n * tenant can probe ids against another tenant and learn which are real, without ever reading one.\n * Leaked ids (URLs, exports, logs, a former employee's notes) then become a census.\n *\n * RFC 9110 §15.5.4 sanctions the fix explicitly — an origin server \"that wishes to 'hide' the current\n * existence of a forbidden target resource MAY instead respond with a status code of 404\". It is also\n * what OWASP's object-level-authorization guidance asks for, and what the well-known practitioner\n * example does: a private repository answers 404 to a non-member rather than confirming it exists.\n *\n * The internal argument is the stronger one. Confinement WITHIN a tenant (organization-unit\n * narrowing) already answers 404 for a row in another unit, because the row filter simply does not\n * match it. So before this change the TENANT boundary — the stronger of the two — disclosed more than\n * the unit boundary inside it. That is backwards, and no reading of the model justifies it.\n *\n * ## What is deliberately NOT folded into this\n *\n * A caller who is INSIDE the row's tenant and merely lacks the operation's role still gets **403**\n * from the role gate. That denial is about the CALLER, discloses nothing (the answer does not depend\n * on any row existing), and collapsing it into 404 would send an operator hunting for a record that\n * is sitting right there. The split this class maintains is: *about the caller* → 403; *about reach*\n * → 404, indistinguishable from absent.\n *\n * The refusal stays fully visible internally: `recordCrossTenantAdministrativeAccess` has already\n * emitted the operator-access audit event by the time this is called, and the `reason` below travels\n * to the logs. `sanitizeErrorForClient` strips `context` for `NOT_FOUND`, so none of it reaches the\n * prober — which is the whole point.\n */\n private buildTenantBoundaryNotFound(\n executionContext: ExecutionContext<any>,\n resourceIdentifier: string,\n reason: string,\n ) {\n return this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, {\n // Must match the missing-row refusal exactly (the `resourceObjects.length !== idsArray.length`\n // path): a different `customMessageReference` would restore the oracle one field lower down.\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { reason, resourceIdentifier },\n });\n }\n\n private async authorizeOrganizations(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n // ── The DATA half of the tenant boundary ────────────────────────────────────────────────────\n //\n // Order matters here and is easy to get wrong: OBSERVE, then ADMIT, then GATE.\n //\n // The observation must come first because a DECLARED crossing is still a platform operator\n // reaching into a customer's tenant, and that is exactly the access an operator-access trail\n // exists to show. An earlier arrangement admitted first and returned, so the sanctioned\n // crossings — the ones a reviewer most wants to see — were the only ones never recorded.\n const rowOrganizationId = this.resolveRowOrganizationId(resourceObject, resourceIdentifier);\n const callerIsInRowTenant = !rowOrganizationId\n || this.holdsOrganizationWideEntryFor(executionContext, rowOrganizationId);\n\n // The admission is RESOLVED first, then observed, then acted on. Order matters three ways and the\n // middle one is easy to lose:\n // - resolving first is what lets the observation name the authorizing grant (the predicate\n // stashes it on the context); observing first recorded every crossing with a blank grant id;\n // - observing before the early return is what keeps SANCTIONED crossings in the trail — they are\n // the ones a reviewer most wants to see, and an earlier arrangement returned before recording;\n // - gating last means an undeclared crossing is recorded AND refused, not silently dropped.\n const crossingIsAdmitted = await this.admitsCrossTenantPlatformAdministration(executionContext, rowOrganizationId);\n\n if (!callerIsInRowTenant) {\n this.recordCrossTenantAdministrativeAccess(resourceObject, resourceIdentifier, executionContext);\n }\n\n // A sanctioned platform-tier crossing is admitted here as well as at `validateParentScopeAccess`\n // — that gate runs only on COLLECTION calls, so admitting at one alone produces a door that works\n // for `list` and 403s for `read`, or the reverse.\n if (crossingIsAdmitted) {\n this.logDebug('Cross-tenant platform administration admitted (resource-object gate)', {\n resourceIdentifier,\n resourceId: String(resourceObject?._id ?? ''),\n });\n return;\n }\n\n // ── Deny-by-default: an undeclared crossing fails closed ─────────────────────────────────────\n //\n // Platform-operator reach into a tenant is an INTENDED capability here (see\n // `.claude/rules/administrative-continuity-floors.md`). What is not intended is reach acquired by\n // POSITION IN THE REQUEST PATH rather than by declaration — ambient authority, and in effect a\n // standing privilege held permanently by every platform administrator over every tenant.\n //\n // The comparisons below cannot see it: on a resource route the URL segment supplies\n // `initiatorIds.organizationId`, so they compare the request against itself and a non-member\n // passes silently. Asking the caller's ROLE ENTRIES is what closes that, and it mirrors what\n // `validateParentScopeAccess` already demands of COLLECTION calls — the asymmetry between the two\n // was the defect, not a design.\n //\n // An operator who needs a crossing gets it the way `grantOwnership` did: a variant declaring\n // `admitsCrossTenantPlatformAdministration`, reviewed, specified and audited. There is\n // deliberately NO runtime bypass — a header or config toggle would reintroduce the standing\n // privilege this removes, which is what NIST SP 800-53 AC-2 warns against.\n //\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — undeclared crossings fail closed.\n if (!callerIsInRowTenant) {\n // Answered as NOT-FOUND rather than FORBIDDEN. Hiding the `reason` (which this comment used to\n // describe on its own) is necessary but not sufficient: the STATUS discriminated existence just\n // as well. See `buildTenantBoundaryNotFound`.\n throw this.buildTenantBoundaryNotFound(\n executionContext, resourceIdentifier, 'cross_tenant_access_not_declared_by_operation_variant',\n );\n }\n\n if (resourceIdentifier === CoreResourceType.ORGANIZATIONS) {\n // For organization resources, check that the resource _id matches the initiator organizationId\n if (resourceObject._id !== initiatorIds.organizationId) {\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'organization_row_is_another_tenant');\n }\n } else {\n // For other resources, check the related organization field identifier\n const orgFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS];\n\n const orgIdFromResource = resourceObject[orgFieldIdentifier];\n\n if (!orgIdFromResource) {\n // A row with no tenant anchor is unattributable, so it is unreachable rather than forbidden —\n // and answering it identically keeps every refusal this method emits on one shape. A branch\n // left at 403 would restore the oracle for exactly the rows whose shape is already broken.\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'row_carries_no_tenant_anchor');\n }\n\n if (orgIdFromResource !== initiatorIds.organizationId) {\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'row_belongs_to_another_tenant');\n }\n }\n }\n\n /**\n * Authorize APPLICATION scope\n */\n private async authorizeApplication(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n if (resourceIdentifier === CoreResourceType.APPLICATION) {\n // For application resources, check that the resource _id matches the initiator applicationId\n if (resourceObject._id !== initiatorIds.applicationId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n } else {\n // For other resources, check the related application field identifier\n const appFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.APPLICATION];\n\n const appIdFromResource = resourceObject[appFieldIdentifier];\n\n if (!appIdFromResource) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n\n if (appIdFromResource !== initiatorIds.applicationId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize ANONYMOUS scope — ownership check via anonymousUserId.\n * For AnonymousUser resources, _id IS the anonymousUserId.\n * For isAnonymizable resources, the anonymousUserId field carries ownership.\n */\n private async authorizeAnonymous(\n resourceObject: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const anonymousUserId = executionContext.anonymousUserId;\n const resourceAnonymousId = resourceObject.anonymousUserId ?? resourceObject._id;\n\n if (resourceAnonymousId !== anonymousUserId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n });\n }\n }\n\n /**\n * Validate that the user has required roles to perform the operation\n */\n private async validateOperationRoles(\n operationRoles: string[],\n executionContext: ExecutionContext<any>,\n /**\n * The resource whose narrowing stamp may admit a unit-scoped caller. Optional because two callers\n * reach this gate for scopes where narrowing cannot apply; omitting it simply means no unit grant\n * can rescue a failing role check, which is the fail-closed direction.\n */\n narrowableResourceIdentifier?: string,\n ): Promise<void> {\n const { initiatorRoles } = executionContext;\n\n // ORGANIZATION-WIDE GRANTS ONLY in this computation. A unit-scoped entry (`organizationUnitId`\n // present) confers authority inside ONE organization unit, so it must not satisfy an operation\n // gate that asks an organization-wide question — otherwise \"ORG_MANAGER of Sales\" would pass every\n // ORG_MANAGER gate in the tenant, which is a privilege escalation rather than a narrowing.\n //\n // A unit grant can still ADMIT, but only through the separate, narrower door below: the stamped\n // narrowing decision, which exists only for resources that explicitly opted in (D-C1/D-C3) and\n // which the repository then uses to confine the rows. Keeping the two apart is the point — this\n // computation must never learn about units.\n const organizationWideRoleInfos = initiatorRoles!.filter(isOrganizationWideRoleInfo);\n\n // Check if user has any of the required roles (considering role hierarchy)\n const userRoles = organizationWideRoleInfos.flatMap(roleInfo => roleInfo.roles);\n\n const hasRequiredRole = operationRoles.some(requiredRole => {\n // Check if user has this role directly or inherits it through hierarchy\n return userRoles.some(userRole => {\n // Determine scope based on role context — resolved against the org-wide entries only, so a\n // unit-scoped duplicate of the same role string can never supply the scope here either.\n const roleInfo = organizationWideRoleInfos.find(r => r.roles.includes(userRole));\n if (!roleInfo) return false;\n\n const scope = roleInfo.relatedPrimaryScope;\n\n // Get the full hierarchy of the user's role\n const hierarchy = this.getRoleHierarchy(userRole, scope);\n\n // Check if the required role is in the hierarchy\n return hierarchy.includes(requiredRole);\n });\n });\n\n // WS-C ADDITIVE admission (D-C3b): no organization-wide grant satisfies the operation, but the\n // narrowing decision found a UNIT grant that does, on a resource that opted into narrowing. Admit\n // — the repository then confines this caller to exactly those units from the same stamped\n // decision. Reached only after the org-wide check has failed, so a unit grant can never widen what\n // an organization-wide grant already conferred; it only rescues a caller who would be denied.\n if (!hasRequiredRole && narrowableResourceIdentifier && this.isAdmittedByUnitScopedGrant(executionContext, narrowableResourceIdentifier)) {\n this.logDebug('Admitted by unit-scoped grant', { resourceIdentifier: narrowableResourceIdentifier, operationRoles });\n return;\n }\n\n if (!hasRequiredRole) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n\n /**\n * Lazy getter for {@link AuditLogsBackendService} — see the `container` constructor param's JSDoc\n * for why this cannot be a constructor injection.\n */\n private resolveAuditLogsService(): AuditLogsBackendService | undefined {\n if (!this.container?.isBound(SAAS_SERVICE_TYPES.AuditLogsService)) return undefined;\n return this.container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n }\n\n /**\n * Record a refusal as a `RESOURCE_OPERATION_DENIED` audit event.\n *\n * ## Why this lives at the funnel rather than at the ~30 throw sites\n *\n * Every public entry point of THIS class converges on the same two phase runners:\n * `authorizeInController` reaches them directly, `authorizeInProgrammaticSurface` shares\n * `authorizeCollectionOperation` with it, and `authorizeInRepositoryAndService` has exactly one\n * caller — `authorizeInController` itself. Instrumenting the two inner phase runners therefore\n * observes every refusal THIS AUTHORIZER MAKES, INCLUDING refusals added later by other work: a\n * new gate that throws inside these methods is audited the day it lands, with no author having to\n * remember this mechanism exists. Instrumenting individual throw sites would have made every\n * future gate a silent omission waiting to happen — the exact failure mode that left 19 event\n * types declared and emitted by nothing.\n *\n * ## What this does NOT claim — corrected 2026-08-27\n *\n * An earlier revision said `authorizeInController` \"is the sole production entry point for every\n * execution surface\". That is false, and it was load-bearing prose: it reads as a guarantee that\n * every execution surface passes the role gate, which is exactly the belief the service tier\n * disproves. A programmatic operation (`ServicesRegistryHandlerBackendService.read` / `list` /\n * `create` / …) enters at the SERVICE tier and reaches no authorizer at all — by design, see\n * {@link authorizeInProgrammaticSurface}. So the correct reading is narrower and still sufficient\n * for this mechanism's purpose: **within this class**, no refusal escapes the funnel. It says\n * nothing about surfaces that never ask.\n *\n * ## Never affects the outcome\n *\n * Every path here is swallowed. The caller has already been correctly refused; an audit-store\n * problem must not convert that clean refusal into a 500. Detection of a lost row is the audit\n * pipeline's own control (`audit_store_failure_total`), not this gate's.\n *\n * assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT — the negative access decision is\n * recorded, attributable, and carries the authority context needed to review it.\n */\n private async emitAuthorizationDenialAudit(\n denialReason: ResourceOperationDenialReason,\n operation: ResourceConfiguration_Operation<any, any, any> | undefined,\n executionContext: ExecutionContext<any>,\n attemptedResourceIds?: string[],\n ): Promise<void> {\n const auditLogsService = this.resolveAuditLogsService();\n if (!auditLogsService || !operation) return;\n\n // Defence-in-depth against an emission loop. Structurally unreachable today — the audit write\n // runs as a REPOSITORY_ONLY super-admin context and repository writes do not route through this\n // authorizer — but a refusal that tried to audit itself would recurse without bound, and this\n // subsystem already carries a documented recursion hazard of exactly that shape (a per-org SIEM\n // dispatch's own config load is a system read that re-enters the audit path). Stateless and\n // concurrency-safe, unlike an in-flight instance flag.\n if (operation.resourceIdentifier === CoreResourceType.AUDIT_LOGS) return;\n\n try {\n const principalUserId = executionContext.initiatorIds?.userId;\n\n const decision = await resolveDenialAuditEmissionDecision(\n { redisService: this.redisService, logger: this.logger },\n {\n principalUserId,\n organizationId: executionContext.initiatorIds?.organizationId,\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n denialReason,\n },\n );\n\n if (!decision.shouldEmit) return;\n\n await auditLogsService.logResourceOperationDenied({\n riskLevel: operation.riskLevel ?? ResourceOperationRiskLevel.LOW,\n actorUserId: principalUserId,\n organizationId: executionContext.initiatorIds?.organizationId,\n applicationId: executionContext.initiatorIds?.applicationId,\n\n denialReason,\n\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantType: operation.variantType,\n variantKey: operation.variantKey,\n resourceOperationLike: operation.resourceOperationLike,\n // `isBulkOperation` is NOT on every member of the operation-variant union (a cron-job\n // variant has no bulk notion), so it must be narrowed before reading — the union-read trap\n // `audit-operation-variants` exists to catch. `in` is the pattern the resource-config\n // factory already uses for this exact field.\n isBulkOperation: 'isBulkOperation' in operation ? operation.isBulkOperation : undefined,\n\n attemptedResourceIds: attemptedResourceIds?.length ? attemptedResourceIds : undefined,\n\n requiredRoles: operation.roles?.length ? operation.roles.map(String) : undefined,\n // Roles AS THEY WERE at decision time. Empty (not absent) when the refusal WAS their\n // absence — `initiatorRoles` is null on the MISSING_INITIATOR path by definition.\n initiatorRoles: (executionContext.initiatorRoles ?? []).flatMap(r => r.roles.map(String)),\n executionType: executionContext.executionType,\n machineCredentialAuthMethod: executionContext.initiatorIds?.machineCredential?.authMethod,\n machineCredentialId: executionContext.initiatorIds?.machineCredential?.credentialId,\n\n subCallDepth: executionContext.subCallDepth,\n\n occurrenceCount: decision.occurrenceCount,\n occurrenceCountIsExact: decision.occurrenceCountIsExact,\n }, executionContext);\n } catch (error) {\n this.logger.warn('Failed to emit the authorization-denial audit event', {\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n denialReason,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n\n /**\n * Run one authorization phase, recording a refusal if it throws.\n *\n * Re-throws unchanged: the audit trail is a side effect of the refusal, never a modifier of it.\n * `reasonFor` maps the caught error to a denial reason, so a phase that can fail two ways (the\n * resource-specific runner refuses on both scope and roles) still records which one occurred.\n */\n private async runAuthorizationPhase(\n phase: () => Promise<void>,\n reasonFor: (error: unknown) => ResourceOperationDenialReason | undefined,\n operation: ResourceConfiguration_Operation<any, any, any> | undefined,\n executionContext: ExecutionContext<any>,\n attemptedResourceIds?: string[],\n ): Promise<void> {\n try {\n await phase();\n } catch (error) {\n const denialReason = reasonFor(error);\n if (denialReason) {\n await this.emitAuthorizationDenialAudit(denialReason, operation, executionContext, attemptedResourceIds);\n }\n throw error;\n }\n }\n\n /**\n * Authorize a controller operation\n *\n * @param id_or_ids - Resource ID(s) for resource-specific operations, or undefined for collection operations\n * @param executionContext - The execution context containing operation and initiator info\n *\n * For collection operations (LIST, CREATE, SEARCH, COUNT):\n * - id_or_ids is undefined\n * - Authorization is based on roles and parent scope (via initiatorIds)\n *\n * For resource-specific operations (READ, UPDATE, DELETE):\n * - id_or_ids must be a valid string or array\n * - Authorization additionally verifies access to the specific resource(s)\n */\n public async authorizeInController(id_or_ids: string | string[] | undefined, executionContext: ExecutionContext<any>): Promise<void> {\n // Extract operation from execution context\n const operation = executionContext.operation;\n\n if (!operation) {\n const error = this.errorBuilder.buildError(\n ErrorType.INTERNAL,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_NO_OPERATION_CONTEXT,\n context: { message: 'No operation found in execution context for controller authorization' }\n }\n );\n throw error;\n }\n\n const isCollectionOperation = (id_or_ids === undefined);\n\n this.logDebug('Starting controller authorization check', {\n resourceIdentifier: operation.resourceIdentifier,\n operationIdentifier: operation.operationIdentifier,\n variantType: operation.variantType,\n resourcePrimaryScope: operation.resourcePrimaryScope,\n operationRoles: operation.roles,\n idOrIds: id_or_ids,\n isCollectionOperation,\n initiatorIds: executionContext.initiatorIds,\n initiatorRoles: executionContext.initiatorRoles?.map(r => ({ roles: r.roles, scope: r.relatedPrimaryScope }))\n });\n\n if (isCollectionOperation) {\n // For collection operations: validate roles and parent scope only\n await this.authorizeCollectionOperation(operation as ResourceConfiguration_Operation<any, any, any>, executionContext);\n } else {\n // For resource-specific operations: full authorization with resource access check\n await this.authorizeInRepositoryAndService(id_or_ids, operation as ResourceConfiguration_Operation<any, any, any>, executionContext);\n }\n\n this.logDebug('Controller authorization check completed successfully');\n }\n\n /**\n * Authorize a NON-CONTROLLER surface that will itself perform row-scoped reads.\n *\n * The ROW-INDEPENDENT half of an authorization decision — FK-path access, parent-scope access and\n * the operation's ROLE gate, evaluated for a (caller, resource type, operation) triple with no row\n * in hand. Delegates to the same {@link authorizeCollectionOperation} the controller tier uses for\n * LIST / SEARCH / COUNT / CREATE, so there is exactly ONE implementation of this predicate.\n *\n * ═══════════════════════════════════════════════════════════════════════════════════════════════\n * ## THE LAYERING DECISION THIS METHOD EXISTS INSIDE — settled 2026-08-27\n * ═══════════════════════════════════════════════════════════════════════════════════════════════\n *\n * **The role ACL is a CONTROLLER-tier gate, and that is deliberate — not an oversight.** The\n * service tier (`ServicesRegistryHandlerBackendService.read` / `list` / `create` / …) applies the\n * repositories' contextual filter and the retention row-hide, and applies NO role check. That was\n * measured rather than assumed, and the measurement is what settles it: of the ~97 service-tier\n * read call sites in the engine, the dominant population is authentication (registration, OAuth /\n * SAML identity-link resolution, credential lookup, token issuance), SCIM provisioning, billing\n * webhook routing, invitation sweeps and feature resolution. **Those run BEFORE a role-bearing\n * principal exists**, or on an internal context that has no business asserting one. Enforcing the\n * operation's declared roles there would deny the reads that ESTABLISH identity — it would break\n * logging in.\n *\n * So the tiers carry different invariants, and both are unconditional at their own tier:\n *\n * | tier | invariant it enforces | enforced by |\n * |---|---|---|\n * | repository | TENANCY + retention visibility — fail-closed, no opt-out | `buildContextualFilter` |\n * | service | the operation PIPELINE (Zod, hooks, custom impl) | `doOperation` |\n * | controller | the caller's ROLES may perform this operation | `authorizeInController` |\n *\n * The service tier is INSIDE the trust boundary: it is reached only by code the framework itself\n * wrote, with a context that code chose. The controller tier is the boundary, because that is where\n * an untrusted principal names an operation.\n *\n * ## When a programmatic surface must nevertheless ask — and why per-hit is the wrong shape\n *\n * The decision above holds while a programmatic read serves the FRAMEWORK. It stops holding the\n * moment a service-tier surface becomes an EXTERNAL read surface: one that takes a caller-supplied\n * query and returns row CONTENT to that caller on their own authority. RAG retrieval\n * (`RagRetrievalBackendService`) is the first, and it is what this method was built for.\n *\n * Such a surface must ask the role question, and it should ask it **once per resource type, before\n * it goes looking** — not once per candidate row. Three reasons, and the first is the one that\n * makes the other two follow:\n *\n * 1. **The role gate is row-INDEPENDENT.** {@link validateOperationRoles} is a function of the\n * caller's grants and the operation's declared roles. Asking it per row asks the same question\n * N times and can only ever get the same answer.\n * 2. **A pre-search refusal has no side channel.** Refusing the type before the search means its\n * rows never enter the candidate pool, so result counts and ranks carry no information about\n * them. A per-row refusal AFTER a search under-fills the caller's `limit`, which is the exact\n * existence side channel a fail-closed pre-filter exists to close.\n * 3. **It costs no rows and no audit storm.** {@link authorizeInRepositoryAndService} pre-FETCHES\n * its target to authorize it, so a per-hit gate would double every hit's I/O; and a refusal\n * emits `RESOURCE_OPERATION_DENIED`, so a query over a partly-invisible corpus would record one\n * denial per dropped row. This path has no pre-fetch and refuses once.\n *\n * ## What it deliberately does NOT do\n *\n * It does not authorize a specific ROW. Nothing here looks at data, so a caller admitted by this\n * gate has been admitted to the resource TYPE only; every row they then reach must still be reached\n * through a read that carries the contextual filter. It is a NECESSARY condition, never a\n * sufficient one — a surface that used it INSTEAD of an authorized read would have replaced a row\n * check with a type check.\n *\n * Nor is it a general licence to re-plumb role enforcement into the service tier. The population in\n * the table above is why that would break authentication; this door is for surfaces that face an\n * external caller, and adding one is a decision to be argued at the surface, not a default.\n *\n * @param operation - The operation whose declared roles gate the resource type. For a read surface\n * this is the target resource's own READ operation.\n * @param executionContext - The caller's authority. Pass a `createForSubCall` context built for\n * `operation`'s resource, never the caller's raw context: the parent-scope and\n * FK phases read `relationshipContexts`, which on a raw context belong to a\n * DIFFERENT resource and would be validated against the wrong resource's keys.\n *\n * assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a non-controller surface that faces an external\n * caller applies the same operation-role gate the controller tier applies, through the same\n * predicate, and its refusal is recorded by the same funnel.\n */\n public async authorizeInProgrammaticSurface(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<void> {\n this.logDebug('Starting programmatic-surface authorization check', {\n resourceIdentifier: operation.resourceIdentifier,\n operationIdentifier: operation.operationIdentifier,\n operationRoles: operation.roles,\n subCallDepth: executionContext.subCallDepth,\n });\n\n await this.authorizeCollectionOperation(operation, executionContext);\n }\n\n /**\n * Authorize a collection operation (LIST, CREATE, SEARCH, COUNT)\n *\n * For collection operations, we don't have specific resource IDs to check.\n * Authorization is based on:\n * 1. Role validation - user must have required roles for the operation\n * 2. Parent scope validation - user must have access to the parent scope (e.g., organization)\n * This is validated through initiatorIds matching the context resource IDs\n * 3. FK relationship validation - if accessed via FK path, validate initiator matches\n */\n private async authorizeCollectionOperation(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { operationIdentifier, roles: operationRoles } = operation;\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n const { initiatorIds, initiatorRoles } = executionContext;\n\n this.logDebug('Authorizing collection operation', {\n operationIdentifier,\n effectiveScope,\n operationRoles,\n initiatorIds,\n relationshipContexts: executionContext.relationshipContexts\n });\n\n // Ensure we have initiator information for authorization\n if (!initiatorIds || !initiatorRoles) {\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.MISSING_INITIATOR, operation, executionContext,\n );\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_MISSING_INITIATOR,\n context: { initiatorIds, initiatorRoles }\n });\n }\n\n // Validate FK relationship access (e.g., /assigned-to-users/{userId}/todos)\n // This ensures users can only access resources via FK paths they own\n await this.runAuthorizationPhase(\n () => this.validateFKRelationshipAccess(executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.FK_RELATIONSHIP_DENIED),\n operation, executionContext,\n );\n\n // WS-C: stamp the narrowing decision before EITHER role gate below. Collection operations are the\n // half that matters most — LIST/SEARCH/COUNT on an opted-in resource is exactly what a unit-scoped\n // principal is meant to reach — and for ORGANIZATIONS scope the role check lives inside\n // `validateParentScopeAccess`, not in `validateOperationRoles`. Stamping here covers both.\n await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n\n // Validate parent scope access through initiatorIds\n // For ORGANIZATIONS scope, this also validates roles in the specific organization\n await this.runAuthorizationPhase(\n () => this.validateParentScopeAccess(operation, executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.PARENT_SCOPE_DENIED),\n operation, executionContext,\n );\n\n // For non-ORGANIZATIONS scopes, validate roles separately\n // (ORGANIZATIONS role validation is done in validateParentScopeAccess to ensure scope-specific checking).\n // Scope-required reference search re-anchors to anchor-scope MEMBERSHIP inside\n // validateParentScopeAccess and intentionally does NOT require the target's own\n // (global/admin) operation roles — skip the separate role check for it too, or\n // a member would be 403'd on `/organizations/{org}/users/search`.\n const isJunctionScopedSearch = executionContext.relationshipContexts?.some(rc => rc.scopeViaJunction);\n if (effectiveScope !== ResourcePrimaryScope.ORGANIZATIONS && !isJunctionScopedSearch) {\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext,\n );\n }\n\n this.logDebug('Collection operation authorization completed successfully');\n }\n\n /**\n * Validate FK relationship access for URL paths like /assigned-to-users/{userId}/todos\n *\n * 🔒 SECURITY: When accessing resources via a FK relationship path, verify the initiator\n * is authorized to use that path. For example:\n * - /assigned-to-users/{userId}/todos → verify userId matches the current user\n * - /created-by-users/{userId}/documents → verify userId matches the current user\n *\n * This prevents users from accessing resources assigned to or created by other users\n * by manipulating the URL path.\n *\n * Authorization behavior by execution type:\n * - USER_REQUEST: Must match the authenticated user's ID\n * - API_KEY: Allowed - API keys have broader access within their scope\n * - INTERNAL: Allowed - internal operations bypass FK validation\n * - PUBLIC: Allowed - public operations don't have identity context\n */\n private async validateFKRelationshipAccess(\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { relationshipContexts, initiatorIds, executionType } = executionContext;\n\n // No FK relationships in the path - nothing to validate\n if (!relationshipContexts || relationshipContexts.length === 0) {\n return;\n }\n\n // Skip FK validation for API keys, internal operations, public operations, webhook callbacks,\n // and anonymous sessions. Anonymous sessions use their own URL pattern\n // (/anonymous-users/{anonymousUserId}/...) and don't traverse user FK paths.\n if (executionContext.isMachineExecution() ||\n executionContext.isInternalExecution() ||\n executionContext.isPublicExecution() ||\n executionContext.isWebhookExecution() ||\n executionContext.isAnonymousExecution()) {\n this.logDebug('Skipping FK relationship validation for non-user execution', {\n executionType,\n reason: 'Machine principals (API keys + client-credentials), internal, public, webhook, and anonymous operations bypass FK user matching'\n });\n return;\n }\n\n this.logDebug('Validating FK relationship access', {\n relationshipContexts,\n initiatorIds,\n executionType\n });\n\n for (const relationshipContext of relationshipContexts) {\n const { resourceType, relationshipField, resourceId } = relationshipContext;\n\n // Only validate FK relationships (those with a relationshipField defined)\n // Standard parent relationships (undefined relationshipField) are handled by validateParentScopeAccess\n if (!relationshipField) {\n continue;\n }\n\n // Validate based on the target resource type\n if (resourceType === CoreResourceType.USERS || resourceType === CoreResourceType.USER_SELF) {\n // User FK paths require the authenticated user to match the URL userId\n // Only USER_REQUEST type has userId in initiatorIds\n if (executionType !== ExecutionContext_ExecutionType.USER_REQUEST) {\n // Consumable tokens cannot access user FK paths\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n relationshipField,\n resourceIdInUrl: resourceId,\n executionType\n }\n });\n }\n\n // User must be authenticated\n if (!initiatorIds?.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n relationshipField,\n resourceIdInUrl: resourceId\n }\n });\n }\n\n // User ID must match\n if (resourceId !== initiatorIds.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n relationshipField,\n resourceIdInUrl: resourceId,\n initiatorUserId: initiatorIds.userId\n }\n });\n }\n }\n // Note: Organization FK relationships (e.g., sharedWithOrganizationId) are validated\n // through the standard parent scope validation\n }\n }\n\n /**\n * Validate that the user has access to the parent scope for collection operations\n *\n * 🔒 SECURITY: This method ensures users can only access resources in scopes they belong to.\n *\n * For ORGANIZATIONS scope: verify user is member of the organization in the URL AND has required roles there\n * For USER_SELF scope: verify the user is accessing their own resources\n * For APPLICATION scope: verify application-level access\n */\n private async validateParentScopeAccess(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { roles: operationRoles } = operation;\n const { initiatorIds, initiatorRoles, relationshipContexts } = executionContext;\n\n // 🔒 Scope-required reference search: a junction-tagged scope param re-anchors\n // authorization to MEMBERSHIP in the anchor scope (e.g. any active role in the\n // org on `/organizations/{org}/users/search`), NOT the TARGET's own\n // (global/admin) operation roles. This matches the junction's own SEARCH\n // (`organizationMembers` SEARCH = ORG_MEMBER) and exposes nothing an org\n // member can't already enumerate via org-members. The global route (no tag)\n // falls through to the scope+roles switch below, so `/users/search` stays\n // admin-only. (The separate operation-role check in\n // `authorizeCollectionOperation` is likewise skipped for this case.)\n const junctionScopedContext = relationshipContexts?.find(rc => rc.scopeViaJunction);\n if (junctionScopedContext) {\n // Resolve the scope this junction-tagged param REPRESENTS by reverse-mapping\n // the scope-root resource types (e.g. `organizations` → ORGANIZATIONS).\n // Generic over ANY scope-root anchor — a future tenant scope (teams, etc.)\n // works unchanged; a non-scope-root anchor (e.g. the reverse `users`-anchored\n // direction, which is not a tenant scope) has no mapping and fails closed.\n const anchorScope = (Object.keys(PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE) as ResourcePrimaryScope[]).find(\n scope => PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE[scope] === junctionScopedContext.resourceType,\n );\n if (!anchorScope) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n });\n }\n // Authorize by MEMBERSHIP in that scope instance: the caller must hold a role\n // for THIS (scope, id). Generic role-scope match — works for any per-instance\n // scope (ORGANIZATIONS today) and fail-closes for scopes with no per-instance\n // role entries (APPLICATION/ANONYMOUS). NOT the target's own (global/admin)\n // operation roles — that bypass is the whole point (members search in-scope,\n // the global route stays admin-only).\n // Org-wide grants only: membership of the anchor scope is an organization-level fact. A\n // unit-scoped entry always sits alongside an org-wide one (a unit assignment presupposes an\n // ORGANIZATION_MEMBERS row), so this cannot deny a legitimate member — and were that ever\n // untrue, denying is the fail-closed direction.\n const isMember = initiatorRoles?.filter(isOrganizationWideRoleInfo).some(\n roleInfo =>\n roleInfo.relatedPrimaryScope === anchorScope &&\n roleInfo.relatedResourceId === junctionScopedContext.resourceId,\n );\n if (!isMember) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n anchorScope,\n scopeResourceType: junctionScopedContext.resourceType,\n scopeResourceId: junctionScopedContext.resourceId,\n },\n });\n }\n return;\n }\n\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n\n this.logDebug('Validating parent scope access', {\n effectiveScope,\n initiatorIds,\n operationRoles\n });\n\n switch (effectiveScope) {\n case ResourcePrimaryScope.ORGANIZATIONS:\n // 🔒 SECURITY: For organization-scoped resources, validate:\n // 1. organizationId is present in the URL\n // 2. User has a role for THIS SPECIFIC organization (not any organization)\n // 3. User's role in this organization satisfies the required operation roles\n // Checked FIRST, before the missing-organizationId refusal below. This gate runs only on\n // COLLECTION calls, where there is no row and therefore no URL-derived organization scope to\n // fall back on — so a platform administrator who is not a member of the tenant genuinely has\n // no `organizationId` here, and an admission placed after that throw would be unreachable by\n // the only principal it exists for. (Per-INSTANCE calls are different: there the scope comes\n // from the URL segment. See the predicate's JSDoc.)\n // On a COLLECTION call there is no row, so the tenant comes from the request's own scope —\n // the only thing available before a fetch. That is weaker than the per-instance gate, which\n // reads the fetched row, and it is why this branch keeps requiring an org-wide entry below.\n if (await this.admitsCrossTenantPlatformAdministration(executionContext, String(initiatorIds?.organizationId ?? ''))) {\n this.logDebug('Cross-tenant platform administration admitted (parent-scope gate)', {\n operationIdentifier: String(operation.operationIdentifier),\n resourceIdentifier: String(operation.resourceIdentifier),\n });\n break;\n }\n\n // ── The SCOPE ROOT has no parent scope, and demanding one refused its own configuration ──\n //\n // Everything below this point asks \"which organization is this request acting INSIDE, and\n // what are the caller's roles THERE\". That question is well-formed for a row inside a\n // tenant. It is not well-formed for the tenant resource itself: `/organizations` has no\n // `:organizationId` segment to populate `initiatorIds.organizationId`, so a collection call\n // on the scope root fell into the refusal directly below and answered 403 to EVERY caller —\n // including the `APP_ADMIN_SUPER_ADMIN` its own LIST and SEARCH declare, and the `APP_USER`\n // its CREATE declares. Measured (2026-08-10): LIST 403, SEARCH 403, CREATE 403, while the\n // per-instance READ answered 200. Three routed, spec-documented doors that answered 403\n // forever.\n //\n // The scope root's roles therefore resolve against the APPLICATION role table, which is where\n // the roles it declares actually live. `validateRolesForScope` expands through\n // `getRoleHierarchy(role, APPLICATION)`; a role unknown in that table expands to the empty\n // set, so an ORGANIZATION role can never satisfy an APPLICATION requirement here.\n //\n // ⚠️ THIS IS NOT A CROSS-TENANT ADMISSION, and it must never become one. Passing this gate\n // buys the right to USE the door, not the right to see every tenant's rows: the repository\n // confines a scope-root collection read to the caller's own organizations through\n // `assignScopeRootCollectionConfinementToFilter`, which reads the SAME\n // `isOwnScopeRootResource` predicate used here so the gate and the filter cannot disagree\n // about what a scope root is. Before that confinement existed, the filter for this exact\n // call compiled to `{}` — the empty predicate — on BOTH adapters, so opening this gate alone\n // would have disclosed every tenant row in the deployment. Do not relax one without the\n // other; see `.claude/plans/organizations-scope-root-collection-gate-analysis.md`.\n if (isOwnScopeRootResource({\n resourceIdentifier: String(operation.resourceIdentifier),\n resourcePrimaryScope: effectiveScope,\n })) {\n const applicationRoles = (initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .filter(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.APPLICATION)\n .flatMap(roleInfo => roleInfo.roles);\n\n if (!this.validateRolesForScope(operationRoles, applicationRoles, ResourcePrimaryScope.APPLICATION)) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope,\n scopeRootResource: String(operation.resourceIdentifier),\n requiredRoles: operationRoles,\n callerApplicationRoles: applicationRoles,\n }\n });\n }\n break;\n }\n\n if (!initiatorIds?.organizationId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n\n // Find user's roles specifically for this organization\n // Org-wide grants only — a unit-scoped entry carries the same scope + org id, so without\n // this filter it could supply the organization's role set from a single unit's grant.\n const orgRoleInfo = initiatorRoles?.filter(isOrganizationWideRoleInfo).find(\n roleInfo =>\n roleInfo.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS &&\n roleInfo.relatedResourceId === initiatorIds.organizationId\n );\n\n if (!orgRoleInfo) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope,\n organizationId: initiatorIds.organizationId,\n userOrganizations: initiatorRoles?.filter(r => r.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS)\n .map(r => r.relatedResourceId) || []\n }\n });\n }\n\n // Validate user has required roles in THIS organization\n const hasRequiredOrgRole = this.validateRolesForScope(\n operationRoles,\n orgRoleInfo.roles,\n ResourcePrimaryScope.ORGANIZATIONS\n );\n\n // WS-C ADDITIVE admission (D-C3b) — the collection-operation half. This branch, not\n // `validateOperationRoles`, is where an ORGANIZATIONS-scoped LIST / SEARCH / COUNT / CREATE\n // resolves its roles, so without this a unit-scoped principal would be denied at the very\n // operations narrowing exists to serve. Same rule as the other half: consulted only after the\n // organization-wide check has failed, and the repository confines the rows from the same stamp.\n if (!hasRequiredOrgRole && this.isAdmittedByUnitScopedGrant(executionContext, operation.resourceIdentifier)) {\n this.logDebug('Collection operation admitted by unit-scoped grant', {\n resourceIdentifier: operation.resourceIdentifier,\n operationRoles,\n });\n break;\n }\n\n if (!hasRequiredOrgRole) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n requiredRoles: operationRoles,\n userRolesInOrg: orgRoleInfo.roles,\n organizationId: initiatorIds.organizationId\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.USER_SELF:\n // For user-scoped resources, userId must be present\n if (!initiatorIds?.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.ANONYMOUS:\n if (!initiatorIds?.anonymousUserId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.APPLICATION:\n // Application scope - no specific parent ID required\n // Access is determined by roles only (validated separately)\n break;\n\n default:\n throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { message: `Unsupported primary scope for collection operation: ${effectiveScope}` }\n });\n }\n }\n\n /**\n * Validate that user's roles satisfy the required operation roles\n * Considers role hierarchy within the given scope\n *\n * @returns true if user has at least one of the required roles\n */\n private validateRolesForScope(\n requiredRoles: string[],\n userRoles: string[],\n scope: ResourcePrimaryScope\n ): boolean {\n return requiredRoles.some(requiredRole =>\n userRoles.some(userRole => {\n const hierarchy = this.getRoleHierarchy(userRole, scope);\n return hierarchy.includes(requiredRole);\n })\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"authorizations.backend.service.js","sourceRoot":"","sources":["../../../../../../src/security/authorizations/services/authorizations.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthExecutionContextFactoryBackendService } from '~wildo-backend-lib/security/authentications/services/auth-execution-context-factory.backend.service';\nimport { inject, injectable, optional } from \"inversify\";\nimport type { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport {\n anyOrganizationUnitGrantInheritsDownward,\n CORE_APP_ROLES,\n expandOrganizationUnitGrantThroughInheritance,\n isOrganizationWideRoleInfo,\n OrganizationUnitNarrowingDecisionKind,\n requiredRolesDeclarePublicAccess,\n resolveOrganizationUnitNarrowingDecision,\n isWildoBackendError,\n} from \"@wildo-ai/saas-models\";\nimport type {\n OrganizationUnitGrantExpansion,\n OrganizationUnitInheritanceNode,\n OrganizationUnitNarrowingStamp,\n} from \"@wildo-ai/saas-models\";\nimport type { ResourcesRegistryBackendService } from \"~wildo-backend-lib/resources/services/resources-registry.backend.service\";\nimport { SAAS_SERVICE_TYPES } from \"~wildo-backend-lib/inject/models/service-types\";\nimport { LoggerService } from \"~wildo-backend-lib/monitoring/logger/services/logger.service\";\nimport { ErrorBuilderBackendService } from \"~wildo-backend-lib/errors/services/error-builder.backend.service\";\nimport { describeCaughtError, projectCaughtErrorLogFields } from \"~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils\";\nimport { RepositoriesRegistryHandlerBackendService } from \"~wildo-backend-lib/base-classes/services/repositories/repositories-registry-handler.backend.service\";\nimport { IdOrIdsOrFilterType } from \"~wildo-backend-lib/base-classes/models/repositories.backend.schemas\";\nimport {\n ResourceConfiguration_Operation,\n CoreResourceType,\n IntrospectionTenancyStance,\n PersistenceAdapter,\n coreResourceShared_FieldIdentifier,\n PlatformAccessGrantStatus,\n PlatformAccessGrants_Operations,\n ResourceOperationVariantType,\n ResourcePrimaryScope,\n isPlatformAccessGrantUsable,\n PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE,\n ResourcesConfig_OperationPathUtils,\n ErrorType,\n ErrorCustomMessageReference,\n RolesConfiguration,\n RoleDefinition,\n DEFAULT_APP_ROLE_CONFIGURATION,\n DEFAULT_ORGANIZATION_ROLES,\n Roles,\n AppRoles,\n OrgRoles,\n CoreResourceOperation,\n ExecutionContext_ExecutionType,\n ResourceOperationDenialReason,\n ResourceOperationRiskLevel\n} from \"@wildo-ai/saas-models\";\nimport type { AuditLogsBackendService } from \"~wildo-backend-lib/compliance/audit-trails/services/audit-logs.backend.service\";\nimport type { RedisService } from \"~wildo-backend-lib/databases/services/redis.service\";\nimport type { Container } from \"inversify\";\nimport { classifyAuthorizationDenial, resolveDenialAuditEmissionDecision } from \"~wildo-backend-lib/security/authorizations/authorization-denial-audit.backend.utils\";\nimport { isOwnScopeRootResource } from \"~wildo-backend-lib/security/authorizations/scope-root-collection-confinement.backend\";\nimport { ExecutionContext } from \"~wildo-backend-lib/runtime/models/execution-context.backend.schemas\";\nimport { ResourceConfiguration_OperationRepositoryPath } from \"@wildo-ai/saas-models\";\n\n@injectable()\nexport class AuthorizationsBackendService {\n\n\n private readonly logDebug: (message: string, context?: Record<string, unknown>) => void;\n\n // Role configuration management\n private appRoles: RolesConfiguration;\n private orgRoles: RolesConfiguration;\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.ErrorBuilderService) private readonly errorBuilder: ErrorBuilderBackendService,\n @inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService) private readonly repositoriesRegistry: RepositoriesRegistryHandlerBackendService,\n /**\n * Source of the organization-unit narrowing registry (WS-C). Added LAST so existing positional\n * construction keeps working; when absent the narrowing lookup resolves to \"no resource is\n * narrowed\", which is the fail-CLOSED direction here rather than the fail-open one: the\n * repositories read the same registry independently, so a resource they see as narrowed and this\n * gate does not ends up with NO stamp — and an unstamped narrowed resource yields no rows.\n */\n @inject(SAAS_SERVICE_TYPES.ResourceRegistryService) @optional() private readonly resourcesRegistry?: ResourcesRegistryBackendService,\n /**\n * Counter store backing the denial-audit escalation ladder. Optional: with no Redis bound the\n * dedup degrades to always-emit, which is the fail-OPEN direction and the correct one — a\n * fail-closed cooldown would let an attacker blind the trail by taking Redis down.\n */\n @inject(SAAS_SERVICE_TYPES.RedisService) @optional() private readonly redisService?: RedisService,\n /**\n * Lazy resolver for {@link AuditLogsBackendService} — the sink for `RESOURCE_OPERATION_DENIED`\n * (the record half of \"record access decisions\"). Deliberately NOT constructor-injected:\n * `AuditLogsBackendService` → `AuditEventDispatcherBackendService` → `QueueBackendService` →\n * `AuthorizationsBackendService` (via `authorizeInController`, which `QueueBackendService` calls\n * on its own enqueue paths) is an existing edge, so a direct constructor inject here would close\n * that chain into an InversifyJS circular-dependency plan failure at boot. Resolved on demand via\n * {@link resolveAuditLogsService} instead — the same lazy-container pattern `WebSocketService`\n * uses to break its own cycle with `NotificationBadgeService`/`ConversationalExecutionBackendService`.\n * Optional and positioned LAST so existing positional construction (and every partial-container\n * test) keeps working; when absent, or when `AuditLogsService` is unbound, the refusal is still\n * enforced, it simply leaves no audit row.\n *\n * Emission is deliberately BEST-EFFORT and can never alter the authorization outcome: the caller\n * has already been refused by the time this is consulted, so letting an audit-store problem turn\n * a correct 403 into a 500 would degrade the system to protect a log. Detection of that gap is\n * the audit pipeline's own control (`audit_store_failure_total`), not this gate's.\n *\n * assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n */\n @inject('Container') @optional() private readonly container?: Container,\n ) {\n\n this.logDebug = this.logger.debugByType('AuthorizationsBackendService');\n this.logger.setDebugTypeLogging('AuthorizationsBackendService', false);\n\n // Initialize default role configurations\n this.initializeRoles();\n }\n\n /**\n * Initialize roles with default configurations and optional custom roles\n */\n private initializeRoles(customRoles?: RolesConfiguration): void {\n // Start with default configurations\n this.appRoles = { ...DEFAULT_APP_ROLE_CONFIGURATION };\n this.orgRoles = { ...DEFAULT_ORGANIZATION_ROLES };\n\n // Add custom roles if provided, filtering by scope\n if (customRoles) {\n this.addCustomRoles(customRoles);\n }\n\n this.logDebug('Role configurations initialized', { appRolesCount: Object.keys(this.appRoles).length, orgRolesCount: Object.keys(this.orgRoles).length, hasCustomRoles: !!customRoles });\n }\n\n /**\n * Initialize roles with custom roles configuration\n */\n public initializeRolesWithCustom(customRoles: RolesConfiguration): void {\n this.initializeRoles(customRoles);\n }\n\n /**\n * Add custom roles, filtering them by relatedPrimaryScope to place them in the correct configuration\n */\n private addCustomRoles(customRoles: RolesConfiguration): void {\n let appRolesAdded = 0;\n let orgRolesAdded = 0;\n const invalidRoles: string[] = [];\n\n for (const [roleKey, roleDefinition] of Object.entries(customRoles)) {\n try {\n // Type cast to RoleDefinition since we know the structure from RolesConfiguration\n const typedRoleDefinition = roleDefinition as RoleDefinition;\n\n switch (typedRoleDefinition.relatedPrimaryScope) {\n case ResourcePrimaryScope.APPLICATION:\n this.appRoles[roleKey] = { ...typedRoleDefinition };\n appRolesAdded++;\n this.logDebug('Custom app role added', { roleKey, role: typedRoleDefinition.role, inheritFrom: typedRoleDefinition.inheritFrom, isSystemRole: typedRoleDefinition.isSystemRole });\n break;\n\n case ResourcePrimaryScope.ORGANIZATIONS:\n this.orgRoles[roleKey] = { ...typedRoleDefinition };\n orgRolesAdded++;\n this.logDebug('Custom org role added', { roleKey, role: typedRoleDefinition.role, inheritFrom: typedRoleDefinition.inheritFrom, isSystemRole: typedRoleDefinition.isSystemRole });\n break;\n\n case ResourcePrimaryScope.USER_SELF:\n // This scope doesn't have dedicated role configurations\n // Log a warning but don't add them\n this.logger.warn('Custom role with unsupported scope ignored', { roleKey, scope: typedRoleDefinition.relatedPrimaryScope, message: 'USER_SELF scope does not support custom roles' });\n invalidRoles.push(roleKey);\n break;\n\n default:\n this.logger.warn('Custom role with unknown scope ignored', { roleKey, scope: typedRoleDefinition.relatedPrimaryScope });\n invalidRoles.push(roleKey);\n break;\n }\n } catch (error) {\n this.logger.error('Failed to add custom role', { roleKey, ...projectCaughtErrorLogFields(error), roleDefinition });\n invalidRoles.push(roleKey);\n }\n }\n\n this.logDebug('Custom roles processing completed', { totalCustomRoles: Object.keys(customRoles).length, appRolesAdded, orgRolesAdded, invalidRoles: invalidRoles.length, invalidRoleKeys: invalidRoles });\n }\n\n public addMultipleCustomRoles(customRoles: RolesConfiguration): void {\n this.addCustomRoles(customRoles);\n }\n\n public addAppRole(roleKey: AppRoles, roleDefinition: RoleDefinition): void {\n // Validate that the role definition has APPLICATION scope\n if (roleDefinition.relatedPrimaryScope !== ResourcePrimaryScope.APPLICATION) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { roleScope: roleDefinition.relatedPrimaryScope, currentRoleScope: ResourcePrimaryScope.APPLICATION, roleKey , roleDefinition } });\n }\n\n this.appRoles[roleKey] = { ...roleDefinition };\n\n this.logDebug('App role added/updated', { roleKey, roleDefinition });\n }\n\n public addOrgRole(roleKey: OrgRoles, roleDefinition: RoleDefinition): void {\n // Validate that the role definition has ORGANIZATIONS scope\n if (roleDefinition.relatedPrimaryScope !== ResourcePrimaryScope.ORGANIZATIONS) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, undefined,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { roleScope: roleDefinition.relatedPrimaryScope, currentRoleScope: ResourcePrimaryScope.ORGANIZATIONS, roleKey , roleDefinition } });\n }\n\n this.orgRoles[roleKey] = { ...roleDefinition };\n\n this.logDebug('Org role added/updated', { roleKey, roleDefinition });\n }\n\n public getAppRole(roleKey: AppRoles): RoleDefinition | undefined {\n return this.appRoles[roleKey];\n }\n\n public getOrgRole(roleKey: OrgRoles): RoleDefinition | undefined {\n return this.orgRoles[roleKey];\n }\n\n public getAppRoles(): RolesConfiguration {\n return { ...this.appRoles };\n }\n\n public getOrgRoles(): RolesConfiguration {\n return { ...this.orgRoles };\n }\n\n public hasAppRole(roleKey: AppRoles): boolean {\n return roleKey in this.appRoles;\n }\n\n public hasOrgRole(roleKey: OrgRoles): boolean {\n return roleKey in this.orgRoles;\n }\n\n public getRoleHierarchy(roleKey: Roles, scope: ResourcePrimaryScope): string[] {\n const rolesConfig = scope === ResourcePrimaryScope.APPLICATION ? this.appRoles : this.orgRoles;\n const roleHierarchy: string[] = [];\n let currentRoleKey: string | undefined = roleKey;\n\n while (currentRoleKey && rolesConfig[currentRoleKey]) {\n roleHierarchy.push(currentRoleKey);\n currentRoleKey = rolesConfig[currentRoleKey].inheritFrom;\n }\n\n return roleHierarchy;\n }\n\n public resetRolesToDefaults(): void {\n this.initializeRoles();\n this.logDebug('Roles reset to default configurations');\n }\n\n /**\n * Reset roles to default configurations with custom roles\n */\n public resetRolesToDefaultsWithCustom(customRoles: RolesConfiguration): void {\n this.initializeRoles(customRoles);\n this.logger.info('Roles reset to default configurations with custom roles');\n }\n\n /**\n * Evaluate the organization-unit narrowing decision for this request and STAMP it on the context.\n *\n * assurance-control: WILDO.ACCESS.SCOPE_CONFINEMENT — the stamp is the conferring-grant\n * record: it names WHY this principal reached this resource, which is the input an access review\n * needs in order to answer that question without reconstructing it from role tables.\n *\n * ## Why here and nowhere else (plan decision D-C6)\n *\n * This is the only place holding all three inputs at once: the operation, its declared roles, and\n * `getRoleHierarchy`. The repository layer — which needs the ANSWER — cannot reach a role-hierarchy\n * resolver without injecting this service, and this service already depends on the repositories\n * registry, so that would invert the dependency direction. Evaluating once and carrying the result\n * also removes the possibility that the gate and the filter disagree: two evaluations of the same\n * inputs can drift, one stamped decision cannot.\n *\n * ## Both halves must land together\n *\n * Admitting a unit grant here without the repository narrowing rows would turn one unit's grant\n * into tenant-wide access — the escalation the whole model exists to prevent. The repository's\n * fail-closed default (an unstamped narrowable resource yields no rows) is what protects the window\n * between them.\n */\n /**\n * PUBLIC seam so a caller that must READ before authorization can stamp first.\n *\n * The controller's context-addressed probes (`resolveContextAddressedSingletonOperationAuthorizationId`\n * and its association twin) resolve WHICH row an id-less operation is about by running a real,\n * narrowed repository read — necessarily BEFORE `authorizeInController`, because the id they produce\n * is the thing being authorized. On a narrowed resource that read would otherwise run against no\n * stamp, fail closed, resolve nothing, and answer NOT_FOUND before authorization ever ran: the same\n * defect this class fixed for `authorizeInRepositoryAndService`, one boundary out.\n *\n * Stamping here rather than exempting the probe is the deliberate half. A probe that skips narrowing\n * would resolve a singleton belonging to a unit the caller does not hold, and the confinement would\n * then depend entirely on a later check noticing — fail-open by default. Stamped, the probe simply\n * does not find it, which is the same answer the row filter gives everywhere else.\n *\n * Safe to call more than once per request: `mergeOrganizationUnitNarrowingStamps` only ever tightens,\n * so a later evaluation can restrict further and never widen.\n */\n public async stampOrganizationUnitNarrowingForOperation(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<void> {\n await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n }\n\n private async resolveAndStampOrganizationUnitNarrowing(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<OrganizationUnitNarrowingStamp> {\n const { resourceIdentifier, operationIdentifier, roles: operationRoles } = operation;\n\n const decision = resolveOrganizationUnitNarrowingDecision({\n resourceType: resourceIdentifier,\n requiredRoles: operationRoles ?? [],\n initiatorRoles: executionContext.initiatorRoles,\n narrowingRegistry: this.resourcesRegistry?.getResourcesRegistry()?.organizationUnitNarrowing ?? {},\n roleHierarchyResolver: (role, scope) => this.getRoleHierarchy(role as Roles, scope),\n });\n\n // Downward inheritance (D-C2): a grant at a unit declaring INHERIT_DOWN also reaches that unit's\n // descendants. Expanding HERE rather than in the repository keeps D-C6's one-evaluation rule\n // intact — the effective unit set travels in the stamp, so the row filter and the write guard\n // cannot end up with different ideas of how far the same grant reaches.\n const expansion =\n decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? await this.expandOrganizationUnitGrant(decision.organizationUnitIds, executionContext)\n : undefined;\n\n const effectiveDecision =\n expansion && decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? { ...decision, organizationUnitIds: expansion.effectiveOrganizationUnitIds }\n : decision;\n\n const stamp: OrganizationUnitNarrowingStamp = {\n resourceType: resourceIdentifier,\n operationIdentifier: String(operationIdentifier),\n requiredRoles: operationRoles ?? [],\n decision: effectiveDecision,\n inheritedOrganizationUnitIds: expansion?.inheritedOrganizationUnitIds,\n };\n\n executionContext.stampOrganizationUnitNarrowingDecision(stamp);\n\n if (effectiveDecision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED) {\n // The conferring grant, recorded at INFO: this is an access decision a reviewer must be able to\n // reconstruct, not a debug detail. Organization-wide decisions are the unchanged norm and stay\n // on the debug channel.\n //\n // Directly-held and inherited units are reported SEPARATELY: with downward inheritance a grant\n // at a root unit reaches the whole chart, and an access review must be able to see that rather\n // than read one effective list that looks narrow (D-C4 watch item 4).\n this.logger.info('Organization-unit narrowed access granted', {\n resourceType: resourceIdentifier,\n operationIdentifier: stamp.operationIdentifier,\n requiredRoles: stamp.requiredRoles,\n conferringOrganizationUnitIds: decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED\n ? decision.organizationUnitIds\n : [],\n inheritedOrganizationUnitIds: stamp.inheritedOrganizationUnitIds ?? [],\n effectiveOrganizationUnitIds: effectiveDecision.organizationUnitIds,\n userId: executionContext.userId,\n organizationId: executionContext.organizationId,\n });\n } else {\n this.logDebug('Organization-unit narrowing decision', { resourceIdentifier, decisionKind: effectiveDecision.kind });\n }\n\n return stamp;\n }\n\n /**\n * Expand directly-held unit grants across the organization tree, per each unit's `inheritanceType`.\n *\n * assurance-control: WILDO.ACCESS.SCOPE_CONFINEMENT — a grant reaches exactly the subtree its unit\n * declares.\n *\n * ## Cost, and the pre-check that keeps it honest\n *\n * Two reads at most, and usually one: the granted units are fetched by id (an indexed `$in` over a\n * handful of ids), and the organization's unit set is fetched ONLY when at least one of them\n * actually declares downward inheritance. An organization whose units are all `NO_INHERITANCE`\n * therefore pays a single small lookup. The subtree test itself is a `path` PREFIX comparison in\n * memory — never a recursive walk, which is the entire reason `path` is materialized (D-C5).\n *\n * ## Failure posture: PROPAGATE, matching the emission phase\n *\n * A read failure is NOT swallowed into \"no inheritance\". Silently returning the unexpanded set\n * gives the principal a grant narrower than the one they hold, which surfaces as missing rows\n * rather than as an error — presenting a failure as data, the exact degradation the execution-context\n * builder refused when it chose to propagate. An UNREGISTERED repository is different and is treated\n * as such: an application with no unit tree has no descendants to find, which is an accurate answer.\n */\n /**\n * The context for reading ORGANIZATION_UNITS from inside authorization.\n *\n * NOT the caller's. This runs on the authorization path for ANY resource operation that opted into\n * unit narrowing, so `executionContext` is keyed to whatever resource the request addressed — a\n * nested route contributes that resource's own FK (`todoId`, `organizationMemberId`, …). The\n * repository's contextual filter is fail-closed on a field the target does not model: it THROWS\n * `CONFIGURATION` / `context_filter` rather than ignoring it, so a unit-narrowed grant on a nested\n * resource would 500 the authorization decision itself. `createForSubCall` narrows the inherited\n * context to what ORGANIZATION_UNITS actually models, which keeps `organizationId` — the scoping\n * this read depends on — and drops the rest.\n *\n * Resolved LAZILY from the container, mirroring how the execution-context creator resolves its own\n * late collaborators: authorization is constructed early in backend startup and a hard constructor\n * dependency here risks a DI cycle. When the container or the creator is unavailable (minimal test\n * containers), fall back to the caller's context — the pre-existing behaviour — rather than failing\n * an authorization decision over a read-context refinement.\n */\n private async createOrganizationUnitReadContext(\n executionContext: ExecutionContext<any>,\n ): Promise<ExecutionContext<any>> {\n try {\n const executionContextCreator = this.container?.get<ExecutionContextCreatorBackendService>(\n SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService,\n );\n if (!executionContextCreator) return executionContext;\n return await executionContextCreator.createForSubCall(\n executionContext,\n CoreResourceType.ORGANIZATION_UNITS,\n CoreResourceOperation.LIST,\n );\n } catch {\n return executionContext;\n }\n }\n\n private async expandOrganizationUnitGrant(\n grantedOrganizationUnitIds: readonly string[],\n executionContext: ExecutionContext<any>,\n ): Promise<OrganizationUnitGrantExpansion> {\n const unexpanded: OrganizationUnitGrantExpansion = {\n effectiveOrganizationUnitIds: [...grantedOrganizationUnitIds],\n inheritedOrganizationUnitIds: [],\n };\n if (grantedOrganizationUnitIds.length === 0) return unexpanded;\n\n const unitRepository = this.repositoriesRegistry.getRepository(CoreResourceType.ORGANIZATION_UNITS);\n if (!unitRepository) return unexpanded;\n\n const unitReadContext = await this.createOrganizationUnitReadContext(executionContext);\n\n const grantedUnits = await unitRepository.list<OrganizationUnitInheritanceNode>(unitReadContext, {\n _id: { $in: [...grantedOrganizationUnitIds] },\n }) ?? [];\n\n if (!anyOrganizationUnitGrantInheritsDownward(grantedUnits)) return unexpanded;\n\n // Scoped to the organization the request is acting in. Org charts are small and bounded, and the\n // alternative — a `path`-prefix query per granted unit — would need a per-adapter `startsWith`\n // operator the portable filter contract does not carry.\n const organizationUnits = await unitRepository.list<OrganizationUnitInheritanceNode>(unitReadContext, {\n organizationId: executionContext.organizationId,\n }) ?? [];\n\n return expandOrganizationUnitGrantThroughInheritance(grantedUnits, organizationUnits);\n }\n\n /**\n * Does a stamped decision ADMIT this caller on the strength of a unit grant alone?\n *\n * Consulted only after the organization-wide role check has already failed. `UNIT_NARROWED` means\n * the decision authority found a unit grant that satisfies the operation on a resource that opted\n * in, so admitting is exactly the ADDITIVE rule (D-C3b): a unit grant widens reach for a principal\n * who would otherwise be denied, and the repository then confines them to those units.\n */\n private isAdmittedByUnitScopedGrant(executionContext: ExecutionContext<any>, resourceIdentifier: string): boolean {\n const stamp = executionContext.getOrganizationUnitNarrowingStamp(resourceIdentifier);\n return stamp?.decision.kind === OrganizationUnitNarrowingDecisionKind.UNIT_NARROWED;\n }\n\n /**\n * Does this operation declare `APP_PUBLIC` — i.e. is it callable with no credential at all?\n *\n * Read from the OPERATION rather than inferred from the context, so the public carve-out above\n * cannot be satisfied by the caller's side of the request alone.\n *\n * Delegates to {@link requiredRolesDeclarePublicAccess}, the ONE named source for what\n * `APP_PUBLIC` means. This used to be a private re-derivation of the same two-line test, and it\n * was one of FOUR such copies (this one, the authentication tier's `operationAdmitsPublicAccess`,\n * and the two role gates that did not have one and therefore refused credentialed callers). A\n * policy expressed as a module-private constant reaches exactly the sites that already agree with\n * it — see `.claude/rules/invariant-call-site-enumeration.md` #13.\n */\n private operationDeclaresPublicAccess(operation: ResourceConfiguration_Operation<any, any, any>): boolean {\n return requiredRolesDeclarePublicAccess((operation as { roles?: string[] }).roles);\n }\n\n public async authorizeInRepositoryAndService(id_or_ids : IdOrIdsOrFilterType, operation: ResourceConfiguration_Operation<any, any, any>, executionContext: ExecutionContext<any>): Promise<void> {\n const { resourceIdentifier, operationIdentifier, variantType, resourcePrimaryScope, roles: operationRoles } = operation;\n\n this.logDebug('Starting authorization check', {\n resourceIdentifier,\n operationIdentifier,\n variantType,\n resourcePrimaryScope,\n operationRoles,\n idOrIds: id_or_ids,\n initiatorIds: executionContext.initiatorIds,\n initiatorRoles: executionContext.initiatorRoles?.map(r => ({ roles: r.roles, scope: r.relatedPrimaryScope }))\n });\n\n // Webhook callbacks are trusted after signature verification — scope filtering via\n // repository is enough, no role-based authorization needed.\n if (executionContext.isWebhookExecution()) {\n this.logDebug('Webhook execution — skipping role-based authorization (scope filtering is applied by repository)');\n return;\n }\n\n /*\n * A PUBLIC operation reached by a PUBLIC caller has no principal to authorize, and that is the\n * declaration rather than a gap.\n *\n * `createForPublicOperation` sets `initiatorIds: null` deliberately — a caller who presented no\n * credential has no identity — so the guard immediately below denies every ADDRESSED public\n * operation with MISSING_INITIATOR. Collection operations never hit it (`authorizeCollectionOperation`\n * is a different path with no pre-fetch), which is why `APP_PUBLIC` looked complete: LIST answered\n * 200 while READ on the same resource, with the same declared role, answered 403.\n *\n * This is the same trade the webhook carve-out above makes, for the same reason: there is no\n * principal whose roles could be checked, the operation itself declares who may call it, and the\n * repository's contextual filter still runs underneath. It is NOT a widening — an operation that\n * does not declare `APP_PUBLIC` cannot reach here, because `ExecutionContextCreator` only mints a\n * public context for an operation that does.\n *\n * BOTH conditions are required on purpose, and the reason has NARROWED since this was written.\n * Keying on the context alone would let any future public-context path reach a non-public\n * operation — that half is unchanged and is the security-relevant one.\n *\n * The other half used to be argued as \"keying on the operation alone would admit a\n * credentialed-but-unauthorized caller to a public operation's addressed form without their roles\n * being examined\". That framing is retired (#153): a credentialed caller IS now admitted to a\n * publicly-declared operation — `validateOperationRoles` treats `APP_PUBLIC` as imposing no\n * positive role requirement, because a declaration that reduced access for presenting a valid\n * credential was the defect, not the design.\n *\n * What the `isPublicExecution()` half still buys is that the credentialed caller takes the FULL\n * path rather than this shortcut: their row pre-fetch runs, their FK-path and parent-scope gates\n * run, and their roles are examined and found to require nothing. This carve-out remains what it\n * says — nobody claimed an identity, and none was required — and is not the mechanism by which an\n * authenticated caller reaches a public operation.\n */\n if (executionContext.isPublicExecution() && this.operationDeclaresPublicAccess(operation)) {\n this.logDebug('Public execution of a publicly-declared operation — no principal to authorize; '\n + 'the repository contextual filter still applies');\n return;\n }\n\n // Ensure we have initiator information for authorization\n if (!executionContext.initiatorIds || !executionContext.initiatorRoles) {\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.MISSING_INITIATOR, operation, executionContext,\n );\n throw this.errorBuilder.buildError( ErrorType.AUTHORIZATION, executionContext,\n { customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_MISSING_INITIATOR,\n context: { initiatorIds: executionContext.initiatorIds, initiatorRoles: executionContext.initiatorRoles} } );\n }\n\n // WS-C: evaluate the unit-narrowing decision and STAMP it HERE — before the authorization\n // pre-fetch below, not just before the role gate.\n //\n // ## Why this position is load-bearing (it was three phases later, and that broke every\n // ## id-addressed operation on a narrowed resource)\n //\n // The pre-fetch a few lines down reads the target row through `doByPath(READ, …)`, which applies\n // `buildContextualFilter` — and that filter fails CLOSED on a narrowable resource carrying no\n // stamp, because \"no decision\" must never be read as \"no restriction\". With the stamp written\n // later, the authorizer's own read was the unstamped request: it matched nothing, the count check\n // threw NOT_FOUND, and the stamping line was never reached. Effect: for EVERY caller including an\n // organization-wide admin, a narrowed resource answered 404 on READ / UPDATE / DELETE by id and\n // was reachable only through the collection verbs — which pass through\n // `authorizeCollectionOperation`, a path with no pre-fetch, and therefore looked healthy.\n //\n // Nothing here depends on the row: the decision is a question about the CALLER (their unit role\n // grants) and the OPERATION (its declared roles). `initiatorRoles` is asserted present directly\n // above, so every input is already in hand.\n //\n // Stamping first is also strictly better than merely correct. It makes the pre-fetch ITSELF\n // narrowed, so a caller naming a row in a unit they do not hold cannot even load it for the\n // authorization phases that follow — the cross-unit refusal happens at the read rather than\n // depending on a later check to notice.\n //\n // Placed before the id extraction so the `FilterQuery` early-return below is covered too. That\n // path deliberately skips the rest of authorization, and letting it skip the stamp as well would\n // leave the repository to fail closed on a request the gate had decided not to examine.\n const narrowingStamp = await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n\n // A DENIED narrowing decision is a statement about the CALLER, so it must surface as one.\n //\n // Stamping before the pre-fetch (above) is what makes the id-addressed path work at all, but it\n // has a consequence that has to be handled HERE rather than left to fall out: a DENIED decision\n // stamps DENY_ALL, the pre-fetch below then reads through a match-nothing predicate, resolves no\n // row, and the count check answers **404 NOT_FOUND**. The caller lacks the role, and we would be\n // telling them the record does not exist.\n //\n // That is wrong in three ways, none of them a leak: a narrowed resource would answer a role denial\n // differently from every other resource in the application; an operator debugging a\n // misconfiguration would hunt for a missing row that is sitting right there; and the module's own\n // contract calls `DECISION_DENIED` a belt-and-braces case that \"would already have thrown\",\n // which stopped being true the moment the stamp preceded the fetch.\n //\n // Running the role gate NOW rather than inventing an error here is deliberate — it is the same\n // gate, the same `AUTHORIZATIONS_ACCESS_DENIED`, and the same `INSUFFICIENT_ROLES` audit reason\n // the caller would have received a few phases later. And it provably refuses: `DENIED` is returned\n // only when no organization-wide grant satisfies the operation (the identical hierarchy\n // computation `validateOperationRoles` performs) AND no unit grant does either (so the\n // `isAdmittedByUnitScopedGrant` rescue cannot fire). No later phase can add authority that the\n // decision did not already consider, so this changes WHICH error surfaces and when — never\n // WHETHER the caller is admitted, and never what data they can reach.\n //\n // The confined-caller case is untouched and still answers 404: a caller who HOLDS a grant but\n // names a row in another unit is `CONFINED_TO_UNITS`, not `DENIED`, so it falls through to the\n // pre-fetch and is deliberately indistinguishable from a row that does not exist (D-1) — that\n // one is about REACH, and must not become an existence oracle.\n // (The refusal itself is raised just below, AFTER the ids are extracted — see there for why.)\n\n // Extract actual IDs from IdOrIdsOrFilterType for processing\n let idsArray: string[] = [];\n\n if (typeof id_or_ids === 'string') {\n idsArray = [id_or_ids];\n } else if (Array.isArray(id_or_ids)) {\n idsArray = id_or_ids;\n } else if (typeof id_or_ids === 'object' && id_or_ids && 'id_or_ids' in id_or_ids) {\n // Extract IDs from combined object\n const { id_or_ids: ids } = id_or_ids;\n if (typeof ids === 'string') {\n idsArray = [ids];\n } else if (Array.isArray(ids)) {\n idsArray = ids;\n }\n } else if (typeof id_or_ids === 'object' && id_or_ids) {\n // For FilterQuery objects, we can't extract specific IDs - skip authorization or use context\n this.logDebug('Authorization called with FilterQuery - unable to extract specific IDs for authorization');\n return; // Skip authorization for filter-based operations\n }\n\n // Raise the DENIED refusal HERE — after the ids are known, and still before the pre-fetch below.\n //\n // The position is a compromise between two constraints that pull opposite ways. It must precede\n // the pre-fetch, or the DENY_ALL stamp turns a role denial into a 404 (the whole point). But an\n // earlier revision raised it before the id extraction and therefore reported the denial with an\n // EMPTY attempted-id list — so `RESOURCE_OPERATION_DENIED` on a narrowed resource recorded no\n // attempted id, while the identical denial on every other resource (raised by the later phase\n // with `idsArray`) recorded one. An access-decision record that silently loses its subject on\n // exactly the resources an application opted in to CONFINE is the wrong half to degrade.\n //\n // The `FilterQuery` early-return above is deliberately NOT covered: that path skips authorization\n // by design and has no ids to report, and the stamp it carries still makes the repository fail\n // closed.\n if (narrowingStamp.decision.kind === OrganizationUnitNarrowingDecisionKind.DENIED) {\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext, idsArray,\n );\n }\n\n // Get repository for the resource to fetch data\n const repository = this.repositoriesRegistry.getRepositoryOrThrow(resourceIdentifier, executionContext);\n\n // Fetch the related elements using the repository\n let resourceObjects: any[] = [];\n\n const operationRepositoryPath: ResourceConfiguration_OperationRepositoryPath = { resourceIdentifier, operationIdentifier: CoreResourceOperation.READ };\n // A cross-tenant-admitted operation (a per-VARIANT opt-in, e.g. `organizations.restore` /\n // `activate` — the RECUPERATIVE platform-operator doors) must read its target UNSCOPED here.\n //\n // ## Why the scoped pre-fetch is wrong for exactly these operations\n //\n // The pre-fetch below reads through `buildContextualFilter`, which scopes to the CALLER's tenant.\n // But these operations run on tenants the caller is deliberately NOT scoped into: a marked tenant\n // confers no authority to its own admins (recovery is out-of-tenant by design — see\n // `.claude/rules/administrative-continuity-floors.md`), so a platform super-administrator restoring\n // it holds no organization-scope entry for it and the scoped read resolves NOTHING → the count\n // check answers 404. The result: `restore` / `activate` — the doors whose entire purpose is to act\n // on a no-authority-status tenant — are structurally unreachable through this path.\n //\n // Reading UNSCOPED here makes this pre-fetch consistent with the crossing that `authorizeOrganizations`\n // already ADMITS at its gate for the same variant, and it mirrors the WRITE side exactly:\n // `assertOrganizationUnitBelongsToCallerTenant` reads `excludeContextualFilter: true` and then makes\n // the tenant decision explicitly. Safe because (a) it is gated on the per-variant opt-in, not global;\n // (b) the row is used ONLY for the authorization decision, never disclosed to the caller; and (c) the\n // operation's role gate (`validateOperationRoles` → APP_ADMIN_SUPER_ADMIN) still runs below and denies\n // any non-operator, so a non-super-admin never reaches the operation regardless of what was read. The\n // crossing itself is audited by `authorizeOrganizations` (`CROSS_TENANT_ADMINISTRATIVE_ACCESS`).\n // Read the flag from BOTH the resolved `operation` param AND `executionContext.operation`. The\n // per-variant opt-in is flattened onto `executionContext.operation` (which is why the sibling\n // predicate `admitsCrossTenantPlatformAdministration()` reads it there, and why the crossing is\n // admitted at `authorizeOrganizations`); the `operation` param can still be the pre-variant\n // object on some dispatch paths. Checking both makes the unscoping consistent with the gate that\n // will admit the crossing a few lines below, regardless of which object carried the variant.\n const crossTenantAdmitted =\n (operation as { admitsCrossTenantPlatformAdministration?: boolean }).admitsCrossTenantPlatformAdministration === true\n || (executionContext.operation as { admitsCrossTenantPlatformAdministration?: boolean } | undefined)\n ?.admitsCrossTenantPlatformAdministration === true;\n try {\n // Use repository read operation to get objects\n\n const obj_s = await repository.doByPath(\n operationRepositoryPath,\n executionContext,\n (idsArray.length === 1) ? idsArray[0] : idsArray,\n undefined,\n crossTenantAdmitted ? { excludeContextualFilter: true } : undefined,\n );\n resourceObjects = (idsArray.length === 1)? [obj_s] : obj_s;\n\n } catch (error) {\n /**\n * \"No rows\" and \"could not look\" are DIFFERENT ANSWERS, and this catch used to\n * destroy the difference.\n *\n * It classified every failure of the authorization pre-fetch as `NOT_FOUND`, so an\n * infrastructure fault reached the client as a missing row. Measured on the dogfood\n * stack 2026-09-01: **78 of 78** recent 404s carried\n * `authorizations_validation_failed`, and NOT ONE of them was an absent record —\n * every one was `introspection_derivation_failed`, the introspection repository\n * refusing because the target application had not been built. That producer takes\n * explicit care to distinguish the two (\"This is reported rather than returned as an\n * empty result, because 'no rows' and 'could not look' are different answers\") and\n * the distinction died here, four frames later.\n *\n * The cost is not cosmetic. It sends every reader to the database for a fault that is\n * in the build; it reports a SERVER fault as a CLIENT error, so a 4xx/5xx alert split\n * cannot see it; and it makes a broken deployment indistinguishable from an empty one.\n *\n * ## Why re-classifying here is safe for the existence oracle\n *\n * The anti-enumeration refusals are ELSEWHERE and are untouched: a row that is absent\n * OR invisible is caught by the `resourceObjects.length !== idsArray.length` check\n * below, which answers `NOT_FOUND` with this same message reference on purpose.\n * Genuine absence never reaches THIS catch — it arrives as a successful read returning\n * fewer rows, not as a throw.\n *\n * So this block only ever sees a fetch that FAILED, and a failure that is independent\n * of the id (a broken build, a dead connection, a missing operation key) reveals\n * nothing about any particular row. A cause that IS `NOT_FOUND` still answers\n * `NOT_FOUND`, unchanged, so the repository's own filtered-out refusal keeps its\n * indistinguishability.\n *\n * The `customMessageReference` is deliberately the SAME in every branch: the sibling\n * refusal at `buildSubjectNotResolvableError` notes that a different reference would\n * restore the oracle one field lower down, and that reasoning binds here too.\n */\n const causeErrorType = isWildoBackendError(error) ? error.type : undefined;\n const fetchFailureErrorType =\n causeErrorType === undefined\n // Not one of ours — a driver error, a TypeError. A server fault by definition, and\n // the one case where the old behavior was least defensible.\n ? ErrorType.INTERNAL\n : causeErrorType;\n const authError = this.errorBuilder.buildError(\n fetchFailureErrorType,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: {\n message: `Failed to fetch resource objects for authorization: ${describeCaughtError(error)}`,\n /**\n * The inner error's own CONTEXT, which this wrapper used to discard.\n *\n * `describeCaughtError` on a `WildoBackendError` yields its message REFERENCE and nothing\n * else, so a structural failure that carefully recorded which operation key was missing\n * arrived here as the bare string `repository_resource_operation_failed`. Every\n * investigation then had to re-run with a temporary log to learn a fact the error already\n * knew — the second time in one session that a swallowed cause cost a debugging cycle.\n *\n * Only the context is lifted, not the whole error: the OUTER shape stays a 404 with no\n * detail for the client (`sanitizeErrorForClient` strips `context`), so this is\n * diagnosability for the log, not disclosure to the caller.\n */\n cause: isWildoBackendError(error) ? error.context : undefined,\n }\n }\n );\n throw authError;\n }\n\n // 🔒 SECURITY / fail-closed: a resource-specific repository READ resolves to\n // `null` when the target row does not exist OR is invisible to the caller's\n // scope. The READ applies a contextual scope/ownership filter, so a\n // cross-scope id (e.g. another organization's todo) also comes back as `null`\n // rather than throwing — the try/catch above never fires for that case. Drop\n // every `null`/`undefined` entry BEFORE the count check so a missing /\n // scope-invisible target fails closed with a clean NOT_FOUND (404), which also\n // avoids leaking the existence of out-of-scope resources.\n //\n // Without this filter the single-id path produced `[null]` (array length 1),\n // which silently passed the length-based count check below\n // (`1 === idsArray.length`) and flowed into performPrimaryScopeAuthorization(),\n // where each per-scope authorizer dereferences `resourceObject.<scopeField>`\n // (e.g. `resourceObject['organizationId']`). That threw a raw `TypeError`\n // (\"Cannot read properties of null\"), which the error pipeline classifies as\n // ErrorType.INTERNAL (CRITICAL) → `logger.fatal()` + HTTP 500 — destabilizing\n // the backend under client retry/poll instead of returning a 404. Filtering at\n // this single choke point fixes it for ALL primary scopes at once, rather than\n // adding a defensive null-check inside every authorize* method.\n resourceObjects = (Array.isArray(resourceObjects) ? resourceObjects : []).filter(\n (resourceObject) => resourceObject !== null && resourceObject !== undefined,\n );\n\n // Check that we found all expected resources\n if (resourceObjects.length !== idsArray.length) {\n // A REFUSAL, recorded as one — even though it surfaces to the caller as 404. This is the\n // cross-tenant probe path: the row is absent OR invisible to this caller, and the two are\n // deliberately indistinguishable in the response so it cannot be used as an existence oracle.\n // The audit row is where the refusal becomes visible to a reviewer; the HTTP response is\n // unchanged. See ResourceOperationDenialReason.SUBJECT_NOT_RESOLVABLE for why a single such\n // row proves nothing and the aggregate is the signal.\n // assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.SUBJECT_NOT_RESOLVABLE, operation, executionContext, idsArray,\n );\n const error = this.errorBuilder.buildError(\n ErrorType.NOT_FOUND,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n }\n );\n throw error;\n }\n\n // Validate FK relationship access (e.g., /assigned-to-users/{userId}/todos/{todoId})\n // This ensures users can only access resources via FK paths they own\n await this.runAuthorizationPhase(\n () => this.validateFKRelationshipAccess(executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.FK_RELATIONSHIP_DENIED),\n operation, executionContext, idsArray,\n );\n\n // Perform authorization checks based on primary scope\n await this.runAuthorizationPhase(\n () => this.performPrimaryScopeAuthorization(resourceObjects, operation, executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.SCOPE_MISMATCH),\n operation, executionContext, idsArray,\n );\n\n // (The unit-narrowing decision was stamped at the TOP of this method — it must precede the\n // authorization pre-fetch, not merely the role gate below. See the comment there.)\n\n // Check that user has required roles to perform the operation\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext, idsArray,\n );\n\n this.logDebug('Authorization check completed successfully');\n }\n\n /**\n * Resolve the effective scope at runtime.\n * For isAnonymizable resources (primaryScope: USER_SELF), the effective scope\n * switches to ANONYMOUS when the caller is an anonymous session.\n */\n private resolveEffectiveScope(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): ResourcePrimaryScope {\n if (operation.resourcePrimaryScope === ResourcePrimaryScope.USER_SELF && executionContext.isAnonymousExecution()) {\n return ResourcePrimaryScope.ANONYMOUS;\n }\n return operation.resourcePrimaryScope;\n }\n\n /**\n * Perform authorization checks based on primary scope\n */\n private async performPrimaryScopeAuthorization(\n resourceObjects: any[],\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { resourceIdentifier } = operation;\n const { initiatorIds } = executionContext;\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n\n for (const resourceObject of resourceObjects) {\n switch (effectiveScope) {\n case ResourcePrimaryScope.USER_SELF:\n await this.authorizeUserSelf(resourceObject, resourceIdentifier, initiatorIds!, executionContext, operation);\n break;\n\n case ResourcePrimaryScope.ORGANIZATIONS:\n await this.authorizeOrganizations(resourceObject, resourceIdentifier, initiatorIds!, executionContext);\n break;\n\n case ResourcePrimaryScope.APPLICATION:\n await this.authorizeApplication(resourceObject, resourceIdentifier, initiatorIds!, executionContext);\n break;\n\n case ResourcePrimaryScope.ANONYMOUS:\n await this.authorizeAnonymous(resourceObject, executionContext);\n break;\n\n default:\n const error = this.errorBuilder.buildError(\n ErrorType.INTERNAL,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { message: `Unsupported primary scope: ${effectiveScope}` }\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize USER_SELF scope — the addressed row must belong to the caller, unless the operation\n * variant is explicitly admitted to administer another person.\n *\n * ## Why the admission exists\n *\n * `USERS` is a self-anchor scope root, so its `resourcePrimaryScope` IS `USER_SELF` and every\n * USERS operation lands here. Without an admission this check made the whole administrative\n * surface self-only: `assign_roles`, `revoke_roles`, `suspend_user`, `unsuspend_user`,\n * `force_password_reset`, the admin READ and the core UPDATE/DELETE all refused against another\n * user, contradicting both the resource specification and the admin UI that surfaces them as\n * per-row actions.\n *\n * ## Why it is per-VARIANT, and why that is not a technicality\n *\n * The two `users | read` variants need opposite answers: the DEFAULT is gated `APP_USER`, so\n * admitting it would let any authenticated user read any other user's row; the `admin` variant is\n * gated `APP_ADMIN_VIEWER` and is exactly the surface that should. A resource-level switch cannot\n * express that, and using one would have opened the wider hole while fixing the narrower one.\n *\n * The admission relaxes WHOSE row may be addressed, never WHO may call — the operation's `roles`\n * gate runs separately and unchanged. Mirrors {@link admitsCrossTenantPlatformAdministration}: an\n * explicit, enumerable, empty-by-default opt-in rather than a privilege-based bypass.\n */\n private async authorizeUserSelf(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>,\n operation?: { admitsCrossSubjectUserAdministration?: boolean; operationIdentifier?: unknown },\n ): Promise<void> {\n // Checked BEFORE either branch: the admission is a property of the OPERATION (\"this verb\n // administers another person\"), not of the shape of the row it happens to address, so it applies\n // equally to the user row itself and to a user-owned child resource.\n if (operation?.admitsCrossSubjectUserAdministration === true) {\n this.logDebug('Cross-subject user administration admitted', {\n operationIdentifier: String(operation.operationIdentifier),\n resourceIdentifier,\n });\n return;\n }\n\n if (resourceIdentifier === CoreResourceType.USERS || resourceIdentifier === CoreResourceType.USER_SELF) {\n // For user resources, check that the resource _id matches the initiator userId\n if (resourceObject._id !== initiatorIds.userId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n } else {\n // For other resources, check the related user field identifier\n const userFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.USERS];\n const userSelfFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.USER_SELF];\n\n const userIdFromResource = resourceObject[userFieldIdentifier] || resourceObject[userSelfFieldIdentifier];\n\n if (!userIdFromResource) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n\n if (userIdFromResource !== initiatorIds.userId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize ORGANIZATIONS scope\n */\n /**\n * Does this request carry a sanctioned platform-tier crossing of the tenant boundary?\n *\n * ## Why this is ONE method and not two checks\n *\n * Tenant isolation on an ORGANIZATIONS-scoped request is enforced at TWO independent gates that\n * run in different phases and read different inputs:\n *\n * - `validateParentScopeAccess` — does the caller hold an organization-WIDE role entry naming\n * this organization? (a ROLES question, asked before the row is fetched)\n * - `authorizeOrganizations` — does the fetched row actually belong to the caller's organization?\n * (a DATA question, asked after)\n *\n * A crossing has to be admitted at BOTH or it is admitted at neither, and the first version of\n * this feature (2026-08-05) opened only the first. One method, two call sites, so they cannot\n * drift.\n *\n * ## What this predicate does NOT buy you (measured over real HTTP, 2026-08-05)\n *\n * Per-instance org-scoped reach for a non-member platform super-administrator **already exists**\n * without any opt-in. `validateOperationRoles` deliberately skips ORGANIZATIONS-scope resources,\n * `validateParentScopeAccess` runs only on collection calls, and `authorizeOrganizations` compares\n * the fetched row's organization against a scope the SAME REQUEST supplied through its URL — so\n * the comparison is close to tautological on a resource route. What the flag genuinely adds is the\n * COLLECTION path (which does refuse today) plus an enumerable, audited declaration of intent.\n *\n * Do not read this predicate as the boundary. Whether a platform operator SHOULD be able to\n * administer any tenant is an open product decision; see\n * `.claude/rules/administrative-continuity-floors.md` and\n * `examples/wonder-todos/e2e/organization-ownership-grant-hostile.e2e.ts` probe F-1.\n *\n * Two conditions, both load-bearing: the OPERATION VARIANT must have opted in (never a blanket\n * super-admin bypass — that would dissolve tenant isolation for every operation a super-admin's\n * role chain satisfies), and the caller must hold `APP_ADMIN_SUPER_ADMIN` at APPLICATION scope\n * specifically.\n *\n * The APPLICATION-scope qualifier is DEFENCE IN DEPTH, not the first line, and the honest version\n * is worth stating: membership `roles` is a free-form string (`OrgRolesSchema` admits any string),\n * so a tenant admin CAN type `APP_ADMIN_SUPER_ADMIN` into their own row. What stops them today is\n * the independent operation-ROLES gate, which resolves an ORGANIZATIONS-scope entry against the\n * organization role table and finds no such key. Verified by mutation: deleting the qualifier\n * changes no current outcome. It stays because it is the only check that still holds if the two\n * role tables ever share a key, or if a future path reaches a gate without the roles gate running.\n *\n * assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — sanctioned, per-operation,\n * platform-tier crossing of a tenant boundary.\n */\n private async admitsCrossTenantPlatformAdministration(\n executionContext: ExecutionContext<any>,\n targetOrganizationId: string,\n ): Promise<boolean> {\n const operation = executionContext.operation as {\n admitsCrossTenantPlatformAdministration?: boolean;\n operationIdentifier?: unknown;\n } | undefined;\n if (operation?.admitsCrossTenantPlatformAdministration !== true) return false;\n\n const holdsPlatformAuthority = (executionContext.initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .filter(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.APPLICATION)\n .some(roleInfo => roleInfo.roles.some(\n heldRole => this.getRoleHierarchy(heldRole as Roles, ResourcePrimaryScope.APPLICATION)\n .includes(CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN),\n ));\n if (!holdsPlatformAuthority) return false;\n\n // ── The bootstrap exemption ────────────────────────────────────────────────────────────────\n // `requestAccess` is how an elevation comes into existence, so gating it on holding one would be\n // circular: an operator would need a grant in order to ask for a grant, and the mechanism could\n // never start. Narrow by construction — the verb writes one grant row in the target tenant and\n // touches nothing else, so the blast radius of an abused request is a notification, an audit row\n // naming the operator, and a decision the tenant can refuse.\n // `PlatformAccessGrants_Operations` deliberately lives in the grants VOCABULARY module, not its\n // resources-config module. Importing it from the config here pulled resource-configuration\n // evaluation into this file's module graph and broke decorator metadata elsewhere — see the note\n // on the enum. Do not \"tidy\" this import back to the config.\n if (String(operation.operationIdentifier ?? '') === PlatformAccessGrants_Operations.REQUEST_ACCESS) {\n return true;\n }\n\n // ── Zero standing privilege ───────────────────────────────────────────────────────────────\n // Holding `APP_ADMIN_SUPER_ADMIN` is no longer sufficient. Declaring the crossing per variant\n // removed AMBIENT authority; requiring a usable grant removes STANDING authority — the operator\n // must have asked for this tenant, been granted a window, and still be inside it. That is what\n // NIST SP 800-53 AC-2 / AC-6(1) and every zero-standing-privilege programme ask for, and what\n // Microsoft's JIT/JEA model implements internally.\n const usableGrant = await this.hasUsablePlatformAccessGrant(executionContext, targetOrganizationId);\n if (typeof usableGrant === 'string' && usableGrant) {\n // Stashed on the CONTEXT, not on the service: the authorizer is a singleton and a field here\n // would leak one request's grant onto another's audit row under concurrency.\n (executionContext as { authorizingPlatformAccessGrantId?: string }).authorizingPlatformAccessGrantId = usableGrant;\n }\n return Boolean(usableGrant);\n }\n\n /**\n * Is there a live elevation for this operator into this tenant?\n *\n * Read on a system context, because the caller is by definition not a member of the tenant whose\n * grants are being read — the resource's `systemAccessPolicy` allows exactly this and nothing else.\n *\n * **Fails CLOSED.** A read error, an unbound repository, a missing resource — every one answers\n * \"no elevation\". The alternative would let an operator restore standing access by breaking the\n * grant store, which is precisely the failure mode a fail-open control is criticised for.\n */\n /**\n * A system execution context for reading grants across tenant boundaries.\n *\n * Lazily resolved from the container, mirroring {@link resolveAuditLogsService}: this service is\n * constructed in contexts (unit suites, partial bindings) where the auth factory is not bound, and\n * a hard constructor dependency would make the authorizer unconstructible there. Returning\n * `undefined` fails the caller CLOSED, which is the correct direction for an admission check.\n */\n private async resolveSystemReadExecutionContext(): Promise<ExecutionContext<any> | undefined> {\n if (!this.container?.isBound?.(SAAS_SERVICE_TYPES.AuthExecutionContextFactory)) return undefined;\n const authEcFactory = this.container.get<AuthExecutionContextFactoryBackendService>(\n SAAS_SERVICE_TYPES.AuthExecutionContextFactory,\n );\n if (typeof authEcFactory?.createForSystemAuthOperation !== 'function') return undefined;\n return await authEcFactory.createForSystemAuthOperation(authEcFactory.getUsersReadOperationPath());\n }\n\n private async hasUsablePlatformAccessGrant(\n executionContext: ExecutionContext<any>,\n targetOrganizationId: string,\n ): Promise<string | boolean> {\n const operatorUserId = executionContext.initiatorIds?.userId;\n if (!operatorUserId || !targetOrganizationId) return false;\n // Returns the GRANT ID (truthy) rather than a bare `true` so the crossing event can name which\n // elevation authorised it. `true` remains possible only for a grant with no `_id`, which the\n // repository does not produce — the union keeps the caller's truthiness check honest either way.\n\n try {\n // `getRepository`, matching how the owner floor reaches its own collections. An earlier\n // revision called a method that does not exist and, because the call was optional-chained,\n // answered \"no grant\" for EVERY caller — a fail-closed bug that looks identical to correct\n // enforcement from the outside. If this ever refuses everything, check the accessor first.\n const repository = this.repositoriesRegistry?.getRepository?.(CoreResourceType.PLATFORM_ACCESS_GRANTS);\n if (!repository?.list) return false;\n\n // A SYSTEM context, not the caller's. The caller is by definition not a member of the tenant\n // whose grants are being read, so the repository's contextual filter would scope the query to\n // the OPERATOR's own organization and find nothing — the elevation would exist, be ACTIVE, and\n // never be seen. Caught by the e2e lane: the grant landed in the database and the crossing was\n // still refused. An earlier revision of this method documented the system context and then\n // passed `executionContext` anyway.\n const systemExecutionContext = await this.resolveSystemReadExecutionContext();\n if (!systemExecutionContext) return false;\n\n const grants = await repository.list<{ status: string; expiresAt: Date }>(systemExecutionContext, {\n organizationId: targetOrganizationId,\n operatorUserId,\n status: PlatformAccessGrantStatus.ACTIVE,\n } as never);\n\n // `isPlatformAccessGrantUsable` re-checks `expiresAt` rather than trusting the ACTIVE filter\n // above. The status is bookkeeping a sweeper maintains; the window is the control, and a grant\n // whose window elapsed must stop working whether or not anything has relabelled it yet.\n const now = new Date();\n const usable = (grants ?? []).find((grant) => isPlatformAccessGrantUsable(grant as never, now));\n return usable ? String((usable as { _id?: unknown })._id ?? '') || true : false;\n } catch {\n return false;\n }\n }\n\n /**\n * Does the caller hold an ORGANIZATION-WIDE role entry naming this exact organization?\n *\n * This is the \"is the caller actually in this tenant?\" question, and it is deliberately asked of\n * the caller's ROLE ENTRIES rather than of `initiatorIds`. On a resource route the URL segment\n * supplies `initiatorIds.organizationId`, so comparing a row against it compares the request with\n * itself. Role entries are the one input a request cannot author for itself.\n *\n * Organization-WIDE only. A unit-narrowed grant confers authority over a unit, not the tenant, and\n * every org-wide gate in this service filters it out — accepting one here would let a unit member\n * pass a tenant-level check.\n */\n private holdsOrganizationWideEntryFor(executionContext: ExecutionContext<any>, organizationId: string): boolean {\n return (executionContext.initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .some(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS\n && String(roleInfo.relatedResourceId ?? '') === organizationId);\n }\n\n /** The tenant a row belongs to: its own id for ORGANIZATIONS, its organization FK otherwise. */\n private resolveRowOrganizationId(resourceObject: any, resourceIdentifier: string): string {\n return resourceIdentifier === CoreResourceType.ORGANIZATIONS\n ? String(resourceObject?._id ?? '')\n : String(resourceObject?.[coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS]] ?? '');\n }\n\n /**\n * Emit {@link CoreAuditableEventType.CROSS_TENANT_ADMINISTRATIVE_ACCESS} when the caller holds no\n * organization-wide role entry for the row's tenant.\n *\n * ## Why membership is measured from role entries\n *\n * `authorizeOrganizations` compares the fetched row's organization against `initiatorIds`, and on\n * a resource route BOTH sides derive from the same request — the URL segment supplies the scope, so\n * the check is close to tautological and a non-member operator passes it in silence. Role entries\n * are the one input the request cannot author for itself, so they are what \"is this caller\n * actually in this tenant?\" has to be asked against.\n *\n * Only ORGANIZATION-WIDE entries count. A unit-narrowed grant confers authority over a unit, not\n * the tenant, and every org-wide gate filters it out — counting one here would classify a genuine\n * cross-tenant reach as ordinary membership and silence the event.\n *\n * Fire-and-forget by construction: no `await`, and the promise's rejection is swallowed. An\n * operator's request must not fail because the audit sink is down, and a fail-closed variant would\n * hand anyone a way to disable operator support by breaking the sink.\n *\n * assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION\n */\n private recordCrossTenantAdministrativeAccess(\n resourceObject: any,\n resourceIdentifier: string,\n executionContext: ExecutionContext<any>,\n ): void {\n const operation = executionContext.operation as {\n operationIdentifier?: unknown;\n variantType?: ResourceOperationVariantType;\n variantKey?: string;\n admitsCrossTenantPlatformAdministration?: boolean;\n } | undefined;\n if (!operation) return;\n\n const rowOrganizationId = this.resolveRowOrganizationId(resourceObject, resourceIdentifier);\n if (!rowOrganizationId) return;\n\n const initiatorRoles = executionContext.initiatorRoles ?? [];\n if (this.holdsOrganizationWideEntryFor(executionContext, rowOrganizationId)) return;\n\n const auditLogsService = this.resolveAuditLogsService();\n // Feature-DETECTED, not merely null-checked. Adding a `log*` method to `AuditLogsBackendService`\n // is a known way to break every partially-mocked test double in this repo: the property is\n // absent, so the CALL throws a TypeError synchronously — before any `.catch()` can make it\n // fire-and-forget. It is not a test-only concern either; a host binding an older audit service\n // takes the same throw. An observer must never be able to fail the request it observes.\n if (typeof auditLogsService?.logCrossTenantAdministrativeAccess !== 'function') return;\n\n try {\n void auditLogsService.logCrossTenantAdministrativeAccess({\n operatorUserId: executionContext.initiatorIds?.userId,\n targetOrganizationId: rowOrganizationId,\n resourceType: resourceIdentifier,\n operationIdentifier: String(operation.operationIdentifier ?? ''),\n variantType: operation.variantType as ResourceOperationVariantType,\n variantKey: operation.variantKey,\n targetResourceIds: resourceObject?._id ? [String(resourceObject._id)] : undefined,\n authorizingGrantId: (executionContext as { authorizingPlatformAccessGrantId?: string }).authorizingPlatformAccessGrantId,\n admissionDeclared: operation.admitsCrossTenantPlatformAdministration === true,\n initiatorRoles: initiatorRoles.flatMap(roleInfo => roleInfo.roles ?? []),\n executionType: executionContext.executionType,\n })?.catch?.(() => undefined);\n } catch {\n // Deliberately swallowed — see the feature-detection note above.\n }\n }\n\n /**\n * Refuse a per-instance tenant-boundary denial in a way that is INDISTINGUISHABLE from a row that\n * does not exist.\n *\n * ## Why 404 and not 403 (RFC 9110 §15.5.4, and an internal inconsistency)\n *\n * Every branch below is reached only AFTER the authorization pre-fetch resolved a row — so answering\n * 403 here while a missing row answers 404 turns the STATUS into an existence oracle: an admin of any\n * tenant can probe ids against another tenant and learn which are real, without ever reading one.\n * Leaked ids (URLs, exports, logs, a former employee's notes) then become a census.\n *\n * RFC 9110 §15.5.4 sanctions the fix explicitly — an origin server \"that wishes to 'hide' the current\n * existence of a forbidden target resource MAY instead respond with a status code of 404\". It is also\n * what OWASP's object-level-authorization guidance asks for, and what the well-known practitioner\n * example does: a private repository answers 404 to a non-member rather than confirming it exists.\n *\n * The internal argument is the stronger one. Confinement WITHIN a tenant (organization-unit\n * narrowing) already answers 404 for a row in another unit, because the row filter simply does not\n * match it. So before this change the TENANT boundary — the stronger of the two — disclosed more than\n * the unit boundary inside it. That is backwards, and no reading of the model justifies it.\n *\n * ## What is deliberately NOT folded into this\n *\n * A caller who is INSIDE the row's tenant and merely lacks the operation's role still gets **403**\n * from the role gate. That denial is about the CALLER, discloses nothing (the answer does not depend\n * on any row existing), and collapsing it into 404 would send an operator hunting for a record that\n * is sitting right there. The split this class maintains is: *about the caller* → 403; *about reach*\n * → 404, indistinguishable from absent.\n *\n * The refusal stays fully visible internally: `recordCrossTenantAdministrativeAccess` has already\n * emitted the operator-access audit event by the time this is called, and the `reason` below travels\n * to the logs. `sanitizeErrorForClient` strips `context` for `NOT_FOUND`, so none of it reaches the\n * prober — which is the whole point.\n */\n private buildTenantBoundaryNotFound(\n executionContext: ExecutionContext<any>,\n resourceIdentifier: string,\n reason: string,\n ) {\n return this.errorBuilder.buildError(ErrorType.NOT_FOUND, executionContext, {\n // Must match the missing-row refusal exactly (the `resourceObjects.length !== idsArray.length`\n // path): a different `customMessageReference` would restore the oracle one field lower down.\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { reason, resourceIdentifier },\n });\n }\n\n private async authorizeOrganizations(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n // ── The DATA half of the tenant boundary ────────────────────────────────────────────────────\n //\n // Order matters here and is easy to get wrong: OBSERVE, then ADMIT, then GATE.\n //\n // The observation must come first because a DECLARED crossing is still a platform operator\n // reaching into a customer's tenant, and that is exactly the access an operator-access trail\n // exists to show. An earlier arrangement admitted first and returned, so the sanctioned\n // crossings — the ones a reviewer most wants to see — were the only ones never recorded.\n const rowOrganizationId = this.resolveRowOrganizationId(resourceObject, resourceIdentifier);\n const callerIsInRowTenant = !rowOrganizationId\n || this.holdsOrganizationWideEntryFor(executionContext, rowOrganizationId);\n\n // The admission is RESOLVED first, then observed, then acted on. Order matters three ways and the\n // middle one is easy to lose:\n // - resolving first is what lets the observation name the authorizing grant (the predicate\n // stashes it on the context); observing first recorded every crossing with a blank grant id;\n // - observing before the early return is what keeps SANCTIONED crossings in the trail — they are\n // the ones a reviewer most wants to see, and an earlier arrangement returned before recording;\n // - gating last means an undeclared crossing is recorded AND refused, not silently dropped.\n const crossingIsAdmitted = await this.admitsCrossTenantPlatformAdministration(executionContext, rowOrganizationId);\n\n if (!callerIsInRowTenant) {\n this.recordCrossTenantAdministrativeAccess(resourceObject, resourceIdentifier, executionContext);\n }\n\n // A sanctioned platform-tier crossing is admitted here as well as at `validateParentScopeAccess`\n // — that gate runs only on COLLECTION calls, so admitting at one alone produces a door that works\n // for `list` and 403s for `read`, or the reverse.\n if (crossingIsAdmitted) {\n this.logDebug('Cross-tenant platform administration admitted (resource-object gate)', {\n resourceIdentifier,\n resourceId: String(resourceObject?._id ?? ''),\n });\n return;\n }\n\n // ── Deny-by-default: an undeclared crossing fails closed ─────────────────────────────────────\n //\n // Platform-operator reach into a tenant is an INTENDED capability here (see\n // `.claude/rules/administrative-continuity-floors.md`). What is not intended is reach acquired by\n // POSITION IN THE REQUEST PATH rather than by declaration — ambient authority, and in effect a\n // standing privilege held permanently by every platform administrator over every tenant.\n //\n // The comparisons below cannot see it: on a resource route the URL segment supplies\n // `initiatorIds.organizationId`, so they compare the request against itself and a non-member\n // passes silently. Asking the caller's ROLE ENTRIES is what closes that, and it mirrors what\n // `validateParentScopeAccess` already demands of COLLECTION calls — the asymmetry between the two\n // was the defect, not a design.\n //\n // An operator who needs a crossing gets it the way `grantOwnership` did: a variant declaring\n // `admitsCrossTenantPlatformAdministration`, reviewed, specified and audited. There is\n // deliberately NO runtime bypass — a header or config toggle would reintroduce the standing\n // privilege this removes, which is what NIST SP 800-53 AC-2 warns against.\n //\n // assurance-control: WILDO.ACCESS.CROSS_TENANT_ADMINISTRATION — undeclared crossings fail closed.\n if (!callerIsInRowTenant) {\n // Answered as NOT-FOUND rather than FORBIDDEN. Hiding the `reason` (which this comment used to\n // describe on its own) is necessary but not sufficient: the STATUS discriminated existence just\n // as well. See `buildTenantBoundaryNotFound`.\n throw this.buildTenantBoundaryNotFound(\n executionContext, resourceIdentifier, 'cross_tenant_access_not_declared_by_operation_variant',\n );\n }\n\n if (resourceIdentifier === CoreResourceType.ORGANIZATIONS) {\n // For organization resources, check that the resource _id matches the initiator organizationId\n if (resourceObject._id !== initiatorIds.organizationId) {\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'organization_row_is_another_tenant');\n }\n } else {\n // For other resources, check the related organization field identifier\n const orgFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS];\n\n const orgIdFromResource = resourceObject[orgFieldIdentifier];\n\n if (!orgIdFromResource) {\n // A row with no tenant anchor is unattributable, so it is unreachable rather than forbidden —\n // and answering it identically keeps every refusal this method emits on one shape. A branch\n // left at 403 would restore the oracle for exactly the rows whose shape is already broken.\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'row_carries_no_tenant_anchor');\n }\n\n if (orgIdFromResource !== initiatorIds.organizationId) {\n throw this.buildTenantBoundaryNotFound(executionContext, resourceIdentifier, 'row_belongs_to_another_tenant');\n }\n }\n }\n\n /**\n * Does this resource DERIVE tenant-anchorless rows rather than store rows under the application?\n *\n * An INTROSPECTION resource declaring {@link IntrospectionTenancyStance.APPLICATION_STRUCTURE} or\n * {@link IntrospectionTenancyStance.APPLICATION_RUNTIME} has no per-row application anchor, and\n * that is its contract rather than an omission: its rows are DERIVED per read (from a companion\n * behavior over the application's source, or from the companion's own runtime services), there is\n * no store to hold a foreign key, and both stances say outright that there is no tenant dimension\n * for a scope predicate to filter on. What separates the two stances is the READ POSTURE\n * (structure may be `APP_PUBLIC`; runtime must be role-gated), which is the operation variants'\n * job and ran before this method — not the anchor question answered here.\n *\n * Fails CLOSED in both directions that matter. With no registry bound the answer is `false`, so\n * the anchor check below still runs; and the stance must be one of the two enumerated anchorless\n * members, so an introspection resource that projects anything else — including a future scoped\n * stance — keeps the check.\n */\n private projectsAnchorlessIntrospection(resourceIdentifier: string): boolean {\n const configuration = this.resourcesRegistry?.tryGetResourceConfiguration(resourceIdentifier);\n const tenancy = configuration?.introspectionBinding?.tenancy;\n return configuration?.persistenceAdapter === PersistenceAdapter.INTROSPECTION\n && (tenancy === IntrospectionTenancyStance.APPLICATION_STRUCTURE\n || tenancy === IntrospectionTenancyStance.APPLICATION_RUNTIME);\n }\n\n /**\n * Authorize APPLICATION scope\n *\n * ## What the per-row anchor check does, and what it cannot do\n *\n * The application is a SINGLETON per database — `ExecutionContextCreator.getApplicationId()` reads\n * the APPLICATION row with an empty filter, on the stated grounds that \"there is one APPLICATION\n * row, so nothing can usefully narrow this read\". So `appIdFromResource !== applicationId` cannot\n * discriminate between applications within a database: both sides resolve to the same row. It is a\n * consistency assertion about correctly-populated rows, not a cross-application isolation control.\n *\n * The `!appIdFromResource` branch is the one with teeth, and for a STORED resource it is right —\n * every `APPLICATION`-anchored resource in the engine declares\n * `parentFieldIdentifier: coreResourceShared_FieldIdentifier[CoreResourceType.APPLICATION]`, so its\n * rows carry the FK and a row without one is malformed.\n *\n * A projection cannot satisfy it at all, which is why the stance is consulted first. Measured\n * before the carve-out existed: an addressed READ on `workbenchApplicationModules` answered 200 to\n * an anonymous caller (the public-execution path returns before this method) and 403 to an\n * authenticated one, while LIST answered 200 to both (collection operations run no row check). The\n * resource could not be fixed from the application side without inventing a field its schema does\n * not declare.\n */\n private async authorizeApplication(\n resourceObject: any,\n resourceIdentifier: string,\n initiatorIds: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n /*\n * Read as: this resource's rows ARE the application, so there is no row-level membership left to\n * check. Deliberately NOT an opt-out flag an operation can declare — a stored resource that\n * simply forgot its FK must keep failing, and only a declared tenancy stance can tell the two\n * apart. Nothing else is relaxed: the operation's `roles` gate ran before this, and the\n * repository's contextual filter runs underneath.\n */\n if (this.projectsAnchorlessIntrospection(resourceIdentifier)) {\n this.logDebug('Anchorless introspection projection — no per-row anchor to authorize', { resourceIdentifier });\n return;\n }\n\n if (resourceIdentifier === CoreResourceType.APPLICATION) {\n // For application resources, check that the resource _id matches the initiator applicationId\n if (resourceObject._id !== initiatorIds.applicationId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n } else {\n // For other resources, check the related application field identifier\n const appFieldIdentifier = coreResourceShared_FieldIdentifier[CoreResourceType.APPLICATION];\n\n const appIdFromResource = resourceObject[appFieldIdentifier];\n\n if (!appIdFromResource) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n\n if (appIdFromResource !== initiatorIds.applicationId) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n }\n\n /**\n * Authorize ANONYMOUS scope — ownership check via anonymousUserId.\n * For AnonymousUser resources, _id IS the anonymousUserId.\n * For isAnonymizable resources, the anonymousUserId field carries ownership.\n */\n private async authorizeAnonymous(\n resourceObject: any,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const anonymousUserId = executionContext.anonymousUserId;\n const resourceAnonymousId = resourceObject.anonymousUserId ?? resourceObject._id;\n\n if (resourceAnonymousId !== anonymousUserId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n });\n }\n }\n\n /**\n * Validate that the user has required roles to perform the operation\n */\n private async validateOperationRoles(\n operationRoles: string[],\n executionContext: ExecutionContext<any>,\n /**\n * The resource whose narrowing stamp may admit a unit-scoped caller. Optional because two callers\n * reach this gate for scopes where narrowing cannot apply; omitting it simply means no unit grant\n * can rescue a failing role check, which is the fail-closed direction.\n */\n narrowableResourceIdentifier?: string,\n ): Promise<void> {\n const { initiatorRoles } = executionContext;\n\n /*\n * A PUBLICLY-DECLARED operation imposes no positive role requirement — on ANY caller.\n *\n * This is the ROLE half of `APP_PUBLIC`, and it is separate from the public-EXECUTION carve-out\n * at the top of `authorizeInRepositoryAndService`. That one answers \"there is no principal to\n * authorize\"; this one answers \"there is a principal, and the operation asks nothing of them\".\n * Both are needed, and having only the first is what produced the defect this closes: an\n * anonymous probe was admitted by the carve-out while the SAME request carrying a valid token\n * fell through to here and was refused, because `APP_PUBLIC` is in nobody's granted role set.\n *\n * Placed BEFORE the org-wide grant computation deliberately. A public declaration is a statement\n * about the OPERATION, so it cannot depend on which grants the caller happens to hold, on the\n * scope those grants resolve against, or on whether a unit-narrowing stamp exists — every one of\n * which is an input the computation below reads and none of which can change the answer.\n *\n * It relaxes the ROLE question only. `validateParentScopeAccess`, `validateFKRelationshipAccess`\n * and the repository's contextual filter all still run, so a public declaration never widens\n * WHICH ROWS a caller reaches — only whether they may ask.\n */\n if (requiredRolesDeclarePublicAccess(operationRoles)) {\n this.logDebug('Operation declares APP_PUBLIC — no positive role requirement for any caller', { operationRoles });\n return;\n }\n\n // ORGANIZATION-WIDE GRANTS ONLY in this computation. A unit-scoped entry (`organizationUnitId`\n // present) confers authority inside ONE organization unit, so it must not satisfy an operation\n // gate that asks an organization-wide question — otherwise \"ORG_MANAGER of Sales\" would pass every\n // ORG_MANAGER gate in the tenant, which is a privilege escalation rather than a narrowing.\n //\n // A unit grant can still ADMIT, but only through the separate, narrower door below: the stamped\n // narrowing decision, which exists only for resources that explicitly opted in (D-C1/D-C3) and\n // which the repository then uses to confine the rows. Keeping the two apart is the point — this\n // computation must never learn about units.\n const organizationWideRoleInfos = initiatorRoles!.filter(isOrganizationWideRoleInfo);\n\n // Check if user has any of the required roles (considering role hierarchy)\n const userRoles = organizationWideRoleInfos.flatMap(roleInfo => roleInfo.roles);\n\n const hasRequiredRole = operationRoles.some(requiredRole => {\n // Check if user has this role directly or inherits it through hierarchy\n return userRoles.some(userRole => {\n // Determine scope based on role context — resolved against the org-wide entries only, so a\n // unit-scoped duplicate of the same role string can never supply the scope here either.\n const roleInfo = organizationWideRoleInfos.find(r => r.roles.includes(userRole));\n if (!roleInfo) return false;\n\n const scope = roleInfo.relatedPrimaryScope;\n\n // Get the full hierarchy of the user's role\n const hierarchy = this.getRoleHierarchy(userRole, scope);\n\n // Check if the required role is in the hierarchy\n return hierarchy.includes(requiredRole);\n });\n });\n\n // WS-C ADDITIVE admission (D-C3b): no organization-wide grant satisfies the operation, but the\n // narrowing decision found a UNIT grant that does, on a resource that opted into narrowing. Admit\n // — the repository then confines this caller to exactly those units from the same stamped\n // decision. Reached only after the org-wide check has failed, so a unit grant can never widen what\n // an organization-wide grant already conferred; it only rescues a caller who would be denied.\n if (!hasRequiredRole && narrowableResourceIdentifier && this.isAdmittedByUnitScopedGrant(executionContext, narrowableResourceIdentifier)) {\n this.logDebug('Admitted by unit-scoped grant', { resourceIdentifier: narrowableResourceIdentifier, operationRoles });\n return;\n }\n\n if (!hasRequiredRole) {\n const error = this.errorBuilder.buildError(\n ErrorType.AUTHORIZATION,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n }\n );\n throw error;\n }\n }\n\n /**\n * Lazy getter for {@link AuditLogsBackendService} — see the `container` constructor param's JSDoc\n * for why this cannot be a constructor injection.\n */\n private resolveAuditLogsService(): AuditLogsBackendService | undefined {\n if (!this.container?.isBound(SAAS_SERVICE_TYPES.AuditLogsService)) return undefined;\n return this.container.get<AuditLogsBackendService>(SAAS_SERVICE_TYPES.AuditLogsService);\n }\n\n /**\n * Record a refusal as a `RESOURCE_OPERATION_DENIED` audit event.\n *\n * ## Why this lives at the funnel rather than at the ~30 throw sites\n *\n * Every public entry point of THIS class converges on the same two phase runners:\n * `authorizeInController` reaches them directly, `authorizeInProgrammaticSurface` shares\n * `authorizeCollectionOperation` with it, and `authorizeInRepositoryAndService` has exactly one\n * caller — `authorizeInController` itself. Instrumenting the two inner phase runners therefore\n * observes every refusal THIS AUTHORIZER MAKES, INCLUDING refusals added later by other work: a\n * new gate that throws inside these methods is audited the day it lands, with no author having to\n * remember this mechanism exists. Instrumenting individual throw sites would have made every\n * future gate a silent omission waiting to happen — the exact failure mode that left 19 event\n * types declared and emitted by nothing.\n *\n * ## What this does NOT claim — corrected 2026-08-27\n *\n * An earlier revision said `authorizeInController` \"is the sole production entry point for every\n * execution surface\". That is false, and it was load-bearing prose: it reads as a guarantee that\n * every execution surface passes the role gate, which is exactly the belief the service tier\n * disproves. A programmatic operation (`ServicesRegistryHandlerBackendService.read` / `list` /\n * `create` / …) enters at the SERVICE tier and reaches no authorizer at all — by design, see\n * {@link authorizeInProgrammaticSurface}. So the correct reading is narrower and still sufficient\n * for this mechanism's purpose: **within this class**, no refusal escapes the funnel. It says\n * nothing about surfaces that never ask.\n *\n * ## Never affects the outcome\n *\n * Every path here is swallowed. The caller has already been correctly refused; an audit-store\n * problem must not convert that clean refusal into a 500. Detection of a lost row is the audit\n * pipeline's own control (`audit_store_failure_total`), not this gate's.\n *\n * assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT — the negative access decision is\n * recorded, attributable, and carries the authority context needed to review it.\n */\n private async emitAuthorizationDenialAudit(\n denialReason: ResourceOperationDenialReason,\n operation: ResourceConfiguration_Operation<any, any, any> | undefined,\n executionContext: ExecutionContext<any>,\n attemptedResourceIds?: string[],\n ): Promise<void> {\n const auditLogsService = this.resolveAuditLogsService();\n if (!auditLogsService || !operation) return;\n\n // Defence-in-depth against an emission loop. Structurally unreachable today — the audit write\n // runs as a REPOSITORY_ONLY super-admin context and repository writes do not route through this\n // authorizer — but a refusal that tried to audit itself would recurse without bound, and this\n // subsystem already carries a documented recursion hazard of exactly that shape (a per-org SIEM\n // dispatch's own config load is a system read that re-enters the audit path). Stateless and\n // concurrency-safe, unlike an in-flight instance flag.\n if (operation.resourceIdentifier === CoreResourceType.AUDIT_LOGS) return;\n\n try {\n const principalUserId = executionContext.initiatorIds?.userId;\n\n const decision = await resolveDenialAuditEmissionDecision(\n { redisService: this.redisService, logger: this.logger },\n {\n principalUserId,\n organizationId: executionContext.initiatorIds?.organizationId,\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n denialReason,\n },\n );\n\n if (!decision.shouldEmit) return;\n\n await auditLogsService.logResourceOperationDenied({\n riskLevel: operation.riskLevel ?? ResourceOperationRiskLevel.LOW,\n actorUserId: principalUserId,\n organizationId: executionContext.initiatorIds?.organizationId,\n applicationId: executionContext.initiatorIds?.applicationId,\n\n denialReason,\n\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantType: operation.variantType,\n variantKey: operation.variantKey,\n resourceOperationLike: operation.resourceOperationLike,\n // `isBulkOperation` is NOT on every member of the operation-variant union (a cron-job\n // variant has no bulk notion), so it must be narrowed before reading — the union-read trap\n // `audit-operation-variants` exists to catch. `in` is the pattern the resource-config\n // factory already uses for this exact field.\n isBulkOperation: 'isBulkOperation' in operation ? operation.isBulkOperation : undefined,\n\n attemptedResourceIds: attemptedResourceIds?.length ? attemptedResourceIds : undefined,\n\n requiredRoles: operation.roles?.length ? operation.roles.map(String) : undefined,\n // Roles AS THEY WERE at decision time. Empty (not absent) when the refusal WAS their\n // absence — `initiatorRoles` is null on the MISSING_INITIATOR path by definition.\n initiatorRoles: (executionContext.initiatorRoles ?? []).flatMap(r => r.roles.map(String)),\n executionType: executionContext.executionType,\n machineCredentialAuthMethod: executionContext.initiatorIds?.machineCredential?.authMethod,\n machineCredentialId: executionContext.initiatorIds?.machineCredential?.credentialId,\n\n subCallDepth: executionContext.subCallDepth,\n\n occurrenceCount: decision.occurrenceCount,\n occurrenceCountIsExact: decision.occurrenceCountIsExact,\n }, executionContext);\n } catch (error) {\n this.logger.warn('Failed to emit the authorization-denial audit event', {\n resourceType: String(operation.resourceIdentifier),\n operationIdentifier: String(operation.operationIdentifier),\n variantKey: operation.variantKey,\n denialReason,\n ...projectCaughtErrorLogFields(error),\n });\n }\n }\n\n /**\n * Run one authorization phase, recording a refusal if it throws.\n *\n * Re-throws unchanged: the audit trail is a side effect of the refusal, never a modifier of it.\n * `reasonFor` maps the caught error to a denial reason, so a phase that can fail two ways (the\n * resource-specific runner refuses on both scope and roles) still records which one occurred.\n */\n private async runAuthorizationPhase(\n phase: () => Promise<void>,\n reasonFor: (error: unknown) => ResourceOperationDenialReason | undefined,\n operation: ResourceConfiguration_Operation<any, any, any> | undefined,\n executionContext: ExecutionContext<any>,\n attemptedResourceIds?: string[],\n ): Promise<void> {\n try {\n await phase();\n } catch (error) {\n const denialReason = reasonFor(error);\n if (denialReason) {\n await this.emitAuthorizationDenialAudit(denialReason, operation, executionContext, attemptedResourceIds);\n }\n throw error;\n }\n }\n\n /**\n * Authorize a controller operation\n *\n * @param id_or_ids - Resource ID(s) for resource-specific operations, or undefined for collection operations\n * @param executionContext - The execution context containing operation and initiator info\n *\n * For collection operations (LIST, CREATE, SEARCH, COUNT):\n * - id_or_ids is undefined\n * - Authorization is based on roles and parent scope (via initiatorIds)\n *\n * For resource-specific operations (READ, UPDATE, DELETE):\n * - id_or_ids must be a valid string or array\n * - Authorization additionally verifies access to the specific resource(s)\n */\n /**\n * Authorize an operation on ROLES ALONE, with no row to fetch.\n *\n * ## Why this exists, and why it is deliberately narrow\n *\n * Every other entry point here authorizes an operation against ROWS — it pre-fetches them, checks\n * scope, checks FK reachability, then checks roles. That is right whenever there is a row.\n *\n * A WebSocket SCOPE subscription has none. It says \"tell me when anything of this type changes\n * under this scope\", which addresses no instance, so the row-shaped questions have no subject and\n * only the role question remains. Passing a scope id in the row's place is the trap this avoids:\n * it would authorize a READ of a row of the subscribed type whose id happens to be an application\n * id, which is not a question anyone asked and which fails for the wrong reason.\n *\n * **This is strictly WEAKER than `authorizeInController` and must never be substituted for it on a\n * path that has an id.** It answers \"may this principal invoke this operation at all\", not \"may\n * this principal reach this row\". Its only caller is the scope-subscription gate, where the\n * notification it admits carries row identities the caller could have listed anyway.\n *\n * Unit narrowing still applies: `resourceIdentifier` is forwarded, so a unit-scoped grant can\n * rescue a failing role check exactly as it does everywhere else.\n */\n public async authorizeOperationRolesOnly(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<void> {\n const { roles: operationRoles, resourceIdentifier } = operation;\n await this.validateOperationRoles(operationRoles, executionContext, resourceIdentifier);\n }\n\n public async authorizeInController(id_or_ids: string | string[] | undefined, executionContext: ExecutionContext<any>): Promise<void> {\n // Extract operation from execution context\n const operation = executionContext.operation;\n\n if (!operation) {\n const error = this.errorBuilder.buildError(\n ErrorType.INTERNAL,\n executionContext,\n {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_NO_OPERATION_CONTEXT,\n context: { message: 'No operation found in execution context for controller authorization' }\n }\n );\n throw error;\n }\n\n const isCollectionOperation = (id_or_ids === undefined);\n\n this.logDebug('Starting controller authorization check', {\n resourceIdentifier: operation.resourceIdentifier,\n operationIdentifier: operation.operationIdentifier,\n variantType: operation.variantType,\n resourcePrimaryScope: operation.resourcePrimaryScope,\n operationRoles: operation.roles,\n idOrIds: id_or_ids,\n isCollectionOperation,\n initiatorIds: executionContext.initiatorIds,\n initiatorRoles: executionContext.initiatorRoles?.map(r => ({ roles: r.roles, scope: r.relatedPrimaryScope }))\n });\n\n if (isCollectionOperation) {\n // For collection operations: validate roles and parent scope only\n await this.authorizeCollectionOperation(operation as ResourceConfiguration_Operation<any, any, any>, executionContext);\n } else {\n // For resource-specific operations: full authorization with resource access check\n await this.authorizeInRepositoryAndService(id_or_ids, operation as ResourceConfiguration_Operation<any, any, any>, executionContext);\n }\n\n this.logDebug('Controller authorization check completed successfully');\n }\n\n /**\n * Authorize a NON-CONTROLLER surface that will itself perform row-scoped reads.\n *\n * The ROW-INDEPENDENT half of an authorization decision — FK-path access, parent-scope access and\n * the operation's ROLE gate, evaluated for a (caller, resource type, operation) triple with no row\n * in hand. Delegates to the same {@link authorizeCollectionOperation} the controller tier uses for\n * LIST / SEARCH / COUNT / CREATE, so there is exactly ONE implementation of this predicate.\n *\n * ═══════════════════════════════════════════════════════════════════════════════════════════════\n * ## THE LAYERING DECISION THIS METHOD EXISTS INSIDE — settled 2026-08-27\n * ═══════════════════════════════════════════════════════════════════════════════════════════════\n *\n * **The role ACL is a CONTROLLER-tier gate, and that is deliberate — not an oversight.** The\n * service tier (`ServicesRegistryHandlerBackendService.read` / `list` / `create` / …) applies the\n * repositories' contextual filter and the retention row-hide, and applies NO role check. That was\n * measured rather than assumed, and the measurement is what settles it: of the ~97 service-tier\n * read call sites in the engine, the dominant population is authentication (registration, OAuth /\n * SAML identity-link resolution, credential lookup, token issuance), SCIM provisioning, billing\n * webhook routing, invitation sweeps and feature resolution. **Those run BEFORE a role-bearing\n * principal exists**, or on an internal context that has no business asserting one. Enforcing the\n * operation's declared roles there would deny the reads that ESTABLISH identity — it would break\n * logging in.\n *\n * So the tiers carry different invariants, and both are unconditional at their own tier:\n *\n * | tier | invariant it enforces | enforced by |\n * |---|---|---|\n * | repository | TENANCY + retention visibility — fail-closed, no opt-out | `buildContextualFilter` |\n * | service | the operation PIPELINE (Zod, hooks, custom impl) | `doOperation` |\n * | controller | the caller's ROLES may perform this operation | `authorizeInController` |\n *\n * The service tier is INSIDE the trust boundary: it is reached only by code the framework itself\n * wrote, with a context that code chose. The controller tier is the boundary, because that is where\n * an untrusted principal names an operation.\n *\n * ## When a programmatic surface must nevertheless ask — and why per-hit is the wrong shape\n *\n * The decision above holds while a programmatic read serves the FRAMEWORK. It stops holding the\n * moment a service-tier surface becomes an EXTERNAL read surface: one that takes a caller-supplied\n * query and returns row CONTENT to that caller on their own authority. RAG retrieval\n * (`RagRetrievalBackendService`) is the first, and it is what this method was built for.\n *\n * Such a surface must ask the role question, and it should ask it **once per resource type, before\n * it goes looking** — not once per candidate row. Three reasons, and the first is the one that\n * makes the other two follow:\n *\n * 1. **The role gate is row-INDEPENDENT.** {@link validateOperationRoles} is a function of the\n * caller's grants and the operation's declared roles. Asking it per row asks the same question\n * N times and can only ever get the same answer.\n * 2. **A pre-search refusal has no side channel.** Refusing the type before the search means its\n * rows never enter the candidate pool, so result counts and ranks carry no information about\n * them. A per-row refusal AFTER a search under-fills the caller's `limit`, which is the exact\n * existence side channel a fail-closed pre-filter exists to close.\n * 3. **It costs no rows and no audit storm.** {@link authorizeInRepositoryAndService} pre-FETCHES\n * its target to authorize it, so a per-hit gate would double every hit's I/O; and a refusal\n * emits `RESOURCE_OPERATION_DENIED`, so a query over a partly-invisible corpus would record one\n * denial per dropped row. This path has no pre-fetch and refuses once.\n *\n * ## What it deliberately does NOT do\n *\n * It does not authorize a specific ROW. Nothing here looks at data, so a caller admitted by this\n * gate has been admitted to the resource TYPE only; every row they then reach must still be reached\n * through a read that carries the contextual filter. It is a NECESSARY condition, never a\n * sufficient one — a surface that used it INSTEAD of an authorized read would have replaced a row\n * check with a type check.\n *\n * Nor is it a general licence to re-plumb role enforcement into the service tier. The population in\n * the table above is why that would break authentication; this door is for surfaces that face an\n * external caller, and adding one is a decision to be argued at the surface, not a default.\n *\n * @param operation - The operation whose declared roles gate the resource type. For a read surface\n * this is the target resource's own READ operation.\n * @param executionContext - The caller's authority. Pass a `createForSubCall` context built for\n * `operation`'s resource, never the caller's raw context: the parent-scope and\n * FK phases read `relationshipContexts`, which on a raw context belong to a\n * DIFFERENT resource and would be validated against the wrong resource's keys.\n *\n * assurance-control: WILDO.ACCESS.LEAST_PRIVILEGE — a non-controller surface that faces an external\n * caller applies the same operation-role gate the controller tier applies, through the same\n * predicate, and its refusal is recorded by the same funnel.\n */\n public async authorizeInProgrammaticSurface(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>,\n ): Promise<void> {\n this.logDebug('Starting programmatic-surface authorization check', {\n resourceIdentifier: operation.resourceIdentifier,\n operationIdentifier: operation.operationIdentifier,\n operationRoles: operation.roles,\n subCallDepth: executionContext.subCallDepth,\n });\n\n await this.authorizeCollectionOperation(operation, executionContext);\n }\n\n /**\n * Authorize a collection operation (LIST, CREATE, SEARCH, COUNT)\n *\n * For collection operations, we don't have specific resource IDs to check.\n * Authorization is based on:\n * 1. Role validation - user must have required roles for the operation\n * 2. Parent scope validation - user must have access to the parent scope (e.g., organization)\n * This is validated through initiatorIds matching the context resource IDs\n * 3. FK relationship validation - if accessed via FK path, validate initiator matches\n */\n private async authorizeCollectionOperation(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { operationIdentifier, roles: operationRoles } = operation;\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n const { initiatorIds, initiatorRoles } = executionContext;\n\n this.logDebug('Authorizing collection operation', {\n operationIdentifier,\n effectiveScope,\n operationRoles,\n initiatorIds,\n relationshipContexts: executionContext.relationshipContexts\n });\n\n // Ensure we have initiator information for authorization\n if (!initiatorIds || !initiatorRoles) {\n await this.emitAuthorizationDenialAudit(\n ResourceOperationDenialReason.MISSING_INITIATOR, operation, executionContext,\n );\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_MISSING_INITIATOR,\n context: { initiatorIds, initiatorRoles }\n });\n }\n\n // Validate FK relationship access (e.g., /assigned-to-users/{userId}/todos)\n // This ensures users can only access resources via FK paths they own\n await this.runAuthorizationPhase(\n () => this.validateFKRelationshipAccess(executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.FK_RELATIONSHIP_DENIED),\n operation, executionContext,\n );\n\n // WS-C: stamp the narrowing decision before EITHER role gate below. Collection operations are the\n // half that matters most — LIST/SEARCH/COUNT on an opted-in resource is exactly what a unit-scoped\n // principal is meant to reach — and for ORGANIZATIONS scope the role check lives inside\n // `validateParentScopeAccess`, not in `validateOperationRoles`. Stamping here covers both.\n await this.resolveAndStampOrganizationUnitNarrowing(operation, executionContext);\n\n // Validate parent scope access through initiatorIds\n // For ORGANIZATIONS scope, this also validates roles in the specific organization\n await this.runAuthorizationPhase(\n () => this.validateParentScopeAccess(operation, executionContext),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.PARENT_SCOPE_DENIED),\n operation, executionContext,\n );\n\n // For non-ORGANIZATIONS scopes, validate roles separately\n // (ORGANIZATIONS role validation is done in validateParentScopeAccess to ensure scope-specific checking).\n // Scope-required reference search re-anchors to anchor-scope MEMBERSHIP inside\n // validateParentScopeAccess and intentionally does NOT require the target's own\n // (global/admin) operation roles — skip the separate role check for it too, or\n // a member would be 403'd on `/organizations/{org}/users/search`.\n const isJunctionScopedSearch = executionContext.relationshipContexts?.some(rc => rc.scopeViaJunction);\n if (effectiveScope !== ResourcePrimaryScope.ORGANIZATIONS && !isJunctionScopedSearch) {\n await this.runAuthorizationPhase(\n () => this.validateOperationRoles(operationRoles, executionContext, operation.resourceIdentifier),\n (error) => classifyAuthorizationDenial(error, ResourceOperationDenialReason.INSUFFICIENT_ROLES),\n operation, executionContext,\n );\n }\n\n this.logDebug('Collection operation authorization completed successfully');\n }\n\n /**\n * Validate FK relationship access for URL paths like /assigned-to-users/{userId}/todos\n *\n * 🔒 SECURITY: When accessing resources via a FK relationship path, verify the initiator\n * is authorized to use that path. For example:\n * - /assigned-to-users/{userId}/todos → verify userId matches the current user\n * - /created-by-users/{userId}/documents → verify userId matches the current user\n *\n * This prevents users from accessing resources assigned to or created by other users\n * by manipulating the URL path.\n *\n * The gate is on IDENTITY, not on execution type (issue #321). A context is admitted on a user-FK\n * path when it carries a `userId` AND that id equals the one in the path — whatever established the\n * identity. Two execution types carry a `userId`:\n * - USER_REQUEST — the session's own user;\n * - CONSUMABLE_TOKEN — the `userId` the token was MINTED for (`createExecutionContextFromRequest`\n * copies `consumableTokenObject.userId` onto `initiatorIds`). It is server-minted, so a bearer can\n * only act as that subject on that path — the same trust a session confers.\n * Machine principals, INTERNAL, PUBLIC, WEBHOOK and ANONYMOUS_SESSION never reach the gate: the\n * early return below skips FK matching for them entirely (machine principals have broader access\n * within their scope; the others carry no person to match). So the identity gate is evaluated for\n * exactly two execution types — USER_REQUEST and CONSUMABLE_TOKEN — and a context of either kind\n * WITHOUT a `userId` is refused: a user-FK path names a person, and a caller with no person cannot\n * be that person.\n *\n * History: after the early return, this used to refuse every non-USER_REQUEST type — which, given\n * that return, meant exactly CONSUMABLE_TOKEN — on the stated premise that \"only USER_REQUEST has a\n * userId\". The premise was false when written (the token bridge already set it); the effect was\n * that no token could act on a user-FK path even for the very user it was minted for.\n */\n private async validateFKRelationshipAccess(\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { relationshipContexts, initiatorIds, executionType } = executionContext;\n\n // No FK relationships in the path - nothing to validate\n if (!relationshipContexts || relationshipContexts.length === 0) {\n return;\n }\n\n // Skip FK validation for API keys, internal operations, public operations, webhook callbacks,\n // and anonymous sessions. Anonymous sessions use their own URL pattern\n // (/anonymous-users/{anonymousUserId}/...) and don't traverse user FK paths.\n if (executionContext.isMachineExecution() ||\n executionContext.isInternalExecution() ||\n executionContext.isPublicExecution() ||\n executionContext.isWebhookExecution() ||\n executionContext.isAnonymousExecution()) {\n this.logDebug('Skipping FK relationship validation for non-user execution', {\n executionType,\n reason: 'Machine principals (API keys + client-credentials), internal, public, webhook, and anonymous operations bypass FK user matching'\n });\n return;\n }\n\n this.logDebug('Validating FK relationship access', {\n relationshipContexts,\n initiatorIds,\n executionType\n });\n\n for (const relationshipContext of relationshipContexts) {\n const { resourceType, relationshipField, resourceId } = relationshipContext;\n\n // Only validate FK relationships (those with a relationshipField defined)\n // Standard parent relationships (undefined relationshipField) are handled by validateParentScopeAccess\n if (!relationshipField) {\n continue;\n }\n\n // Validate based on the target resource type\n if (resourceType === CoreResourceType.USERS || resourceType === CoreResourceType.USER_SELF) {\n // A user-FK path names a person. Admission requires a `userId` on the context (USER_REQUEST\n // session or CONSUMABLE_TOKEN minted for that user) that EQUALS the one in the path. There is\n // deliberately no execution-type branch here — see the method JSDoc (issue #321).\n if (!initiatorIds?.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n relationshipField,\n resourceIdInUrl: resourceId\n }\n });\n }\n\n // User ID must match\n if (resourceId !== initiatorIds.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n relationshipField,\n resourceIdInUrl: resourceId,\n initiatorUserId: initiatorIds.userId\n }\n });\n }\n }\n // Note: Organization FK relationships (e.g., sharedWithOrganizationId) are validated\n // through the standard parent scope validation\n }\n }\n\n /**\n * Validate that the user has access to the parent scope for collection operations\n *\n * 🔒 SECURITY: This method ensures users can only access resources in scopes they belong to.\n *\n * For ORGANIZATIONS scope: verify user is member of the organization in the URL AND has required roles there\n * For USER_SELF scope: verify the user is accessing their own resources\n * For APPLICATION scope: verify application-level access\n */\n private async validateParentScopeAccess(\n operation: ResourceConfiguration_Operation<any, any, any>,\n executionContext: ExecutionContext<any>\n ): Promise<void> {\n const { roles: operationRoles } = operation;\n const { initiatorIds, initiatorRoles, relationshipContexts } = executionContext;\n\n // 🔒 Scope-required reference search: a junction-tagged scope param re-anchors\n // authorization to MEMBERSHIP in the anchor scope (e.g. any active role in the\n // org on `/organizations/{org}/users/search`), NOT the TARGET's own\n // (global/admin) operation roles. This matches the junction's own SEARCH\n // (`organizationMembers` SEARCH = ORG_MEMBER) and exposes nothing an org\n // member can't already enumerate via org-members. The global route (no tag)\n // falls through to the scope+roles switch below, so `/users/search` stays\n // admin-only. (The separate operation-role check in\n // `authorizeCollectionOperation` is likewise skipped for this case.)\n const junctionScopedContext = relationshipContexts?.find(rc => rc.scopeViaJunction);\n if (junctionScopedContext) {\n // Resolve the scope this junction-tagged param REPRESENTS by reverse-mapping\n // the scope-root resource types (e.g. `organizations` → ORGANIZATIONS).\n // Generic over ANY scope-root anchor — a future tenant scope (teams, etc.)\n // works unchanged; a non-scope-root anchor (e.g. the reverse `users`-anchored\n // direction, which is not a tenant scope) has no mapping and fails closed.\n const anchorScope = (Object.keys(PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE) as ResourcePrimaryScope[]).find(\n scope => PRIMARY_SCOPE_TO_CORE_RESOURCE_TYPE[scope] === junctionScopedContext.resourceType,\n );\n if (!anchorScope) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n });\n }\n // Authorize by MEMBERSHIP in that scope instance: the caller must hold a role\n // for THIS (scope, id). Generic role-scope match — works for any per-instance\n // scope (ORGANIZATIONS today) and fail-closes for scopes with no per-instance\n // role entries (APPLICATION/ANONYMOUS). NOT the target's own (global/admin)\n // operation roles — that bypass is the whole point (members search in-scope,\n // the global route stays admin-only).\n // Org-wide grants only: membership of the anchor scope is an organization-level fact. A\n // unit-scoped entry always sits alongside an org-wide one (a unit assignment presupposes an\n // ORGANIZATION_MEMBERS row), so this cannot deny a legitimate member — and were that ever\n // untrue, denying is the fail-closed direction.\n const isMember = initiatorRoles?.filter(isOrganizationWideRoleInfo).some(\n roleInfo =>\n roleInfo.relatedPrimaryScope === anchorScope &&\n roleInfo.relatedResourceId === junctionScopedContext.resourceId,\n );\n if (!isMember) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n anchorScope,\n scopeResourceType: junctionScopedContext.resourceType,\n scopeResourceId: junctionScopedContext.resourceId,\n },\n });\n }\n return;\n }\n\n const effectiveScope = this.resolveEffectiveScope(operation, executionContext);\n\n this.logDebug('Validating parent scope access', {\n effectiveScope,\n initiatorIds,\n operationRoles\n });\n\n switch (effectiveScope) {\n case ResourcePrimaryScope.ORGANIZATIONS:\n // 🔒 SECURITY: For organization-scoped resources, validate:\n // 1. organizationId is present in the URL\n // 2. User has a role for THIS SPECIFIC organization (not any organization)\n // 3. User's role in this organization satisfies the required operation roles\n // Checked FIRST, before the missing-organizationId refusal below. This gate runs only on\n // COLLECTION calls, where there is no row and therefore no URL-derived organization scope to\n // fall back on — so a platform administrator who is not a member of the tenant genuinely has\n // no `organizationId` here, and an admission placed after that throw would be unreachable by\n // the only principal it exists for. (Per-INSTANCE calls are different: there the scope comes\n // from the URL segment. See the predicate's JSDoc.)\n // On a COLLECTION call there is no row, so the tenant comes from the request's own scope —\n // the only thing available before a fetch. That is weaker than the per-instance gate, which\n // reads the fetched row, and it is why this branch keeps requiring an org-wide entry below.\n if (await this.admitsCrossTenantPlatformAdministration(executionContext, String(initiatorIds?.organizationId ?? ''))) {\n this.logDebug('Cross-tenant platform administration admitted (parent-scope gate)', {\n operationIdentifier: String(operation.operationIdentifier),\n resourceIdentifier: String(operation.resourceIdentifier),\n });\n break;\n }\n\n // ── The SCOPE ROOT has no parent scope, and demanding one refused its own configuration ──\n //\n // Everything below this point asks \"which organization is this request acting INSIDE, and\n // what are the caller's roles THERE\". That question is well-formed for a row inside a\n // tenant. It is not well-formed for the tenant resource itself: `/organizations` has no\n // `:organizationId` segment to populate `initiatorIds.organizationId`, so a collection call\n // on the scope root fell into the refusal directly below and answered 403 to EVERY caller —\n // including the `APP_ADMIN_SUPER_ADMIN` its own LIST and SEARCH declare, and the `APP_USER`\n // its CREATE declares. Measured (2026-08-10): LIST 403, SEARCH 403, CREATE 403, while the\n // per-instance READ answered 200. Three routed, spec-documented doors that answered 403\n // forever.\n //\n // The scope root's roles therefore resolve against the APPLICATION role table, which is where\n // the roles it declares actually live. `validateRolesForScope` expands through\n // `getRoleHierarchy(role, APPLICATION)`; a role unknown in that table expands to the empty\n // set, so an ORGANIZATION role can never satisfy an APPLICATION requirement here.\n //\n // ⚠️ THIS IS NOT A CROSS-TENANT ADMISSION, and it must never become one. Passing this gate\n // buys the right to USE the door, not the right to see every tenant's rows: the repository\n // confines a scope-root collection read to the caller's own organizations through\n // `assignScopeRootCollectionConfinementToFilter`, which reads the SAME\n // `isOwnScopeRootResource` predicate used here so the gate and the filter cannot disagree\n // about what a scope root is. Before that confinement existed, the filter for this exact\n // call compiled to `{}` — the empty predicate — on BOTH adapters, so opening this gate alone\n // would have disclosed every tenant row in the deployment. Do not relax one without the\n // other; see `.claude/plans/organizations-scope-root-collection-gate-analysis.md`.\n if (isOwnScopeRootResource({\n resourceIdentifier: String(operation.resourceIdentifier),\n resourcePrimaryScope: effectiveScope,\n })) {\n const applicationRoles = (initiatorRoles ?? [])\n .filter(isOrganizationWideRoleInfo)\n .filter(roleInfo => roleInfo.relatedPrimaryScope === ResourcePrimaryScope.APPLICATION)\n .flatMap(roleInfo => roleInfo.roles);\n\n if (!this.validateRolesForScope(operationRoles, applicationRoles, ResourcePrimaryScope.APPLICATION)) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope,\n scopeRootResource: String(operation.resourceIdentifier),\n requiredRoles: operationRoles,\n callerApplicationRoles: applicationRoles,\n }\n });\n }\n break;\n }\n\n if (!initiatorIds?.organizationId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n\n // Find user's roles specifically for this organization\n // Org-wide grants only — a unit-scoped entry carries the same scope + org id, so without\n // this filter it could supply the organization's role set from a single unit's grant.\n const orgRoleInfo = initiatorRoles?.filter(isOrganizationWideRoleInfo).find(\n roleInfo =>\n roleInfo.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS &&\n roleInfo.relatedResourceId === initiatorIds.organizationId\n );\n\n if (!orgRoleInfo) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope,\n organizationId: initiatorIds.organizationId,\n userOrganizations: initiatorRoles?.filter(r => r.relatedPrimaryScope === ResourcePrimaryScope.ORGANIZATIONS)\n .map(r => r.relatedResourceId) || []\n }\n });\n }\n\n // Validate user has required roles in THIS organization\n const hasRequiredOrgRole = this.validateRolesForScope(\n operationRoles,\n orgRoleInfo.roles,\n ResourcePrimaryScope.ORGANIZATIONS\n );\n\n // WS-C ADDITIVE admission (D-C3b) — the collection-operation half. This branch, not\n // `validateOperationRoles`, is where an ORGANIZATIONS-scoped LIST / SEARCH / COUNT / CREATE\n // resolves its roles, so without this a unit-scoped principal would be denied at the very\n // operations narrowing exists to serve. Same rule as the other half: consulted only after the\n // organization-wide check has failed, and the repository confines the rows from the same stamp.\n if (!hasRequiredOrgRole && this.isAdmittedByUnitScopedGrant(executionContext, operation.resourceIdentifier)) {\n this.logDebug('Collection operation admitted by unit-scoped grant', {\n resourceIdentifier: operation.resourceIdentifier,\n operationRoles,\n });\n break;\n }\n\n if (!hasRequiredOrgRole) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n requiredRoles: operationRoles,\n userRolesInOrg: orgRoleInfo.roles,\n organizationId: initiatorIds.organizationId\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.USER_SELF:\n // For user-scoped resources, userId must be present\n if (!initiatorIds?.userId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.ANONYMOUS:\n if (!initiatorIds?.anonymousUserId) {\n throw this.errorBuilder.buildError(ErrorType.AUTHORIZATION, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_ACCESS_DENIED,\n context: {\n // diagnostic (log-only)\n effectiveScope\n }\n });\n }\n break;\n\n case ResourcePrimaryScope.APPLICATION:\n // Application scope - no specific parent ID required\n // Access is determined by roles only (validated separately)\n break;\n\n default:\n throw this.errorBuilder.buildError(ErrorType.INTERNAL, executionContext, {\n customMessageReference: ErrorCustomMessageReference.AUTHORIZATIONS_VALIDATION_FAILED,\n context: { message: `Unsupported primary scope for collection operation: ${effectiveScope}` }\n });\n }\n }\n\n /**\n * Validate that user's roles satisfy the required operation roles\n * Considers role hierarchy within the given scope\n *\n * The SECOND role gate in this class, and the reason the `APP_PUBLIC` admission below is repeated\n * rather than inherited: an ORGANIZATIONS-scoped operation resolves its roles HERE, inside\n * `validateParentScopeAccess`, and never reaches {@link validateOperationRoles} —\n * `authorizeCollectionOperation` skips that call for ORGANIZATIONS scope precisely because this\n * branch has already answered the question. A public declaration honoured at only one of the two\n * would mean `APP_PUBLIC` worked on APPLICATION-scoped resources and refused on organization-scoped\n * ones, which is the same defect one scope over.\n *\n * The caller has ALREADY proven tenancy by the time this runs — the ORGANIZATIONS branch resolves\n * an `orgRoleInfo` for this specific organization, and the scope-root branch confines the read\n * separately — so admitting on a public declaration here grants the right to ASK, never a wider\n * set of rows.\n *\n * @returns true if user has at least one of the required roles, or the operation declares public\n * access (in which case it requires none)\n */\n private validateRolesForScope(\n requiredRoles: string[],\n userRoles: string[],\n scope: ResourcePrimaryScope\n ): boolean {\n if (requiredRolesDeclarePublicAccess(requiredRoles)) return true;\n\n return requiredRoles.some(requiredRole =>\n userRoles.some(userRole => {\n const hierarchy = this.getRoleHierarchy(userRole, scope);\n return hierarchy.includes(requiredRole);\n })\n );\n }\n}\n"]}
|