@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.
Files changed (265) hide show
  1. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts +14 -3
  2. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.d.ts.map +1 -1
  3. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js +115 -22
  4. package/dist/esm/base-classes/services/controllers/controller-resource.backend.service.js.map +1 -1
  5. package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts +3 -1
  6. package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.d.ts.map +1 -1
  7. package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js +8 -3
  8. package/dist/esm/base-classes/services/controllers/controllers-registry-handler.backend.service.js.map +1 -1
  9. package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts +11 -0
  10. package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.d.ts.map +1 -1
  11. package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js +11 -2
  12. package/dist/esm/base-classes/services/repositories/field-clearing-partition.backend.js.map +1 -1
  13. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts +1 -0
  14. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.d.ts.map +1 -1
  15. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js +6 -1
  16. package/dist/esm/base-classes/services/repositories/http-api/http-api-resource-repository.backend.service.js.map +1 -1
  17. package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.d.ts.map +1 -1
  18. package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js +16 -0
  19. package/dist/esm/base-classes/services/repositories/http-api/odata-query-compiler.backend.js.map +1 -1
  20. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts +20 -6
  21. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.d.ts.map +1 -1
  22. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js +88 -32
  23. package/dist/esm/base-classes/services/repositories/infrastructure-tier-contract.backend.js.map +1 -1
  24. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.d.ts +3 -1
  25. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.d.ts.map +1 -1
  26. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.js +32 -7
  27. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-repository.backend.service.js.map +1 -1
  28. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts +8 -5
  29. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.d.ts.map +1 -1
  30. package/dist/esm/base-classes/services/repositories/introspection/introspection-resource-source.backend.port.js.map +1 -1
  31. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts +31 -0
  32. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.d.ts.map +1 -1
  33. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js +127 -5
  34. package/dist/esm/base-classes/services/repositories/postgresql-resource-repository.backend.service.js.map +1 -1
  35. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts +71 -1
  36. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.d.ts.map +1 -1
  37. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js +62 -2
  38. package/dist/esm/base-classes/services/repositories/repositories-registry-handler.backend.service.js.map +1 -1
  39. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts +21 -0
  40. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.d.ts.map +1 -1
  41. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js +126 -4
  42. package/dist/esm/base-classes/services/repositories/repository-resource.backend.service.js.map +1 -1
  43. package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts +3 -26
  44. package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.d.ts.map +1 -1
  45. package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.js +3 -68
  46. package/dist/esm/base-classes/services/services/resource-operation-implementation-coverage.backend.utils.js.map +1 -1
  47. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.d.ts.map +1 -1
  48. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js +4 -2
  49. package/dist/esm/base-classes/services/services/services-registry-handler.backend.service.js.map +1 -1
  50. package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js +6 -6
  51. package/dist/esm/billing/services/custom-impl/billing-account.mutations.custom-impl.backend.service.js.map +1 -1
  52. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts +38 -0
  53. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.d.ts.map +1 -1
  54. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js +40 -0
  55. package/dist/esm/compliance/audit-trails/services/audit-event-dispatcher.backend.service.js.map +1 -1
  56. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts +20 -0
  57. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.d.ts.map +1 -1
  58. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js +28 -0
  59. package/dist/esm/compliance/audit-trails/services/audit-logs.backend.service.js.map +1 -1
  60. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts +12 -0
  61. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map +1 -0
  62. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js +118 -0
  63. package/dist/esm/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.js.map +1 -0
  64. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.d.ts.map +1 -1
  65. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js +8 -5
  66. package/dist/esm/compliance/audit-trails/services/siem-webhook-delivery.backend.service.js.map +1 -1
  67. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.d.ts.map +1 -1
  68. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js +14 -0
  69. package/dist/esm/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.js.map +1 -1
  70. package/dist/esm/config/custom/application-config-controller.backend.service.d.ts.map +1 -1
  71. package/dist/esm/config/custom/application-config-controller.backend.service.js +7 -1
  72. package/dist/esm/config/custom/application-config-controller.backend.service.js.map +1 -1
  73. package/dist/esm/config/models/app-config.backend.schemas.d.ts +4 -0
  74. package/dist/esm/config/models/app-config.backend.schemas.d.ts.map +1 -1
  75. package/dist/esm/config/services/app-configuration.backend.utils.d.ts +10 -1
  76. package/dist/esm/config/services/app-configuration.backend.utils.d.ts.map +1 -1
  77. package/dist/esm/config/services/app-configuration.backend.utils.js +13 -2
  78. package/dist/esm/config/services/app-configuration.backend.utils.js.map +1 -1
  79. package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.d.ts +2 -2
  80. package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js +2 -2
  81. package/dist/esm/data-seeding/services/shared/data-seed-scope-iteration.shared.utils.js.map +1 -1
  82. package/dist/esm/databases/models/filter.backend.schemas.js +2 -2
  83. package/dist/esm/databases/models/filter.backend.schemas.js.map +1 -1
  84. package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.d.ts.map +1 -1
  85. package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js +20 -1
  86. package/dist/esm/databases/services/aggregation/aggregation-authorization.backend.service.js.map +1 -1
  87. package/dist/esm/databases/services/redis.service.d.ts +27 -0
  88. package/dist/esm/databases/services/redis.service.d.ts.map +1 -1
  89. package/dist/esm/databases/services/redis.service.js +29 -0
  90. package/dist/esm/databases/services/redis.service.js.map +1 -1
  91. package/dist/esm/errors/services/error-handler.backend.service.d.ts.map +1 -1
  92. package/dist/esm/errors/services/error-handler.backend.service.js +5 -0
  93. package/dist/esm/errors/services/error-handler.backend.service.js.map +1 -1
  94. package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts +41 -0
  95. package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.d.ts.map +1 -0
  96. package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js +40 -0
  97. package/dist/esm/external-data/controllers/external-data-admin.backend.contracts.js.map +1 -0
  98. package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts +64 -0
  99. package/dist/esm/external-data/controllers/external-data-admin.backend.controller.d.ts.map +1 -0
  100. package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js +193 -0
  101. package/dist/esm/external-data/controllers/external-data-admin.backend.controller.js.map +1 -0
  102. package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts +13 -2
  103. package/dist/esm/external-data/external-data-pipeline-run.backend.service.d.ts.map +1 -1
  104. package/dist/esm/external-data/external-data-pipeline-run.backend.service.js +8 -2
  105. package/dist/esm/external-data/external-data-pipeline-run.backend.service.js.map +1 -1
  106. package/dist/esm/external-data/external-data-transform.backend.d.ts.map +1 -1
  107. package/dist/esm/external-data/external-data-transform.backend.js +7 -1
  108. package/dist/esm/external-data/external-data-transform.backend.js.map +1 -1
  109. package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts +2 -0
  110. package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.d.ts.map +1 -1
  111. package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js +13 -0
  112. package/dist/esm/external-data/models/external-data-pipeline-state.backend.schemas.js.map +1 -1
  113. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts +14 -0
  114. package/dist/esm/external-providers/services/external-providers-registry.backend.service.d.ts.map +1 -1
  115. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js +6 -0
  116. package/dist/esm/external-providers/services/external-providers-registry.backend.service.js.map +1 -1
  117. package/dist/esm/files/controllers/file.controller.d.ts +24 -1
  118. package/dist/esm/files/controllers/file.controller.d.ts.map +1 -1
  119. package/dist/esm/files/controllers/file.controller.js +66 -2
  120. package/dist/esm/files/controllers/file.controller.js.map +1 -1
  121. package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts +17 -0
  122. package/dist/esm/files/handlers/file-upload-route-locals.backend.types.d.ts.map +1 -0
  123. package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js +1 -0
  124. package/dist/esm/files/handlers/file-upload-route-locals.backend.types.js.map +1 -0
  125. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts +5 -1
  126. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.d.ts.map +1 -1
  127. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js +42 -3
  128. package/dist/esm/files/handlers/resource-file-upload-handler.backend.service.js.map +1 -1
  129. package/dist/esm/files/services/file-operation-handler.backend.service.d.ts +18 -0
  130. package/dist/esm/files/services/file-operation-handler.backend.service.d.ts.map +1 -1
  131. package/dist/esm/files/services/file-operation-handler.backend.service.js +36 -28
  132. package/dist/esm/files/services/file-operation-handler.backend.service.js.map +1 -1
  133. package/dist/esm/files/services/file-upload-grant.backend.service.d.ts +163 -0
  134. package/dist/esm/files/services/file-upload-grant.backend.service.d.ts.map +1 -0
  135. package/dist/esm/files/services/file-upload-grant.backend.service.js +442 -0
  136. package/dist/esm/files/services/file-upload-grant.backend.service.js.map +1 -0
  137. package/dist/esm/files/services/files.backend.service.d.ts +19 -0
  138. package/dist/esm/files/services/files.backend.service.d.ts.map +1 -1
  139. package/dist/esm/files/services/files.backend.service.js +78 -15
  140. package/dist/esm/files/services/files.backend.service.js.map +1 -1
  141. package/dist/esm/files/utils/file-uploader.utils.d.ts.map +1 -1
  142. package/dist/esm/files/utils/file-uploader.utils.js +12 -0
  143. package/dist/esm/files/utils/file-uploader.utils.js.map +1 -1
  144. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js +5 -5
  145. package/dist/esm/flows-actors/a2a/services/a2a-task-cancellation.backend.service.js.map +1 -1
  146. package/dist/esm/flows-actors/services/agents.backend.service.d.ts +79 -0
  147. package/dist/esm/flows-actors/services/agents.backend.service.d.ts.map +1 -1
  148. package/dist/esm/flows-actors/services/agents.backend.service.js +319 -42
  149. package/dist/esm/flows-actors/services/agents.backend.service.js.map +1 -1
  150. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts +151 -41
  151. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.d.ts.map +1 -1
  152. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js +300 -139
  153. package/dist/esm/flows-actors/utils/acp-session-runner.backend.utils.js.map +1 -1
  154. package/dist/esm/index.d.ts +4 -1
  155. package/dist/esm/index.d.ts.map +1 -1
  156. package/dist/esm/index.js +14 -1
  157. package/dist/esm/index.js.map +1 -1
  158. package/dist/esm/inject/models/container.d.ts.map +1 -1
  159. package/dist/esm/inject/models/container.js +4 -0
  160. package/dist/esm/inject/models/container.js.map +1 -1
  161. package/dist/esm/inject/models/service-types.d.ts +3 -0
  162. package/dist/esm/inject/models/service-types.d.ts.map +1 -1
  163. package/dist/esm/inject/models/service-types.js +2 -0
  164. package/dist/esm/inject/models/service-types.js.map +1 -1
  165. package/dist/esm/mcp/controllers/mcp.controller.d.ts.map +1 -1
  166. package/dist/esm/mcp/controllers/mcp.controller.js +12 -4
  167. package/dist/esm/mcp/controllers/mcp.controller.js.map +1 -1
  168. package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts +34 -0
  169. package/dist/esm/mcp/models/mcp-tool.backend.schemas.d.ts.map +1 -1
  170. package/dist/esm/mcp/models/mcp-tool.backend.schemas.js +42 -0
  171. package/dist/esm/mcp/models/mcp-tool.backend.schemas.js.map +1 -1
  172. package/dist/esm/mcp/services/mcp-server.backend.service.d.ts +29 -1
  173. package/dist/esm/mcp/services/mcp-server.backend.service.d.ts.map +1 -1
  174. package/dist/esm/mcp/services/mcp-server.backend.service.js +131 -3
  175. package/dist/esm/mcp/services/mcp-server.backend.service.js.map +1 -1
  176. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts +64 -2
  177. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.d.ts.map +1 -1
  178. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js +130 -6
  179. package/dist/esm/mcp/services/mcp-tool-adapter.backend.service.js.map +1 -1
  180. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts +9 -0
  181. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.d.ts.map +1 -1
  182. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js +11 -36
  183. package/dist/esm/notifications/services/notifications-dispatcher.backend.service.js.map +1 -1
  184. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.d.ts.map +1 -1
  185. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js +9 -7
  186. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.backend.service.js.map +1 -1
  187. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts +5 -5
  188. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.d.ts.map +1 -1
  189. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js +14 -13
  190. package/dist/esm/notifications/webhooks/outbound/batches/m2m-webhook-delivery.batch.utils.js.map +1 -1
  191. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts +2 -1
  192. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.d.ts.map +1 -1
  193. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js +2 -2
  194. package/dist/esm/notifications/webhooks/outbound/m2m-webhook-signed-request.backend.utils.js.map +1 -1
  195. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.d.ts.map +1 -1
  196. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js +9 -7
  197. package/dist/esm/notifications/webhooks/outbound/services/webhook-config-test-endpoint.custom-impl.backend.service.js.map +1 -1
  198. package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.d.ts.map +1 -1
  199. package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.js +4 -1
  200. package/dist/esm/organizations/services/organization-unit-custom-implementation.backend.service.js.map +1 -1
  201. package/dist/esm/requests/service/websocket.service.d.ts.map +1 -1
  202. package/dist/esm/requests/service/websocket.service.js +56 -7
  203. package/dist/esm/requests/service/websocket.service.js.map +1 -1
  204. package/dist/esm/resources/models/custom-service-implementations.backend.definition.d.ts.map +1 -1
  205. package/dist/esm/resources/models/custom-service-implementations.backend.definition.js +2 -0
  206. package/dist/esm/resources/models/custom-service-implementations.backend.definition.js.map +1 -1
  207. package/dist/esm/resources/services/resource-id.backend.service.js +3 -3
  208. package/dist/esm/resources/services/resource-id.backend.service.js.map +1 -1
  209. package/dist/esm/resources/services/resources-registry.backend.service.js +1 -1
  210. package/dist/esm/resources/services/resources-registry.backend.service.js.map +1 -1
  211. package/dist/esm/runtime/services/execution-context-creator.backend.service.d.ts.map +1 -1
  212. package/dist/esm/runtime/services/execution-context-creator.backend.service.js +13 -7
  213. package/dist/esm/runtime/services/execution-context-creator.backend.service.js.map +1 -1
  214. package/dist/esm/runtime/services/start-application.backend.service.d.ts +28 -0
  215. package/dist/esm/runtime/services/start-application.backend.service.d.ts.map +1 -1
  216. package/dist/esm/runtime/services/start-application.backend.service.js +82 -0
  217. package/dist/esm/runtime/services/start-application.backend.service.js.map +1 -1
  218. package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts +3 -23
  219. package/dist/esm/security/authentications/models/jwt.backend.schemas.d.ts.map +1 -1
  220. package/dist/esm/security/authentications/models/jwt.backend.schemas.js +20 -45
  221. package/dist/esm/security/authentications/models/jwt.backend.schemas.js.map +1 -1
  222. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts +9 -1
  223. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.d.ts.map +1 -1
  224. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js +9 -1
  225. package/dist/esm/security/authentications/services/auth-methods/auth-method-management.backend.service.js.map +1 -1
  226. package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.d.ts.map +1 -1
  227. package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js +5 -3
  228. package/dist/esm/security/authentications/services/auth-methods/auth-mfa.backend.service.js.map +1 -1
  229. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts +25 -1
  230. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.d.ts.map +1 -1
  231. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js +55 -4
  232. package/dist/esm/security/authentications/services/auth-token-issuer.backend.service.js.map +1 -1
  233. package/dist/esm/security/authorizations/initiator-organization-confinement.backend.d.ts.map +1 -1
  234. package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js +24 -1
  235. package/dist/esm/security/authorizations/initiator-organization-confinement.backend.js.map +1 -1
  236. package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts +117 -0
  237. package/dist/esm/security/authorizations/privileged-access-review.backend.utils.d.ts.map +1 -0
  238. package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js +104 -0
  239. package/dist/esm/security/authorizations/privileged-access-review.backend.utils.js.map +1 -0
  240. package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts +101 -6
  241. package/dist/esm/security/authorizations/services/authorizations.backend.service.d.ts.map +1 -1
  242. package/dist/esm/security/authorizations/services/authorizations.backend.service.js +210 -30
  243. package/dist/esm/security/authorizations/services/authorizations.backend.service.js.map +1 -1
  244. package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts +18 -1
  245. package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.d.ts.map +1 -1
  246. package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js +110 -74
  247. package/dist/esm/security/consumable-tokens/batches/consumable-tokens-cleanup.batch.backend.service.js.map +1 -1
  248. package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts +22 -0
  249. package/dist/esm/security/consumable-tokens/consumable-token-models.exports.d.ts.map +1 -0
  250. package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js +22 -0
  251. package/dist/esm/security/consumable-tokens/consumable-token-models.exports.js.map +1 -0
  252. package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts +17 -3
  253. package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.d.ts.map +1 -1
  254. package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js +12 -0
  255. package/dist/esm/security/consumable-tokens/models/consumable-tokens.backend.resources-config.schemas.js.map +1 -1
  256. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts +20 -0
  257. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.d.ts.map +1 -1
  258. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js +58 -5
  259. package/dist/esm/security/consumable-tokens/services/consumable-token.backend.service.js.map +1 -1
  260. package/dist/esm/security/jwt/services/jwt.backend.service.d.ts.map +1 -1
  261. package/dist/esm/security/jwt/services/jwt.backend.service.js +1 -18
  262. package/dist/esm/security/jwt/services/jwt.backend.service.js.map +1 -1
  263. package/dist/tsconfig.build.tsbuildinfo +1 -1
  264. package/package.json +15 -9
  265. package/dist/esm/.builder.pid +0 -9
