@tellescope/sdk 1.256.13 → 1.256.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js +1 -1
- package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js +388 -0
- package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/integrations_redacted.test.js +3 -3
- package/lib/cjs/tests/api_tests/integrations_redacted.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js +272 -0
- package/lib/cjs/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js +103 -162
- package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +336 -0
- package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +354 -0
- package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +389 -0
- package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +324 -0
- package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +282 -0
- package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +249 -0
- package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +281 -0
- package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js +390 -0
- package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js +1003 -0
- package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js +323 -0
- package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js +335 -0
- package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +237 -0
- package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js +349 -0
- package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +314 -0
- package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js +362 -0
- package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js +366 -0
- package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js +248 -0
- package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js +138 -0
- package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +201 -0
- package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js +278 -0
- package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js +155 -0
- package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js +88 -0
- package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +230 -0
- package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +242 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js +148 -0
- package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js +388 -0
- package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js +222 -0
- package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +354 -0
- package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js +442 -0
- package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js +156 -0
- package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js +329 -0
- package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/cjs/tests/api_tests/webhook_error_handling.test.js +2 -2
- package/lib/cjs/tests/api_tests/webhook_error_handling.test.js.map +1 -1
- package/lib/cjs/tests/setup_isolated.d.ts +68 -0
- package/lib/cjs/tests/setup_isolated.d.ts.map +1 -0
- package/lib/cjs/tests/setup_isolated.js +232 -0
- package/lib/cjs/tests/setup_isolated.js.map +1 -0
- package/lib/cjs/tests/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +287 -227
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js +89 -0
- package/lib/cjs/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +140 -0
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js +1 -1
- package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js +383 -0
- package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
- package/lib/esm/tests/api_tests/integrations_redacted.test.js +3 -3
- package/lib/esm/tests/api_tests/integrations_redacted.test.js.map +1 -1
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts +20 -0
- package/lib/esm/tests/api_tests/organization_signup.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js +264 -0
- package/lib/esm/tests/api_tests/organization_signup.test.js.map +1 -0
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.js +104 -163
- package/lib/esm/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +332 -0
- package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +350 -0
- package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +382 -0
- package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +317 -0
- package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +277 -0
- package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +244 -0
- package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +276 -0
- package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js +386 -0
- package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js +996 -0
- package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js +316 -0
- package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js +331 -0
- package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +233 -0
- package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js +345 -0
- package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +310 -0
- package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js +358 -0
- package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js +362 -0
- package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js +243 -0
- package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js +134 -0
- package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +194 -0
- package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js +271 -0
- package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js +151 -0
- package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.js +84 -0
- package/lib/esm/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +223 -0
- package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +238 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js +144 -0
- package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js +381 -0
- package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js +218 -0
- package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +350 -0
- package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js +435 -0
- package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.js +149 -0
- package/lib/esm/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js +324 -0
- package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
- package/lib/esm/tests/api_tests/webhook_error_handling.test.js +2 -2
- package/lib/esm/tests/api_tests/webhook_error_handling.test.js.map +1 -1
- package/lib/esm/tests/setup_isolated.d.ts +68 -0
- package/lib/esm/tests/setup_isolated.d.ts.map +1 -0
- package/lib/esm/tests/setup_isolated.js +221 -0
- package/lib/esm/tests/setup_isolated.js.map +1 -0
- package/lib/esm/tests/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +287 -227
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js +85 -0
- package/lib/esm/tests/unit_tests/do_not_send_address.test.js.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +113 -0
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/tests/api_tests/auto_merge_form_submission.test.ts +1 -1
- package/src/tests/api_tests/enduser_observations_auto_review.test.ts +358 -0
- package/src/tests/api_tests/integrations_redacted.test.ts +1 -1
- package/src/tests/api_tests/organization_signup.test.ts +240 -0
- package/src/tests/api_tests/purchase_made_trigger.test.ts +29 -41
- package/src/tests/api_tests/security/add-to-journey-foreign-enduserid.test.ts +207 -0
- package/src/tests/api_tests/security/{F-0005-ai-conversations-rbac.test.ts → ai-conversations-rbac.test.ts} +14 -14
- package/src/tests/api_tests/security/{F-0166-allowed-paths-wildcard-bypass.test.ts → allowed-paths-confinement.test.ts} +11 -11
- package/src/tests/api_tests/security/automated-actions-process-gate.test.ts +237 -0
- package/src/tests/api_tests/security/booking-info-idor-token-mint.test.ts +224 -0
- package/src/tests/api_tests/security/{F-0053-cascade-role-rename-cross-tenant.test.ts → cascade-role-rename-cross-tenant.test.ts} +10 -10
- package/src/tests/api_tests/security/{F-0001-data-sync-redaction-bypass.test.ts → data-sync-redaction-bypass.test.ts} +9 -9
- package/src/tests/api_tests/security/{F-0006-develop-health-benefit-verification-rbac.test.ts → develop-health-benefit-verification-rbac.test.ts} +7 -8
- package/src/tests/api_tests/security/{F-0116-F-0119-enduser-cross-create.test.ts → enduser-cross-create.test.ts} +25 -25
- package/src/tests/api_tests/security/{F-0106-F-0110-enduser-write-restrictions.test.ts → enduser-write-restrictions.test.ts} +12 -14
- package/src/tests/api_tests/security/form-logic-js-execution.test.ts +183 -0
- package/src/tests/api_tests/security/{F-0145-globalunique-leak.test.ts → globalunique-conflict-redaction.test.ts} +5 -6
- package/src/tests/api_tests/security/{F-0008-handle-incoming-communication-cross-tenant.test.ts → handle-incoming-communication-cross-tenant.test.ts} +8 -8
- package/src/tests/api_tests/security/{F-0007-invite-user-enumeration.test.ts → invite-user-enumeration.test.ts} +8 -8
- package/src/tests/api_tests/security/{F-0151-load-inbox-redaction.test.ts → load-inbox-redaction.test.ts} +5 -6
- package/src/tests/api_tests/security/{F-0016-prototype-pollution.test.ts → prototype-pollution.test.ts} +4 -4
- package/src/tests/api_tests/security/{F-0025-proxy-image-unauth-ssrf.test.ts → proxy-image-unauth-ssrf.test.ts} +11 -12
- package/src/tests/api_tests/security/{F-0013-sanitize-user-html-with-iframes.test.ts → sanitize-user-html-with-iframes.test.ts} +5 -5
- package/src/tests/api_tests/security/{F-0013-sanitize-user-html.test.ts → sanitize-user-html.test.ts} +4 -4
- package/src/tests/api_tests/security/schema-adminonly-enforcement.test.ts +287 -0
- package/src/tests/api_tests/security/{F-0076-self-admin-role-assignment.test.ts → self-admin-role-assignment.test.ts} +13 -13
- package/src/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.ts +162 -0
- package/src/tests/api_tests/security/{F-0015-webhook-outbound-ssrf.test.ts → webhook-outbound-ssrf.test.ts} +13 -14
- package/src/tests/api_tests/security/{F-0155-webhook-timeout.test.ts → webhook-timeout.test.ts} +6 -7
- package/src/tests/api_tests/tickets_bulk_assign_from_queue.test.ts +279 -0
- package/src/tests/api_tests/webhook_error_handling.test.ts +1 -1
- package/src/tests/setup_isolated.ts +170 -0
- package/src/tests/tests.ts +60 -18
- package/src/tests/unit_tests/do_not_send_address.test.ts +60 -0
- package/src/tests/unit_tests/openapi_spec_freshness.test.ts +88 -0
- package/test_generated.pdf +0 -0
- package/src/tests/api_tests/security/readonly-enduser-preview.test.ts +0 -301
|
@@ -14,8 +14,7 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
|
14
14
|
const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Regression test
|
|
18
|
-
* reopened 2026-08-17 for the `develop_health_run_benefit_verification` sub-item.
|
|
17
|
+
* Regression test: the `develop_health_run_benefit_verification` RBAC gate.
|
|
19
18
|
*
|
|
20
19
|
* `enduser_eligibility_results.develop_health_run_benefit_verification` is registered with
|
|
21
20
|
* `noAccessPermissions: true` (packages/private/api/api/v1/api.ts, ~line 24606). Before the fix,
|
|
@@ -39,7 +38,7 @@ const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.
|
|
|
39
38
|
* Post-fix: the handler throws 403 before touching `DB.endusers` at all. Test passes.
|
|
40
39
|
*/
|
|
41
40
|
export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
42
|
-
log_header("
|
|
41
|
+
log_header("develop_health benefit verification RBAC regression")
|
|
43
42
|
|
|
44
43
|
const roleName = `f0006-develop-health-no-access-${Date.now()}`
|
|
45
44
|
let rbapId: string | undefined
|
|
@@ -74,7 +73,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
74
73
|
// Pre-fix: proceeds to DB.endusers.findById and either 400s on validation (fake id) or
|
|
75
74
|
// succeeds and forwards PHI to Develop Health (real id) — never a 403.
|
|
76
75
|
await async_test(
|
|
77
|
-
"
|
|
76
|
+
"enduser_eligibility_results.develop_health_run_benefit_verification must throw 403 when role denies endusers/enduser_eligibility_results",
|
|
78
77
|
() => sdkNonAdmin.api.enduser_eligibility_results.develop_health_run_benefit_verification({
|
|
79
78
|
enduserId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
80
79
|
providerUserId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
@@ -122,7 +121,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
122
121
|
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
123
122
|
|
|
124
123
|
await async_test(
|
|
125
|
-
"
|
|
124
|
+
"a provider role with enduser access passes the gate (reaches 'Integration not found', not 403)",
|
|
126
125
|
() => sdkNonAdmin.api.enduser_eligibility_results.develop_health_run_benefit_verification({
|
|
127
126
|
enduserId: new ObjectId().toHexString(),
|
|
128
127
|
providerUserId: new ObjectId().toHexString(),
|
|
@@ -159,7 +158,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
159
158
|
// the handler throws "Integration not found" BEFORE reaching the (now read-scoped) enduser load,
|
|
160
159
|
// and the enduser load is what the create>read fix governs. Exercising it would need either a real
|
|
161
160
|
// Develop Health integration or reordering the handler purely for the test. It is covered by code
|
|
162
|
-
// review +
|
|
161
|
+
// review + the systemic follow-up. If a Develop Health sandbox integration is ever available
|
|
163
162
|
// in the test org, add: role { endusers: create 'All', read 'Assigned' } → call with a real
|
|
164
163
|
// enduser NOT assigned to the caller → expect the enduser-not-found path, not a successful forward.
|
|
165
164
|
} finally {
|
|
@@ -194,11 +193,11 @@ if (require.main === module) {
|
|
|
194
193
|
|
|
195
194
|
runTests()
|
|
196
195
|
.then(() => {
|
|
197
|
-
console.log("✅
|
|
196
|
+
console.log("✅ develop_health_run_benefit_verification RBAC test suite completed successfully")
|
|
198
197
|
process.exit(0)
|
|
199
198
|
})
|
|
200
199
|
.catch((error) => {
|
|
201
|
-
console.error("❌
|
|
200
|
+
console.error("❌ develop_health_run_benefit_verification RBAC test suite failed:", error)
|
|
202
201
|
process.exit(1)
|
|
203
202
|
})
|
|
204
203
|
}
|
|
@@ -16,10 +16,10 @@ const CROSS_ENDUSER_MESSAGE = "enduserId does not match creator id for enduser s
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Regression test for the enduser cross-enduser CREATE gating gaps:
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* enduser_observations
|
|
20
|
+
* enduser_orders
|
|
21
|
+
* managed_content_records
|
|
22
|
+
* chat_rooms (enduserIds-only gate; staff userIds targeting is by-design)
|
|
23
23
|
*
|
|
24
24
|
* Each model exposed enduserActions.create with an `enduserId`/`enduserIds` field that
|
|
25
25
|
* lacked a write-side gate, letting an authenticated enduser create records bound to a
|
|
@@ -30,7 +30,7 @@ const CROSS_ENDUSER_MESSAGE = "enduserId does not match creator id for enduser s
|
|
|
30
30
|
* legitimate path (self-create + staff-create) still works.
|
|
31
31
|
*/
|
|
32
32
|
export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
33
|
-
log_header("
|
|
33
|
+
log_header("enduser cross-enduser create gates")
|
|
34
34
|
|
|
35
35
|
let attackerId: string | undefined
|
|
36
36
|
let victimId: string | undefined
|
|
@@ -53,10 +53,10 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
53
53
|
await attackerSDK.authenticate(attackerEmail, ENDUSER_PASSWORD)
|
|
54
54
|
|
|
55
55
|
// ============================================================
|
|
56
|
-
//
|
|
56
|
+
// enduser_observations
|
|
57
57
|
// ============================================================
|
|
58
58
|
await async_test(
|
|
59
|
-
`
|
|
59
|
+
`enduser cannot create observation on another enduser (createOne)`,
|
|
60
60
|
() => attackerSDK.api.enduser_observations.createOne({
|
|
61
61
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
62
62
|
measurement: { unit: 'mmHg', value: 220 },
|
|
@@ -64,7 +64,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
64
64
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
65
65
|
)
|
|
66
66
|
await async_test(
|
|
67
|
-
`
|
|
67
|
+
`enduser cannot create observation on another enduser (createMany)`,
|
|
68
68
|
() => attackerSDK.api.enduser_observations.createSome([{
|
|
69
69
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
70
70
|
measurement: { unit: 'mmHg', value: 220 },
|
|
@@ -74,7 +74,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
74
74
|
|
|
75
75
|
// Positive control: enduser CAN create an observation on their OWN record
|
|
76
76
|
await async_test(
|
|
77
|
-
`
|
|
77
|
+
`enduser can still create observation on own record`,
|
|
78
78
|
() => attackerSDK.api.enduser_observations.createOne({
|
|
79
79
|
enduserId: attackerId!, category: 'vital-signs', status: 'final',
|
|
80
80
|
measurement: { unit: 'mmHg', value: 120 },
|
|
@@ -83,7 +83,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
83
83
|
)
|
|
84
84
|
// Positive control: staff CAN create an observation on any tenant enduser
|
|
85
85
|
await async_test(
|
|
86
|
-
`
|
|
86
|
+
`staff can still create observation on any enduser`,
|
|
87
87
|
() => sdk.api.enduser_observations.createOne({
|
|
88
88
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
89
89
|
measurement: { unit: 'mmHg', value: 118 },
|
|
@@ -92,61 +92,61 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
// ============================================================
|
|
95
|
-
//
|
|
95
|
+
// enduser_orders
|
|
96
96
|
// ============================================================
|
|
97
97
|
const orderPayload = (enduserId: string) => ({
|
|
98
98
|
enduserId, externalId: `f0117-${Date.now()}`, source: 'f0117-source',
|
|
99
99
|
title: 'f0117 order', status: 'pending',
|
|
100
100
|
})
|
|
101
101
|
await async_test(
|
|
102
|
-
`
|
|
102
|
+
`enduser cannot create order on another enduser`,
|
|
103
103
|
() => attackerSDK.api.enduser_orders.createOne(orderPayload(victimId!) as any),
|
|
104
104
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
105
105
|
)
|
|
106
106
|
await async_test(
|
|
107
|
-
`
|
|
107
|
+
`enduser can still create order on own record`,
|
|
108
108
|
() => attackerSDK.api.enduser_orders.createOne(orderPayload(attackerId!) as any),
|
|
109
109
|
{ onResult: (o: any) => { if (o?.id) createdOrderIds.push(o.id); return o?.enduserId === attackerId } },
|
|
110
110
|
)
|
|
111
111
|
await async_test(
|
|
112
|
-
`
|
|
112
|
+
`staff can still create order on any enduser`,
|
|
113
113
|
() => sdk.api.enduser_orders.createOne(orderPayload(victimId!) as any),
|
|
114
114
|
{ onResult: (o: any) => { if (o?.id) createdOrderIds.push(o.id); return o?.enduserId === victimId } },
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
// ============================================================
|
|
118
|
-
//
|
|
118
|
+
// managed_content_records
|
|
119
119
|
// ============================================================
|
|
120
120
|
await async_test(
|
|
121
|
-
`
|
|
121
|
+
`enduser cannot create content with allowUnauthenticatedAccess`,
|
|
122
122
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
123
123
|
title: 'f0119 phishing', textContent: 'x', allowUnauthenticatedAccess: true,
|
|
124
124
|
} as any),
|
|
125
125
|
{ shouldError: true, onError: e => e.message === "allowUnauthenticatedAccess cannot be set by endusers" },
|
|
126
126
|
)
|
|
127
127
|
await async_test(
|
|
128
|
-
`
|
|
128
|
+
`enduser cannot create content with publicRead`,
|
|
129
129
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
130
130
|
title: 'f0119 broadcast', textContent: 'x', publicRead: true,
|
|
131
131
|
} as any),
|
|
132
132
|
{ shouldError: true, onError: e => e.message === "publicRead cannot be set by endusers" },
|
|
133
133
|
)
|
|
134
134
|
await async_test(
|
|
135
|
-
`
|
|
135
|
+
`enduser cannot create content bound to another enduser`,
|
|
136
136
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
137
137
|
title: 'f0119 cross', textContent: 'x', enduserId: victimId!,
|
|
138
138
|
} as any),
|
|
139
139
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
140
140
|
)
|
|
141
141
|
await async_test(
|
|
142
|
-
`
|
|
142
|
+
`enduser can still create ordinary content`,
|
|
143
143
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
144
144
|
title: 'f0119 ok', textContent: 'hello',
|
|
145
145
|
} as any),
|
|
146
146
|
{ onResult: (o: any) => { if (o?.id) createdContentIds.push(o.id); return !o?.publicRead && !o?.allowUnauthenticatedAccess } },
|
|
147
147
|
)
|
|
148
148
|
await async_test(
|
|
149
|
-
`
|
|
149
|
+
`staff can still create public content`,
|
|
150
150
|
() => sdk.api.managed_content_records.createOne({
|
|
151
151
|
title: 'f0119 staff public', textContent: 'x', publicRead: true,
|
|
152
152
|
} as any),
|
|
@@ -154,11 +154,11 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
154
154
|
)
|
|
155
155
|
|
|
156
156
|
// ============================================================
|
|
157
|
-
//
|
|
157
|
+
// chat_rooms (enduserIds-only gate; staff userIds targeting is by-design)
|
|
158
158
|
// ============================================================
|
|
159
159
|
const staffId = sdk.userInfo.id
|
|
160
160
|
await async_test(
|
|
161
|
-
`
|
|
161
|
+
`enduser cannot add another patient to a chat room (enduserIds)`,
|
|
162
162
|
() => attackerSDK.api.chat_rooms.createOne({
|
|
163
163
|
type: 'internal', enduserIds: [attackerId!, victimId!], userIds: [staffId],
|
|
164
164
|
} as any),
|
|
@@ -166,7 +166,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
166
166
|
)
|
|
167
167
|
// Positive control: patient CAN create a room with care-team staff + self (intended feature)
|
|
168
168
|
await async_test(
|
|
169
|
-
`
|
|
169
|
+
`enduser can still create a room with staff + self`,
|
|
170
170
|
() => attackerSDK.api.chat_rooms.createOne({
|
|
171
171
|
type: 'internal', enduserIds: [attackerId!], userIds: [staffId],
|
|
172
172
|
} as any),
|
|
@@ -174,7 +174,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
174
174
|
)
|
|
175
175
|
// Positive control: staff can still create multi-patient rooms
|
|
176
176
|
await async_test(
|
|
177
|
-
`
|
|
177
|
+
`staff can still create a room with multiple endusers`,
|
|
178
178
|
() => sdk.api.chat_rooms.createOne({
|
|
179
179
|
type: 'internal', enduserIds: [attackerId!, victimId!], userIds: [staffId],
|
|
180
180
|
} as any),
|
|
@@ -211,7 +211,7 @@ if (require.main === module) {
|
|
|
211
211
|
|
|
212
212
|
runTests()
|
|
213
213
|
.then(() => {
|
|
214
|
-
console.log("✅
|
|
214
|
+
console.log("✅ enduser cross-create test suite completed successfully")
|
|
215
215
|
process.exit(0)
|
|
216
216
|
})
|
|
217
217
|
.catch((error) => {
|
|
@@ -71,9 +71,7 @@ const restrictedFormResponseUpdates = (staffId: string, otherEnduserId: string):
|
|
|
71
71
|
})
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Regression test
|
|
75
|
-
* (security-audit/findings/F-0106-enduser-self-update-admin-only-fields.md,
|
|
76
|
-
* security-audit/findings/F-0110-form-responses-enduser-update-admin-only-fields.md).
|
|
74
|
+
* Regression test: enduser self-updates must not write staff-only fields on `endusers` or `form_responses`.
|
|
77
75
|
*
|
|
78
76
|
* Endusers could PATCH admin-only / access-bearing / attribution-bearing fields on
|
|
79
77
|
* their own endusers record (assignedTo, tags, references, ...) and their own
|
|
@@ -88,7 +86,7 @@ const restrictedFormResponseUpdates = (staffId: string, otherEnduserId: string):
|
|
|
88
86
|
* - staff sessions can still update the restricted fields
|
|
89
87
|
*/
|
|
90
88
|
export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
91
|
-
log_header("
|
|
89
|
+
log_header("enduser write restrictions (enduserUpdatesDisabled)")
|
|
92
90
|
|
|
93
91
|
let enduserId: string | undefined
|
|
94
92
|
let otherEnduserId: string | undefined
|
|
@@ -111,7 +109,7 @@ export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session,
|
|
|
111
109
|
const enduserSDK = new EnduserSession({ host, businessId })
|
|
112
110
|
await enduserSDK.authenticate(enduserEmail, ENDUSER_PASSWORD)
|
|
113
111
|
|
|
114
|
-
const form = await sdk.api.forms.createOne({ title: '
|
|
112
|
+
const form = await sdk.api.forms.createOne({ title: 'Write Restriction Test Form' })
|
|
115
113
|
formId = form.id
|
|
116
114
|
const { response: formResponse } = await sdk.api.form_responses.prepare_form_response({
|
|
117
115
|
formId: form.id,
|
|
@@ -119,34 +117,34 @@ export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session,
|
|
|
119
117
|
})
|
|
120
118
|
formResponseId = formResponse.id
|
|
121
119
|
|
|
122
|
-
// ----
|
|
120
|
+
// ---- enduser self-update of restricted endusers fields must 400 ----
|
|
123
121
|
for (const [field, value] of Object.entries(restrictedEnduserUpdates(sdk.userInfo.id, enduser.id))) {
|
|
124
122
|
await async_test(
|
|
125
|
-
`
|
|
123
|
+
`enduser cannot self-update endusers.${field}`,
|
|
126
124
|
() => enduserSDK.api.endusers.updateOne(enduser.id, { [field]: value } as any),
|
|
127
125
|
{ shouldError: true, onError: e => e.message === `${field} cannot be updated by endusers` },
|
|
128
126
|
)
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
//
|
|
129
|
+
// Variant A persistence check: the rejected assignedTo write must not
|
|
132
130
|
// have granted the staff read-filter match.
|
|
133
131
|
await async_test(
|
|
134
|
-
'
|
|
132
|
+
'rejected assignedTo write did not persist',
|
|
135
133
|
() => sdk.api.endusers.getOne(enduser.id),
|
|
136
134
|
{ onResult: e => !e.assignedTo?.length && !e.tags?.length && e.externalId === undefined },
|
|
137
135
|
)
|
|
138
136
|
|
|
139
|
-
// ----
|
|
137
|
+
// ---- enduser self-update of restricted form_responses fields must 400 ----
|
|
140
138
|
for (const [field, value] of Object.entries(restrictedFormResponseUpdates(sdk.userInfo.id, otherEnduser.id))) {
|
|
141
139
|
await async_test(
|
|
142
|
-
`
|
|
140
|
+
`enduser cannot self-update form_responses.${field}`,
|
|
143
141
|
() => enduserSDK.api.form_responses.updateOne(formResponse.id, { [field]: value } as any),
|
|
144
142
|
{ shouldError: true, onError: e => e.message === `${field} cannot be updated by endusers` },
|
|
145
143
|
)
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
await async_test(
|
|
149
|
-
'
|
|
147
|
+
'rejected writes did not persist (markedAsSubmitted, procedureCodes, submittedBy, enduserId)',
|
|
150
148
|
() => sdk.api.form_responses.getOne(formResponse.id),
|
|
151
149
|
{ onResult: fr => (
|
|
152
150
|
!fr.markedAsSubmitted && !fr.procedureCodes?.length && fr.submittedBy === undefined
|
|
@@ -238,11 +236,11 @@ if (require.main === module) {
|
|
|
238
236
|
|
|
239
237
|
runTests()
|
|
240
238
|
.then(() => {
|
|
241
|
-
console.log("✅
|
|
239
|
+
console.log("✅ enduser write-restriction test suite completed successfully")
|
|
242
240
|
process.exit(0)
|
|
243
241
|
})
|
|
244
242
|
.catch((error) => {
|
|
245
|
-
console.error("❌
|
|
243
|
+
console.error("❌ enduser write-restriction test suite failed:", error)
|
|
246
244
|
process.exit(1)
|
|
247
245
|
})
|
|
248
246
|
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
require('source-map-support').install();
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
assert_checks,
|
|
5
|
+
Check,
|
|
6
|
+
setup_isolated_tenant,
|
|
7
|
+
} from "../../setup_isolated"
|
|
8
|
+
|
|
9
|
+
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
10
|
+
|
|
11
|
+
const RAND = () => Math.random().toString(36).slice(2, 10)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Regression test: `$JS(...)` must be rejected in stored conditional logic.
|
|
15
|
+
*
|
|
16
|
+
* `responses_satisfy_conditions` (utilities/src/utils.ts) compiled a stored condition value of the
|
|
17
|
+
* form `$JS(...)` with `new Function()` and executed it — in every form-filler's browser, including
|
|
18
|
+
* anonymous visitors on public intake pages, AND inside the API process (automation_triggers.ts
|
|
19
|
+
* trigger matching on every form submission, ai_agent/form_filling.ts voice-agent navigation). The
|
|
20
|
+
* API process holds every tenant's database handle, so a condition authored by staff in one tenant
|
|
21
|
+
* reached all of them. Any staff user or API key with form_fields write access could plant one by
|
|
22
|
+
* typing into the free-text $gt/$lt box — no API call required.
|
|
23
|
+
*
|
|
24
|
+
* The sink is removed. This asserts the second half of the fix: `compoundFilterValidator` rejects the
|
|
25
|
+
* syntax at write time on every field that feeds that evaluator, so it cannot be reintroduced through
|
|
26
|
+
* stored configuration. The runtime half — that a `$JS` value is never evaluated — is covered by the
|
|
27
|
+
* pure-function cases in `form_conditional_logic_tests` in tests.ts.
|
|
28
|
+
*
|
|
29
|
+
* The five condition locations were established by enumerating every `responses_satisfy_conditions`
|
|
30
|
+
* call site, and all five are covered here. That completeness matters: the first run of this test
|
|
31
|
+
* caught a half fix. `event.conditions` is wrapped in an `orValidator`, which returns the first arm
|
|
32
|
+
* that does not throw, and its permissive `optional: optionalAnyObjectValidator` arm was declared
|
|
33
|
+
* before the guarded one — so the payload was accepted and stored even though the validator had been
|
|
34
|
+
* swapped. Pointing a field at the guard is not the same as the guard being reachable, which is why
|
|
35
|
+
* every location gets an assertion rather than an argument.
|
|
36
|
+
*
|
|
37
|
+
* Each rejection is paired with a positive control using the same shape without `$JS(`, so a passing
|
|
38
|
+
* test cannot be explained by the write failing for an unrelated reason.
|
|
39
|
+
*/
|
|
40
|
+
export const form_logic_js_execution_checks = async (): Promise<Check[]> => {
|
|
41
|
+
const checks: Check[] = []
|
|
42
|
+
const record = (label: string, pass: boolean, detail: string) => checks.push({ label, pass, detail })
|
|
43
|
+
|
|
44
|
+
const JS_PAYLOAD = '$JS(return 0)'
|
|
45
|
+
const SAFE_VALUE = '18'
|
|
46
|
+
|
|
47
|
+
const condition = (value: string) => ({ $and: [{ condition: { 'someFieldId': { $gt: value } } }] })
|
|
48
|
+
const previousFields = (value: string) => ([{
|
|
49
|
+
type: 'compoundLogic',
|
|
50
|
+
info: { fieldId: '000000000000000000000000', priority: 5, label: '', condition: condition(value) },
|
|
51
|
+
}])
|
|
52
|
+
|
|
53
|
+
const attempt = async (fn: () => Promise<any>) => (
|
|
54
|
+
fn().then(() => ({ accepted: true, detail: 'accepted' }))
|
|
55
|
+
.catch((e: any) => ({ accepted: false, detail: `rejected: ${e?.message || e}` }))
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
let tenant: Awaited<ReturnType<typeof setup_isolated_tenant>> | undefined
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
tenant = await setup_isolated_tenant({ name: `F0200 ${RAND()}`, users: [{ isAdmin: true }], apiKeys: 0 })
|
|
62
|
+
const sdk = tenant.sdk
|
|
63
|
+
|
|
64
|
+
const form = await sdk.api.forms.createOne({ title: `${RAND()}` })
|
|
65
|
+
const field = await sdk.api.form_fields.createOne({
|
|
66
|
+
formId: form.id, title: 'anchor', type: 'string', previousFields: [{ type: 'root', info: {} }],
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
/* ===== 1. previousFields[].info.condition — the field the finding was reported against ===== */
|
|
70
|
+
|
|
71
|
+
const controlCreate = await attempt(() => sdk.api.form_fields.createOne({
|
|
72
|
+
formId: form.id, title: 'control', type: 'string',
|
|
73
|
+
previousFields: previousFields(SAFE_VALUE) as any,
|
|
74
|
+
}))
|
|
75
|
+
record(
|
|
76
|
+
'control: form_fields.createOne accepts a normal $gt condition',
|
|
77
|
+
controlCreate.accepted, controlCreate.detail,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
const payloadCreate = await attempt(() => sdk.api.form_fields.createOne({
|
|
81
|
+
formId: form.id, title: 'payload', type: 'string',
|
|
82
|
+
previousFields: previousFields(JS_PAYLOAD) as any,
|
|
83
|
+
}))
|
|
84
|
+
record(
|
|
85
|
+
'1a: form_fields.createOne rejects $JS( in previousFields condition',
|
|
86
|
+
!payloadCreate.accepted, payloadCreate.detail,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const payloadUpdate = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
90
|
+
previousFields: previousFields(JS_PAYLOAD) as any,
|
|
91
|
+
}))
|
|
92
|
+
record(
|
|
93
|
+
'1b: form_fields.updateOne rejects $JS( in previousFields condition',
|
|
94
|
+
!payloadUpdate.accepted, payloadUpdate.detail,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
/* ===== 2. groupShowCondition ===== */
|
|
98
|
+
|
|
99
|
+
const groupControl = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
100
|
+
groupShowCondition: condition(SAFE_VALUE) as any,
|
|
101
|
+
}))
|
|
102
|
+
record('control: groupShowCondition accepts a normal condition', groupControl.accepted, groupControl.detail)
|
|
103
|
+
|
|
104
|
+
const groupPayload = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
105
|
+
groupShowCondition: condition(JS_PAYLOAD) as any,
|
|
106
|
+
}))
|
|
107
|
+
record('2: form_fields.updateOne rejects $JS( in groupShowCondition', !groupPayload.accepted, groupPayload.detail)
|
|
108
|
+
|
|
109
|
+
/* ===== 3. options.optionDetails[].showCondition ===== */
|
|
110
|
+
|
|
111
|
+
const optionControl = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
112
|
+
options: { optionDetails: [{ option: 'A', showCondition: condition(SAFE_VALUE) }] } as any,
|
|
113
|
+
}))
|
|
114
|
+
record('control: optionDetails showCondition accepts a normal condition', optionControl.accepted, optionControl.detail)
|
|
115
|
+
|
|
116
|
+
const optionPayload = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
117
|
+
options: { optionDetails: [{ option: 'A', showCondition: condition(JS_PAYLOAD) }] } as any,
|
|
118
|
+
}))
|
|
119
|
+
record('3: form_fields.updateOne rejects $JS( in optionDetails showCondition', !optionPayload.accepted, optionPayload.detail)
|
|
120
|
+
|
|
121
|
+
/* ===== 4. options.productConditions[].showCondition ===== */
|
|
122
|
+
|
|
123
|
+
const productControl = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
124
|
+
options: { productConditions: [{ productId: '000000000000000000000000', showCondition: condition(SAFE_VALUE) }] } as any,
|
|
125
|
+
}))
|
|
126
|
+
record('control: productConditions showCondition accepts a normal condition', productControl.accepted, productControl.detail)
|
|
127
|
+
|
|
128
|
+
const productPayload = await attempt(() => sdk.api.form_fields.updateOne(field.id, {
|
|
129
|
+
options: { productConditions: [{ productId: '000000000000000000000000', showCondition: condition(JS_PAYLOAD) }] } as any,
|
|
130
|
+
}))
|
|
131
|
+
record('4: form_fields.updateOne rejects $JS( in productConditions showCondition', !productPayload.accepted, productPayload.detail)
|
|
132
|
+
|
|
133
|
+
/* ===== 5. automation_triggers — the server-side evaluation path ===== */
|
|
134
|
+
|
|
135
|
+
const trigger = (conditions: object, extraInfo: object = {}) => ({
|
|
136
|
+
title: `${RAND()}`,
|
|
137
|
+
status: 'Inactive',
|
|
138
|
+
event: { type: 'Form Submitted', info: { formId: form.id, ...extraInfo }, ...conditions },
|
|
139
|
+
action: { type: 'Add Tags', info: { tags: ['security-regression'] } },
|
|
140
|
+
} as any)
|
|
141
|
+
|
|
142
|
+
const triggerControl = await attempt(() => sdk.api.automation_triggers.createOne(
|
|
143
|
+
trigger({ conditions: condition(SAFE_VALUE) })
|
|
144
|
+
))
|
|
145
|
+
record('control: automation_triggers accepts normal event conditions', triggerControl.accepted, triggerControl.detail)
|
|
146
|
+
|
|
147
|
+
// NOTE: this is the case that caught the half fix — the orValidator's permissive arm accepted it.
|
|
148
|
+
const triggerPayload = await attempt(() => sdk.api.automation_triggers.createOne(
|
|
149
|
+
trigger({ conditions: condition(JS_PAYLOAD) })
|
|
150
|
+
))
|
|
151
|
+
record('5a: automation_triggers rejects $JS( in event.conditions', !triggerPayload.accepted, triggerPayload.detail)
|
|
152
|
+
|
|
153
|
+
const byFormIdPayload = await attempt(() => sdk.api.automation_triggers.createOne(
|
|
154
|
+
trigger({}, { conditionsByFormId: { [form.id]: condition(JS_PAYLOAD) } })
|
|
155
|
+
))
|
|
156
|
+
record('5b: automation_triggers rejects $JS( in event.info.conditionsByFormId', !byFormIdPayload.accepted, byFormIdPayload.detail)
|
|
157
|
+
} finally {
|
|
158
|
+
// Teardown BEFORE anything asserts — assert calls process.exit, which skips pending finallys and
|
|
159
|
+
// would strand the provisioned tenant permanently.
|
|
160
|
+
if (tenant) { try { await tenant.teardown() } catch (e) { console.error('teardown failed', e) } }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return checks
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Asserting wrapper, for standalone runs and for sequential use in the suite. */
|
|
167
|
+
export const form_logic_js_execution_tests = async () => {
|
|
168
|
+
assert_checks('$JS in stored conditional logic', await form_logic_js_execution_checks())
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Allow running this test file independently
|
|
172
|
+
if (require.main === module) {
|
|
173
|
+
console.log(`🌐 Using API URL: ${host}`)
|
|
174
|
+
form_logic_js_execution_tests()
|
|
175
|
+
.then(() => {
|
|
176
|
+
console.log("✅ form logic JS execution test suite completed successfully")
|
|
177
|
+
process.exit(0)
|
|
178
|
+
})
|
|
179
|
+
.catch((error) => {
|
|
180
|
+
console.error("❌ form logic JS execution test suite failed:", error)
|
|
181
|
+
process.exit(1)
|
|
182
|
+
})
|
|
183
|
+
}
|
|
@@ -10,8 +10,7 @@ import { setup_tests } from "../../setup"
|
|
|
10
10
|
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Regression test
|
|
14
|
-
* (security-audit/findings/F-0145-globalunique-conflict-leaks-cross-tenant-record.md).
|
|
13
|
+
* Regression test: a globalUnique conflict response must not echo the matched record.
|
|
15
14
|
*
|
|
16
15
|
* The create endpoint generator's unconditional globalUnique-enforcement block
|
|
17
16
|
* (routing.ts, "globalUnique should be enforced even if _overrideUnique is true")
|
|
@@ -24,7 +23,7 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
|
24
23
|
* 409 body's existingRecord exposes nothing beyond _id + businessId.
|
|
25
24
|
*/
|
|
26
25
|
export const globalunique_leak_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
27
|
-
log_header("
|
|
26
|
+
log_header("globalUnique conflict response redaction")
|
|
28
27
|
|
|
29
28
|
let userId: string | undefined
|
|
30
29
|
try {
|
|
@@ -33,7 +32,7 @@ export const globalunique_leak_tests = async ({ sdk } : { sdk: Session, sdkNonAd
|
|
|
33
32
|
userId = user.id
|
|
34
33
|
|
|
35
34
|
await async_test(
|
|
36
|
-
'
|
|
35
|
+
'globalUnique 409 existingRecord exposes only _id + businessId (no email/hashedPass)',
|
|
37
36
|
() => sdk.api.users.createOne({ email, _overrideUnique: true } as any),
|
|
38
37
|
{
|
|
39
38
|
shouldError: true,
|
|
@@ -68,11 +67,11 @@ if (require.main === module) {
|
|
|
68
67
|
|
|
69
68
|
runTests()
|
|
70
69
|
.then(() => {
|
|
71
|
-
console.log("✅
|
|
70
|
+
console.log("✅ globalUnique leak test suite completed successfully")
|
|
72
71
|
process.exit(0)
|
|
73
72
|
})
|
|
74
73
|
.catch((error) => {
|
|
75
|
-
console.error("❌
|
|
74
|
+
console.error("❌ globalUnique leak test suite failed:", error)
|
|
76
75
|
process.exit(1)
|
|
77
76
|
})
|
|
78
77
|
}
|
|
@@ -27,7 +27,7 @@ const post = async (path: string, body: any, headers: Record<string, string> = {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Regression test
|
|
30
|
+
* Regression test: `handle_incoming_communication` tenant scoping.
|
|
31
31
|
*
|
|
32
32
|
* `journeys.handle_incoming_communication` previously used `buildAllQueries({ unrestricted: true, organizationIds: [] }).endusers.findById(enduserId)`,
|
|
33
33
|
* permitting cross-tenant lookup of any enduser by id. The handler then called `handleIncomingCommunication(...)`
|
|
@@ -45,7 +45,7 @@ const post = async (path: string, body: any, headers: Record<string, string> = {
|
|
|
45
45
|
* enduser — the post-fix code returns 404 before any side effects fire, and the assertion confirms that.
|
|
46
46
|
*/
|
|
47
47
|
export const handle_incoming_communication_cross_tenant_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
48
|
-
log_header("
|
|
48
|
+
log_header("handle_incoming_communication cross-tenant rejection")
|
|
49
49
|
|
|
50
50
|
// ====================================================================
|
|
51
51
|
// Assertion 1: nonexistent enduserId returns 404 (baseline; regression
|
|
@@ -58,19 +58,19 @@ export const handle_incoming_communication_cross_tenant_tests = async ({ sdk, sd
|
|
|
58
58
|
{ Authorization: `Bearer ${sdk.authToken}` },
|
|
59
59
|
)
|
|
60
60
|
await async_test(
|
|
61
|
-
"
|
|
61
|
+
"handle_incoming_communication with nonexistent enduserId returns 404",
|
|
62
62
|
async () => ({ status: nonexistentRes.status }),
|
|
63
63
|
{ onResult: r => r.status === 404 },
|
|
64
64
|
)
|
|
65
65
|
|
|
66
66
|
// ====================================================================
|
|
67
|
-
// Assertion 2: cross-tenant enduserId returns 404 (the actual
|
|
67
|
+
// Assertion 2: cross-tenant enduserId returns 404 (the actual fix).
|
|
68
68
|
// Env-gated; skipped when cross-org infra isn't configured.
|
|
69
69
|
// Safe to run post-fix because the tenant-scoped DB returns null for
|
|
70
70
|
// cross-tenant lookups — no handleIncomingCommunication side effect fires.
|
|
71
71
|
// ====================================================================
|
|
72
72
|
if (!(CROSS_ORG_API_KEY && CROSS_ORG_TARGET_BUSINESS_ID)) {
|
|
73
|
-
console.log("
|
|
73
|
+
console.log(" Skipping cross-tenant rejection assertion — CROSS_ORG_* env vars not set")
|
|
74
74
|
return
|
|
75
75
|
}
|
|
76
76
|
|
|
@@ -96,7 +96,7 @@ export const handle_incoming_communication_cross_tenant_tests = async ({ sdk, sd
|
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
await async_test(
|
|
99
|
-
"
|
|
99
|
+
"handle_incoming_communication with cross-tenant enduserId returns 404 (no side effect)",
|
|
100
100
|
async () => ({
|
|
101
101
|
status: crossRes.status,
|
|
102
102
|
message: crossRes.data?.message ?? null,
|
|
@@ -120,11 +120,11 @@ if (require.main === module) {
|
|
|
120
120
|
|
|
121
121
|
runTests()
|
|
122
122
|
.then(() => {
|
|
123
|
-
console.log("✅
|
|
123
|
+
console.log("✅ handle_incoming_communication cross-tenant test suite completed successfully")
|
|
124
124
|
process.exit(0)
|
|
125
125
|
})
|
|
126
126
|
.catch((error) => {
|
|
127
|
-
console.error("❌
|
|
127
|
+
console.error("❌ handle_incoming_communication cross-tenant test suite failed:", error)
|
|
128
128
|
process.exit(1)
|
|
129
129
|
})
|
|
130
130
|
}
|