@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Session } from "../../sdk"
|
|
2
|
-
import { log_header,
|
|
2
|
+
import { log_header, async_test, poll_for_results } from "@tellescope/testing"
|
|
3
3
|
import { Enduser } from "@tellescope/types-client"
|
|
4
4
|
import { setup_tests } from "../setup"
|
|
5
5
|
|
|
@@ -8,6 +8,14 @@ const host = process.env.API_URL || "http://localhost:8080"
|
|
|
8
8
|
export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
9
9
|
log_header("Automation Trigger Tests (Purchase Made)")
|
|
10
10
|
|
|
11
|
+
// Trigger handling is fire-and-forget, and triggers apply newest-first, so the oldest matching
|
|
12
|
+
// trigger's tag lands last — a fixed sleep races it. Same approach as poll_for_tag in
|
|
13
|
+
// stripe_webhook_triggers.test.ts.
|
|
14
|
+
const enduser_with_tags = (enduserId: string, tags: string[]) => poll_for_results(
|
|
15
|
+
() => sdk.api.endusers.getOne(enduserId),
|
|
16
|
+
e => tags.every(t => e.tags?.includes(t)),
|
|
17
|
+
)
|
|
18
|
+
|
|
11
19
|
// Create products for testing
|
|
12
20
|
const product1 = await sdk.api.products.createOne({
|
|
13
21
|
title: 'Premium Course Package',
|
|
@@ -150,10 +158,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
150
158
|
cost: { amount: 9999, currency: 'USD' },
|
|
151
159
|
processor: 'Stripe'
|
|
152
160
|
})
|
|
153
|
-
await wait(undefined, 500) // Brief wait for trigger processing
|
|
154
161
|
await async_test(
|
|
155
162
|
"Purchase Made - Any Purchase",
|
|
156
|
-
() =>
|
|
163
|
+
() => enduser_with_tags(enduser1.id, ['Purchase-Any']),
|
|
157
164
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') }
|
|
158
165
|
)
|
|
159
166
|
|
|
@@ -165,10 +172,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
165
172
|
cost: { amount: 9999, currency: 'USD' },
|
|
166
173
|
processor: 'Stripe'
|
|
167
174
|
})
|
|
168
|
-
await wait(undefined, 500)
|
|
169
175
|
await async_test(
|
|
170
176
|
"Purchase Made - Exact Title Match",
|
|
171
|
-
() =>
|
|
177
|
+
() => enduser_with_tags(enduser2.id, ['Purchase-Exact-Title']),
|
|
172
178
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Exact-Title') }
|
|
173
179
|
)
|
|
174
180
|
|
|
@@ -180,10 +186,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
180
186
|
cost: { amount: 4999, currency: 'USD' },
|
|
181
187
|
processor: 'Stripe'
|
|
182
188
|
})
|
|
183
|
-
await wait(undefined, 500)
|
|
184
189
|
await async_test(
|
|
185
190
|
"Purchase Made - Product ID Match",
|
|
186
|
-
() =>
|
|
191
|
+
() => enduser_with_tags(enduser3.id, ['Purchase-Product-ID']),
|
|
187
192
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Product-ID') }
|
|
188
193
|
)
|
|
189
194
|
|
|
@@ -195,10 +200,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
195
200
|
cost: { amount: 9999, currency: 'USD' },
|
|
196
201
|
processor: 'Stripe'
|
|
197
202
|
})
|
|
198
|
-
await wait(undefined, 500)
|
|
199
203
|
await async_test(
|
|
200
204
|
"Purchase Made - Partial Title Match (case insensitive 'course')",
|
|
201
|
-
() =>
|
|
205
|
+
() => enduser_with_tags(enduser4.id, ['Purchase-Partial-Course']),
|
|
202
206
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Partial-Course') }
|
|
203
207
|
)
|
|
204
208
|
|
|
@@ -210,10 +214,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
210
214
|
cost: { amount: 14999, currency: 'USD' },
|
|
211
215
|
processor: 'Stripe'
|
|
212
216
|
})
|
|
213
|
-
await wait(undefined, 500)
|
|
214
217
|
await async_test(
|
|
215
218
|
"Purchase Made - Partial Title Match (case insensitive 'ANALYTICS')",
|
|
216
|
-
() =>
|
|
219
|
+
() => enduser_with_tags(enduser5.id, ['Purchase-Partial-Analytics']),
|
|
217
220
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Partial-Analytics') }
|
|
218
221
|
)
|
|
219
222
|
|
|
@@ -225,10 +228,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
225
228
|
cost: { amount: 4999, currency: 'USD' },
|
|
226
229
|
processor: 'Stripe'
|
|
227
230
|
})
|
|
228
|
-
await wait(undefined, 500)
|
|
229
231
|
await async_test(
|
|
230
232
|
"Purchase Made - No Partial Title Match",
|
|
231
|
-
() =>
|
|
233
|
+
() => enduser_with_tags(enduser6.id, ['Purchase-Any']),
|
|
232
234
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') && !e.tags?.includes('Purchase-Partial-Course') && !e.tags?.includes('Purchase-Partial-Analytics') }
|
|
233
235
|
)
|
|
234
236
|
|
|
@@ -240,10 +242,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
240
242
|
cost: { amount: 9999, currency: 'USD' },
|
|
241
243
|
processor: 'Stripe'
|
|
242
244
|
})
|
|
243
|
-
await wait(undefined, 500)
|
|
244
245
|
await async_test(
|
|
245
246
|
"Purchase Made - Mixed Case Partial Title Match",
|
|
246
|
-
() =>
|
|
247
|
+
() => enduser_with_tags(enduser7.id, ['Purchase-Partial-Course']),
|
|
247
248
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Partial-Course') }
|
|
248
249
|
)
|
|
249
250
|
|
|
@@ -255,10 +256,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
255
256
|
cost: { amount: 9999, currency: 'USD' },
|
|
256
257
|
processor: 'Stripe'
|
|
257
258
|
})
|
|
258
|
-
await wait(undefined, 500)
|
|
259
259
|
await async_test(
|
|
260
260
|
"Purchase Made - Multiple Partial Matches (matches 'premium')",
|
|
261
|
-
() =>
|
|
261
|
+
() => enduser_with_tags(enduser8.id, ['Purchase-Multiple-Partial']),
|
|
262
262
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Multiple-Partial') }
|
|
263
263
|
)
|
|
264
264
|
|
|
@@ -270,10 +270,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
270
270
|
cost: { amount: 14999, currency: 'USD' },
|
|
271
271
|
processor: 'Stripe'
|
|
272
272
|
})
|
|
273
|
-
await wait(undefined, 500)
|
|
274
273
|
await async_test(
|
|
275
274
|
"Purchase Made - Multiple Partial Matches (matches 'advanced')",
|
|
276
|
-
() =>
|
|
275
|
+
() => enduser_with_tags(enduser9.id, ['Purchase-Multiple-Partial']),
|
|
277
276
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Multiple-Partial') }
|
|
278
277
|
)
|
|
279
278
|
|
|
@@ -285,10 +284,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
285
284
|
cost: { amount: 9999, currency: 'USD' },
|
|
286
285
|
processor: 'Stripe'
|
|
287
286
|
})
|
|
288
|
-
await wait(undefined, 500)
|
|
289
287
|
await async_test(
|
|
290
288
|
"Purchase Made - Case Insensitive (lowercase filter 'mixed' matches 'MIXED')",
|
|
291
|
-
() =>
|
|
289
|
+
() => enduser_with_tags(enduser10.id, ['Purchase-Case-Test']),
|
|
292
290
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Case-Test') }
|
|
293
291
|
)
|
|
294
292
|
|
|
@@ -300,10 +298,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
300
298
|
cost: { amount: 4999, currency: 'USD' },
|
|
301
299
|
processor: 'Stripe'
|
|
302
300
|
})
|
|
303
|
-
await wait(undefined, 500)
|
|
304
301
|
await async_test(
|
|
305
302
|
"Purchase Made - Case Insensitive (uppercase filter 'UPPER' matches 'upper')",
|
|
306
|
-
() =>
|
|
303
|
+
() => enduser_with_tags(enduser11.id, ['Purchase-Case-Test']),
|
|
307
304
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Case-Test') }
|
|
308
305
|
)
|
|
309
306
|
|
|
@@ -315,10 +312,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
315
312
|
cost: { amount: 14999, currency: 'USD' },
|
|
316
313
|
processor: 'Stripe'
|
|
317
314
|
})
|
|
318
|
-
await wait(undefined, 500)
|
|
319
315
|
await async_test(
|
|
320
316
|
"Purchase Made - Case Insensitive (mixed case filter 'MiXeD' matches 'MiXeD')",
|
|
321
|
-
() =>
|
|
317
|
+
() => enduser_with_tags(enduser12.id, ['Purchase-Case-Test']),
|
|
322
318
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Case-Test') }
|
|
323
319
|
)
|
|
324
320
|
|
|
@@ -330,10 +326,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
330
326
|
cost: { amount: 9999, currency: 'USD' },
|
|
331
327
|
processor: 'Stripe'
|
|
332
328
|
})
|
|
333
|
-
await wait(undefined, 500)
|
|
334
329
|
await async_test(
|
|
335
330
|
"Purchase Made - Empty titlePartialMatches Array (should trigger like any purchase)",
|
|
336
|
-
() =>
|
|
331
|
+
() => enduser_with_tags(enduser13.id, ['Purchase-Empty-Array', 'Purchase-Any']),
|
|
337
332
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Empty-Array') && !!e.tags?.includes('Purchase-Any') }
|
|
338
333
|
)
|
|
339
334
|
|
|
@@ -345,10 +340,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
345
340
|
cost: { amount: 4999, currency: 'USD' },
|
|
346
341
|
processor: 'Stripe'
|
|
347
342
|
})
|
|
348
|
-
await wait(undefined, 500)
|
|
349
343
|
await async_test(
|
|
350
344
|
"Purchase Made - Empty Title (should not trigger partial match filters)",
|
|
351
|
-
() =>
|
|
345
|
+
() => enduser_with_tags(enduser14.id, ['Purchase-Any']),
|
|
352
346
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') && !e.tags?.includes('Purchase-No-Title-Test') }
|
|
353
347
|
)
|
|
354
348
|
|
|
@@ -360,10 +354,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
360
354
|
processor: 'Stripe',
|
|
361
355
|
couponCodes: ['SUMMER20'],
|
|
362
356
|
})
|
|
363
|
-
await wait(undefined, 500)
|
|
364
357
|
await async_test(
|
|
365
358
|
"Purchase Made - Coupon Code Match (exact)",
|
|
366
|
-
() =>
|
|
359
|
+
() => enduser_with_tags(enduser15.id, ['Purchase-Coupon-Summer20', 'Purchase-Coupon-Empty']),
|
|
367
360
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Coupon-Summer20') && !!e.tags?.includes('Purchase-Coupon-Empty') }
|
|
368
361
|
)
|
|
369
362
|
|
|
@@ -376,10 +369,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
376
369
|
processor: 'Stripe',
|
|
377
370
|
couponCodes: ['summer20'],
|
|
378
371
|
})
|
|
379
|
-
await wait(undefined, 500)
|
|
380
372
|
await async_test(
|
|
381
373
|
"Purchase Made - Coupon Code Case Mismatch (case sensitive, 'summer20' vs 'SUMMER20')",
|
|
382
|
-
() =>
|
|
374
|
+
() => enduser_with_tags(enduser16.id, ['Purchase-Any']),
|
|
383
375
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') && !e.tags?.includes('Purchase-Coupon-Summer20') }
|
|
384
376
|
)
|
|
385
377
|
|
|
@@ -391,10 +383,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
391
383
|
processor: 'Stripe',
|
|
392
384
|
couponCodes: ['WINTER10'],
|
|
393
385
|
})
|
|
394
|
-
await wait(undefined, 500)
|
|
395
386
|
await async_test(
|
|
396
387
|
"Purchase Made - Non-matching Coupon Code",
|
|
397
|
-
() =>
|
|
388
|
+
() => enduser_with_tags(enduser17.id, ['Purchase-Any']),
|
|
398
389
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') && !e.tags?.includes('Purchase-Coupon-Summer20') }
|
|
399
390
|
)
|
|
400
391
|
|
|
@@ -406,10 +397,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
406
397
|
cost: { amount: 9999, currency: 'USD' },
|
|
407
398
|
processor: 'Stripe',
|
|
408
399
|
})
|
|
409
|
-
await wait(undefined, 500)
|
|
410
400
|
await async_test(
|
|
411
401
|
"Purchase Made - No Coupon Data (backward compat)",
|
|
412
|
-
() =>
|
|
402
|
+
() => enduser_with_tags(enduser18.id, ['Purchase-Any', 'Purchase-Coupon-Empty']),
|
|
413
403
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Any') && !!e.tags?.includes('Purchase-Coupon-Empty') && !e.tags?.includes('Purchase-Coupon-Summer20') }
|
|
414
404
|
)
|
|
415
405
|
|
|
@@ -421,10 +411,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
421
411
|
processor: 'Stripe',
|
|
422
412
|
couponCodes: ['SUMMER20'],
|
|
423
413
|
})
|
|
424
|
-
await wait(undefined, 500)
|
|
425
414
|
await async_test(
|
|
426
415
|
"Purchase Made - Title AND Coupon Match",
|
|
427
|
-
() =>
|
|
416
|
+
() => enduser_with_tags(enduser19.id, ['Purchase-Title-And-Coupon']),
|
|
428
417
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Title-And-Coupon') }
|
|
429
418
|
)
|
|
430
419
|
|
|
@@ -435,10 +424,9 @@ export const purchase_made_trigger_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
435
424
|
cost: { amount: 9999, currency: 'USD' },
|
|
436
425
|
processor: 'Stripe',
|
|
437
426
|
})
|
|
438
|
-
await wait(undefined, 500)
|
|
439
427
|
await async_test(
|
|
440
428
|
"Purchase Made - Title Matches But Coupon Missing (AND semantics)",
|
|
441
|
-
() =>
|
|
429
|
+
() => enduser_with_tags(enduser20.id, ['Purchase-Exact-Title']),
|
|
442
430
|
{ onResult: (e: Enduser) => !!e.tags?.includes('Purchase-Exact-Title') && !e.tags?.includes('Purchase-Title-And-Coupon') }
|
|
443
431
|
)
|
|
444
432
|
|
|
@@ -0,0 +1,207 @@
|
|
|
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
|
+
// far enough out that a locally running worker never claims the rows we inspect
|
|
14
|
+
const FUTURE_START = () => new Date(Date.now() + 60 * 60 * 1000)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Regression test: `endusers.add_to_journey` must not enroll another tenant's enduser.
|
|
18
|
+
*
|
|
19
|
+
* `endusers.add_to_journey` inserted an `automated_actions` row for EACH caller-supplied `enduserId`
|
|
20
|
+
* with only mongoId-shape validation and no tenant-membership check. The preceding
|
|
21
|
+
* `DB.endusers.updateMany` is scoped but its result was discarded, and
|
|
22
|
+
* `DB.automated_actions.insertMany` is a direct write that bypasses the `ensureValidDependentKeys`
|
|
23
|
+
* foreign-key check the generic CRUD route gets. The resulting row is stamped
|
|
24
|
+
* `businessId: <caller's tenant>` while carrying `enduserId: <a victim in another tenant>`.
|
|
25
|
+
*
|
|
26
|
+
* The worker then dereferences that enduser with the raw driver and no `businessId`
|
|
27
|
+
* (worker/modules/automations.ts, the worker's unscoped raw-driver lookup family), so the victim's record loads
|
|
28
|
+
* under the attacker's automation: `pushFormsToPortal` copies the victim's PHI into the attacker's
|
|
29
|
+
* `form_responses` (readable by their staff) and `iterableCustomEvent` writes an attacker-authored
|
|
30
|
+
* note into the victim's chart. This plant is the reachability that made those three exploitable.
|
|
31
|
+
*
|
|
32
|
+
* There are TWO independent plant sites and a fix to only one is a half fix:
|
|
33
|
+
* - inline branch, taken when `automationStepId` is supplied (api.ts add_to_journey handler)
|
|
34
|
+
* - module branch, taken when it is not: `handle_automation_event`'s
|
|
35
|
+
* `validEnduserIds = conditionsQuery ? <scoped find> : event.enduserIds` passes caller ids
|
|
36
|
+
* straight through for a step with NO conditions.
|
|
37
|
+
* Both are covered below (A1/A2).
|
|
38
|
+
*
|
|
39
|
+
* Design notes:
|
|
40
|
+
* - Two provisioned tenants, so the victim is a real foreign enduser and we can also assert their
|
|
41
|
+
* record was not mutated. Both must come from provisioning: `add_to_journey` is
|
|
42
|
+
* `requiresSubscription: true`, and a `create_and_join` org is born with an expired subscription.
|
|
43
|
+
* - The steps use `setEnduserStatus` — no vendor, no Bedrock — and `startAt` is an hour out so a
|
|
44
|
+
* running worker cannot process the rows before we read them.
|
|
45
|
+
* - `throttle` is deliberately omitted: it is the only way add_to_journey's per-pair rate limit can
|
|
46
|
+
* throw.
|
|
47
|
+
* - Everything is observable through `automated_actions` reads, so the worker is never needed.
|
|
48
|
+
*
|
|
49
|
+
* RED (pre-fix): A1, A2 and B2 fail — the victim's id appears in the attacker tenant's
|
|
50
|
+
* automated_actions. GREEN (post-fix): the foreign id is silently dropped and the caller's own
|
|
51
|
+
* endusers still enroll normally.
|
|
52
|
+
*/
|
|
53
|
+
export const add_to_journey_foreign_enduserid_checks = async (): Promise<Check[]> => {
|
|
54
|
+
const checks: Check[] = []
|
|
55
|
+
const record = (label: string, pass: boolean, detail: string) => checks.push({ label, pass, detail })
|
|
56
|
+
|
|
57
|
+
let attacker: Awaited<ReturnType<typeof setup_isolated_tenant>> | undefined
|
|
58
|
+
let victimTenant: Awaited<ReturnType<typeof setup_isolated_tenant>> | undefined
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
/* ================= fixtures: two isolated tenants ================= */
|
|
62
|
+
|
|
63
|
+
;[attacker, victimTenant] = await Promise.all([
|
|
64
|
+
setup_isolated_tenant({ name: `F0196 attacker ${RAND()}`, users: [{ isAdmin: true }], apiKeys: 0 }),
|
|
65
|
+
setup_isolated_tenant({ name: `F0196 victim ${RAND()}`, users: [{ isAdmin: true }], apiKeys: 0 }),
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
const victim = await victimTenant.sdk.api.endusers.createOne({ fname: 'F0196', lname: 'Victim' })
|
|
69
|
+
const own = await attacker.sdk.api.endusers.createOne({ fname: 'F0196', lname: 'OwnPatient' })
|
|
70
|
+
|
|
71
|
+
record(
|
|
72
|
+
'setup: two separate tenants, victim belongs to the other one',
|
|
73
|
+
attacker.businessId !== victimTenant.businessId && !!victim.id && !!own.id,
|
|
74
|
+
`attacker=${attacker.businessId} victim tenant=${victimTenant.businessId} victimEnduser=${victim.id}`,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
// one journey + onJourneyStart step per branch, so the per-(enduser,journey) throttle bucket and
|
|
78
|
+
// the row sets stay independent
|
|
79
|
+
const makeJourney = async (title: string) => {
|
|
80
|
+
const journey = await attacker!.sdk.api.journeys.createOne({ title: `${title} ${RAND()}` })
|
|
81
|
+
const step = await attacker!.sdk.api.automation_steps.createOne({
|
|
82
|
+
journeyId: journey.id,
|
|
83
|
+
// benign and worker-local: no vendor, no Bedrock. NO `conditions`, which is precisely the
|
|
84
|
+
// vulnerable branch in handle_automation_event.
|
|
85
|
+
action: { type: 'setEnduserStatus', info: { status: 'F0196' } },
|
|
86
|
+
events: [{ type: 'onJourneyStart', info: {} }],
|
|
87
|
+
} as any)
|
|
88
|
+
return { journey, step }
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const inline = await makeJourney('F0196 inline')
|
|
92
|
+
const modulePath = await makeJourney('F0196 module')
|
|
93
|
+
const mixed = await makeJourney('F0196 mixed')
|
|
94
|
+
|
|
95
|
+
/** every automated_actions row the attacker tenant can see for a journey */
|
|
96
|
+
const rowsFor = async (journeyId: string) => (
|
|
97
|
+
await attacker!.sdk.api.automated_actions.getSome({ filter: { journeyId } } as any)
|
|
98
|
+
)
|
|
99
|
+
const enduserIdsFor = async (journeyId: string) => (await rowsFor(journeyId)).map((r: any) => r.enduserId)
|
|
100
|
+
|
|
101
|
+
/* ===== A: the foreign id must never be planted, on EITHER branch ===== */
|
|
102
|
+
|
|
103
|
+
// A1 — inline branch: automationStepId supplied
|
|
104
|
+
const inlineResult = await attacker.sdk.api.endusers.add_to_journey({
|
|
105
|
+
enduserIds: [victim.id],
|
|
106
|
+
journeyId: inline.journey.id,
|
|
107
|
+
automationStepId: inline.step.id,
|
|
108
|
+
startAt: FUTURE_START(),
|
|
109
|
+
} as any).then(() => 'resolved').catch((e: any) => `rejected: ${e?.message || e}`)
|
|
110
|
+
|
|
111
|
+
const inlineIds = await enduserIdsFor(inline.journey.id)
|
|
112
|
+
record(
|
|
113
|
+
'A1: inline branch (automationStepId) does not plant a foreign enduserId',
|
|
114
|
+
!inlineIds.includes(victim.id),
|
|
115
|
+
`call=${inlineResult}; automated_actions enduserIds=${JSON.stringify(inlineIds)} (must not contain ${victim.id})`,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
// A2 — module branch: no automationStepId, so it routes through handle_automation_event
|
|
119
|
+
const moduleResult = await attacker.sdk.api.endusers.add_to_journey({
|
|
120
|
+
enduserIds: [victim.id],
|
|
121
|
+
journeyId: modulePath.journey.id,
|
|
122
|
+
startAt: FUTURE_START(),
|
|
123
|
+
} as any).then(() => 'resolved').catch((e: any) => `rejected: ${e?.message || e}`)
|
|
124
|
+
|
|
125
|
+
const moduleIds = await enduserIdsFor(modulePath.journey.id)
|
|
126
|
+
record(
|
|
127
|
+
'A2: module branch (no automationStepId) does not plant a foreign enduserId',
|
|
128
|
+
!moduleIds.includes(victim.id),
|
|
129
|
+
`call=${moduleResult}; automated_actions enduserIds=${JSON.stringify(moduleIds)} (must not contain ${victim.id})`,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
// A3 — the victim's own record must be untouched (the scoped updateMany should already ensure it)
|
|
133
|
+
const victimAfter = await victimTenant.sdk.api.endusers.getOne(victim.id)
|
|
134
|
+
const victimJourneys = (victimAfter as any)?.journeys ?? {}
|
|
135
|
+
record(
|
|
136
|
+
'A3: the victim enduser was not enrolled in the attacker\'s journey',
|
|
137
|
+
!victimJourneys[inline.journey.id] && !victimJourneys[modulePath.journey.id],
|
|
138
|
+
`victim journeys=${JSON.stringify(victimJourneys)}`,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
/* ===== B: legitimate use must keep working ===== */
|
|
142
|
+
|
|
143
|
+
// B1 — positive control on both branches, so a blanket failure can't masquerade as a fix
|
|
144
|
+
await attacker.sdk.api.endusers.add_to_journey({
|
|
145
|
+
enduserIds: [own.id],
|
|
146
|
+
journeyId: inline.journey.id,
|
|
147
|
+
automationStepId: inline.step.id,
|
|
148
|
+
startAt: FUTURE_START(),
|
|
149
|
+
} as any)
|
|
150
|
+
await attacker.sdk.api.endusers.add_to_journey({
|
|
151
|
+
enduserIds: [own.id],
|
|
152
|
+
journeyId: modulePath.journey.id,
|
|
153
|
+
startAt: FUTURE_START(),
|
|
154
|
+
} as any)
|
|
155
|
+
|
|
156
|
+
const inlineOwn = await enduserIdsFor(inline.journey.id)
|
|
157
|
+
const moduleOwn = await enduserIdsFor(modulePath.journey.id)
|
|
158
|
+
record(
|
|
159
|
+
'B1: the caller\'s OWN enduser still enrolls on both branches',
|
|
160
|
+
inlineOwn.includes(own.id) && moduleOwn.includes(own.id),
|
|
161
|
+
`inline=${JSON.stringify(inlineOwn)} module=${JSON.stringify(moduleOwn)} (both must contain ${own.id})`,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
// B2 — a mixed list must enroll the visible id and drop only the foreign one: proves an
|
|
165
|
+
// intersect, not an all-or-nothing rejection
|
|
166
|
+
const mixedResult = await attacker.sdk.api.endusers.add_to_journey({
|
|
167
|
+
enduserIds: [own.id, victim.id],
|
|
168
|
+
journeyId: mixed.journey.id,
|
|
169
|
+
automationStepId: mixed.step.id,
|
|
170
|
+
startAt: FUTURE_START(),
|
|
171
|
+
} as any).then(() => 'resolved').catch((e: any) => `rejected: ${e?.message || e}`)
|
|
172
|
+
|
|
173
|
+
const mixedIds = await enduserIdsFor(mixed.journey.id)
|
|
174
|
+
record(
|
|
175
|
+
'B2: a mixed list enrolls the visible enduser and drops only the foreign one',
|
|
176
|
+
mixedIds.includes(own.id) && !mixedIds.includes(victim.id),
|
|
177
|
+
`call=${mixedResult}; enduserIds=${JSON.stringify(mixedIds)} (want ${own.id}, not ${victim.id})`,
|
|
178
|
+
)
|
|
179
|
+
} finally {
|
|
180
|
+
// Teardown happens here, BEFORE anything asserts — assert calls process.exit and would otherwise
|
|
181
|
+
// strand these tenants permanently (nothing can delete an organization record).
|
|
182
|
+
for (const t of [attacker, victimTenant]) {
|
|
183
|
+
if (t) { try { await t.teardown() } catch (e) { console.error('teardown failed', e) } }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return checks
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Asserting wrapper, for standalone runs and for sequential use in the suite. */
|
|
191
|
+
export const add_to_journey_foreign_enduserid_tests = async () => {
|
|
192
|
+
assert_checks('add_to_journey foreign enduserId', await add_to_journey_foreign_enduserid_checks())
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Allow running this test file independently
|
|
196
|
+
if (require.main === module) {
|
|
197
|
+
console.log(`🌐 Using API URL: ${host}`)
|
|
198
|
+
add_to_journey_foreign_enduserid_tests()
|
|
199
|
+
.then(() => {
|
|
200
|
+
console.log("✅ add_to_journey foreign enduserId test suite completed successfully")
|
|
201
|
+
process.exit(0)
|
|
202
|
+
})
|
|
203
|
+
.catch((error) => {
|
|
204
|
+
console.error("❌ add_to_journey foreign enduserId test suite failed:", error)
|
|
205
|
+
process.exit(1)
|
|
206
|
+
})
|
|
207
|
+
}
|
|
@@ -14,7 +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
|
|
17
|
+
* Regression test: `ai_conversations` RBAC.
|
|
18
18
|
*
|
|
19
19
|
* Both `ai_conversations.send_message` and `ai_conversations.generate_ai_decision` are
|
|
20
20
|
* registered with `noAccessPermissions: true` ([api.ts:22699, 22721](packages/private/api/api/v1/api.ts)).
|
|
@@ -46,7 +46,7 @@ const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.
|
|
|
46
46
|
* Post-fix: both endpoints throw 403 before any work happens. Test passes.
|
|
47
47
|
*/
|
|
48
48
|
export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
49
|
-
log_header("
|
|
49
|
+
log_header("ai_conversations RBAC bypass regression")
|
|
50
50
|
|
|
51
51
|
const roleName = `f0005-ai-conversations-no-access-${Date.now()}`
|
|
52
52
|
const grantRoleName = `f0005-ai-conversations-create-granted-${Date.now()}`
|
|
@@ -83,9 +83,9 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
83
83
|
// 3a. send_message must throw 403 (or equivalent access error). Pre-fix: succeeds (or
|
|
84
84
|
// fails downstream in Bedrock without 403). Post-fix: throws before any work.
|
|
85
85
|
await async_test(
|
|
86
|
-
"
|
|
86
|
+
"ai_conversations.send_message must throw 403 when role denies ai_conversations",
|
|
87
87
|
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
88
|
-
message: '
|
|
88
|
+
message: 'regression test',
|
|
89
89
|
type: 'Test',
|
|
90
90
|
} as any),
|
|
91
91
|
{
|
|
@@ -105,12 +105,12 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
105
105
|
// Pre-fix: handler responds 200 with {} immediately and processes in background.
|
|
106
106
|
// Post-fix: handler throws 403 before res.json({}).
|
|
107
107
|
await async_test(
|
|
108
|
-
"
|
|
108
|
+
"ai_conversations.generate_ai_decision must throw 403 when role denies endusers/ai_conversations",
|
|
109
109
|
() => sdkNonAdmin.api.ai_conversations.generate_ai_decision({
|
|
110
110
|
enduserId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
111
111
|
automationStepId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
112
112
|
outcomes: ['yes', 'no'],
|
|
113
|
-
prompt: '
|
|
113
|
+
prompt: 'regression test',
|
|
114
114
|
sources: [{ type: 'SMS', limit: 1 }], // non-empty so the validator passes; access check then fires
|
|
115
115
|
} as any),
|
|
116
116
|
{
|
|
@@ -145,9 +145,9 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
145
145
|
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
146
146
|
|
|
147
147
|
await async_test(
|
|
148
|
-
"
|
|
148
|
+
"ai_conversations.send_message must NOT be access-denied when role grants create",
|
|
149
149
|
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
150
|
-
message: '
|
|
150
|
+
message: 'positive-case test',
|
|
151
151
|
type: 'Test',
|
|
152
152
|
maxTokens: 1,
|
|
153
153
|
} as any)
|
|
@@ -168,9 +168,9 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
168
168
|
// existing conversation — send_message with conversationId returns the full stored history
|
|
169
169
|
// and appends to it. Fake id is fine: the access check must fire before any lookup.
|
|
170
170
|
await async_test(
|
|
171
|
-
"
|
|
171
|
+
"ai_conversations.send_message with conversationId must 403 when role denies read/update",
|
|
172
172
|
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
173
|
-
message: '
|
|
173
|
+
message: 'conversationId bypass test',
|
|
174
174
|
type: 'Test',
|
|
175
175
|
maxTokens: 1,
|
|
176
176
|
conversationId: new ObjectId().toHexString(),
|
|
@@ -205,9 +205,9 @@ export const ai_conversations_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk:
|
|
|
205
205
|
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
206
206
|
|
|
207
207
|
await async_test(
|
|
208
|
-
"
|
|
208
|
+
"ai_conversations.send_message must not 500 for Assigned-access (default provider) role",
|
|
209
209
|
() => sdkNonAdmin.api.ai_conversations.send_message({
|
|
210
|
-
message: '
|
|
210
|
+
message: 'assigned-access regression test',
|
|
211
211
|
type: 'Test',
|
|
212
212
|
maxTokens: 1,
|
|
213
213
|
} as any)
|
|
@@ -267,11 +267,11 @@ if (require.main === module) {
|
|
|
267
267
|
|
|
268
268
|
runTests()
|
|
269
269
|
.then(() => {
|
|
270
|
-
console.log("✅
|
|
270
|
+
console.log("✅ ai_conversations RBAC test suite completed successfully")
|
|
271
271
|
process.exit(0)
|
|
272
272
|
})
|
|
273
273
|
.catch((error) => {
|
|
274
|
-
console.error("❌
|
|
274
|
+
console.error("❌ ai_conversations RBAC test suite failed:", error)
|
|
275
275
|
process.exit(1)
|
|
276
276
|
})
|
|
277
277
|
}
|
|
@@ -12,7 +12,7 @@ import { setup_tests } from "../../setup"
|
|
|
12
12
|
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Regression test
|
|
15
|
+
* Regression test — allowedPaths wildcard disables path confinement entirely.
|
|
16
16
|
*
|
|
17
17
|
* Several public, unauthenticated endpoints mint a JWT confined to a small set of API paths via an
|
|
18
18
|
* `allowedPaths` claim. The enforcement predicate (api/modules/authentication.ts checkAccess)
|
|
@@ -69,7 +69,7 @@ type Probe = {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
72
|
-
log_header("
|
|
72
|
+
log_header("allowedPaths wildcard bypasses session path confinement")
|
|
73
73
|
|
|
74
74
|
const probes: Probe[] = []
|
|
75
75
|
|
|
@@ -157,7 +157,7 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
157
157
|
|
|
158
158
|
// -- public form (no wildcard in its allowedPaths)
|
|
159
159
|
const form = await sdk.api.forms.createOne({
|
|
160
|
-
title: `
|
|
160
|
+
title: `path confinement ${RAND()}`,
|
|
161
161
|
allowPublicURL: true,
|
|
162
162
|
})
|
|
163
163
|
formId = form.id
|
|
@@ -179,7 +179,7 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
179
179
|
})
|
|
180
180
|
|
|
181
181
|
const product = await sdk.api.products.createOne({
|
|
182
|
-
title: `
|
|
182
|
+
title: `product ${RAND()}`,
|
|
183
183
|
cost: { amount: 500, currency: 'USD' },
|
|
184
184
|
processor: 'Stripe',
|
|
185
185
|
} as any)
|
|
@@ -193,13 +193,13 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
193
193
|
|
|
194
194
|
const joinLinkToken = `f0166-join-${RAND()}${RAND()}`
|
|
195
195
|
const joinEvent = await sdk.api.calendar_events.createOne({
|
|
196
|
-
title: '
|
|
196
|
+
title: 'join', durationInMinutes: 30, startTimeInMS: Date.now() + 3600_000,
|
|
197
197
|
attendees: [{ type: 'enduser', id: joinEnduser.id, joinLinkToken }],
|
|
198
198
|
} as any)
|
|
199
199
|
eventIds.push(joinEvent.id)
|
|
200
200
|
|
|
201
201
|
const unrelatedEvent = await sdk.api.calendar_events.createOne({
|
|
202
|
-
title: '
|
|
202
|
+
title: 'unrelated', durationInMinutes: 30, startTimeInMS: Date.now() + 3600_000,
|
|
203
203
|
attendees: [{ type: 'enduser', id: joinEnduser.id }],
|
|
204
204
|
} as any)
|
|
205
205
|
eventIds.push(unrelatedEvent.id)
|
|
@@ -219,7 +219,7 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
219
219
|
|
|
220
220
|
const startLinkToken = `f0166-start-${RAND()}${RAND()}`
|
|
221
221
|
const startEvent = await sdk.api.calendar_events.createOne({
|
|
222
|
-
title: '
|
|
222
|
+
title: 'start', durationInMinutes: 30, startTimeInMS: Date.now() + 3600_000,
|
|
223
223
|
attendees: [{ type: 'user', id: hostUser.id }, { type: 'enduser', id: joinEnduser.id }],
|
|
224
224
|
startLinkToken,
|
|
225
225
|
} as any)
|
|
@@ -553,7 +553,7 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
553
553
|
const S7 = 'S7 appointment-booking'
|
|
554
554
|
|
|
555
555
|
const bookingTemplate = await sdk.api.calendar_event_templates.createOne({
|
|
556
|
-
title: `
|
|
556
|
+
title: `booking ${RAND()}`, durationInMinutes: 30,
|
|
557
557
|
})
|
|
558
558
|
templateId = bookingTemplate.id
|
|
559
559
|
|
|
@@ -656,7 +656,7 @@ export const allowed_paths_confinement_tests = async ({ sdk } : { sdk: Session,
|
|
|
656
656
|
const failures = probes.filter(p => !p.pass)
|
|
657
657
|
|
|
658
658
|
console.log('')
|
|
659
|
-
console.log('
|
|
659
|
+
console.log(' full probe table')
|
|
660
660
|
console.log(' ' + '-'.repeat(112))
|
|
661
661
|
const scenarios = probes.map(p => p.scenario).filter((s, i, all) => all.indexOf(s) === i)
|
|
662
662
|
for (const scenario of scenarios) {
|
|
@@ -711,11 +711,11 @@ if (require.main === module) {
|
|
|
711
711
|
|
|
712
712
|
runTests()
|
|
713
713
|
.then(() => {
|
|
714
|
-
console.log("✅
|
|
714
|
+
console.log("✅ allowedPaths confinement test suite completed successfully")
|
|
715
715
|
process.exit(0)
|
|
716
716
|
})
|
|
717
717
|
.catch((error) => {
|
|
718
|
-
console.error("❌
|
|
718
|
+
console.error("❌ allowedPaths confinement test suite failed:", error)
|
|
719
719
|
process.exit(1)
|
|
720
720
|
})
|
|
721
721
|
}
|