@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
|
@@ -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: `invite_user` cross-tenant enumeration.
|
|
31
31
|
*
|
|
32
32
|
* `users.invite_user` previously used `buildAllQueries({ unrestricted: true, organizationIds: [] }).users.findOne({ email })`
|
|
33
33
|
* to enforce platform-wide email uniqueness and threw the distinctive `"A user with this email already exists"`
|
|
@@ -50,7 +50,7 @@ const post = async (path: string, body: any, headers: Record<string, string> = {
|
|
|
50
50
|
* env vars are not set, mirroring cross_org_api_key.test.ts convention.
|
|
51
51
|
*/
|
|
52
52
|
export const invite_user_enumeration_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
53
|
-
log_header("
|
|
53
|
+
log_header("users.invite_user cross-tenant enumeration regression")
|
|
54
54
|
|
|
55
55
|
// Reset state so prior tests' rate-limit accounting doesn't leak in.
|
|
56
56
|
await sdk.reset_db()
|
|
@@ -85,7 +85,7 @@ export const invite_user_enumeration_tests = async ({ sdk, sdkNonAdmin } : { sdk
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
await async_test(
|
|
88
|
-
"
|
|
88
|
+
"invite_user rate-limits within ~12 rapid requests (defense-in-depth; no invites sent)",
|
|
89
89
|
async () => ({ rateLimitedAt }),
|
|
90
90
|
{ onResult: r => r.rateLimitedAt >= 0 && r.rateLimitedAt <= 12 },
|
|
91
91
|
)
|
|
@@ -111,7 +111,7 @@ export const invite_user_enumeration_tests = async ({ sdk, sdkNonAdmin } : { sdk
|
|
|
111
111
|
)
|
|
112
112
|
|
|
113
113
|
await async_test(
|
|
114
|
-
"
|
|
114
|
+
"invite_user same-tenant duplicate returns 400 'already exists' (unchanged)",
|
|
115
115
|
async () => ({
|
|
116
116
|
status: sameTenantRes.status,
|
|
117
117
|
message: sameTenantRes.data?.message ?? '',
|
|
@@ -124,7 +124,7 @@ export const invite_user_enumeration_tests = async ({ sdk, sdkNonAdmin } : { sdk
|
|
|
124
124
|
// Env-gated; skipped when cross-org infra not configured.
|
|
125
125
|
// ====================================================================
|
|
126
126
|
if (!(CROSS_ORG_API_KEY && CROSS_ORG_TARGET_BUSINESS_ID)) {
|
|
127
|
-
console.log("
|
|
127
|
+
console.log(" Skipping cross-tenant silent no-op assertion — CROSS_ORG_* env vars not set")
|
|
128
128
|
return
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -160,7 +160,7 @@ export const invite_user_enumeration_tests = async ({ sdk, sdkNonAdmin } : { sdk
|
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
await async_test(
|
|
163
|
-
"
|
|
163
|
+
"cross-tenant invite of existing email must NOT return 'already exists' (no enumeration)",
|
|
164
164
|
async () => ({
|
|
165
165
|
status: crossRes.status,
|
|
166
166
|
message: crossRes.data?.message ?? '',
|
|
@@ -188,11 +188,11 @@ if (require.main === module) {
|
|
|
188
188
|
|
|
189
189
|
runTests()
|
|
190
190
|
.then(() => {
|
|
191
|
-
console.log("✅
|
|
191
|
+
console.log("✅ invite_user enumeration test suite completed successfully")
|
|
192
192
|
process.exit(0)
|
|
193
193
|
})
|
|
194
194
|
.catch((error) => {
|
|
195
|
-
console.error("❌
|
|
195
|
+
console.error("❌ invite_user enumeration test suite failed:", error)
|
|
196
196
|
process.exit(1)
|
|
197
197
|
})
|
|
198
198
|
}
|
|
@@ -12,8 +12,7 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
|
12
12
|
const ENDUSER_PASSWORD = 'F0151TestPassword!123'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Regression test
|
|
16
|
-
* (security-audit/findings/F-0151-load-inbox-data-endusers-unredacted.md).
|
|
15
|
+
* Regression test: `load_inbox_data` must apply enduser field redactions.
|
|
17
16
|
*
|
|
18
17
|
* load_inbox_data serialized $lookup'ed endusers via convert_id_name only (NOT applyRedactions),
|
|
19
18
|
* so endusers.hashedPassword (redactions:['all']) leaked to staff sessions — while the sibling
|
|
@@ -24,7 +23,7 @@ const ENDUSER_PASSWORD = 'F0151TestPassword!123'
|
|
|
24
23
|
* assert the returned enduser entry has NO hashedPassword.
|
|
25
24
|
*/
|
|
26
25
|
export const load_inbox_redaction_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
27
|
-
log_header("
|
|
26
|
+
log_header("load_inbox_data enduser redaction")
|
|
28
27
|
|
|
29
28
|
let enduserId: string | undefined
|
|
30
29
|
let emailId: string | undefined
|
|
@@ -42,7 +41,7 @@ export const load_inbox_redaction_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
42
41
|
emailId = seeded.id
|
|
43
42
|
|
|
44
43
|
await async_test(
|
|
45
|
-
'
|
|
44
|
+
'load_inbox_data does not leak enduser.hashedPassword to staff',
|
|
46
45
|
() => sdk.api.endusers.load_inbox_data({ enduserIds: [enduser.id] } as any),
|
|
47
46
|
{
|
|
48
47
|
onResult: (r: any) => {
|
|
@@ -71,11 +70,11 @@ if (require.main === module) {
|
|
|
71
70
|
|
|
72
71
|
runTests()
|
|
73
72
|
.then(() => {
|
|
74
|
-
console.log("✅
|
|
73
|
+
console.log("✅ load_inbox_data redaction test suite completed successfully")
|
|
75
74
|
process.exit(0)
|
|
76
75
|
})
|
|
77
76
|
.catch((error) => {
|
|
78
|
-
console.error("❌
|
|
77
|
+
console.error("❌ load_inbox_data redaction test suite failed:", error)
|
|
79
78
|
process.exit(1)
|
|
80
79
|
})
|
|
81
80
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { add_value_for_dotted_key } from "@tellescope/utilities"
|
|
2
2
|
|
|
3
|
-
// Regression test
|
|
3
|
+
// Regression test: prototype pollution via dotted-key assignment.
|
|
4
4
|
// add_value_for_dotted_key must NOT write through __proto__/constructor/prototype path segments
|
|
5
5
|
// (which would pollute Object.prototype process-wide), while still performing legitimate dotted assignment.
|
|
6
6
|
//
|
|
7
7
|
// Pure-function test — no Session needed. Runs in the main suite and standalone:
|
|
8
|
-
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/
|
|
8
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/prototype-pollution.test.js
|
|
9
9
|
|
|
10
10
|
const fail = (msg: string) => { throw new Error(msg) }
|
|
11
11
|
|
|
12
12
|
export const prototype_pollution_tests = async () => {
|
|
13
|
-
console.log("Running
|
|
13
|
+
console.log("Running prototype-pollution regression tests")
|
|
14
14
|
|
|
15
15
|
// 1. __proto__ path must not pollute Object.prototype
|
|
16
16
|
add_value_for_dotted_key({ insurance: {} } as any, 'insurance.__proto__.__pp_a__', 'polluted')
|
|
@@ -40,7 +40,7 @@ export const prototype_pollution_tests = async () => {
|
|
|
40
40
|
add_value_for_dotted_key(flat, 'name', 'ok')
|
|
41
41
|
if (flat.name !== 'ok') fail('single-key assignment broke')
|
|
42
42
|
|
|
43
|
-
console.log("✅
|
|
43
|
+
console.log("✅ prototype-pollution regression tests passed")
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (require.main === module) {
|
|
@@ -22,15 +22,14 @@ const assert_local_api = () => {
|
|
|
22
22
|
const hostname = new URL(host).hostname
|
|
23
23
|
if (!LOCAL_HOSTNAMES.includes(hostname)) {
|
|
24
24
|
throw new Error(
|
|
25
|
-
`
|
|
25
|
+
`SSRF tests must run against a local API (got ${host}). `
|
|
26
26
|
+ `127.0.0.1 would resolve to the API server rather than this machine, so the tests would be meaningless.`
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* Regression tests
|
|
33
|
-
* (security-audit/findings/F-0025-proxy-image-unauth-ssrf.md).
|
|
32
|
+
* Regression tests: `/v1/proxy-image` must refuse internal and non-image destinations.
|
|
34
33
|
*
|
|
35
34
|
* GET /v1/proxy-image accepted an arbitrary ?url= and streamed the upstream response body straight
|
|
36
35
|
* back with Access-Control-Allow-Origin: *, with no authentication, no destination validation and no
|
|
@@ -58,7 +57,7 @@ const assert_local_api = () => {
|
|
|
58
57
|
* the vulnerability proof.
|
|
59
58
|
*/
|
|
60
59
|
export const proxy_image_ssrf_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
61
|
-
log_header("
|
|
60
|
+
log_header("proxy-image unauthenticated SSRF")
|
|
62
61
|
assert_local_api()
|
|
63
62
|
|
|
64
63
|
const SENTINEL = `f0025-sentinel-${Date.now()}-${Math.random().toString(36).slice(2)}`
|
|
@@ -95,7 +94,7 @@ export const proxy_image_ssrf_tests = async ({ sdk } : { sdk: Session, sdkNonAdm
|
|
|
95
94
|
|
|
96
95
|
// T1 — the core SSRF: an unauthenticated caller must not be able to read an internal resource.
|
|
97
96
|
await async_test(
|
|
98
|
-
'
|
|
97
|
+
'proxy-image does not stream an internal non-image resource to an unauthenticated caller',
|
|
99
98
|
call_unauthenticated,
|
|
100
99
|
{
|
|
101
100
|
// Positive control: a numeric status proves we actually reached our API rather than failing to
|
|
@@ -111,7 +110,7 @@ export const proxy_image_ssrf_tests = async ({ sdk } : { sdk: Session, sdkNonAdm
|
|
|
111
110
|
// T2 — the unauthenticated surface itself: the request must be refused outright, and the
|
|
112
111
|
// destination must never be contacted (no SSRF-as-a-side-effect even when the body is withheld).
|
|
113
112
|
await async_test(
|
|
114
|
-
'
|
|
113
|
+
'proxy-image refuses an unauthenticated request without contacting the destination',
|
|
115
114
|
call_unauthenticated,
|
|
116
115
|
{ onResult: (r: any) => r.status >= 400 && r.status < 500 && r.sentinelHits === 0 },
|
|
117
116
|
)
|
|
@@ -129,26 +128,26 @@ export const proxy_image_ssrf_tests = async ({ sdk } : { sdk: Session, sdkNonAdm
|
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
await async_test(
|
|
132
|
-
'
|
|
131
|
+
'proxy-image refuses a private destination even for an authenticated staff session',
|
|
133
132
|
() => call_authenticated(sentinelURL),
|
|
134
133
|
{ onResult: (r: any) => r.status === 400 && r.sentinelHits === 0 },
|
|
135
134
|
)
|
|
136
135
|
|
|
137
136
|
await async_test(
|
|
138
|
-
'
|
|
137
|
+
'proxy-image refuses cloud metadata for an authenticated staff session',
|
|
139
138
|
() => call_authenticated('https://169.254.169.254/latest/meta-data/'),
|
|
140
139
|
{ onResult: (r: any) => r.status === 400 },
|
|
141
140
|
)
|
|
142
141
|
|
|
143
142
|
// Scheme and port are pinned: only https on 443, which is all the PDF export ever needs.
|
|
144
143
|
await async_test(
|
|
145
|
-
'
|
|
144
|
+
'proxy-image refuses a plain http destination',
|
|
146
145
|
() => call_authenticated('http://example.com/logo.png'),
|
|
147
146
|
{ onResult: (r: any) => r.status === 400 },
|
|
148
147
|
)
|
|
149
148
|
|
|
150
149
|
await async_test(
|
|
151
|
-
'
|
|
150
|
+
'proxy-image refuses a non-443 port',
|
|
152
151
|
() => call_authenticated('https://example.com:8443/logo.png'),
|
|
153
152
|
{ onResult: (r: any) => r.status === 400 },
|
|
154
153
|
)
|
|
@@ -169,11 +168,11 @@ if (require.main === module) {
|
|
|
169
168
|
|
|
170
169
|
runTests()
|
|
171
170
|
.then(() => {
|
|
172
|
-
console.log("✅
|
|
171
|
+
console.log("✅ proxy-image SSRF test suite completed successfully")
|
|
173
172
|
process.exit(0)
|
|
174
173
|
})
|
|
175
174
|
.catch((error) => {
|
|
176
|
-
console.error("❌
|
|
175
|
+
console.error("❌ proxy-image SSRF test suite failed:", error)
|
|
177
176
|
process.exit(1)
|
|
178
177
|
})
|
|
179
178
|
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { DEFAULT_IFRAME_SANDBOX, replace_form_field_template_values, sanitize_user_html, sanitize_user_html_with_iframes } from "@tellescope/utilities"
|
|
2
2
|
|
|
3
|
-
// Companion to
|
|
3
|
+
// Companion to sanitize-user-html.test.ts (pattern 06 — XSS via dangerouslySetInnerHTML).
|
|
4
4
|
//
|
|
5
5
|
// sanitize_user_html_with_iframes is the variant used by the live form's field description, so
|
|
6
6
|
// admins can embed video / scheduling widgets. It permits <iframe> and NOTHING else beyond what
|
|
7
7
|
// sanitize_user_html allows. This asserts:
|
|
8
|
-
// 1. permitting iframe did not reopen any of the
|
|
8
|
+
// 1. permitting iframe did not reopen any of the base vectors (the full payload list is re-run)
|
|
9
9
|
// 2. only absolute https iframes survive — relative, protocol-relative, http, javascript:, data:
|
|
10
10
|
// and srcdoc frames are dropped, along with their fallback content
|
|
11
11
|
// 3. the restrictive sandbox is forced, but an author-supplied sandbox is honored
|
|
12
12
|
// 4. sanitize_user_html itself still strips iframes (the boundary between the two functions)
|
|
13
13
|
//
|
|
14
14
|
// Pure-function test — no Session needed. Runs as part of the main suite and standalone:
|
|
15
|
-
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/
|
|
15
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js
|
|
16
16
|
|
|
17
17
|
const fail = (msg: string) => { throw new Error(msg) }
|
|
18
18
|
|
|
19
|
-
// Same as has_no_executable_vector in the
|
|
19
|
+
// Same as has_no_executable_vector in the base sanitizer test, minus the '<iframe' clause (iframes are
|
|
20
20
|
// expected in this function's output). Everything else must still be neutralized.
|
|
21
21
|
const has_no_executable_vector_allowing_iframe = (out: string) => {
|
|
22
22
|
const o = out.toLowerCase()
|
|
@@ -49,7 +49,7 @@ export const sanitize_user_html_with_iframes_tests = async () => {
|
|
|
49
49
|
console.log("Running sanitize_user_html_with_iframes XSS regression tests")
|
|
50
50
|
|
|
51
51
|
// ---------------------------------------------------------------------------------------------
|
|
52
|
-
// 1. Re-run the full
|
|
52
|
+
// 1. Re-run the full base payload set — permitting iframe must not be a general regression
|
|
53
53
|
// ---------------------------------------------------------------------------------------------
|
|
54
54
|
const xssPayloads: [string, string][] = [
|
|
55
55
|
['img onerror', `<img src=x onerror="alert(document.domain)">`],
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { sanitize_user_html } from "@tellescope/utilities"
|
|
2
2
|
|
|
3
|
-
// Regression test
|
|
3
|
+
// Regression test: XSS via dangerouslySetInnerHTML.
|
|
4
4
|
// sanitize_user_html is the canonical render-time sanitizer that replaced remove_script_tags
|
|
5
5
|
// at every dangerouslySetInnerHTML sink. This asserts it neutralizes XSS vectors (incl. encoded /
|
|
6
6
|
// whitespace / mixed-case / iframe-srcdoc bypass variants) while preserving legitimate
|
|
7
7
|
// customization HTML (tables, headings, lists, links, images, inline styles).
|
|
8
8
|
//
|
|
9
9
|
// Pure-function test — no Session needed. Runs as part of the main suite and standalone:
|
|
10
|
-
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/
|
|
10
|
+
// ./build_cjs.sh && cd packages/public/sdk && node -r dotenv/config lib/cjs/tests/api_tests/security/sanitize-user-html.test.js
|
|
11
11
|
|
|
12
12
|
const fail = (msg: string) => { throw new Error(msg) }
|
|
13
13
|
|
|
@@ -31,7 +31,7 @@ const has_no_executable_vector = (out: string) => {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export const sanitize_user_html_xss_tests = async () => {
|
|
34
|
-
console.log("Running
|
|
34
|
+
console.log("Running sanitize_user_html XSS regression tests")
|
|
35
35
|
|
|
36
36
|
const xssPayloads: [string, string][] = [
|
|
37
37
|
['img onerror', `<img src=x onerror="alert(document.domain)">`],
|
|
@@ -99,7 +99,7 @@ export const sanitize_user_html_xss_tests = async () => {
|
|
|
99
99
|
const mixed = sanitize_user_html(`<p>Hello <b>name</b></p><img src=x onerror="steal()">`)
|
|
100
100
|
if (!(mixed.includes('<b>name</b>') && !/\son[a-z]+\s*=/.test(mixed.toLowerCase()))) fail(`mixed content not handled: ${mixed}`)
|
|
101
101
|
|
|
102
|
-
console.log("✅
|
|
102
|
+
console.log("✅ sanitize_user_html XSS regression tests passed")
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (require.main === module) {
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
require('source-map-support').install();
|
|
2
|
+
|
|
3
|
+
import axios from "axios"
|
|
4
|
+
|
|
5
|
+
import { Session } from "../../../sdk"
|
|
6
|
+
import {
|
|
7
|
+
assert,
|
|
8
|
+
log_header,
|
|
9
|
+
} from "@tellescope/testing"
|
|
10
|
+
import { PROVIDER_PERMISSIONS } from "@tellescope/constants"
|
|
11
|
+
import { setup_tests } from "../../setup"
|
|
12
|
+
|
|
13
|
+
const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
14
|
+
|
|
15
|
+
const RAND = () => Math.random().toString(36).slice(2, 10)
|
|
16
|
+
|
|
17
|
+
const ALL = 'All' as const
|
|
18
|
+
const FULL_ACCESS = { create: ALL, read: ALL, update: ALL, delete: ALL }
|
|
19
|
+
|
|
20
|
+
type Check = {
|
|
21
|
+
label: string,
|
|
22
|
+
pass: boolean,
|
|
23
|
+
detail: string,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Regression test: `adminOnly` custom actions must be enforced at runtime, not merely declared.
|
|
28
|
+
*
|
|
29
|
+
* `adminOnly: true` on a CUSTOM action in schema.ts was documentation-only. The runtime gate
|
|
30
|
+
* (routing.ts:944) reads the flag off the options object built by getCustomEndpointFields, and
|
|
31
|
+
* api.ts:609 set `adminOnly: o.adminOnly` without ever consulting `action.adminOnly`. So every
|
|
32
|
+
* admin-only custom action had to declare the flag twice, and the copies desynced: 11 of 20
|
|
33
|
+
* declared custom actions were unenforced at runtime while both public doc artifacts
|
|
34
|
+
* (openapi.json and the unauthenticated GET /documentation feed, which read the SCHEMA flag)
|
|
35
|
+
* advertised "**Admin only.**".
|
|
36
|
+
*
|
|
37
|
+
* DEFAULT CRUD actions never had this bug — routing.ts:2434 etc. read
|
|
38
|
+
* model.defaultActions.<op>.adminOnly straight off the schema. The fix
|
|
39
|
+
* (`adminOnly: o.adminOnly ?? action.adminOnly`) makes custom actions behave the same way.
|
|
40
|
+
*
|
|
41
|
+
* Five of the 11 were de-flagged in the schema instead, because the flag itself was wrong and
|
|
42
|
+
* enforcing it would revert a deliberate decision: users.invite_user carries an explicit
|
|
43
|
+
* "no longer admin only, but controlled by users.create" and send_invitation_to_existing is its
|
|
44
|
+
* sibling; organizations.create_and_join is the self-service signup path and would 401 every new
|
|
45
|
+
* org (a fresh user has no roles — the handler is what grants Admin); sync_note_to_canvas is
|
|
46
|
+
* designed around `access: 'read'` for non-admin callers; background_errors.mark_read substitutes
|
|
47
|
+
* its own RBAC check that intentionally admits non-admins holding the verb.
|
|
48
|
+
*
|
|
49
|
+
* SAFETY: every probe fails EARLY inside its handler — after the adminOnly gate but before any
|
|
50
|
+
* vendor call. Pre-fix these requests really do reach the handler, and these handlers talk to
|
|
51
|
+
* Twilio, Athena and Canvas:
|
|
52
|
+
* - trigger_events : no `action` key + an absent triggerId => the loop `continue`s (inert)
|
|
53
|
+
* - athena-subscription: frequency 1 trips the `frequency < 5` guard on the handler's first line
|
|
54
|
+
* - sync-athena : 404s on the missing Athena integration (skipped if one exists)
|
|
55
|
+
* - link-twilio : takes NO parameters and can CREATE A REAL TWILIO SUBACCOUNT, so it is
|
|
56
|
+
* probed only when the org already has a twilioSID (handler short-circuits)
|
|
57
|
+
* - twilio-embed : no phoneNumberSid => 404 no-config or 400, both before any Twilio call
|
|
58
|
+
* - handle-autoreply : absent enduserId => `if (!enduser) return` (communications.ts:42)
|
|
59
|
+
* Input validation runs BEFORE the adminOnly gate (routing.ts:921 orders access, then validate),
|
|
60
|
+
* so every probe body must be schema-VALID or the test would prove nothing.
|
|
61
|
+
*
|
|
62
|
+
* RED (pre-fix): the six group-B rows fail — each reaches its handler and returns a non-401.
|
|
63
|
+
* GREEN (post-fix): all six return 401 "Admin access only"; the group-A controls are unchanged.
|
|
64
|
+
*/
|
|
65
|
+
export const schema_adminonly_enforcement_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
66
|
+
log_header("schema-declared adminOnly must be enforced on custom actions")
|
|
67
|
+
|
|
68
|
+
const checks: Check[] = []
|
|
69
|
+
const record = (label: string, pass: boolean, detail: string) => checks.push({ label, pass, detail })
|
|
70
|
+
|
|
71
|
+
// Raw axios: the SDK's parseError discards the HTTP status, and the status is the whole point.
|
|
72
|
+
const request = async (
|
|
73
|
+
authToken: string, method: 'get' | 'post', path: string, data?: any,
|
|
74
|
+
) => {
|
|
75
|
+
const r = await axios.request({
|
|
76
|
+
method,
|
|
77
|
+
url: `${host}/v1${path}`,
|
|
78
|
+
...method === 'get' ? { params: data } : { data },
|
|
79
|
+
headers: { Authorization: `Bearer ${authToken}` },
|
|
80
|
+
validateStatus: () => true,
|
|
81
|
+
})
|
|
82
|
+
return { status: r.status, body: r.data }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const isAdminDenial = (r: { status: number, body: any }) => (
|
|
86
|
+
r.status === 401 && r.body?.message === 'Admin access only'
|
|
87
|
+
)
|
|
88
|
+
const summarize = (r: { status: number, body: any }) => (
|
|
89
|
+
`${r.status} ${(JSON.stringify(r.body) ?? '').slice(0, 120)}`
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
let roleId = ''
|
|
93
|
+
let attackerId = ''
|
|
94
|
+
let enduserId = ''
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
/* ================= fixtures ================= */
|
|
98
|
+
|
|
99
|
+
const role = `f0191-staff-${RAND()}`
|
|
100
|
+
const rbap = await sdk.api.role_based_access_permissions.createOne({
|
|
101
|
+
role,
|
|
102
|
+
permissions: {
|
|
103
|
+
...PROVIDER_PERMISSIONS,
|
|
104
|
+
// grant exactly the verbs the actions under test declare, so a rejection proves the ADMIN
|
|
105
|
+
// gate fired rather than ordinary RBAC
|
|
106
|
+
automation_triggers: FULL_ACCESS,
|
|
107
|
+
organizations: FULL_ACCESS,
|
|
108
|
+
availability_blocks: FULL_ACCESS,
|
|
109
|
+
background_errors: FULL_ACCESS,
|
|
110
|
+
users: FULL_ACCESS,
|
|
111
|
+
},
|
|
112
|
+
} as any)
|
|
113
|
+
roleId = rbap.id
|
|
114
|
+
|
|
115
|
+
const attacker = await sdk.api.users.createOne({
|
|
116
|
+
email: `f0191-attacker-${RAND()}@tellescope.example`,
|
|
117
|
+
fname: 'F0191', lname: 'Staff',
|
|
118
|
+
verifiedEmail: true,
|
|
119
|
+
notificationEmailsDisabled: true,
|
|
120
|
+
roles: [role],
|
|
121
|
+
} as any)
|
|
122
|
+
attackerId = attacker.id
|
|
123
|
+
|
|
124
|
+
const attackerToken = (await sdk.api.users.generate_auth_token({ id: attackerId })).authToken
|
|
125
|
+
const adminToken = (await sdk.api.users.generate_auth_token({ id: sdk.userInfo.id })).authToken
|
|
126
|
+
|
|
127
|
+
const attackerSDK = new Session({ host, authToken: attackerToken })
|
|
128
|
+
await attackerSDK.refresh_session()
|
|
129
|
+
record(
|
|
130
|
+
'setup: attacker is a non-admin holding every verb under test',
|
|
131
|
+
attackerSDK.userInfo.id === attackerId && !(attackerSDK.userInfo.roles ?? []).includes('Admin'),
|
|
132
|
+
`id=${attackerSDK.userInfo.id} roles=${JSON.stringify(attackerSDK.userInfo.roles)}`,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const enduser = await sdk.api.endusers.createOne({ fname: 'F0191', lname: 'Patient' })
|
|
136
|
+
enduserId = enduser.id
|
|
137
|
+
|
|
138
|
+
// A guaranteed-valid, guaranteed-absent id: create then delete, so probes hit the handler's
|
|
139
|
+
// "not found" branch rather than tripping input validation (which runs BEFORE the admin gate).
|
|
140
|
+
const doomed = await sdk.api.endusers.createOne({ fname: 'F0191', lname: 'Absent' })
|
|
141
|
+
const ABSENT_ID = doomed.id
|
|
142
|
+
await sdk.api.endusers.deleteOne(ABSENT_ID)
|
|
143
|
+
|
|
144
|
+
/* ===== environment guards for the two probes input alone cannot make safe ===== */
|
|
145
|
+
|
|
146
|
+
let athenaIntegrationExists = false
|
|
147
|
+
try {
|
|
148
|
+
const existing = await sdk.api.integrations.load_redacted({})
|
|
149
|
+
athenaIntegrationExists = !!existing.integrations.find((i: any) => /athena/i.test(i.title ?? ''))
|
|
150
|
+
} catch { /* load not permitted — assume absent */ }
|
|
151
|
+
|
|
152
|
+
let orgHasTwilioSID = false
|
|
153
|
+
try {
|
|
154
|
+
const org = await sdk.api.organizations.getOne(sdk.userInfo.businessId)
|
|
155
|
+
orgHasTwilioSID = !!(org as any)?.twilioSID
|
|
156
|
+
} catch { /* ignore */ }
|
|
157
|
+
|
|
158
|
+
/* ===== GROUP B: the six genuine gaps — each must become 401 ===== */
|
|
159
|
+
|
|
160
|
+
const groupB: {
|
|
161
|
+
label: string, method: 'get' | 'post', path: string, data?: any, skip?: string,
|
|
162
|
+
}[] = [
|
|
163
|
+
{
|
|
164
|
+
label: 'automation_triggers.trigger_events',
|
|
165
|
+
method: 'post', path: '/automation-triggers/trigger-events',
|
|
166
|
+
// no `action` key: stays off the arbitrary-action-execution branch entirely
|
|
167
|
+
data: { triggers: [{ enduserId, automationTriggerId: ABSENT_ID }] },
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
label: 'organizations.add_athena_subscription',
|
|
171
|
+
method: 'post', path: '/organizations/athena-subscription',
|
|
172
|
+
data: { type: 'patients', frequency: 1 }, // trips `frequency < 5` on the handler's first line
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
label: 'organizations.sync_athena_subscription',
|
|
176
|
+
method: 'post', path: '/organizations/sync-athena-subscription',
|
|
177
|
+
data: { type: 'patients' },
|
|
178
|
+
skip: athenaIntegrationExists
|
|
179
|
+
? 'org HAS an Athena integration — probing would call Athena.process_subscription for real'
|
|
180
|
+
: undefined,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
label: 'organizations.link_twilio',
|
|
184
|
+
method: 'post', path: '/organizations/link-twilio',
|
|
185
|
+
data: {},
|
|
186
|
+
skip: orgHasTwilioSID
|
|
187
|
+
? undefined
|
|
188
|
+
: 'org has no twilioSID — probing would CREATE A REAL TWILIO SUBACCOUNT',
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
label: 'organizations.load_twilio_embed',
|
|
192
|
+
method: 'get', path: '/organizations/twilio-embed',
|
|
193
|
+
data: { type: 'tfn-verification' }, // no phoneNumberSid => rejected before any Twilio call
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
label: 'availability_blocks.handle_autoreply',
|
|
197
|
+
method: 'post', path: '/handle-out-of-office-autoreply',
|
|
198
|
+
data: { channel: 'Email', enduserId: ABSENT_ID }, // communications.ts:42 `if (!enduser) return`
|
|
199
|
+
},
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
for (const probe of groupB) {
|
|
203
|
+
if (probe.skip) {
|
|
204
|
+
record(`B: ${probe.label} rejects a non-admin`, true, `SKIPPED (safety) — ${probe.skip}`)
|
|
205
|
+
continue
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const attackerResult = await request(attackerToken, probe.method, probe.path, probe.data)
|
|
209
|
+
// baseline: an admin must NOT be admin-denied on the same path, so a blanket 401 can't pass
|
|
210
|
+
const baseline = await request(adminToken, probe.method, probe.path, probe.data)
|
|
211
|
+
const badProbe = isAdminDenial(baseline)
|
|
212
|
+
|
|
213
|
+
record(
|
|
214
|
+
`B: ${probe.label} rejects a non-admin`,
|
|
215
|
+
!badProbe && isAdminDenial(attackerResult),
|
|
216
|
+
`attacker=${summarize(attackerResult)} | admin baseline=${baseline.status}`
|
|
217
|
+
+ (badProbe ? ' BAD PROBE: admin was also admin-denied' : ''),
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* ===== GROUP A: de-flagged actions must NOT become admin-only ===== */
|
|
222
|
+
|
|
223
|
+
const groupA: { label: string, method: 'get' | 'post', path: string, data?: any }[] = [
|
|
224
|
+
{
|
|
225
|
+
label: 'organizations.sync_note_to_canvas',
|
|
226
|
+
method: 'post', path: '/organizations/sync-note-to-canvas',
|
|
227
|
+
data: { enduserId: ABSENT_ID, note: 'control' }, // 404 Enduser not found
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
label: 'background_errors.mark_read',
|
|
231
|
+
method: 'post', path: '/background-errors/mark-read', data: {},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
label: 'users.send_invitation_to_existing',
|
|
235
|
+
method: 'post', path: '/invite-existing-user-to-organization',
|
|
236
|
+
// takes userId (not email); an absent id hits RecordNotFoundError, well short of any invite
|
|
237
|
+
data: { userId: ABSENT_ID },
|
|
238
|
+
},
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
for (const probe of groupA) {
|
|
242
|
+
const r = await request(attackerToken, probe.method, probe.path, probe.data)
|
|
243
|
+
record(
|
|
244
|
+
`A: ${probe.label} stays reachable by a non-admin (flag intentionally dropped)`,
|
|
245
|
+
!isAdminDenial(r),
|
|
246
|
+
`${summarize(r)} (expected a handler response, not 401 Admin access only)`,
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* ===== report: print full table first, then assert (harness exits on first failure) ===== */
|
|
251
|
+
console.log('\n check summary:')
|
|
252
|
+
for (const c of checks) {
|
|
253
|
+
console.log(` ${c.pass ? 'PASS' : 'FAIL'} ${c.label} — ${c.detail}`)
|
|
254
|
+
}
|
|
255
|
+
console.log('')
|
|
256
|
+
|
|
257
|
+
for (const c of checks) {
|
|
258
|
+
assert(c.pass, `${c.label} — ${c.detail}`, c.label)
|
|
259
|
+
}
|
|
260
|
+
} finally {
|
|
261
|
+
if (enduserId) { try { await sdk.api.endusers.deleteOne(enduserId) } catch {} }
|
|
262
|
+
if (attackerId) { try { await sdk.api.users.deleteOne(attackerId) } catch {} }
|
|
263
|
+
if (roleId) { try { await sdk.api.role_based_access_permissions.deleteOne(roleId) } catch {} }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Allow running this test file independently
|
|
268
|
+
if (require.main === module) {
|
|
269
|
+
console.log(`🌐 Using API URL: ${host}`)
|
|
270
|
+
const sdk = new Session({ host })
|
|
271
|
+
const sdkNonAdmin = new Session({ host })
|
|
272
|
+
|
|
273
|
+
const runTests = async () => {
|
|
274
|
+
await setup_tests(sdk, sdkNonAdmin)
|
|
275
|
+
await schema_adminonly_enforcement_tests({ sdk, sdkNonAdmin })
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
runTests()
|
|
279
|
+
.then(() => {
|
|
280
|
+
console.log("✅ schema adminOnly enforcement test suite completed successfully")
|
|
281
|
+
process.exit(0)
|
|
282
|
+
})
|
|
283
|
+
.catch((error) => {
|
|
284
|
+
console.error("❌ schema adminOnly enforcement test suite failed:", error)
|
|
285
|
+
process.exit(1)
|
|
286
|
+
})
|
|
287
|
+
}
|