@@ -0,0 +1,12 @@
1
+ import { type ResourceCustomServiceImplementationFactory } from '../../../base-classes/services/services/resource-operation-custom-implementation.factory.backend';
2
+ /**
3
+ * Registers the postfix invalidation on the ORGANIZATION SIEM-export-config CREATE and UPDATE.
4
+ *
5
+ * The handler is synchronous and cannot fail — `invalidateSiemConfig` is a `Map.delete` — so unlike
6
+ * the Redis-backed feature-cache equivalent there is nothing to fire-and-forget and no error path.
7
+ * A `logger.warn` on an unresolvable organization id keeps the gap observable rather than silent:
8
+ * failing the write would be the wrong trade, because refusing a config edit to protect a cache
9
+ * inverts the priority, but a silently un-invalidated entry is the exact defect this file fixes.
10
+ */
11
+ export declare function createSiemExportConfigCacheInvalidationFactories(): ResourceCustomServiceImplementationFactory[];
12
+ //# sourceMappingURL=siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siem-export-config-cache-invalidation.custom-impl.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.ts"],"names":[],"mappings":"AAkDA,OAAO,EAEL,KAAK,0CAA0C,EAChD,MAAM,4GAA4G,CAAC;AAkDpH;;;;;;;;GAQG;AACH,wBAAgB,gDAAgD,IAAI,0CAA0C,EAAE,CAuC/G"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Postfix-hook custom-service implementation that drops an organization's cached SIEM export
3
+ * config after an engine-routed write to `ORGANIZATION_SIEM_EXPORT_CONFIG`.
4
+ *
5
+ * Without this, `AuditEventDispatcherBackendService` served a stale config for up to
6
+ * `SIEM_CONFIG_CACHE_TTL_MS` (5 minutes) with no invalidation of any kind, so an organization that
7
+ * ENABLED its SIEM sink kept resolving the cached `null` and had its authenticated audit events
8
+ * routed to no sink for that window. Audit events are not replayed, so those deliveries were lost
9
+ * rather than delayed. The window is also PER PROCESS, because the cache is an in-process `Map` —
10
+ * a multi-instance deployment had N independent windows.
11
+ *
12
+ * ## Why the hook sits on the RESOURCE and not on the config service
13
+ *
14
+ * `AuthOrganizationConfigurationService.saveSiemExportConfig` is the obvious call site and is only
15
+ * ONE of the writers: the config is an ordinary resource, so an update also lands through
16
+ * `ServicesRegistryHandler.update` on `organizationSiemExportConfig` directly. Hooking the service
17
+ * would have applied the invariant at one of two sites — the shape
18
+ * `.claude/rules/invariant-call-site-enumeration.md` records twenty-odd times. The resource
19
+ * operation is the chokepoint both writers pass through, because `saveSiemExportConfig` dispatches
20
+ * its own write via `ServicesRegistryHandler`.
21
+ *
22
+ * ## Coverage matrix
23
+ *
24
+ * | Operation | Variant | Covered | Why |
25
+ * |-----------|------------------|---------|-----|
26
+ * | `CREATE` | `INTERNAL_CALL` | ✅ | The lazy `createAsSystem` materialisation on the userless login path, and the first real configuration. Service tier, so a postfix hook is reachable. |
27
+ * | `UPDATE` | `INTERNAL_CALL` | ✅ | Every edit, including `saveSiemExportConfig`. Service tier. |
28
+ * | `DELETE` | `REPOSITORY_ONLY`| ❌ | Deliberate, twice over: `doOperation` throws on `REPOSITORY_ONLY`, so the service tier where custom implementations run is unreachable BY CONSTRUCTION and a registration here would fail startup; and its only caller is the `onParentDelete` cascade, which fires when the owning organization is itself being hard-deleted — nothing dispatches audit events for a deleted tenant, so the entry is moot and TTL-expires. |
29
+ * | `READ` | `API_CALL` | ❌ | Reads do not stale a cache. |
30
+ *
31
+ * **`APPLICATION_SIEM_EXPORT_CONFIG` is deliberately NOT registered.** The dispatcher's cache is
32
+ * keyed by `organizationId` and it only ever loads the ORGANIZATION variant
33
+ * (`loadSiemExportConfig(ec, ORGANIZATION, orgId)`), because SIEM fan-out is per authenticated
34
+ * tenant. The APPLICATION variant is settable and inert — no producer emits app-scoped deliveries —
35
+ * so there is no app-scoped cache entry to invalidate. When an app-scoped producer lands, it gets
36
+ * its own cache and its own registration in the same change.
37
+ *
38
+ * **The framework default-seed is also not covered, and does not need to be.**
39
+ * `organizationSiemExportConfigDefaultSeed` writes a DISABLED default at the repository tier during
40
+ * organization creation, before the organization can have raised an audit event, so there is no
41
+ * entry in the map to stale.
42
+ *
43
+ * Excluded by the same tier boundary as every other postfix hook: repository-direct writes, and raw
44
+ * database writes that bypass the engine.
45
+ */
46
+ import { CoreResourceOperation, CoreResourceType, ResourceOperationVariantType, } from '@wildo-ai/saas-models';
47
+ import { createResourceCustomServiceImplementation, } from '../../../base-classes/services/services/resource-operation-custom-implementation.factory.backend.js';
48
+ import { SAAS_SERVICE_TYPES } from '../../../inject/models/service-types.js';
49
+ /** The operations whose writes can stale the dispatcher's cache. See the coverage matrix above. */
50
+ const INVALIDATING_OPERATIONS = [
51
+ CoreResourceOperation.CREATE,
52
+ CoreResourceOperation.UPDATE,
53
+ ];
54
+ const INTERNAL_DEFAULT_PATH = {
55
+ variantType: ResourceOperationVariantType.INTERNAL_CALL,
56
+ isOperationDefault: true,
57
+ };
58
+ /**
59
+ * Resolve the organization whose cache entry must go, with a three-tier fallback.
60
+ *
61
+ * 1. **The postfix result** — the persisted row. CREATE and UPDATE both return it, and it carries
62
+ * `organizationId` (injected by the polymorphism engine), so this is the normal path.
63
+ * 2. **`utils.currentObject`** — fetched by the framework before a non-CREATE custom impl runs.
64
+ * Load-bearing when an implementation returns something other than the row.
65
+ * 3. **`executionContext.organizationId`** — the scope the request runs under.
66
+ *
67
+ * Mirrors `resolveOrgIdsForInvalidation` in
68
+ * `scope-features-cache-invalidation.custom-impl.backend.service.ts`; see that file for the
69
+ * reasoning behind each tier.
70
+ */
71
+ function resolveOrganizationId(result, utils, executionContext) {
72
+ const fromResult = result != null && typeof result === 'object' && 'organizationId' in result
73
+ ? result.organizationId
74
+ : undefined;
75
+ if (fromResult)
76
+ return fromResult;
77
+ const fromCurrent = utils.currentObject?.organizationId;
78
+ if (fromCurrent)
79
+ return fromCurrent;
80
+ return executionContext.organizationId ?? undefined;
81
+ }
82
+ /**
83
+ * Registers the postfix invalidation on the ORGANIZATION SIEM-export-config CREATE and UPDATE.
84
+ *
85
+ * The handler is synchronous and cannot fail — `invalidateSiemConfig` is a `Map.delete` — so unlike
86
+ * the Redis-backed feature-cache equivalent there is nothing to fire-and-forget and no error path.
87
+ * A `logger.warn` on an unresolvable organization id keeps the gap observable rather than silent:
88
+ * failing the write would be the wrong trade, because refusing a config edit to protect a cache
89
+ * inverts the priority, but a silently un-invalidated entry is the exact defect this file fixes.
90
+ */
91
+ export function createSiemExportConfigCacheInvalidationFactories() {
92
+ return INVALIDATING_OPERATIONS.map((operationIdentifier) => (_rr, container) => {
93
+ const dispatcher = container.get(SAAS_SERVICE_TYPES.AuditEventDispatcherService);
94
+ return createResourceCustomServiceImplementation({
95
+ operationPath: {
96
+ resourceIdentifier: CoreResourceType.ORGANIZATION_SIEM_EXPORT_CONFIG,
97
+ operationIdentifier,
98
+ ...INTERNAL_DEFAULT_PATH,
99
+ },
100
+ handlers: {
101
+ postfixCoreOperations: async (_id, res, executionContext, operationPath, utils) => {
102
+ const organizationId = resolveOrganizationId(res, utils, executionContext);
103
+ if (!organizationId) {
104
+ utils.logger.warn('Could not resolve organizationId for SIEM export config cache invalidation — the dispatcher may serve a stale config for up to its TTL', {
105
+ operationIdentifier: String(operationPath.operationIdentifier),
106
+ resourceIdentifier: operationPath.resourceIdentifier,
107
+ rowId: _id,
108
+ });
109
+ return res;
110
+ }
111
+ dispatcher.invalidateSiemConfig(organizationId);
112
+ return res;
113
+ },
114
+ },
115
+ });
116
+ });
117
+ }
118
+ //# sourceMappingURL=siem-export-config-cache-invalidation.custom-impl.backend.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siem-export-config-cache-invalidation.custom-impl.backend.service.js","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-export-config-cache-invalidation.custom-impl.backend.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yCAAyC,GAE1C,MAAM,4GAA4G,CAAC;AAEpH,OAAO,EAAE,kBAAkB,EAAE,MAAM,gDAAgD,CAAC;AAKpF,mGAAmG;AACnG,MAAM,uBAAuB,GAAG;IAC9B,qBAAqB,CAAC,MAAM;IAC5B,qBAAqB,CAAC,MAAM;CACpB,CAAC;AAEX,MAAM,qBAAqB,GAAG;IAC5B,WAAW,EAAE,4BAA4B,CAAC,aAAa;IACvD,kBAAkB,EAAE,IAAI;CAChB,CAAC;AAIX;;;;;;;;;;;;GAYG;AACH,SAAS,qBAAqB,CAC5B,MAAe,EACf,KAAmD,EACnD,gBAAuC;IAEvC,MAAM,UAAU,GACd,MAAM,IAAI,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,gBAAgB,IAAI,MAAM;QACxE,CAAC,CAAE,MAAgC,CAAC,cAAc;QAClD,CAAC,CAAC,SAAS,CAAC;IAChB,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAElC,MAAM,WAAW,GAAI,KAAK,CAAC,aAAmD,EAAE,cAAc,CAAC;IAC/F,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,OAAO,gBAAgB,CAAC,cAAc,IAAI,SAAS,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gDAAgD;IAC9D,OAAO,uBAAuB,CAAC,GAAG,CAChC,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE;QAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAC9B,kBAAkB,CAAC,2BAA2B,CAC/C,CAAC;QACF,OAAO,yCAAyC,CAAC;YAC/C,aAAa,EAAE;gBACb,kBAAkB,EAAE,gBAAgB,CAAC,+BAA+B;gBACpE,mBAAmB;gBACnB,GAAG,qBAAqB;aACzB;YACD,QAAQ,EAAE;gBACR,qBAAqB,EAAE,KAAK,EAC1B,GAAuB,EACvB,GAAY,EACZ,gBAAuC,EACvC,aAA4D,EAC5D,KAAmD,EACjC,EAAE;oBACpB,MAAM,cAAc,GAAG,qBAAqB,CAAC,GAAG,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;oBAC3E,IAAI,CAAC,cAAc,EAAE,CAAC;wBACpB,KAAK,CAAC,MAAM,CAAC,IAAI,CACf,wIAAwI,EACxI;4BACE,mBAAmB,EAAE,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC;4BAC9D,kBAAkB,EAAE,aAAa,CAAC,kBAAkB;4BACpD,KAAK,EAAE,GAAG;yBACX,CACF,CAAC;wBACF,OAAO,GAAG,CAAC;oBACb,CAAC;oBACD,UAAU,CAAC,oBAAoB,CAAC,cAAc,CAAC,CAAC;oBAChD,OAAO,GAAG,CAAC;gBACb,CAAC;aACF;SACF,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Postfix-hook custom-service implementation that drops an organization's cached SIEM export\n * config after an engine-routed write to `ORGANIZATION_SIEM_EXPORT_CONFIG`.\n *\n * Without this, `AuditEventDispatcherBackendService` served a stale config for up to\n * `SIEM_CONFIG_CACHE_TTL_MS` (5 minutes) with no invalidation of any kind, so an organization that\n * ENABLED its SIEM sink kept resolving the cached `null` and had its authenticated audit events\n * routed to no sink for that window. Audit events are not replayed, so those deliveries were lost\n * rather than delayed. The window is also PER PROCESS, because the cache is an in-process `Map` —\n * a multi-instance deployment had N independent windows.\n *\n * ## Why the hook sits on the RESOURCE and not on the config service\n *\n * `AuthOrganizationConfigurationService.saveSiemExportConfig` is the obvious call site and is only\n * ONE of the writers: the config is an ordinary resource, so an update also lands through\n * `ServicesRegistryHandler.update` on `organizationSiemExportConfig` directly. Hooking the service\n * would have applied the invariant at one of two sites — the shape\n * `.claude/rules/invariant-call-site-enumeration.md` records twenty-odd times. The resource\n * operation is the chokepoint both writers pass through, because `saveSiemExportConfig` dispatches\n * its own write via `ServicesRegistryHandler`.\n *\n * ## Coverage matrix\n *\n * | Operation | Variant | Covered | Why |\n * |-----------|------------------|---------|-----|\n * | `CREATE` | `INTERNAL_CALL` | ✅ | The lazy `createAsSystem` materialisation on the userless login path, and the first real configuration. Service tier, so a postfix hook is reachable. |\n * | `UPDATE` | `INTERNAL_CALL` | ✅ | Every edit, including `saveSiemExportConfig`. Service tier. |\n * | `DELETE` | `REPOSITORY_ONLY`| ❌ | Deliberate, twice over: `doOperation` throws on `REPOSITORY_ONLY`, so the service tier where custom implementations run is unreachable BY CONSTRUCTION and a registration here would fail startup; and its only caller is the `onParentDelete` cascade, which fires when the owning organization is itself being hard-deleted — nothing dispatches audit events for a deleted tenant, so the entry is moot and TTL-expires. |\n * | `READ` | `API_CALL` | ❌ | Reads do not stale a cache. |\n *\n * **`APPLICATION_SIEM_EXPORT_CONFIG` is deliberately NOT registered.** The dispatcher's cache is\n * keyed by `organizationId` and it only ever loads the ORGANIZATION variant\n * (`loadSiemExportConfig(ec, ORGANIZATION, orgId)`), because SIEM fan-out is per authenticated\n * tenant. The APPLICATION variant is settable and inert — no producer emits app-scoped deliveries —\n * so there is no app-scoped cache entry to invalidate. When an app-scoped producer lands, it gets\n * its own cache and its own registration in the same change.\n *\n * **The framework default-seed is also not covered, and does not need to be.**\n * `organizationSiemExportConfigDefaultSeed` writes a DISABLED default at the repository tier during\n * organization creation, before the organization can have raised an audit event, so there is no\n * entry in the map to stale.\n *\n * Excluded by the same tier boundary as every other postfix hook: repository-direct writes, and raw\n * database writes that bypass the engine.\n */\nimport {\n CoreResourceOperation,\n CoreResourceType,\n ResourceOperationVariantType,\n} from '@wildo-ai/saas-models';\nimport {\n createResourceCustomServiceImplementation,\n type ResourceCustomServiceImplementationFactory,\n} from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation.factory.backend';\nimport { AuditEventDispatcherBackendService } from '~wildo-backend-lib/compliance/audit-trails/services/audit-event-dispatcher.backend.service';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport type { ResourceOperation_CustomImplementation_Utils } from '~wildo-backend-lib/base-classes/services/services/resource-operation-custom-implementation-base.backend.service';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport type { ResourceConfiguration_OperationPath } from '@wildo-ai/saas-models';\n\n/** The operations whose writes can stale the dispatcher's cache. See the coverage matrix above. */\nconst INVALIDATING_OPERATIONS = [\n CoreResourceOperation.CREATE,\n CoreResourceOperation.UPDATE,\n] as const;\n\nconst INTERNAL_DEFAULT_PATH = {\n variantType: ResourceOperationVariantType.INTERNAL_CALL,\n isOperationDefault: true,\n} as const;\n\ntype RowWithOrganizationId = { organizationId?: string };\n\n/**\n * Resolve the organization whose cache entry must go, with a three-tier fallback.\n *\n * 1. **The postfix result** — the persisted row. CREATE and UPDATE both return it, and it carries\n * `organizationId` (injected by the polymorphism engine), so this is the normal path.\n * 2. **`utils.currentObject`** — fetched by the framework before a non-CREATE custom impl runs.\n * Load-bearing when an implementation returns something other than the row.\n * 3. **`executionContext.organizationId`** — the scope the request runs under.\n *\n * Mirrors `resolveOrgIdsForInvalidation` in\n * `scope-features-cache-invalidation.custom-impl.backend.service.ts`; see that file for the\n * reasoning behind each tier.\n */\nfunction resolveOrganizationId(\n result: unknown,\n utils: ResourceOperation_CustomImplementation_Utils,\n executionContext: ExecutionContext<any>,\n): string | undefined {\n const fromResult =\n result != null && typeof result === 'object' && 'organizationId' in result\n ? (result as RowWithOrganizationId).organizationId\n : undefined;\n if (fromResult) return fromResult;\n\n const fromCurrent = (utils.currentObject as RowWithOrganizationId | undefined)?.organizationId;\n if (fromCurrent) return fromCurrent;\n\n return executionContext.organizationId ?? undefined;\n}\n\n/**\n * Registers the postfix invalidation on the ORGANIZATION SIEM-export-config CREATE and UPDATE.\n *\n * The handler is synchronous and cannot fail — `invalidateSiemConfig` is a `Map.delete` — so unlike\n * the Redis-backed feature-cache equivalent there is nothing to fire-and-forget and no error path.\n * A `logger.warn` on an unresolvable organization id keeps the gap observable rather than silent:\n * failing the write would be the wrong trade, because refusing a config edit to protect a cache\n * inverts the priority, but a silently un-invalidated entry is the exact defect this file fixes.\n */\nexport function createSiemExportConfigCacheInvalidationFactories(): ResourceCustomServiceImplementationFactory[] {\n return INVALIDATING_OPERATIONS.map(\n (operationIdentifier) => (_rr, container) => {\n const dispatcher = container.get<AuditEventDispatcherBackendService>(\n SAAS_SERVICE_TYPES.AuditEventDispatcherService,\n );\n return createResourceCustomServiceImplementation({\n operationPath: {\n resourceIdentifier: CoreResourceType.ORGANIZATION_SIEM_EXPORT_CONFIG,\n operationIdentifier,\n ...INTERNAL_DEFAULT_PATH,\n },\n handlers: {\n postfixCoreOperations: async (\n _id: string | undefined,\n res: unknown,\n executionContext: ExecutionContext<any>,\n operationPath: ResourceConfiguration_OperationPath<any, any>,\n utils: ResourceOperation_CustomImplementation_Utils,\n ): Promise<unknown> => {\n const organizationId = resolveOrganizationId(res, utils, executionContext);\n if (!organizationId) {\n utils.logger.warn(\n 'Could not resolve organizationId for SIEM export config cache invalidation — the dispatcher may serve a stale config for up to its TTL',\n {\n operationIdentifier: String(operationPath.operationIdentifier),\n resourceIdentifier: operationPath.resourceIdentifier,\n rowId: _id,\n },\n );\n return res;\n }\n dispatcher.invalidateSiemConfig(organizationId);\n return res;\n },\n },\n });\n },\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"siem-webhook-delivery.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"siem-webhook-delivery.backend.service.d.ts","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts"],"names":[],"mappings":"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"}
@@ -34,15 +34,18 @@ import { AppConfigurationService } from '../../../config/services/app-configurat
34
34
  import { AuditEventDispatcherBackendService } from './audit-event-dispatcher.backend.service.js';
35
35
  import { RepositoriesRegistryHandlerBackendService } from '../../../base-classes/services/repositories/repositories-registry-handler.backend.service.js';
36
36
  import { ExecutionContextCreatorBackendService } from '../../../runtime/services/execution-context-creator.backend.service.js';
37
- import { CoreResourceType, CoreResourceOperation, CORE_APP_ROLES, ResourcePrimaryScope, WildoHeaderKeys, SiemDeliveryDlqStatus, SIEMEventFormat, AuthScopeType, coreResourceShared_FieldIdentifier, } from '@wildo-ai/saas-models';
37
+ import { CoreResourceType, CoreResourceOperation, CORE_APP_ROLES, ResourcePrimaryScope, WildoHeaderKeys, SiemDeliveryDlqStatus, SIEMEventFormat, AuthScopeType, coreResourceShared_FieldIdentifier, SIEM_DELIVERY_RELIABILITY_CONTRACT, SIEM_CIRCUIT_BREAKER_COOLDOWN_MS, } from '@wildo-ai/saas-models';
38
38
  import { CEF_PROJECTION, LEEF_PROJECTION, cefAgentSeverityHeaderValue, SiemFieldProjectionKind, } from './utils/siem-projection-contract.backend.utils.js';
39
39
  import { buildOcsfEvent } from './utils/siem-ocsf-projection.backend.utils.js';
40
40
  import { CEF_HEADER_MAX_CHARACTERS, CEF_MAX_CHARACTERS, LEEF_HEADER_MAX_CHARACTERS, LEEF_MAX_CHARACTERS, LEEF_TAB_DELIMITER_HEADER_VALUE, } from './utils/siem-dictionary.backend.utils.js';
41
41
  import { describeCaughtError, projectCaughtErrorLogFields, } from '../../../errors/utils/error-log-level-classification.backend.utils.js';
42
- /** Default circuit breaker threshold */
43
- const CIRCUIT_BREAKER_THRESHOLD = 5;
44
- /** Circuit breaker cooldown (ms) */
45
- const CIRCUIT_BREAKER_COOLDOWN_MS = 5 * 60 * 1000; // 5 minutes
42
+ /**
43
+ * Circuit-breaker bounds come from `SIEM_DELIVERY_RELIABILITY_CONTRACT`, which the customer
44
+ * documentation also projects: what an operator is told about a paused destination is what this
45
+ * service applies.
46
+ */
47
+ const CIRCUIT_BREAKER_THRESHOLD = SIEM_DELIVERY_RELIABILITY_CONTRACT.circuitBreakerFailureThreshold;
48
+ const CIRCUIT_BREAKER_COOLDOWN_MS = SIEM_CIRCUIT_BREAKER_COOLDOWN_MS;
46
49
  /** Prefix for encrypted credentials (H6) */
47
50
  const ENCRYPTED_CREDENTIAL_PREFIX = 'encrypted:aes-256-gcm:';
48
51
  /** HKDF-like domain separator for SIEM encryption key derivation */
@@ -1 +1 @@
1
- {"version":3,"file":"siem-webhook-delivery.backend.service.js","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SIEM Webhook Delivery Backend Service\n *\n * Layer 3 of the three-layer audit event pipeline (Step 18).\n * Purpose-built for delivering security audit events to customer SIEM endpoints.\n * NOT a generic M2M webhook sender.\n *\n * Responsibilities:\n * - HTTP POST to webhook URL with configured auth\n * - HMAC-SHA256 signature for hmac_sha256 auth method\n * - Exponential backoff retries\n * - Circuit breaker after N consecutive failures per org\n * - CEF/LEEF format conversion (when eventFormat !== json_structured)\n * - Idempotency via eventId\n */\n\nimport 'reflect-metadata';\nimport { inject, injectable } from 'inversify';\nimport { createHmac, createHash, createCipheriv, createDecipheriv, randomBytes } from 'crypto';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport { AuditEventDispatcherBackendService } from './audit-event-dispatcher.backend.service';\nimport { RepositoriesRegistryHandlerBackendService } from '~wildo-backend-lib/base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport {\n type SecurityAuditEventEnvelope,\n type SiemExportConfigBase,\n type ResourceType,\n CoreResourceType,\n CoreResourceOperation,\n CORE_APP_ROLES,\n ResourcePrimaryScope,\n WildoHeaderKeys,\n SiemDeliveryDlqStatus,\n SIEMEventFormat,\n AuthScopeType,\n coreResourceShared_FieldIdentifier,\n} from '@wildo-ai/saas-models';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport {\n CEF_PROJECTION,\n LEEF_PROJECTION,\n cefAgentSeverityHeaderValue,\n SiemFieldProjectionKind,\n type SiemProjectionContext,\n type SiemProjectionContract,\n} from './utils/siem-projection-contract.backend.utils';\nimport { buildOcsfEvent } from './utils/siem-ocsf-projection.backend.utils';\nimport {\n CEF_HEADER_MAX_CHARACTERS,\n CEF_MAX_CHARACTERS,\n LEEF_HEADER_MAX_CHARACTERS,\n LEEF_MAX_CHARACTERS,\n LEEF_TAB_DELIMITER_HEADER_VALUE,\n type CefWireKey,\n type LeefWireKey,\n} from './utils/siem-dictionary.backend.utils';\nimport {\n describeCaughtError,\n projectCaughtErrorLogFields,\n} from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\n/** Circuit breaker state per organization */\ninterface CircuitBreakerState {\n consecutiveFailures: number;\n lastFailureAt: Date | null;\n circuitOpenUntil: Date | null;\n}\n\n/** Payload shape enqueued by AuditEventDispatcherBackendService */\nexport interface SIEMDeliveryJobPayload {\n envelope: SecurityAuditEventEnvelope;\n envelopeHmac?: string; // F6: HMAC integrity signature\n organizationId: string;\n /**\n * Delivery scope. Defaults to {@link AuthScopeType.ORGANIZATION}. The worker is scope-generic (the\n * circuit-breaker key, DLQ variant, and scope FK all derive from it), but `'application'`\n * is currently produced ONLY by the SIEM-DLQ retry custom-impl — there is no first-time\n * app-scoped producer, so the APPLICATION path is reserved / dormant. See\n * `AuditEventDispatcherBackendService.dispatchToOrganizationAuditSinks`.\n */\n scopeType?: AuthScopeType;\n scopeId?: string;\n siemConfig: {\n webhookUrl: string;\n authMethod: string;\n authCredential?: string;\n authHeaderName?: string;\n eventFormat: string;\n customHeaders?: Record<string, string>;\n delivery: {\n batchSize: number;\n batchWindowSeconds: number;\n retryAttempts: number;\n retryBackoffSeconds: number;\n timeoutSeconds: number;\n };\n };\n}\n\n/** Default circuit breaker threshold */\nconst CIRCUIT_BREAKER_THRESHOLD = 5;\n/** Circuit breaker cooldown (ms) */\nconst CIRCUIT_BREAKER_COOLDOWN_MS = 5 * 60 * 1000; // 5 minutes\n/** Prefix for encrypted credentials (H6) */\nconst ENCRYPTED_CREDENTIAL_PREFIX = 'encrypted:aes-256-gcm:';\n/** HKDF-like domain separator for SIEM encryption key derivation */\nconst SIEM_KEY_DOMAIN = 'wildo:siem:credential:v1';\n/**\n * Appended when the `eventData` detail bag is truncated, so the loss is VISIBLE to the receiver\n * rather than silent. A SOC that sees a JSON fragment ending mid-object cannot tell a truncation\n * from a serializer bug; this marker makes the difference explicit on the wire.\n */\nconst SIEM_EVENT_DATA_TRUNCATION_MARKER = '...[truncated]';\n/**\n * Maximum characters of serialized `eventData` carried in the single CEF/LEEF detail field,\n * INCLUDING {@link SIEM_EVENT_DATA_TRUNCATION_MARKER} when truncation occurs — the emitted value\n * never exceeds this bound.\n *\n * This is the CEF extension dictionary's own published length for `msg`, not a Wildo-invented\n * policy. LEEF publishes no per-attribute ceiling, so the same bound is applied there for\n * cross-format consistency: an unbounded detail bag is the realistic way a CEF/LEEF line grows\n * large enough for a receiver to reject it, which would fail the delivery into the DLQ.\n *\n * spec-cite: Implementing ArcSight CEF v26, Oct 2023 — ArcSight Extension Dictionary, \"CEF Key\n * Names for Event Producers\", `msg` row: full name `message`, data type `String`, length `1023`,\n * \"An arbitrary message giving more details about the event.\"\n *\n * The bound is applied to the ESCAPED value, i.e. to what actually goes on the wire. An earlier\n * revision bounded the value BEFORE escaping, on the reading that the ceiling describes the field's\n * CONTENT and escape sequences are transport encoding a receiver strips before it ever sees the\n * field. That reading is defensible and the document does not settle it — which is precisely why the\n * post-escape bound is the one to hold: escaping only ever expands (`=` → `\\=`, `\\` → `\\\\`), so a\n * value within the ceiling once encoded is necessarily within it once decoded. Bounding the encoded\n * form satisfies BOTH readings; bounding the decoded form satisfies only one, and an escape-heavy\n * bag sitting at the ceiling would have gone out over-long under the other.\n */\nconst SIEM_EVENT_DATA_DETAIL_MAX_CHARS = 1023;\n\n// The per-key ceilings and the `devTimeFormat` pattern used to live here as hand-kept constants\n// beside the formatter. They now live in the dictionary spine (`siem-dictionary.backend.utils.ts`),\n// DERIVED from the transcribed rows, because a ceiling maintained next to a key list is the same\n// artefact as the key list itself: adding a key and forgetting its published maximum was possible\n// right up until the derivation existed.\n//\n// Line comments, not a JSDoc block — a `/** */` here would attach to the class below it.\n\n@injectable()\nexport class SIEMWebhookDeliveryBackendService {\n private readonly logDebug: (message: string, context?: Record<string, unknown>) => void;\n private readonly circuitBreakers: Map<string, CircuitBreakerState> = new Map();\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.AppConfigService) private readonly appConfigService: AppConfigurationService,\n @inject(SAAS_SERVICE_TYPES.AuditEventDispatcherService) private readonly auditEventDispatcher: AuditEventDispatcherBackendService,\n @inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService) private readonly repositoriesRegistry: RepositoriesRegistryHandlerBackendService,\n @inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService) private readonly executionContextCreator: ExecutionContextCreatorBackendService,\n ) {\n this.logDebug = this.logger.debugByType('SIEMWebhookDeliveryBackendService');\n this.logger.setDebugTypeLogging('SIEMWebhookDeliveryBackendService', false);\n }\n\n /**\n * Process a SIEM delivery job from the queue.\n * Called by the job consumer when a `siem.webhook-delivery` batch job is dequeued.\n */\n public async processDelivery(payload: SIEMDeliveryJobPayload): Promise<void> {\n const { envelope, envelopeHmac, organizationId, siemConfig } = payload;\n const scopeType = payload.scopeType ?? AuthScopeType.ORGANIZATION;\n const scopeId = payload.scopeId ?? organizationId;\n const circuitKey = `${scopeType}:${scopeId}`;\n\n // F6: Verify envelope integrity before processing\n if (envelopeHmac) {\n if (!this.auditEventDispatcher.verifyEnvelopeHmac(envelope, envelopeHmac)) {\n this.logger.error?.('SIEM envelope HMAC verification failed — possible tampering', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n });\n await this._enqueueToDLQ(payload, 'hmac_verification_failed');\n return;\n }\n }\n\n // Circuit breaker check — M11: DLQ instead of silent drop\n if (this._isCircuitOpen(circuitKey)) {\n this.logDebug('Circuit breaker open for scope, sending to DLQ', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n });\n await this._enqueueToDLQ(payload, 'circuit_breaker_open');\n return;\n }\n\n // Format the body\n const body = this._formatBody(envelope, siemConfig.eventFormat);\n\n // Build headers\n const headers = this._buildHeaders(body, siemConfig);\n\n // Attempt delivery with retries\n const maxRetries = siemConfig.delivery.retryAttempts;\n const baseBackoffMs = siemConfig.delivery.retryBackoffSeconds * 1000;\n const timeoutMs = siemConfig.delivery.timeoutSeconds * 1000;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await this._sendHttpPost(siemConfig.webhookUrl, body, headers, timeoutMs);\n\n this._recordSuccess(circuitKey);\n\n this.logDebug('SIEM webhook delivered successfully', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n attempt,\n });\n return;\n } catch (error) {\n const isLastAttempt = attempt === maxRetries;\n\n if (isLastAttempt) {\n this._recordFailure(circuitKey);\n\n this.logger.error?.('SIEM webhook delivery failed after all retries', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n attempts: attempt + 1,\n ...projectCaughtErrorLogFields(error),\n });\n\n // `describeCaughtError`, not an `instanceof Error` ternary: this string is\n // PERSISTED as the DLQ record's failure reason, and a `WildoError_Backend`\n // is a plain object — the ternary would store `'[object Object]'` for every\n // structured fault, making the DLQ untriageable.\n await this._enqueueToDLQ(payload, 'retries_exhausted', describeCaughtError(error));\n } else {\n const backoffMs = baseBackoffMs * Math.pow(2, attempt);\n this.logDebug('SIEM webhook delivery failed, retrying', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n attempt,\n nextRetryMs: backoffMs,\n });\n await this._sleep(backoffMs);\n }\n }\n }\n }\n\n /**\n * Format the event body based on the configured event format.\n *\n * `json_structured` ships the envelope verbatim. CEF and LEEF are flat, single-line `key=value`\n * grammars, so they project the envelope in two tiers: the standard/indexed keys each grammar\n * defines (`cat`, `outcome`, `src`, …), followed by the free-form `eventData` bag serialized\n * into that grammar's single detail field. Every envelope field therefore reaches all three\n * formats; only the ENCODING differs.\n */\n private _formatBody(envelope: SecurityAuditEventEnvelope, eventFormat: string): string {\n switch (eventFormat) {\n case SIEMEventFormat.CEF:\n return this._formatAsCEF(envelope);\n case SIEMEventFormat.LEEF:\n return this._formatAsLEEF(envelope);\n case SIEMEventFormat.OCSF:\n // OCSF is JSON, so there is no escaping/bounding layer here — the projection returns a\n // document and the only transport concern is serialisation.\n return JSON.stringify(buildOcsfEvent(envelope));\n case SIEMEventFormat.JSON_STRUCTURED:\n default:\n return JSON.stringify(envelope);\n }\n }\n\n /**\n * Format event as CEF (Common Event Format).\n * CEF:Version|Device Vendor|Device Product|Device Version|Signature ID|Name|Severity|Extension\n */\n private _formatAsCEF(envelope: SecurityAuditEventEnvelope): string {\n const cefSeverity = cefAgentSeverityHeaderValue(envelope.severity);\n const ext = (value: string): string => this._escapeCEFExtensionValue(value);\n const header = (field: string, value: string): string => this._emitBoundedHeaderField(field, value, CEF_HEADER_MAX_CHARACTERS);\n const eventDataDetail = this._serializeEventDataDetail(envelope, ext);\n // CEF extensions are SPACE-delimited, so that is what `join` means for this grammar.\n const pair = (key: CefWireKey, value: string): string => this._emitPair(key, value, ext, CEF_MAX_CHARACTERS);\n const join = (...fragments: readonly string[]): string => fragments.join(' ');\n\n // Driven by CEF_PROJECTION, so a field cannot be dropped by being forgotten — the contract is\n // exhaustive over the envelope type and declaration order is wire order. The per-field reasoning,\n // citations and the csN-budget decision all live there, next to the mapping they justify.\n const extensions = this._renderProjection(CEF_PROJECTION, envelope, { pair, join, eventDataDetail })\n .join(' ');\n\n // Header fields 5 and 6 are DIFFERENT questions and used to receive the same answer. Field 5,\n // `Device Event Class ID`, is the stable signature a QID/correlation rule keys on — `eventType` is\n // exactly that. Field 6, `Name`, is documented as \"a human-readable and understandable description\n // of the event\", so `user_account_locked` twice gave a SOC a machine token in the column its\n // console renders as the event title.\n // spec-cite: Implementing ArcSight CEF v26, Oct 2023 — \"Header Field Definitions\", `deviceEventClassId`\n // row (\"a unique identifier for each event-type … also known as Signature ID\") and `name` row\n // (String, 512): \"a string representing a human-readable and understandable description of the event.\"\n return `CEF:0|${header('deviceVendor', 'Wildo')}|${header('deviceProduct', 'SecurityAudit')}|${header('deviceVersion', envelope.sourceVersion)}|${header('deviceEventClassId', envelope.eventType)}|${header('name', this._humanizeEventType(envelope.eventType))}|${cefSeverity}|${extensions}`;\n }\n\n /**\n * Format event as LEEF (Log Event Extended Format — IBM QRadar).\n * LEEF:Version|Vendor|Product|Version|EventID|Extension\n *\n * The serialized `eventData` bag rides a custom `eventData` attribute. It is deliberately NOT\n * called `msg` as in the CEF projection: `msg` earns that name in CEF by being a dictionary key\n * with a defined meaning, whereas LEEF publishes no such key — borrowing CEF's vocabulary here\n * would imply a standard attribute that does not exist. Each grammar gets the name that is\n * correct within it.\n * spec-cite: N/A — `eventData` is a Wildo-chosen custom attribute name, not a LEEF-defined key.\n */\n private _formatAsLEEF(envelope: SecurityAuditEventEnvelope): string {\n const val = (value: string): string => this._escapeLEEFValue(value);\n const header = (field: string, value: string): string => this._emitBoundedHeaderField(field, value, LEEF_HEADER_MAX_CHARACTERS);\n const eventDataDetail = this._serializeEventDataDetail(envelope, val);\n // LEEF attributes are TAB-delimited (we emit no `DelimiterCharacter`), so that is `join` here.\n const pair = (key: LeefWireKey, value: string): string => this._emitPair(key, value, val, LEEF_MAX_CHARACTERS);\n const join = (...fragments: readonly string[]): string => fragments.join('\\t');\n\n // Driven by LEEF_PROJECTION. LEEF reaches ALL 27 envelope fields because a LEEF custom key stays\n // searchable in QRadar, where a CEF custom extension does not — see the contract for the citation.\n //\n // `sev`, `devTime` and `devTimeFormat` are rendered BY the contract now. They used to be appended\n // here, which looked like a formatter detail and was a hole: a key emitted outside `pair` skips\n // its published ceiling, the duplicate-key check, and the declared-vs-emitted test — and `sev`\n // is precisely a key with a published constraint (`1-10`).\n const extensions = this._renderProjection(LEEF_PROJECTION, envelope, { pair, join, eventDataDetail })\n .join('\\t');\n\n // Six header fields, not five. The sixth is the attribute DelimiterCharacter, which every\n // LEEF 2.0 example in the guide carries and ours omitted — see LEEF_TAB_DELIMITER_HEADER_VALUE:\n // a parser splitting a 2.0 header into six fields was consuming our first attribute as it.\n // Vendor and Product go through `header()` too, though they are constants that need neither\n // escaping nor bounding. The point is that EVERY header field goes through the one door, so\n // \"is this field covered?\" is answerable by looking rather than by reasoning about each value —\n // the same reason `rt` was routed through `pair` even though digits never change.\n return `LEEF:2.0|${header('vendor', 'Wildo')}|${header('product', 'SecurityAudit')}|${header('productVersion', envelope.sourceVersion)}|${header('eventId', envelope.eventType)}|${LEEF_TAB_DELIMITER_HEADER_VALUE}|${extensions}`;\n }\n\n /**\n * Serialize `envelope.eventData` into the single detail field that CEF (`msg`) and LEEF\n * (`eventData`) each carry, or `undefined` when there is nothing worth saying — the caller's\n * `.filter(Boolean)` then drops the key entirely instead of emitting an empty one.\n *\n * Without this, CEF/LEEF subscribers received ONLY the curated standard keys while\n * `json_structured` subscribers received the whole bag: a silent capability gap between\n * formats, not a deliberate reduction.\n *\n * REJECTED ALTERNATIVE — flattening each `eventData` entry into its own extension key\n * (`lockoutDuration=15`, `sessionId=…`). It reads better as SIEM columns, but it is unsound\n * here. `eventData` is an OPEN, app-extensible bag whose keys routinely collide both with the\n * CEF/LEEF dictionaries and with the envelope fields already projected above it: the\n * `USER_LOGIN_FAILED` bag alone carries `failureReason`, `ipAddress` and `email`, which the\n * dispatcher has already promoted onto the envelope and which this formatter already emits as\n * `reason`, `src` and `suser`. Flattening would therefore put `src=` on the line TWICE and leave\n * which one wins to the receiver's parser. Nested objects and arrays have no flat\n * representation either. One JSON field keeps the standard keys authoritative AND the bag\n * lossless, at the cost of a second parse step on the receiving end.\n *\n * The returned JSON is escaped by the CALLER for its grammar, so a backslash ends up encoded\n * twice — once by `JSON.stringify`, once by the CEF/LEEF escaper. That is correct and\n * required: a receiver un-escapes the wire grammar first, then parses the JSON.\n */\n private _serializeEventDataDetail(\n envelope: SecurityAuditEventEnvelope,\n escapeForGrammar: (value: string) => string,\n ): string | undefined {\n // Defensive: the envelope TYPE requires `eventData`, but this formatter also runs over\n // envelopes replayed from the DLQ, where a stored bag can be absent or malformed. An\n // unguarded `Object.keys(undefined)` here would throw inside delivery.\n const eventData: unknown = envelope.eventData;\n if (!eventData || typeof eventData !== 'object' || Object.keys(eventData).length === 0) {\n return undefined;\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(eventData);\n } catch {\n // A circular / unserializable bag must not fail the whole delivery — the standard keys\n // above it are still valuable to a SOC, so drop only the detail field.\n this.logDebug('SIEM eventData detail omitted — bag is not JSON-serializable', {\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n });\n return undefined;\n }\n\n // `JSON.stringify` returns `undefined` for a value it cannot represent at all; the guard\n // above makes that unreachable for a non-empty plain object, but a `toJSON()` returning\n // `undefined` would still land here.\n if (!serialized) return undefined;\n\n if (escapeForGrammar(serialized).length <= SIEM_EVENT_DATA_DETAIL_MAX_CHARS) return serialized;\n\n // Largest prefix whose ESCAPED form, marker included, still fits. A prefix length cannot be\n // computed arithmetically because expansion depends on which characters the prefix contains,\n // and it is not uniform across the two grammars (CEF escapes `=`, LEEF does not). Binary search\n // costs O(log n) escape passes and is exact; a fixed safety margin would be a guess that is\n // simultaneously too small for a delimiter-dense bag and wasteful for an ordinary one.\n let fits = 0;\n let tooLong = serialized.length;\n while (fits < tooLong) {\n const candidate = Math.ceil((fits + tooLong) / 2);\n if (escapeForGrammar(this._truncateDetail(serialized, candidate)).length <= SIEM_EVENT_DATA_DETAIL_MAX_CHARS) {\n fits = candidate;\n } else {\n tooLong = candidate - 1;\n }\n }\n const truncated = this._truncateDetail(serialized, fits);\n\n this.logDebug('SIEM eventData detail truncated to the CEF/LEEF detail-field ceiling', {\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n originalLength: serialized.length,\n emittedLength: truncated.length,\n escapedLength: escapeForGrammar(truncated).length,\n maxChars: SIEM_EVENT_DATA_DETAIL_MAX_CHARS,\n });\n return truncated;\n }\n\n /**\n * Cut `serialized` to `length` UTF-16 units and append the truncation marker.\n *\n * The marker is counted INSIDE the ceiling by the caller's search, not appended beyond it — a\n * bound that its own truncation overshoots is not a bound. A cut landing between the halves of a\n * surrogate pair would emit a lone surrogate, which `JSON.parse` on the receiving end rejects with\n * a different error than the truncation it actually is, so the trailing half-pair is dropped.\n */\n private _truncateDetail(serialized: string, length: number): string {\n const cut = serialized.slice(0, length);\n const last = cut.charCodeAt(cut.length - 1);\n const endsOnHighSurrogate = last >= 0xd800 && last <= 0xdbff;\n return `${endsOnHighSurrogate ? cut.slice(0, -1) : cut}${SIEM_EVENT_DATA_TRUNCATION_MARKER}`;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Wire-format escaping\n //\n // CEF and LEEF are single-line, delimiter-separated grammars with NO quoting construct: a\n // delimiter appearing raw inside a value does not produce a malformed record that a parser\n // rejects — it produces a WELL-FORMED record with silently wrong fields. That failure mode is\n // why these helpers exist and why EVERY interpolated string value goes through one of them\n // rather than only the fields believed to be risky today. `outcomeReason` in particular is free\n // text sourced from `eventData.failureReason` / `eventData.reason`, so it is the first projected\n // field with no vocabulary constraining its characters.\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Escape a value for a CEF *extension* (`key=value`) slot.\n *\n * The extension is a space-separated `key=value` list whose parser delimits on the next\n * `<key>=`, so per the CEF standard:\n * - `\\` becomes `\\\\` — it is the escape character itself, which is why it MUST be replaced\n * first; doing it later would re-escape the backslashes introduced by the rules below.\n * - `=` becomes `\\=` — an unescaped `=` is read as the start of the next key/value pair.\n * - CR/LF become the two-character sequences `\\r` / `\\n` — a real newline terminates the\n * record and truncates every remaining field.\n *\n * Spaces are deliberately NOT escaped: the grammar permits them inside extension values (a\n * value is delimited by the next `<key>=`, not by whitespace).\n * spec-cite: Implementing ArcSight CEF v26, Oct 2023 — \"Character Encoding\" / the extension\n * escaping rules for pipe, backslash and equals in the Extension field.\n */\n private _escapeCEFExtensionValue(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/=/g, '\\\\=')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n }\n\n /**\n * Escape a value for a LEEF attribute slot.\n *\n * LEEF pairs are TAB-delimited, so a literal tab fabricates an extra attribute and a newline\n * terminates the record; both are encoded as their escape sequences (`\\` first, for the same\n * reason as above). `=` needs NO escaping here — a LEEF parser splits each pair on its FIRST\n * `=`, so subsequent `=` characters remain part of the value.\n * spec-cite: N/A — LEEF publishes no escaping table for attribute values; these rules are\n * derived from its tab-delimited, newline-terminated record structure, which is why the `=`\n * asymmetry with CEF above is deliberate rather than an oversight.\n */\n private _escapeLEEFValue(value: string): string {\n // ⚠️ `|` and `^` are deliberately NOT escaped, and the reasoning is the point rather than the\n // conclusion. The guide's best practices say to AVOID them in keys and values — it defines no\n // escape for them, because LEEF 2.0's answer is the header's `DelimiterCharacter`, which lets a\n // producer CHOOSE the attribute delimiter (caret is a documented choice). Inventing `\\|` would\n // therefore corrupt the value at every conformant receiver, which is strictly worse than the\n // mis-parse it guards against — and that mis-parse needs a non-conformant parser splitting the\n // whole line on `|`, since the header ends at its fifth. We emit no `DelimiterCharacter`, so the\n // delimiter is TAB and a caret in a value is inert. If a `DelimiterCharacter` is ever emitted,\n // THAT character becomes escapable-or-forbidden and this decision must be re-taken.\n // spec-cite: IBM QRadar LEEF Version 2 (© IBM 2013, 2016) — \"Best practices Guidelines for LEEF\n // events\": \"Use alphanumeric (A-Z, a-z, and 0-9) characters, but avoid tab, pipe, or caret\n // delimiters in your event payload keys and values\"; Table 2, `Delimiter Character` row.\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n }\n\n /**\n * Escape a value for a CEF or LEEF *header* slot (the `|`-delimited prefix shared by both\n * grammars).\n *\n * A literal `|` would fabricate a header field and shift every subsequent one — including the\n * severity and the entire extension — so it is escaped as `\\|`. Headers cannot span lines at\n * all (there is no multi-line encoding for them, unlike extension values), so newlines are\n * folded to a space rather than escaped.\n *\n * Applied defensively: `sourceVersion` is read straight from the `APP_VERSION` environment\n * variable and `eventType` is app-extensible, so neither is guaranteed delimiter-free.\n */\n private _escapeSIEMHeaderField(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\|/g, '\\\\|')\n // Any CR or LF, in any combination — not just `\\r?\\n`. A LONE `\\r` slipped through that form,\n // and a bare CR terminates a record for readers that treat it as a line ending.\n .replace(/[\\r\\n]+/g, ' ');\n }\n\n /**\n * Render a projection contract into its emitted fragments, in declaration order.\n *\n * Only `extension` entries produce wire output. `header` entries are carried by the caller's header\n * construction and `not-projected` entries deliberately produce nothing — both exist in the contract\n * so that COVERAGE is a property of the type rather than of anyone's memory.\n */\n private _renderProjection<K extends string>(\n contract: SiemProjectionContract<SecurityAuditEventEnvelope, K>,\n envelope: SecurityAuditEventEnvelope,\n context: SiemProjectionContext<K>,\n ): string[] {\n const fragments: string[] = [];\n for (const projection of Object.values(contract)) {\n if (projection.kind !== SiemFieldProjectionKind.EXTENSION) continue;\n const fragment = projection.render(envelope, context);\n if (fragment) fragments.push(fragment);\n }\n return fragments;\n }\n\n /**\n * Emit one `key=value` pair, escaped for its grammar and bounded by the key's PUBLISHED ceiling.\n *\n * The bound is measured on the ESCAPED value for the same reason as the detail bag: escaping only\n * expands, so bounding the encoded form is the only bound that holds under both readings of what a\n * published length governs. A key absent from `maxByKey` has no published limit and is emitted\n * whole — the table never invents one.\n *\n * Truncation is LOUD. Losing the tail of an id or an email is a data defect, not a formatting\n * detail, and the receiver cannot tell a truncated value from a short one.\n */\n private _emitPair<K extends string>(\n key: K,\n rawValue: string,\n escapeForGrammar: (value: string) => string,\n maxByKey: Readonly<Record<string, number>>,\n ): string {\n return `${key}=${this._boundToPublishedLength(key, rawValue, escapeForGrammar, maxByKey[key])}`;\n }\n\n /**\n * Escape a value and bound the ESCAPED result at its published ceiling, or emit it whole when the\n * document publishes none.\n *\n * Shared by the extension path ({@link _emitPair}) and the header path\n * ({@link _emitBoundedHeaderField}) because both answer the same question and only one of them used\n * to. Header fields never passed through `_emitPair`, so every published header size — most\n * pointedly `deviceVersion`'s 31 characters, which carries `APP_VERSION` — was unenforced while the\n * extension ceilings were being carefully derived from the dictionary one layer away. Two code\n * paths for one rule is how that happened; there is one now.\n *\n * The bound is measured on the escaped form for the reason given at\n * {@link SIEM_EVENT_DATA_DETAIL_MAX_CHARS}: escaping only expands, so a value within the ceiling\n * once encoded is within it once decoded, which satisfies both readings of what a published length\n * governs. Truncation is LOUD — losing the tail of a version or an id is a data defect, and the\n * receiver cannot tell a truncated value from a short one.\n */\n private _boundToPublishedLength(\n fieldName: string,\n rawValue: string,\n escapeForGrammar: (value: string) => string,\n max: number | undefined,\n ): string {\n const escaped = escapeForGrammar(rawValue);\n if (max === undefined || escaped.length <= max) return escaped;\n\n let fits = 0;\n let tooLong = rawValue.length;\n while (fits < tooLong) {\n const candidate = Math.ceil((fits + tooLong) / 2);\n if (escapeForGrammar(rawValue.slice(0, candidate)).length <= max) fits = candidate;\n else tooLong = candidate - 1;\n }\n const cut = rawValue.slice(0, fits);\n const lastCode = cut.charCodeAt(cut.length - 1);\n const kept = lastCode >= 0xd800 && lastCode <= 0xdbff ? cut.slice(0, -1) : cut;\n\n this.logger.warn?.('SIEM field truncated to its published ceiling', {\n key: fieldName,\n maxChars: max,\n originalLength: rawValue.length,\n emittedLength: kept.length,\n });\n return escapeForGrammar(kept);\n }\n\n /**\n * Emit one `|`-delimited header field, escaped for the shared header grammar and bounded by the\n * size its document publishes for THAT slot.\n *\n * A header field cannot be dropped when it misbehaves — an omitted field shifts every field after\n * it and silently re-interprets the whole record — so the only available degradation is truncation.\n */\n private _emitBoundedHeaderField(\n fieldName: string,\n rawValue: string,\n maxByField: Readonly<Record<string, number>>,\n ): string {\n return this._boundToPublishedLength(\n fieldName,\n rawValue,\n (value) => this._escapeSIEMHeaderField(value),\n maxByField[fieldName],\n );\n }\n\n /**\n * `user_account_locked` → `User account locked`, for CEF's human-readable `Name` header field.\n *\n * Derived rather than authored: the envelope carries no display label, and inventing a lookup table\n * would be a second vocabulary to keep in sync with `CoreAuditableEventType` — the drift shape this\n * codebase keeps paying for. A derivation cannot go stale.\n *\n * Deliberately NOT applied to `Device Event Class ID`, which must stay the machine token: a\n * correlation rule keyed on a prettified string would break the moment the prettifier changed.\n */\n private _humanizeEventType(eventType: string): string {\n const words = eventType.replace(/[_-]+/g, ' ').trim();\n return words ? `${words.charAt(0).toUpperCase()}${words.slice(1)}` : eventType;\n }\n\n /**\n * Build HTTP headers for the SIEM webhook request.\n */\n private _buildHeaders(\n body: string,\n siemConfig: SIEMDeliveryJobPayload['siemConfig'],\n ): Record<string, string> {\n const headers: Record<string, string> = {\n // Second reader of `eventFormat` in this file (the first is `_formatBody`). Both route\n // through the SIEMEventFormat vocabulary so a future format value cannot be added to the\n // switch and silently forgotten here, where the wrong Content-Type makes a receiver reject\n // an otherwise well-formed body.\n // OCSF is JSON too, so the test is \"is this a TEXT grammar\", not \"is it json_structured\".\n // Reading it the other way would have shipped OCSF as `text/plain` — a well-formed body a\n // receiver may refuse to parse, which is this workstream's signature failure shape.\n [WildoHeaderKeys.CONTENT_TYPE]: siemConfig.eventFormat === SIEMEventFormat.CEF || siemConfig.eventFormat === SIEMEventFormat.LEEF\n ? 'text/plain'\n : 'application/json',\n };\n\n // Apply custom headers first (auth headers override if needed)\n if (siemConfig.customHeaders) {\n Object.assign(headers, siemConfig.customHeaders);\n }\n\n // H6: Resolve (decrypt) the credential before use\n const resolvedCredential = this._resolveCredential(siemConfig.authCredential);\n\n // Apply auth method\n switch (siemConfig.authMethod) {\n case 'bearer_token':\n if (resolvedCredential) {\n headers[WildoHeaderKeys.AUTHORIZATION] = `Bearer ${resolvedCredential}`;\n }\n break;\n\n case 'api_key_header': {\n const headerName = siemConfig.authHeaderName || WildoHeaderKeys.API_KEY;\n if (resolvedCredential) {\n headers[headerName] = resolvedCredential;\n }\n break;\n }\n\n case 'hmac_sha256':\n if (resolvedCredential) {\n const hmac = createHmac('sha256', resolvedCredential)\n .update(body)\n .digest('hex');\n headers[WildoHeaderKeys.X_SIGNATURE_256] = `sha256=${hmac}`;\n }\n break;\n\n case 'none':\n default:\n break;\n }\n\n return headers;\n }\n\n /**\n * Send HTTP POST to the SIEM webhook endpoint.\n */\n private async _sendHttpPost(\n url: string,\n body: string,\n headers: Record<string, string>,\n timeoutMs: number,\n ): Promise<void> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const responseText = await response.text().catch(() => '');\n throw new Error(\n `SIEM webhook returned HTTP ${response.status}: ${responseText.slice(0, 200)}`\n );\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Circuit Breaker\n // ─────────────────────────────────────────────────────────────\n\n private _isCircuitOpen(circuitKey: string): boolean {\n const state = this.circuitBreakers.get(circuitKey);\n if (!state || !state.circuitOpenUntil) return false;\n\n if (new Date() > state.circuitOpenUntil) {\n state.circuitOpenUntil = null;\n return false;\n }\n\n return true;\n }\n\n private _recordSuccess(circuitKey: string): void {\n this.circuitBreakers.delete(circuitKey);\n }\n\n private _recordFailure(circuitKey: string): void {\n let state = this.circuitBreakers.get(circuitKey);\n if (!state) {\n state = { consecutiveFailures: 0, lastFailureAt: null, circuitOpenUntil: null };\n this.circuitBreakers.set(circuitKey, state);\n }\n\n state.consecutiveFailures++;\n state.lastFailureAt = new Date();\n\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = new Date(Date.now() + CIRCUIT_BREAKER_COOLDOWN_MS);\n this.logger.warn('SIEM circuit breaker opened', {\n circuitKey,\n consecutiveFailures: state.consecutiveFailures,\n cooldownMs: CIRCUIT_BREAKER_COOLDOWN_MS,\n });\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // M11: Dead Letter Queue\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Persist failed SIEM delivery events to a MongoDB-backed DLQ resource\n * instead of silently dropping them. DLQ entries conform to SiemDeliveryDlqBase\n * and are queryable/retryable through the standard resource engine.\n */\n private async _enqueueToDLQ(\n payload: SIEMDeliveryJobPayload,\n failureReason: string,\n errorMessage?: string,\n ): Promise<void> {\n const scopeType = payload.scopeType ?? AuthScopeType.ORGANIZATION;\n const scopeId = payload.scopeId ?? payload.organizationId;\n try {\n const dlqResourceType = scopeType === AuthScopeType.APPLICATION\n ? CoreResourceType.APPLICATION_SIEM_DELIVERY_DLQ\n : CoreResourceType.ORGANIZATION_SIEM_DELIVERY_DLQ;\n // Polymorphic scope FK field name: `organizationId` for the ORG variant,\n // `applicationId` for the APP variant (the polymorphism engine's per-variant column).\n const scopeFieldIdentifier = scopeType === AuthScopeType.APPLICATION\n ? coreResourceShared_FieldIdentifier[CoreResourceType.APPLICATION]\n : coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS];\n\n const ec = await this._getDlqExecutionContext(dlqResourceType, scopeFieldIdentifier, scopeId);\n const dlqRepo = this.repositoriesRegistry.getRepositoryOrThrow(dlqResourceType);\n\n const dlqEntry = {\n // The polymorphic scope FK (organizationId / applicationId) is NOT on\n // SiemDeliveryDlqBaseSchema — the polymorphism engine appends it per variant as an\n // excludeFromCreate, context-injected column. Its AUTHORITATIVE write comes from\n // `enrichDataWithContext` reading it off the EC's context map (seeded in\n // `_getDlqExecutionContext`), because the strict CREATE-DTO strips this field from\n // the payload. We ALSO set it here — mirroring the M2M webhook-delivery-log sibling\n // (`buildScopeFkInjection`) — so both delivery-failure paths read identically; it is\n // harmless (stripped, then re-injected by enrichment) rather than the source of truth.\n [scopeFieldIdentifier]: scopeId,\n eventId: payload.envelope.eventId,\n eventPayload: payload.envelope,\n failureReason: `${failureReason}${errorMessage ? `: ${errorMessage}` : ''}`,\n failureCount: 1,\n lastAttemptAt: new Date(),\n nextRetryAt: failureReason === 'retries_exhausted' ? undefined : new Date(Date.now() + 5 * 60 * 1000),\n status: failureReason === 'retries_exhausted' ? SiemDeliveryDlqStatus.EXHAUSTED : SiemDeliveryDlqStatus.PENDING_RETRY,\n };\n\n await dlqRepo.create(ec, dlqEntry);\n\n this.logger.warn('SIEM delivery event persisted to DLQ', {\n scopeType,\n scopeId,\n eventId: payload.envelope.eventId,\n eventType: payload.envelope.eventType,\n failureReason,\n });\n } catch (dlqError) {\n this.logger.error?.('Failed to enqueue SIEM event to DLQ', {\n scopeType,\n scopeId,\n eventId: payload.envelope.eventId,\n ...projectCaughtErrorLogFields(dlqError),\n });\n }\n }\n\n /**\n * Create a REPOSITORY-DIRECT internal ExecutionContext for the DLQ create.\n *\n * SIEM delivery runs in an async queue worker with no user EC, so this synthesises a\n * system super-admin context via `createForInternalRepositoryOperation` — the blessed seam\n * for repository-tier internal writes (shared with FILES / JOB_* / notification-badge) that\n * resolves the DLQ's `REPOSITORY_ONLY` CREATE variant. It also uses the CORRECT polymorphic\n * `dlqResourceType` (the prior hand-rolled path hardcoded the ORG variant even for APP-scoped\n * deliveries).\n *\n * CRITICAL — the scope-FK injection channel: the DLQ's scope FK (organizationId /\n * applicationId) is an excludeFromCreate, context-injected column the polymorphism engine\n * appends per variant; the strict CREATE-DTO strips it from the payload, so it is persisted\n * ONLY by `enrichDataWithContext` reading it off THIS context map. An earlier version passed\n * an EMPTY map → the required scope FK was never injected → Mongoose \"organizationId: Path\n * required\" → every retries-exhausted SIEM delivery was silently lost instead of\n * dead-lettered. An INTERNALLY_INITIATED EC fail-closed rejects org/user identity on\n * `initiatorIds`, so the context map is the ONLY correct channel for the ORGANIZATION scope FK.\n */\n private async _getDlqExecutionContext(\n dlqResourceType: ResourceType,\n scopeFieldIdentifier: string,\n scopeId: string,\n ): Promise<ExecutionContext<any>> {\n return this.executionContextCreator.createForInternalRepositoryOperation({\n resourceType: dlqResourceType,\n operationIdentifier: CoreResourceOperation.CREATE,\n contextResourcesFieldIdentifier: new Map([[scopeFieldIdentifier, scopeId]]),\n initiatorIds: null,\n initiatorRoles: [\n { roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN], relatedPrimaryScope: ResourcePrimaryScope.APPLICATION },\n ],\n });\n }\n\n // ─────────────────────────────────────────────────────────────\n // H6: SIEM Credential Encryption/Decryption\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Derive a 32-byte AES-256 key from the app's session encryption key\n * using a domain-specific separator to avoid key reuse.\n */\n private _deriveSIEMEncryptionKey(): Buffer {\n const baseKey = this.appConfigService.secrets.security.session.encryptionKey;\n return createHash('sha256')\n .update(`${SIEM_KEY_DOMAIN}:${baseKey}`)\n .digest();\n }\n\n /**\n * H6: Resolve a credential value — decrypts if encrypted, returns as-is if plaintext.\n * Encrypted format: `encrypted:aes-256-gcm:{iv_hex}:{authTag_hex}:{ciphertext_hex}`\n */\n private _resolveCredential(credential: string | undefined): string | undefined {\n if (!credential) return undefined;\n\n if (!credential.startsWith(ENCRYPTED_CREDENTIAL_PREFIX)) {\n // Plaintext credential — log a warning for security awareness\n this.logDebug('SIEM credential is plaintext (not encrypted at rest). Consider re-saving via admin API to encrypt.');\n return credential;\n }\n\n try {\n const payload = credential.slice(ENCRYPTED_CREDENTIAL_PREFIX.length);\n const [ivHex, authTagHex, ciphertextHex] = payload.split(':');\n if (!ivHex || !authTagHex || !ciphertextHex) {\n throw new Error('Invalid encrypted credential format');\n }\n\n const key = this._deriveSIEMEncryptionKey();\n const iv = Buffer.from(ivHex, 'hex');\n const authTag = Buffer.from(authTagHex, 'hex');\n const ciphertext = Buffer.from(ciphertextHex, 'hex');\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch (error) {\n this.logger.error?.(\n 'Failed to decrypt SIEM credential',\n projectCaughtErrorLogFields(error),\n );\n return undefined;\n }\n }\n\n /**\n * H6: Encrypt a plaintext credential for storage.\n * Returns the encrypted string in format: `encrypted:aes-256-gcm:{iv}:{authTag}:{ciphertext}`\n *\n * Called by admin API when saving SIEM configuration.\n */\n public encryptCredential(plaintext: string): string {\n const key = this._deriveSIEMEncryptionKey();\n const iv = randomBytes(12); // 96-bit IV for GCM\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return `${ENCRYPTED_CREDENTIAL_PREFIX}${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;\n }\n\n /**\n * Sleep utility for exponential backoff.\n */\n private _sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n"]}
1
+ {"version":3,"file":"siem-webhook-delivery.backend.service.js","sourceRoot":"","sources":["../../../../../../src/compliance/audit-trails/services/siem-webhook-delivery.backend.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SIEM Webhook Delivery Backend Service\n *\n * Layer 3 of the three-layer audit event pipeline (Step 18).\n * Purpose-built for delivering security audit events to customer SIEM endpoints.\n * NOT a generic M2M webhook sender.\n *\n * Responsibilities:\n * - HTTP POST to webhook URL with configured auth\n * - HMAC-SHA256 signature for hmac_sha256 auth method\n * - Exponential backoff retries\n * - Circuit breaker after N consecutive failures per org\n * - CEF/LEEF format conversion (when eventFormat !== json_structured)\n * - Idempotency via eventId\n */\n\nimport 'reflect-metadata';\nimport { inject, injectable } from 'inversify';\nimport { createHmac, createHash, createCipheriv, createDecipheriv, randomBytes } from 'crypto';\nimport { SAAS_SERVICE_TYPES } from '~wildo-backend-lib/inject/models/service-types';\nimport { LoggerService } from '~wildo-backend-lib/monitoring/logger/services/logger.service';\nimport { AppConfigurationService } from '~wildo-backend-lib/config/services/app-configuration.backend.service';\nimport { AuditEventDispatcherBackendService } from './audit-event-dispatcher.backend.service';\nimport { RepositoriesRegistryHandlerBackendService } from '~wildo-backend-lib/base-classes/services/repositories/repositories-registry-handler.backend.service';\nimport { ExecutionContextCreatorBackendService } from '~wildo-backend-lib/runtime/services/execution-context-creator.backend.service';\nimport {\n type SecurityAuditEventEnvelope,\n type SiemExportConfigBase,\n type ResourceType,\n CoreResourceType,\n CoreResourceOperation,\n CORE_APP_ROLES,\n ResourcePrimaryScope,\n WildoHeaderKeys,\n SiemDeliveryDlqStatus,\n SIEMEventFormat,\n AuthScopeType,\n coreResourceShared_FieldIdentifier,\n SIEM_DELIVERY_RELIABILITY_CONTRACT,\n SIEM_CIRCUIT_BREAKER_COOLDOWN_MS,\n} from '@wildo-ai/saas-models';\nimport type { ExecutionContext } from '~wildo-backend-lib/runtime/models/execution-context.backend.schemas';\nimport {\n CEF_PROJECTION,\n LEEF_PROJECTION,\n cefAgentSeverityHeaderValue,\n SiemFieldProjectionKind,\n type SiemProjectionContext,\n type SiemProjectionContract,\n} from './utils/siem-projection-contract.backend.utils';\nimport { buildOcsfEvent } from './utils/siem-ocsf-projection.backend.utils';\nimport {\n CEF_HEADER_MAX_CHARACTERS,\n CEF_MAX_CHARACTERS,\n LEEF_HEADER_MAX_CHARACTERS,\n LEEF_MAX_CHARACTERS,\n LEEF_TAB_DELIMITER_HEADER_VALUE,\n type CefWireKey,\n type LeefWireKey,\n} from './utils/siem-dictionary.backend.utils';\nimport {\n describeCaughtError,\n projectCaughtErrorLogFields,\n} from '~wildo-backend-lib/errors/utils/error-log-level-classification.backend.utils';\n\n/** Circuit breaker state per organization */\ninterface CircuitBreakerState {\n consecutiveFailures: number;\n lastFailureAt: Date | null;\n circuitOpenUntil: Date | null;\n}\n\n/** Payload shape enqueued by AuditEventDispatcherBackendService */\nexport interface SIEMDeliveryJobPayload {\n envelope: SecurityAuditEventEnvelope;\n envelopeHmac?: string; // F6: HMAC integrity signature\n organizationId: string;\n /**\n * Delivery scope. Defaults to {@link AuthScopeType.ORGANIZATION}. The worker is scope-generic (the\n * circuit-breaker key, DLQ variant, and scope FK all derive from it), but `'application'`\n * is currently produced ONLY by the SIEM-DLQ retry custom-impl — there is no first-time\n * app-scoped producer, so the APPLICATION path is reserved / dormant. See\n * `AuditEventDispatcherBackendService.dispatchToOrganizationAuditSinks`.\n */\n scopeType?: AuthScopeType;\n scopeId?: string;\n siemConfig: {\n webhookUrl: string;\n authMethod: string;\n authCredential?: string;\n authHeaderName?: string;\n eventFormat: string;\n customHeaders?: Record<string, string>;\n delivery: {\n batchSize: number;\n batchWindowSeconds: number;\n retryAttempts: number;\n retryBackoffSeconds: number;\n timeoutSeconds: number;\n };\n };\n}\n\n/**\n * Circuit-breaker bounds come from `SIEM_DELIVERY_RELIABILITY_CONTRACT`, which the customer\n * documentation also projects: what an operator is told about a paused destination is what this\n * service applies.\n */\nconst CIRCUIT_BREAKER_THRESHOLD = SIEM_DELIVERY_RELIABILITY_CONTRACT.circuitBreakerFailureThreshold;\nconst CIRCUIT_BREAKER_COOLDOWN_MS = SIEM_CIRCUIT_BREAKER_COOLDOWN_MS;\n/** Prefix for encrypted credentials (H6) */\nconst ENCRYPTED_CREDENTIAL_PREFIX = 'encrypted:aes-256-gcm:';\n/** HKDF-like domain separator for SIEM encryption key derivation */\nconst SIEM_KEY_DOMAIN = 'wildo:siem:credential:v1';\n/**\n * Appended when the `eventData` detail bag is truncated, so the loss is VISIBLE to the receiver\n * rather than silent. A SOC that sees a JSON fragment ending mid-object cannot tell a truncation\n * from a serializer bug; this marker makes the difference explicit on the wire.\n */\nconst SIEM_EVENT_DATA_TRUNCATION_MARKER = '...[truncated]';\n/**\n * Maximum characters of serialized `eventData` carried in the single CEF/LEEF detail field,\n * INCLUDING {@link SIEM_EVENT_DATA_TRUNCATION_MARKER} when truncation occurs — the emitted value\n * never exceeds this bound.\n *\n * This is the CEF extension dictionary's own published length for `msg`, not a Wildo-invented\n * policy. LEEF publishes no per-attribute ceiling, so the same bound is applied there for\n * cross-format consistency: an unbounded detail bag is the realistic way a CEF/LEEF line grows\n * large enough for a receiver to reject it, which would fail the delivery into the DLQ.\n *\n * spec-cite: Implementing ArcSight CEF v26, Oct 2023 — ArcSight Extension Dictionary, \"CEF Key\n * Names for Event Producers\", `msg` row: full name `message`, data type `String`, length `1023`,\n * \"An arbitrary message giving more details about the event.\"\n *\n * The bound is applied to the ESCAPED value, i.e. to what actually goes on the wire. An earlier\n * revision bounded the value BEFORE escaping, on the reading that the ceiling describes the field's\n * CONTENT and escape sequences are transport encoding a receiver strips before it ever sees the\n * field. That reading is defensible and the document does not settle it — which is precisely why the\n * post-escape bound is the one to hold: escaping only ever expands (`=` → `\\=`, `\\` → `\\\\`), so a\n * value within the ceiling once encoded is necessarily within it once decoded. Bounding the encoded\n * form satisfies BOTH readings; bounding the decoded form satisfies only one, and an escape-heavy\n * bag sitting at the ceiling would have gone out over-long under the other.\n */\nconst SIEM_EVENT_DATA_DETAIL_MAX_CHARS = 1023;\n\n// The per-key ceilings and the `devTimeFormat` pattern used to live here as hand-kept constants\n// beside the formatter. They now live in the dictionary spine (`siem-dictionary.backend.utils.ts`),\n// DERIVED from the transcribed rows, because a ceiling maintained next to a key list is the same\n// artefact as the key list itself: adding a key and forgetting its published maximum was possible\n// right up until the derivation existed.\n//\n// Line comments, not a JSDoc block — a `/** */` here would attach to the class below it.\n\n@injectable()\nexport class SIEMWebhookDeliveryBackendService {\n private readonly logDebug: (message: string, context?: Record<string, unknown>) => void;\n private readonly circuitBreakers: Map<string, CircuitBreakerState> = new Map();\n\n constructor(\n @inject(SAAS_SERVICE_TYPES.Logger) private readonly logger: LoggerService,\n @inject(SAAS_SERVICE_TYPES.AppConfigService) private readonly appConfigService: AppConfigurationService,\n @inject(SAAS_SERVICE_TYPES.AuditEventDispatcherService) private readonly auditEventDispatcher: AuditEventDispatcherBackendService,\n @inject(SAAS_SERVICE_TYPES.RepositoriesRegistryHandlerService) private readonly repositoriesRegistry: RepositoriesRegistryHandlerBackendService,\n @inject(SAAS_SERVICE_TYPES.ExecutionContextCreatorBackendService) private readonly executionContextCreator: ExecutionContextCreatorBackendService,\n ) {\n this.logDebug = this.logger.debugByType('SIEMWebhookDeliveryBackendService');\n this.logger.setDebugTypeLogging('SIEMWebhookDeliveryBackendService', false);\n }\n\n /**\n * Process a SIEM delivery job from the queue.\n * Called by the job consumer when a `siem.webhook-delivery` batch job is dequeued.\n */\n public async processDelivery(payload: SIEMDeliveryJobPayload): Promise<void> {\n const { envelope, envelopeHmac, organizationId, siemConfig } = payload;\n const scopeType = payload.scopeType ?? AuthScopeType.ORGANIZATION;\n const scopeId = payload.scopeId ?? organizationId;\n const circuitKey = `${scopeType}:${scopeId}`;\n\n // F6: Verify envelope integrity before processing\n if (envelopeHmac) {\n if (!this.auditEventDispatcher.verifyEnvelopeHmac(envelope, envelopeHmac)) {\n this.logger.error?.('SIEM envelope HMAC verification failed — possible tampering', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n });\n await this._enqueueToDLQ(payload, 'hmac_verification_failed');\n return;\n }\n }\n\n // Circuit breaker check — M11: DLQ instead of silent drop\n if (this._isCircuitOpen(circuitKey)) {\n this.logDebug('Circuit breaker open for scope, sending to DLQ', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n });\n await this._enqueueToDLQ(payload, 'circuit_breaker_open');\n return;\n }\n\n // Format the body\n const body = this._formatBody(envelope, siemConfig.eventFormat);\n\n // Build headers\n const headers = this._buildHeaders(body, siemConfig);\n\n // Attempt delivery with retries\n const maxRetries = siemConfig.delivery.retryAttempts;\n const baseBackoffMs = siemConfig.delivery.retryBackoffSeconds * 1000;\n const timeoutMs = siemConfig.delivery.timeoutSeconds * 1000;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await this._sendHttpPost(siemConfig.webhookUrl, body, headers, timeoutMs);\n\n this._recordSuccess(circuitKey);\n\n this.logDebug('SIEM webhook delivered successfully', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n attempt,\n });\n return;\n } catch (error) {\n const isLastAttempt = attempt === maxRetries;\n\n if (isLastAttempt) {\n this._recordFailure(circuitKey);\n\n this.logger.error?.('SIEM webhook delivery failed after all retries', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n attempts: attempt + 1,\n ...projectCaughtErrorLogFields(error),\n });\n\n // `describeCaughtError`, not an `instanceof Error` ternary: this string is\n // PERSISTED as the DLQ record's failure reason, and a `WildoError_Backend`\n // is a plain object — the ternary would store `'[object Object]'` for every\n // structured fault, making the DLQ untriageable.\n await this._enqueueToDLQ(payload, 'retries_exhausted', describeCaughtError(error));\n } else {\n const backoffMs = baseBackoffMs * Math.pow(2, attempt);\n this.logDebug('SIEM webhook delivery failed, retrying', {\n scopeType,\n scopeId,\n eventId: envelope.eventId,\n attempt,\n nextRetryMs: backoffMs,\n });\n await this._sleep(backoffMs);\n }\n }\n }\n }\n\n /**\n * Format the event body based on the configured event format.\n *\n * `json_structured` ships the envelope verbatim. CEF and LEEF are flat, single-line `key=value`\n * grammars, so they project the envelope in two tiers: the standard/indexed keys each grammar\n * defines (`cat`, `outcome`, `src`, …), followed by the free-form `eventData` bag serialized\n * into that grammar's single detail field. Every envelope field therefore reaches all three\n * formats; only the ENCODING differs.\n */\n private _formatBody(envelope: SecurityAuditEventEnvelope, eventFormat: string): string {\n switch (eventFormat) {\n case SIEMEventFormat.CEF:\n return this._formatAsCEF(envelope);\n case SIEMEventFormat.LEEF:\n return this._formatAsLEEF(envelope);\n case SIEMEventFormat.OCSF:\n // OCSF is JSON, so there is no escaping/bounding layer here — the projection returns a\n // document and the only transport concern is serialisation.\n return JSON.stringify(buildOcsfEvent(envelope));\n case SIEMEventFormat.JSON_STRUCTURED:\n default:\n return JSON.stringify(envelope);\n }\n }\n\n /**\n * Format event as CEF (Common Event Format).\n * CEF:Version|Device Vendor|Device Product|Device Version|Signature ID|Name|Severity|Extension\n */\n private _formatAsCEF(envelope: SecurityAuditEventEnvelope): string {\n const cefSeverity = cefAgentSeverityHeaderValue(envelope.severity);\n const ext = (value: string): string => this._escapeCEFExtensionValue(value);\n const header = (field: string, value: string): string => this._emitBoundedHeaderField(field, value, CEF_HEADER_MAX_CHARACTERS);\n const eventDataDetail = this._serializeEventDataDetail(envelope, ext);\n // CEF extensions are SPACE-delimited, so that is what `join` means for this grammar.\n const pair = (key: CefWireKey, value: string): string => this._emitPair(key, value, ext, CEF_MAX_CHARACTERS);\n const join = (...fragments: readonly string[]): string => fragments.join(' ');\n\n // Driven by CEF_PROJECTION, so a field cannot be dropped by being forgotten — the contract is\n // exhaustive over the envelope type and declaration order is wire order. The per-field reasoning,\n // citations and the csN-budget decision all live there, next to the mapping they justify.\n const extensions = this._renderProjection(CEF_PROJECTION, envelope, { pair, join, eventDataDetail })\n .join(' ');\n\n // Header fields 5 and 6 are DIFFERENT questions and used to receive the same answer. Field 5,\n // `Device Event Class ID`, is the stable signature a QID/correlation rule keys on — `eventType` is\n // exactly that. Field 6, `Name`, is documented as \"a human-readable and understandable description\n // of the event\", so `user_account_locked` twice gave a SOC a machine token in the column its\n // console renders as the event title.\n // spec-cite: Implementing ArcSight CEF v26, Oct 2023 — \"Header Field Definitions\", `deviceEventClassId`\n // row (\"a unique identifier for each event-type … also known as Signature ID\") and `name` row\n // (String, 512): \"a string representing a human-readable and understandable description of the event.\"\n return `CEF:0|${header('deviceVendor', 'Wildo')}|${header('deviceProduct', 'SecurityAudit')}|${header('deviceVersion', envelope.sourceVersion)}|${header('deviceEventClassId', envelope.eventType)}|${header('name', this._humanizeEventType(envelope.eventType))}|${cefSeverity}|${extensions}`;\n }\n\n /**\n * Format event as LEEF (Log Event Extended Format — IBM QRadar).\n * LEEF:Version|Vendor|Product|Version|EventID|Extension\n *\n * The serialized `eventData` bag rides a custom `eventData` attribute. It is deliberately NOT\n * called `msg` as in the CEF projection: `msg` earns that name in CEF by being a dictionary key\n * with a defined meaning, whereas LEEF publishes no such key — borrowing CEF's vocabulary here\n * would imply a standard attribute that does not exist. Each grammar gets the name that is\n * correct within it.\n * spec-cite: N/A — `eventData` is a Wildo-chosen custom attribute name, not a LEEF-defined key.\n */\n private _formatAsLEEF(envelope: SecurityAuditEventEnvelope): string {\n const val = (value: string): string => this._escapeLEEFValue(value);\n const header = (field: string, value: string): string => this._emitBoundedHeaderField(field, value, LEEF_HEADER_MAX_CHARACTERS);\n const eventDataDetail = this._serializeEventDataDetail(envelope, val);\n // LEEF attributes are TAB-delimited (we emit no `DelimiterCharacter`), so that is `join` here.\n const pair = (key: LeefWireKey, value: string): string => this._emitPair(key, value, val, LEEF_MAX_CHARACTERS);\n const join = (...fragments: readonly string[]): string => fragments.join('\\t');\n\n // Driven by LEEF_PROJECTION. LEEF reaches ALL 27 envelope fields because a LEEF custom key stays\n // searchable in QRadar, where a CEF custom extension does not — see the contract for the citation.\n //\n // `sev`, `devTime` and `devTimeFormat` are rendered BY the contract now. They used to be appended\n // here, which looked like a formatter detail and was a hole: a key emitted outside `pair` skips\n // its published ceiling, the duplicate-key check, and the declared-vs-emitted test — and `sev`\n // is precisely a key with a published constraint (`1-10`).\n const extensions = this._renderProjection(LEEF_PROJECTION, envelope, { pair, join, eventDataDetail })\n .join('\\t');\n\n // Six header fields, not five. The sixth is the attribute DelimiterCharacter, which every\n // LEEF 2.0 example in the guide carries and ours omitted — see LEEF_TAB_DELIMITER_HEADER_VALUE:\n // a parser splitting a 2.0 header into six fields was consuming our first attribute as it.\n // Vendor and Product go through `header()` too, though they are constants that need neither\n // escaping nor bounding. The point is that EVERY header field goes through the one door, so\n // \"is this field covered?\" is answerable by looking rather than by reasoning about each value —\n // the same reason `rt` was routed through `pair` even though digits never change.\n return `LEEF:2.0|${header('vendor', 'Wildo')}|${header('product', 'SecurityAudit')}|${header('productVersion', envelope.sourceVersion)}|${header('eventId', envelope.eventType)}|${LEEF_TAB_DELIMITER_HEADER_VALUE}|${extensions}`;\n }\n\n /**\n * Serialize `envelope.eventData` into the single detail field that CEF (`msg`) and LEEF\n * (`eventData`) each carry, or `undefined` when there is nothing worth saying — the caller's\n * `.filter(Boolean)` then drops the key entirely instead of emitting an empty one.\n *\n * Without this, CEF/LEEF subscribers received ONLY the curated standard keys while\n * `json_structured` subscribers received the whole bag: a silent capability gap between\n * formats, not a deliberate reduction.\n *\n * REJECTED ALTERNATIVE — flattening each `eventData` entry into its own extension key\n * (`lockoutDuration=15`, `sessionId=…`). It reads better as SIEM columns, but it is unsound\n * here. `eventData` is an OPEN, app-extensible bag whose keys routinely collide both with the\n * CEF/LEEF dictionaries and with the envelope fields already projected above it: the\n * `USER_LOGIN_FAILED` bag alone carries `failureReason`, `ipAddress` and `email`, which the\n * dispatcher has already promoted onto the envelope and which this formatter already emits as\n * `reason`, `src` and `suser`. Flattening would therefore put `src=` on the line TWICE and leave\n * which one wins to the receiver's parser. Nested objects and arrays have no flat\n * representation either. One JSON field keeps the standard keys authoritative AND the bag\n * lossless, at the cost of a second parse step on the receiving end.\n *\n * The returned JSON is escaped by the CALLER for its grammar, so a backslash ends up encoded\n * twice — once by `JSON.stringify`, once by the CEF/LEEF escaper. That is correct and\n * required: a receiver un-escapes the wire grammar first, then parses the JSON.\n */\n private _serializeEventDataDetail(\n envelope: SecurityAuditEventEnvelope,\n escapeForGrammar: (value: string) => string,\n ): string | undefined {\n // Defensive: the envelope TYPE requires `eventData`, but this formatter also runs over\n // envelopes replayed from the DLQ, where a stored bag can be absent or malformed. An\n // unguarded `Object.keys(undefined)` here would throw inside delivery.\n const eventData: unknown = envelope.eventData;\n if (!eventData || typeof eventData !== 'object' || Object.keys(eventData).length === 0) {\n return undefined;\n }\n\n let serialized: string;\n try {\n serialized = JSON.stringify(eventData);\n } catch {\n // A circular / unserializable bag must not fail the whole delivery — the standard keys\n // above it are still valuable to a SOC, so drop only the detail field.\n this.logDebug('SIEM eventData detail omitted — bag is not JSON-serializable', {\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n });\n return undefined;\n }\n\n // `JSON.stringify` returns `undefined` for a value it cannot represent at all; the guard\n // above makes that unreachable for a non-empty plain object, but a `toJSON()` returning\n // `undefined` would still land here.\n if (!serialized) return undefined;\n\n if (escapeForGrammar(serialized).length <= SIEM_EVENT_DATA_DETAIL_MAX_CHARS) return serialized;\n\n // Largest prefix whose ESCAPED form, marker included, still fits. A prefix length cannot be\n // computed arithmetically because expansion depends on which characters the prefix contains,\n // and it is not uniform across the two grammars (CEF escapes `=`, LEEF does not). Binary search\n // costs O(log n) escape passes and is exact; a fixed safety margin would be a guess that is\n // simultaneously too small for a delimiter-dense bag and wasteful for an ordinary one.\n let fits = 0;\n let tooLong = serialized.length;\n while (fits < tooLong) {\n const candidate = Math.ceil((fits + tooLong) / 2);\n if (escapeForGrammar(this._truncateDetail(serialized, candidate)).length <= SIEM_EVENT_DATA_DETAIL_MAX_CHARS) {\n fits = candidate;\n } else {\n tooLong = candidate - 1;\n }\n }\n const truncated = this._truncateDetail(serialized, fits);\n\n this.logDebug('SIEM eventData detail truncated to the CEF/LEEF detail-field ceiling', {\n eventId: envelope.eventId,\n eventType: envelope.eventType,\n originalLength: serialized.length,\n emittedLength: truncated.length,\n escapedLength: escapeForGrammar(truncated).length,\n maxChars: SIEM_EVENT_DATA_DETAIL_MAX_CHARS,\n });\n return truncated;\n }\n\n /**\n * Cut `serialized` to `length` UTF-16 units and append the truncation marker.\n *\n * The marker is counted INSIDE the ceiling by the caller's search, not appended beyond it — a\n * bound that its own truncation overshoots is not a bound. A cut landing between the halves of a\n * surrogate pair would emit a lone surrogate, which `JSON.parse` on the receiving end rejects with\n * a different error than the truncation it actually is, so the trailing half-pair is dropped.\n */\n private _truncateDetail(serialized: string, length: number): string {\n const cut = serialized.slice(0, length);\n const last = cut.charCodeAt(cut.length - 1);\n const endsOnHighSurrogate = last >= 0xd800 && last <= 0xdbff;\n return `${endsOnHighSurrogate ? cut.slice(0, -1) : cut}${SIEM_EVENT_DATA_TRUNCATION_MARKER}`;\n }\n\n // ─────────────────────────────────────────────────────────────\n // Wire-format escaping\n //\n // CEF and LEEF are single-line, delimiter-separated grammars with NO quoting construct: a\n // delimiter appearing raw inside a value does not produce a malformed record that a parser\n // rejects — it produces a WELL-FORMED record with silently wrong fields. That failure mode is\n // why these helpers exist and why EVERY interpolated string value goes through one of them\n // rather than only the fields believed to be risky today. `outcomeReason` in particular is free\n // text sourced from `eventData.failureReason` / `eventData.reason`, so it is the first projected\n // field with no vocabulary constraining its characters.\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Escape a value for a CEF *extension* (`key=value`) slot.\n *\n * The extension is a space-separated `key=value` list whose parser delimits on the next\n * `<key>=`, so per the CEF standard:\n * - `\\` becomes `\\\\` — it is the escape character itself, which is why it MUST be replaced\n * first; doing it later would re-escape the backslashes introduced by the rules below.\n * - `=` becomes `\\=` — an unescaped `=` is read as the start of the next key/value pair.\n * - CR/LF become the two-character sequences `\\r` / `\\n` — a real newline terminates the\n * record and truncates every remaining field.\n *\n * Spaces are deliberately NOT escaped: the grammar permits them inside extension values (a\n * value is delimited by the next `<key>=`, not by whitespace).\n * spec-cite: Implementing ArcSight CEF v26, Oct 2023 — \"Character Encoding\" / the extension\n * escaping rules for pipe, backslash and equals in the Extension field.\n */\n private _escapeCEFExtensionValue(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/=/g, '\\\\=')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n }\n\n /**\n * Escape a value for a LEEF attribute slot.\n *\n * LEEF pairs are TAB-delimited, so a literal tab fabricates an extra attribute and a newline\n * terminates the record; both are encoded as their escape sequences (`\\` first, for the same\n * reason as above). `=` needs NO escaping here — a LEEF parser splits each pair on its FIRST\n * `=`, so subsequent `=` characters remain part of the value.\n * spec-cite: N/A — LEEF publishes no escaping table for attribute values; these rules are\n * derived from its tab-delimited, newline-terminated record structure, which is why the `=`\n * asymmetry with CEF above is deliberate rather than an oversight.\n */\n private _escapeLEEFValue(value: string): string {\n // ⚠️ `|` and `^` are deliberately NOT escaped, and the reasoning is the point rather than the\n // conclusion. The guide's best practices say to AVOID them in keys and values — it defines no\n // escape for them, because LEEF 2.0's answer is the header's `DelimiterCharacter`, which lets a\n // producer CHOOSE the attribute delimiter (caret is a documented choice). Inventing `\\|` would\n // therefore corrupt the value at every conformant receiver, which is strictly worse than the\n // mis-parse it guards against — and that mis-parse needs a non-conformant parser splitting the\n // whole line on `|`, since the header ends at its fifth. We emit no `DelimiterCharacter`, so the\n // delimiter is TAB and a caret in a value is inert. If a `DelimiterCharacter` is ever emitted,\n // THAT character becomes escapable-or-forbidden and this decision must be re-taken.\n // spec-cite: IBM QRadar LEEF Version 2 (© IBM 2013, 2016) — \"Best practices Guidelines for LEEF\n // events\": \"Use alphanumeric (A-Z, a-z, and 0-9) characters, but avoid tab, pipe, or caret\n // delimiters in your event payload keys and values\"; Table 2, `Delimiter Character` row.\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\t/g, '\\\\t')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\n/g, '\\\\n');\n }\n\n /**\n * Escape a value for a CEF or LEEF *header* slot (the `|`-delimited prefix shared by both\n * grammars).\n *\n * A literal `|` would fabricate a header field and shift every subsequent one — including the\n * severity and the entire extension — so it is escaped as `\\|`. Headers cannot span lines at\n * all (there is no multi-line encoding for them, unlike extension values), so newlines are\n * folded to a space rather than escaped.\n *\n * Applied defensively: `sourceVersion` is read straight from the `APP_VERSION` environment\n * variable and `eventType` is app-extensible, so neither is guaranteed delimiter-free.\n */\n private _escapeSIEMHeaderField(value: string): string {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\\|/g, '\\\\|')\n // Any CR or LF, in any combination — not just `\\r?\\n`. A LONE `\\r` slipped through that form,\n // and a bare CR terminates a record for readers that treat it as a line ending.\n .replace(/[\\r\\n]+/g, ' ');\n }\n\n /**\n * Render a projection contract into its emitted fragments, in declaration order.\n *\n * Only `extension` entries produce wire output. `header` entries are carried by the caller's header\n * construction and `not-projected` entries deliberately produce nothing — both exist in the contract\n * so that COVERAGE is a property of the type rather than of anyone's memory.\n */\n private _renderProjection<K extends string>(\n contract: SiemProjectionContract<SecurityAuditEventEnvelope, K>,\n envelope: SecurityAuditEventEnvelope,\n context: SiemProjectionContext<K>,\n ): string[] {\n const fragments: string[] = [];\n for (const projection of Object.values(contract)) {\n if (projection.kind !== SiemFieldProjectionKind.EXTENSION) continue;\n const fragment = projection.render(envelope, context);\n if (fragment) fragments.push(fragment);\n }\n return fragments;\n }\n\n /**\n * Emit one `key=value` pair, escaped for its grammar and bounded by the key's PUBLISHED ceiling.\n *\n * The bound is measured on the ESCAPED value for the same reason as the detail bag: escaping only\n * expands, so bounding the encoded form is the only bound that holds under both readings of what a\n * published length governs. A key absent from `maxByKey` has no published limit and is emitted\n * whole — the table never invents one.\n *\n * Truncation is LOUD. Losing the tail of an id or an email is a data defect, not a formatting\n * detail, and the receiver cannot tell a truncated value from a short one.\n */\n private _emitPair<K extends string>(\n key: K,\n rawValue: string,\n escapeForGrammar: (value: string) => string,\n maxByKey: Readonly<Record<string, number>>,\n ): string {\n return `${key}=${this._boundToPublishedLength(key, rawValue, escapeForGrammar, maxByKey[key])}`;\n }\n\n /**\n * Escape a value and bound the ESCAPED result at its published ceiling, or emit it whole when the\n * document publishes none.\n *\n * Shared by the extension path ({@link _emitPair}) and the header path\n * ({@link _emitBoundedHeaderField}) because both answer the same question and only one of them used\n * to. Header fields never passed through `_emitPair`, so every published header size — most\n * pointedly `deviceVersion`'s 31 characters, which carries `APP_VERSION` — was unenforced while the\n * extension ceilings were being carefully derived from the dictionary one layer away. Two code\n * paths for one rule is how that happened; there is one now.\n *\n * The bound is measured on the escaped form for the reason given at\n * {@link SIEM_EVENT_DATA_DETAIL_MAX_CHARS}: escaping only expands, so a value within the ceiling\n * once encoded is within it once decoded, which satisfies both readings of what a published length\n * governs. Truncation is LOUD — losing the tail of a version or an id is a data defect, and the\n * receiver cannot tell a truncated value from a short one.\n */\n private _boundToPublishedLength(\n fieldName: string,\n rawValue: string,\n escapeForGrammar: (value: string) => string,\n max: number | undefined,\n ): string {\n const escaped = escapeForGrammar(rawValue);\n if (max === undefined || escaped.length <= max) return escaped;\n\n let fits = 0;\n let tooLong = rawValue.length;\n while (fits < tooLong) {\n const candidate = Math.ceil((fits + tooLong) / 2);\n if (escapeForGrammar(rawValue.slice(0, candidate)).length <= max) fits = candidate;\n else tooLong = candidate - 1;\n }\n const cut = rawValue.slice(0, fits);\n const lastCode = cut.charCodeAt(cut.length - 1);\n const kept = lastCode >= 0xd800 && lastCode <= 0xdbff ? cut.slice(0, -1) : cut;\n\n this.logger.warn?.('SIEM field truncated to its published ceiling', {\n key: fieldName,\n maxChars: max,\n originalLength: rawValue.length,\n emittedLength: kept.length,\n });\n return escapeForGrammar(kept);\n }\n\n /**\n * Emit one `|`-delimited header field, escaped for the shared header grammar and bounded by the\n * size its document publishes for THAT slot.\n *\n * A header field cannot be dropped when it misbehaves — an omitted field shifts every field after\n * it and silently re-interprets the whole record — so the only available degradation is truncation.\n */\n private _emitBoundedHeaderField(\n fieldName: string,\n rawValue: string,\n maxByField: Readonly<Record<string, number>>,\n ): string {\n return this._boundToPublishedLength(\n fieldName,\n rawValue,\n (value) => this._escapeSIEMHeaderField(value),\n maxByField[fieldName],\n );\n }\n\n /**\n * `user_account_locked` → `User account locked`, for CEF's human-readable `Name` header field.\n *\n * Derived rather than authored: the envelope carries no display label, and inventing a lookup table\n * would be a second vocabulary to keep in sync with `CoreAuditableEventType` — the drift shape this\n * codebase keeps paying for. A derivation cannot go stale.\n *\n * Deliberately NOT applied to `Device Event Class ID`, which must stay the machine token: a\n * correlation rule keyed on a prettified string would break the moment the prettifier changed.\n */\n private _humanizeEventType(eventType: string): string {\n const words = eventType.replace(/[_-]+/g, ' ').trim();\n return words ? `${words.charAt(0).toUpperCase()}${words.slice(1)}` : eventType;\n }\n\n /**\n * Build HTTP headers for the SIEM webhook request.\n */\n private _buildHeaders(\n body: string,\n siemConfig: SIEMDeliveryJobPayload['siemConfig'],\n ): Record<string, string> {\n const headers: Record<string, string> = {\n // Second reader of `eventFormat` in this file (the first is `_formatBody`). Both route\n // through the SIEMEventFormat vocabulary so a future format value cannot be added to the\n // switch and silently forgotten here, where the wrong Content-Type makes a receiver reject\n // an otherwise well-formed body.\n // OCSF is JSON too, so the test is \"is this a TEXT grammar\", not \"is it json_structured\".\n // Reading it the other way would have shipped OCSF as `text/plain` — a well-formed body a\n // receiver may refuse to parse, which is this workstream's signature failure shape.\n [WildoHeaderKeys.CONTENT_TYPE]: siemConfig.eventFormat === SIEMEventFormat.CEF || siemConfig.eventFormat === SIEMEventFormat.LEEF\n ? 'text/plain'\n : 'application/json',\n };\n\n // Apply custom headers first (auth headers override if needed)\n if (siemConfig.customHeaders) {\n Object.assign(headers, siemConfig.customHeaders);\n }\n\n // H6: Resolve (decrypt) the credential before use\n const resolvedCredential = this._resolveCredential(siemConfig.authCredential);\n\n // Apply auth method\n switch (siemConfig.authMethod) {\n case 'bearer_token':\n if (resolvedCredential) {\n headers[WildoHeaderKeys.AUTHORIZATION] = `Bearer ${resolvedCredential}`;\n }\n break;\n\n case 'api_key_header': {\n const headerName = siemConfig.authHeaderName || WildoHeaderKeys.API_KEY;\n if (resolvedCredential) {\n headers[headerName] = resolvedCredential;\n }\n break;\n }\n\n case 'hmac_sha256':\n if (resolvedCredential) {\n const hmac = createHmac('sha256', resolvedCredential)\n .update(body)\n .digest('hex');\n headers[WildoHeaderKeys.X_SIGNATURE_256] = `sha256=${hmac}`;\n }\n break;\n\n case 'none':\n default:\n break;\n }\n\n return headers;\n }\n\n /**\n * Send HTTP POST to the SIEM webhook endpoint.\n */\n private async _sendHttpPost(\n url: string,\n body: string,\n headers: Record<string, string>,\n timeoutMs: number,\n ): Promise<void> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers,\n body,\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const responseText = await response.text().catch(() => '');\n throw new Error(\n `SIEM webhook returned HTTP ${response.status}: ${responseText.slice(0, 200)}`\n );\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // Circuit Breaker\n // ─────────────────────────────────────────────────────────────\n\n private _isCircuitOpen(circuitKey: string): boolean {\n const state = this.circuitBreakers.get(circuitKey);\n if (!state || !state.circuitOpenUntil) return false;\n\n if (new Date() > state.circuitOpenUntil) {\n state.circuitOpenUntil = null;\n return false;\n }\n\n return true;\n }\n\n private _recordSuccess(circuitKey: string): void {\n this.circuitBreakers.delete(circuitKey);\n }\n\n private _recordFailure(circuitKey: string): void {\n let state = this.circuitBreakers.get(circuitKey);\n if (!state) {\n state = { consecutiveFailures: 0, lastFailureAt: null, circuitOpenUntil: null };\n this.circuitBreakers.set(circuitKey, state);\n }\n\n state.consecutiveFailures++;\n state.lastFailureAt = new Date();\n\n if (state.consecutiveFailures >= CIRCUIT_BREAKER_THRESHOLD) {\n state.circuitOpenUntil = new Date(Date.now() + CIRCUIT_BREAKER_COOLDOWN_MS);\n this.logger.warn('SIEM circuit breaker opened', {\n circuitKey,\n consecutiveFailures: state.consecutiveFailures,\n cooldownMs: CIRCUIT_BREAKER_COOLDOWN_MS,\n });\n }\n }\n\n // ─────────────────────────────────────────────────────────────\n // M11: Dead Letter Queue\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Persist failed SIEM delivery events to a MongoDB-backed DLQ resource\n * instead of silently dropping them. DLQ entries conform to SiemDeliveryDlqBase\n * and are queryable/retryable through the standard resource engine.\n */\n private async _enqueueToDLQ(\n payload: SIEMDeliveryJobPayload,\n failureReason: string,\n errorMessage?: string,\n ): Promise<void> {\n const scopeType = payload.scopeType ?? AuthScopeType.ORGANIZATION;\n const scopeId = payload.scopeId ?? payload.organizationId;\n try {\n const dlqResourceType = scopeType === AuthScopeType.APPLICATION\n ? CoreResourceType.APPLICATION_SIEM_DELIVERY_DLQ\n : CoreResourceType.ORGANIZATION_SIEM_DELIVERY_DLQ;\n // Polymorphic scope FK field name: `organizationId` for the ORG variant,\n // `applicationId` for the APP variant (the polymorphism engine's per-variant column).\n const scopeFieldIdentifier = scopeType === AuthScopeType.APPLICATION\n ? coreResourceShared_FieldIdentifier[CoreResourceType.APPLICATION]\n : coreResourceShared_FieldIdentifier[CoreResourceType.ORGANIZATIONS];\n\n const ec = await this._getDlqExecutionContext(dlqResourceType, scopeFieldIdentifier, scopeId);\n const dlqRepo = this.repositoriesRegistry.getRepositoryOrThrow(dlqResourceType);\n\n const dlqEntry = {\n // The polymorphic scope FK (organizationId / applicationId) is NOT on\n // SiemDeliveryDlqBaseSchema — the polymorphism engine appends it per variant as an\n // excludeFromCreate, context-injected column. Its AUTHORITATIVE write comes from\n // `enrichDataWithContext` reading it off the EC's context map (seeded in\n // `_getDlqExecutionContext`), because the strict CREATE-DTO strips this field from\n // the payload. We ALSO set it here — mirroring the M2M webhook-delivery-log sibling\n // (`buildScopeFkInjection`) — so both delivery-failure paths read identically; it is\n // harmless (stripped, then re-injected by enrichment) rather than the source of truth.\n [scopeFieldIdentifier]: scopeId,\n eventId: payload.envelope.eventId,\n eventPayload: payload.envelope,\n failureReason: `${failureReason}${errorMessage ? `: ${errorMessage}` : ''}`,\n failureCount: 1,\n lastAttemptAt: new Date(),\n nextRetryAt: failureReason === 'retries_exhausted' ? undefined : new Date(Date.now() + 5 * 60 * 1000),\n status: failureReason === 'retries_exhausted' ? SiemDeliveryDlqStatus.EXHAUSTED : SiemDeliveryDlqStatus.PENDING_RETRY,\n };\n\n await dlqRepo.create(ec, dlqEntry);\n\n this.logger.warn('SIEM delivery event persisted to DLQ', {\n scopeType,\n scopeId,\n eventId: payload.envelope.eventId,\n eventType: payload.envelope.eventType,\n failureReason,\n });\n } catch (dlqError) {\n this.logger.error?.('Failed to enqueue SIEM event to DLQ', {\n scopeType,\n scopeId,\n eventId: payload.envelope.eventId,\n ...projectCaughtErrorLogFields(dlqError),\n });\n }\n }\n\n /**\n * Create a REPOSITORY-DIRECT internal ExecutionContext for the DLQ create.\n *\n * SIEM delivery runs in an async queue worker with no user EC, so this synthesises a\n * system super-admin context via `createForInternalRepositoryOperation` — the blessed seam\n * for repository-tier internal writes (shared with FILES / JOB_* / notification-badge) that\n * resolves the DLQ's `REPOSITORY_ONLY` CREATE variant. It also uses the CORRECT polymorphic\n * `dlqResourceType` (the prior hand-rolled path hardcoded the ORG variant even for APP-scoped\n * deliveries).\n *\n * CRITICAL — the scope-FK injection channel: the DLQ's scope FK (organizationId /\n * applicationId) is an excludeFromCreate, context-injected column the polymorphism engine\n * appends per variant; the strict CREATE-DTO strips it from the payload, so it is persisted\n * ONLY by `enrichDataWithContext` reading it off THIS context map. An earlier version passed\n * an EMPTY map → the required scope FK was never injected → Mongoose \"organizationId: Path\n * required\" → every retries-exhausted SIEM delivery was silently lost instead of\n * dead-lettered. An INTERNALLY_INITIATED EC fail-closed rejects org/user identity on\n * `initiatorIds`, so the context map is the ONLY correct channel for the ORGANIZATION scope FK.\n */\n private async _getDlqExecutionContext(\n dlqResourceType: ResourceType,\n scopeFieldIdentifier: string,\n scopeId: string,\n ): Promise<ExecutionContext<any>> {\n return this.executionContextCreator.createForInternalRepositoryOperation({\n resourceType: dlqResourceType,\n operationIdentifier: CoreResourceOperation.CREATE,\n contextResourcesFieldIdentifier: new Map([[scopeFieldIdentifier, scopeId]]),\n initiatorIds: null,\n initiatorRoles: [\n { roles: [CORE_APP_ROLES.APP_ADMIN_SUPER_ADMIN], relatedPrimaryScope: ResourcePrimaryScope.APPLICATION },\n ],\n });\n }\n\n // ─────────────────────────────────────────────────────────────\n // H6: SIEM Credential Encryption/Decryption\n // ─────────────────────────────────────────────────────────────\n\n /**\n * Derive a 32-byte AES-256 key from the app's session encryption key\n * using a domain-specific separator to avoid key reuse.\n */\n private _deriveSIEMEncryptionKey(): Buffer {\n const baseKey = this.appConfigService.secrets.security.session.encryptionKey;\n return createHash('sha256')\n .update(`${SIEM_KEY_DOMAIN}:${baseKey}`)\n .digest();\n }\n\n /**\n * H6: Resolve a credential value — decrypts if encrypted, returns as-is if plaintext.\n * Encrypted format: `encrypted:aes-256-gcm:{iv_hex}:{authTag_hex}:{ciphertext_hex}`\n */\n private _resolveCredential(credential: string | undefined): string | undefined {\n if (!credential) return undefined;\n\n if (!credential.startsWith(ENCRYPTED_CREDENTIAL_PREFIX)) {\n // Plaintext credential — log a warning for security awareness\n this.logDebug('SIEM credential is plaintext (not encrypted at rest). Consider re-saving via admin API to encrypt.');\n return credential;\n }\n\n try {\n const payload = credential.slice(ENCRYPTED_CREDENTIAL_PREFIX.length);\n const [ivHex, authTagHex, ciphertextHex] = payload.split(':');\n if (!ivHex || !authTagHex || !ciphertextHex) {\n throw new Error('Invalid encrypted credential format');\n }\n\n const key = this._deriveSIEMEncryptionKey();\n const iv = Buffer.from(ivHex, 'hex');\n const authTag = Buffer.from(authTagHex, 'hex');\n const ciphertext = Buffer.from(ciphertextHex, 'hex');\n\n const decipher = createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);\n return decrypted.toString('utf8');\n } catch (error) {\n this.logger.error?.(\n 'Failed to decrypt SIEM credential',\n projectCaughtErrorLogFields(error),\n );\n return undefined;\n }\n }\n\n /**\n * H6: Encrypt a plaintext credential for storage.\n * Returns the encrypted string in format: `encrypted:aes-256-gcm:{iv}:{authTag}:{ciphertext}`\n *\n * Called by admin API when saving SIEM configuration.\n */\n public encryptCredential(plaintext: string): string {\n const key = this._deriveSIEMEncryptionKey();\n const iv = randomBytes(12); // 96-bit IV for GCM\n const cipher = createCipheriv('aes-256-gcm', key, iv);\n\n const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return `${ENCRYPTED_CREDENTIAL_PREFIX}${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`;\n }\n\n /**\n * Sleep utility for exponential backoff.\n */\n private _sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ocsf-activity-mapping.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../../../src/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAkC,sBAAsB,EAAsD,MAAM,uBAAuB,CAAC;AAGnJ,oFAAoF;AACpF,oBAAY,kBAAkB;IAC5B,uCAAuC;IACvC,OAAO,IAAI;IACX,6EAA6E;IAC7E,KAAK,KAAK;CACX;AAED,sEAAsE;AACtE,oBAAY,0BAA0B;IACpC,8HAA8H;IAC9H,KAAK,IAAI;IACT,6DAA6D;IAC7D,MAAM,IAAI;IACV,mHAAmH;IACnH,OAAO,IAAI;IACX,KAAK,KAAK;CACX;AAED,oEAAoE;AACpE,oBAAY,eAAe;IACzB,MAAM,IAAI;IACV,uFAAuF;IACvF,IAAI,IAAI;IACR,MAAM,IAAI;IACV,MAAM,IAAI;IACV,KAAK,KAAK;CACX;AAED,yEAAyE;AACzE,oBAAY,4BAA4B;IACtC,MAAM,IAAI;IACV,IAAI,IAAI;IACR,MAAM,IAAI;IACV,MAAM,IAAI;IACV,IAAI,IAAI;IACR,sEAAsE;IACtE,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,OAAO,IAAI;IACX,QAAQ,KAAK;IACb,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,2GAA2G;IAC3G,MAAM,KAAK;IACX,KAAK,KAAK;CACX;AAED,uEAAuE;AACvE,oBAAY,0BAA0B;IACpC,MAAM,IAAI;IACV,MAAM,IAAI;IACV,MAAM,IAAI;IACV,MAAM,IAAI;IACV,OAAO,IAAI;IACX,IAAI,IAAI;IACR,MAAM,IAAI;IACV,eAAe,IAAI;IACnB,cAAc,IAAI;IAClB,eAAe,KAAK;IACpB,eAAe,KAAK;IACpB,kBAAkB,KAAK;IACvB,mBAAmB,KAAK;IACxB,iBAAiB,KAAK;IACtB,iBAAiB,KAAK;IACtB,YAAY,KAAK;IACjB,YAAY,KAAK;IACjB,4BAA4B,KAAK;IACjC,+BAA+B,KAAK;IACpC,KAAK,KAAK;CACX;AAgBD;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CA6IxF,CAAC;AAwBF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEjG;AAED;;;;;;GAMG;AACH,oBAAY,kBAAkB;IAC5B,OAAO,IAAI;IACX,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,MAAM,IAAI;IACV,IAAI,IAAI;IACR,SAAS,IAAI;IACb,GAAG,IAAI;IACP,IAAI,IAAI;IACR,GAAG,IAAI;IACP,MAAM,KAAK;IACX,oBAAoB,KAAK;IACzB,IAAI,KAAK;IACT,KAAK,KAAK;CACX;AAyCD,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAK5E;AAuCD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUlF"}
1
+ {"version":3,"file":"ocsf-activity-mapping.backend.utils.d.ts","sourceRoot":"","sources":["../../../../../../../src/compliance/audit-trails/services/utils/ocsf-activity-mapping.backend.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAkC,sBAAsB,EAAsD,MAAM,uBAAuB,CAAC;AAGnJ,oFAAoF;AACpF,oBAAY,kBAAkB;IAC5B,uCAAuC;IACvC,OAAO,IAAI;IACX,6EAA6E;IAC7E,KAAK,KAAK;CACX;AAED,sEAAsE;AACtE,oBAAY,0BAA0B;IACpC,8HAA8H;IAC9H,KAAK,IAAI;IACT,6DAA6D;IAC7D,MAAM,IAAI;IACV,mHAAmH;IACnH,OAAO,IAAI;IACX,KAAK,KAAK;CACX;AAED,oEAAoE;AACpE,oBAAY,eAAe;IACzB,MAAM,IAAI;IACV,uFAAuF;IACvF,IAAI,IAAI;IACR,MAAM,IAAI;IACV,MAAM,IAAI;IACV,KAAK,KAAK;CACX;AAED,yEAAyE;AACzE,oBAAY,4BAA4B;IACtC,MAAM,IAAI;IACV,IAAI,IAAI;IACR,MAAM,IAAI;IACV,MAAM,IAAI;IACV,IAAI,IAAI;IACR,sEAAsE;IACtE,MAAM,IAAI;IACV,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,OAAO,IAAI;IACX,QAAQ,KAAK;IACb,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,2GAA2G;IAC3G,MAAM,KAAK;IACX,KAAK,KAAK;CACX;AAED,uEAAuE;AACvE,oBAAY,0BAA0B;IACpC,MAAM,IAAI;IACV,MAAM,IAAI;IACV,MAAM,IAAI;IACV,MAAM,IAAI;IACV,OAAO,IAAI;IACX,IAAI,IAAI;IACR,MAAM,IAAI;IACV,eAAe,IAAI;IACnB,cAAc,IAAI;IAClB,eAAe,KAAK;IACpB,eAAe,KAAK;IACpB,kBAAkB,KAAK;IACvB,mBAAmB,KAAK;IACxB,iBAAiB,KAAK;IACtB,iBAAiB,KAAK;IACtB,YAAY,KAAK;IACjB,YAAY,KAAK;IACjB,4BAA4B,KAAK;IACjC,+BAA+B,KAAK;IACpC,KAAK,KAAK;CACX;AAgBD;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,QAAQ,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CA2JxF,CAAC;AAwBF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEjG;AAED;;;;;;GAMG;AACH,oBAAY,kBAAkB;IAC5B,OAAO,IAAI;IACX,IAAI,IAAI;IACR,QAAQ,IAAI;IACZ,MAAM,IAAI;IACV,MAAM,IAAI;IACV,IAAI,IAAI;IACR,SAAS,IAAI;IACb,GAAG,IAAI;IACP,IAAI,IAAI;IACR,GAAG,IAAI;IACP,MAAM,KAAK;IACX,oBAAoB,KAAK;IACzB,IAAI,KAAK;IACT,KAAK,KAAK;CACX;AAyCD,+FAA+F;AAC/F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;CACzC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAK5E;AAuCD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUlF"}
@@ -181,6 +181,13 @@ export const OCSF_ACTIVITY_BY_EVENT_TYPE = {
181
181
  [CoreAuditableEventType.USER_PASSWORD_SET]: OcsfAuthenticationActivity.OTHER,
182
182
  [CoreAuditableEventType.USER_REFRESH_TOKEN_REUSE_DETECTED]: OcsfAuthenticationActivity.OTHER,
183
183
  [CoreAuditableEventType.USER_SESSION_EXPIRED]: OcsfAuthenticationActivity.LOGOFF,
184
+ /*
185
+ * LOGOFF, like the expiry above: the session is terminated and no longer exists, which is what the
186
+ * OCSF verb states. The DIFFERENCE between the two — time elapsed versus a cap displacing a live
187
+ * chain — is not expressible in `activity_id`, so it rides the typed eventData and the WARNING
188
+ * severity instead. Mapping it to OTHER would have lost the one thing a SIEM correlates on.
189
+ */
190
+ [CoreAuditableEventType.USER_SESSION_EVICTED]: OcsfAuthenticationActivity.LOGOFF,
184
191
  [CoreAuditableEventType.USER_SMS_OTP_FAILED]: OcsfAuthenticationActivity.LOGON,
185
192
  [CoreAuditableEventType.USER_SMS_OTP_SENT]: OcsfAuthenticationActivity.PREAUTH,
186
193
  [CoreAuditableEventType.USER_SMS_OTP_VERIFIED]: OcsfAuthenticationActivity.LOGON,
@@ -190,6 +197,10 @@ export const OCSF_ACTIVITY_BY_EVENT_TYPE = {
190
197
  [CoreAuditableEventType.USER_TOKEN_REFRESHED]: OcsfAuthenticationActivity.OTHER,
191
198
  [CoreAuditableEventType.USER_TOTP_DISABLED]: OcsfAuthenticationActivity.OTHER,
192
199
  // ── AUTHORIZATION ──
200
+ // A file upload grant delegates one upload under the minter's authority; issuing/revoking it is not
201
+ // one of 6003's CRUD verbs on a resource.
202
+ [CoreAuditableEventType.FILE_UPLOAD_GRANT_ISSUED]: OcsfApiActivity.OTHER,
203
+ [CoreAuditableEventType.FILE_UPLOAD_GRANT_REVOKED]: OcsfApiActivity.OTHER,
193
204
  [CoreAuditableEventType.APPLICATION_SUPER_ADMIN_FLOOR_BREACHED]: OcsfApiActivity.OTHER,
194
205
  [CoreAuditableEventType.CROSS_TENANT_ADMINISTRATIVE_ACCESS]: OcsfApiActivity.OTHER,
195
206
  [CoreAuditableEventType.OAUTH2_PROVIDER_BLOCKED]: OcsfApiActivity.OTHER,
@@ -208,6 +219,9 @@ export const OCSF_ACTIVITY_BY_EVENT_TYPE = {
208
219
  [CoreAuditableEventType.USER_APP_ROLES_CHANGED]: OcsfApiActivity.OTHER, // a role change is not one of 6003 CRUD verbs
209
220
  // ── DATA_ACCESS ──
210
221
  [CoreAuditableEventType.FIELD_ACCESS]: OcsfApiActivity.READ,
222
+ // CREATE, not OTHER: redeeming a grant IS the creation of one FILES row — the one DATA_ACCESS event
223
+ // whose CRUD verb is derivable from the type, like PLATFORM_DIRECTORY_ACCESS below.
224
+ [CoreAuditableEventType.FILE_UPLOAD_GRANT_REDEEMED]: OcsfApiActivity.CREATE,
211
225
  [CoreAuditableEventType.MACHINE_ACCESS]: OcsfApiActivity.OTHER, // names a surface reach (A2A/MCP turn), not a CRUD verb on a resource
212
226
  // READ, not OTHER: enumerating a directory IS a read of resource rows, and it is the one case
213
227
  // where the CRUD verb IS derivable from the event type — the event only ever names a collection