@tellescope/sdk 1.256.14 → 1.256.16
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/sdk.d.ts +2 -2
- 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 +1 -1
- package/lib/cjs/tests/api_tests/organization_signup.test.js +1 -1
- 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-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/file-link-session-confinement.test.d.ts +5 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.d.ts.map +1 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.test.js +357 -0
- package/lib/cjs/tests/api_tests/security/file-link-session-confinement.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/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/tests.d.ts.map +1 -1
- package/lib/cjs/tests/tests.js +60 -46
- package/lib/cjs/tests/tests.js.map +1 -1
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +1 -1
- package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +1 -1
- package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/lib/esm/enduser.d.ts +0 -1
- package/lib/esm/enduser.d.ts.map +1 -1
- package/lib/esm/sdk.d.ts +4 -5
- package/lib/esm/sdk.d.ts.map +1 -1
- package/lib/esm/session.d.ts +0 -1
- package/lib/esm/session.d.ts.map +1 -1
- 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 +1 -1
- package/lib/esm/tests/api_tests/organization_signup.test.js +1 -1
- 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-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/file-link-session-confinement.test.d.ts +5 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.d.ts.map +1 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.test.js +349 -0
- package/lib/esm/tests/api_tests/security/file-link-session-confinement.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/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/tests.d.ts.map +1 -1
- package/lib/esm/tests/tests.js +38 -24
- package/lib/esm/tests/tests.js.map +1 -1
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +1 -1
- package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +1 -1
- 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 +2 -2
- package/src/tests/api_tests/purchase_made_trigger.test.ts +29 -41
- package/src/tests/api_tests/security/{F-0196-add-to-journey-foreign-enduserid.test.ts → add-to-journey-foreign-enduserid.test.ts} +6 -7
- 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/{F-0192-automated-actions-process-gate.test.ts → automated-actions-process-gate.test.ts} +6 -7
- package/src/tests/api_tests/security/{F-0179-booking-info-idor-token-mint.test.ts → booking-info-idor-token-mint.test.ts} +5 -6
- 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/file-link-session-confinement.test.ts +291 -0
- 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/{F-0191-schema-adminonly-enforcement.test.ts → schema-adminonly-enforcement.test.ts} +6 -7
- 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/{F-0185-startlinktoken-enduser-staff-escalation.test.ts → startlinktoken-enduser-staff-escalation.test.ts} +6 -6
- 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/webhook_error_handling.test.ts +1 -1
- package/src/tests/tests.ts +43 -24
- package/src/tests/unit_tests/openapi_spec_freshness.test.ts +1 -1
- package/test_generated.pdf +0 -0
- package/src/tests/api_tests/security/readonly-enduser-preview.test.ts +0 -301
|
@@ -16,14 +16,14 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
|
16
16
|
const OTHER_TENANT_API_KEY = "ba745e25162bb95a795c5fa1af70df188d93c4d3aac9c48b34a5c8c9dd7b80f7"
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Tenant-boundary guard for cascade_role_rename (relates to
|
|
19
|
+
* Tenant-boundary guard for cascade_role_rename (relates to a prior internal review,
|
|
20
20
|
* which was investigated and closed as a FALSE POSITIVE — see that file for the code trace).
|
|
21
21
|
*
|
|
22
22
|
* The `cascade_role_rename` side-effect handler
|
|
23
23
|
* ([event_handlers_v2/role_based_access_permissions.ts](packages/private/api/api/v1/event_handlers_v2/role_based_access_permissions.ts))
|
|
24
24
|
* runs when a `role_based_access_permissions` doc's `role` field changes. It finds every user
|
|
25
25
|
* with the old role name (via `DBUnrestricted.users`) and rewrites their `roles` array, then
|
|
26
|
-
* deauthenticates them.
|
|
26
|
+
* deauthenticates them. An earlier review hypothesized this query was globally cross-tenant. It is NOT:
|
|
27
27
|
* `DBUnrestricted` bypasses per-user/per-role RBAC but is STILL scoped to the acting session's
|
|
28
28
|
* `businessId` (see `modifyFilterForAccessConstraint` injecting `{ businessId }` at
|
|
29
29
|
* database.ts:1761-1763, reached via the `unrestricted: true` branch at database.ts:2137-2144).
|
|
@@ -42,7 +42,7 @@ const OTHER_TENANT_API_KEY = "ba745e25162bb95a795c5fa1af70df188d93c4d3aac9c48b34
|
|
|
42
42
|
* A collision-proof unique role name (timestamped) is used so the test never touches real roles.
|
|
43
43
|
*/
|
|
44
44
|
export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
45
|
-
log_header("
|
|
45
|
+
log_header("cascade role rename cross-tenant regression")
|
|
46
46
|
|
|
47
47
|
const stamp = Date.now()
|
|
48
48
|
const ROLE_OLD = `XTenantRename_${stamp}`
|
|
@@ -55,7 +55,7 @@ export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Se
|
|
|
55
55
|
let rbapId: string | undefined
|
|
56
56
|
// We create dedicated throwaway users in BOTH tenants and delete them in `finally`. We never
|
|
57
57
|
// mutate any pre-existing user (an earlier version of this test clobbered the apiKey's own
|
|
58
|
-
// admin user via getSome+replaceObjectFields
|
|
58
|
+
// admin user via getSome+replaceObjectFields). controlUser lives in
|
|
59
59
|
// Tenant A and SHOULD be renamed by the same-tenant cascade; victimUser lives in Tenant B and
|
|
60
60
|
// must be UNTOUCHED.
|
|
61
61
|
let controlUserId: string | undefined
|
|
@@ -92,7 +92,7 @@ export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Se
|
|
|
92
92
|
assert(
|
|
93
93
|
victimUser.businessId !== tenantABusinessId,
|
|
94
94
|
`Victim user shares businessId with Tenant A (${victimUser.businessId}) — not a cross-tenant scenario`,
|
|
95
|
-
'
|
|
95
|
+
'setup: tenants are distinct',
|
|
96
96
|
)
|
|
97
97
|
const victimBefore = await sdkOther.api.users.getOne(victimUserId)
|
|
98
98
|
const controlBefore = await sdk.api.users.getOne(controlUserId)
|
|
@@ -100,7 +100,7 @@ export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Se
|
|
|
100
100
|
JSON.stringify(victimBefore.roles) === JSON.stringify([ROLE_OLD])
|
|
101
101
|
&& JSON.stringify(controlBefore.roles) === JSON.stringify([ROLE_OLD]),
|
|
102
102
|
`Setup failed: expected both users to hold [${ROLE_OLD}] (victim=${JSON.stringify(victimBefore.roles)}, control=${JSON.stringify(controlBefore.roles)})`,
|
|
103
|
-
'
|
|
103
|
+
'setup: both users hold ROLE_OLD',
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
// 5. Tenant A renames the role. This triggers cascade_role_rename.
|
|
@@ -113,7 +113,7 @@ export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Se
|
|
|
113
113
|
JSON.stringify(victimAfter.roles) === JSON.stringify([ROLE_OLD]),
|
|
114
114
|
`CROSS-TENANT LEAK: Tenant B victim roles changed to ${JSON.stringify(victimAfter.roles)} `
|
|
115
115
|
+ `after Tenant A renamed its role. Expected [${ROLE_OLD}].`,
|
|
116
|
-
'
|
|
116
|
+
'Tenant B user roles unaffected by other-tenant role rename',
|
|
117
117
|
)
|
|
118
118
|
|
|
119
119
|
// 7. POSITIVE CONTROL — the Tenant A control user SHOULD be renamed (same-tenant cascade intact).
|
|
@@ -122,7 +122,7 @@ export const cascade_role_rename_cross_tenant_tests = async ({ sdk } : { sdk: Se
|
|
|
122
122
|
JSON.stringify(controlAfter.roles) === JSON.stringify([ROLE_NEW]),
|
|
123
123
|
`Same-tenant cascade broken: Tenant A control roles are ${JSON.stringify(controlAfter.roles)}, `
|
|
124
124
|
+ `expected [${ROLE_NEW}].`,
|
|
125
|
-
'
|
|
125
|
+
'Tenant A user roles renamed by same-tenant cascade',
|
|
126
126
|
)
|
|
127
127
|
} finally {
|
|
128
128
|
// Cleanup: delete both throwaway users and the role doc. Never touches pre-existing users.
|
|
@@ -151,11 +151,11 @@ if (require.main === module) {
|
|
|
151
151
|
|
|
152
152
|
runTests()
|
|
153
153
|
.then(() => {
|
|
154
|
-
console.log("✅
|
|
154
|
+
console.log("✅ cascade role rename cross-tenant test suite completed successfully")
|
|
155
155
|
process.exit(0)
|
|
156
156
|
})
|
|
157
157
|
.catch((error) => {
|
|
158
|
-
console.error("❌
|
|
158
|
+
console.error("❌ cascade role rename cross-tenant test suite failed:", error)
|
|
159
159
|
process.exit(1)
|
|
160
160
|
})
|
|
161
161
|
}
|
|
@@ -41,7 +41,7 @@ const collectViolations = (results: { modelName: string, recordId: string, data:
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Regression test
|
|
44
|
+
* Regression test: `/v1/data-sync` redaction.
|
|
45
45
|
*
|
|
46
46
|
* The /v1/data-sync handler must apply the central applyRedactions() pipeline to
|
|
47
47
|
* every non-deleted record. The original bug: redactions were gated behind
|
|
@@ -63,7 +63,7 @@ const collectViolations = (results: { modelName: string, recordId: string, data:
|
|
|
63
63
|
* Post-fix: assertion passes.
|
|
64
64
|
*/
|
|
65
65
|
export const data_sync_redaction_bypass_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
66
|
-
log_header("
|
|
66
|
+
log_header("/v1/data-sync field-redaction bypass regression")
|
|
67
67
|
|
|
68
68
|
const roleName = `f0001-data-sync-bypass-${Date.now()}`
|
|
69
69
|
let testEnduserId: string | undefined
|
|
@@ -124,13 +124,13 @@ export const data_sync_redaction_bypass_tests = async ({ sdk, sdkNonAdmin } : {
|
|
|
124
124
|
// would pass vacuously — guard against that.
|
|
125
125
|
const userRecordsInStream = sync.results.filter(r => r.modelName === 'users').length
|
|
126
126
|
await async_test(
|
|
127
|
-
"
|
|
127
|
+
"guard: /v1/data-sync sync stream contains at least one user record",
|
|
128
128
|
async () => ({ userRecords: userRecordsInStream, totalRecords: sync.results.length }),
|
|
129
129
|
{ onResult: r => r.userRecords >= 1 },
|
|
130
130
|
)
|
|
131
131
|
|
|
132
132
|
await async_test(
|
|
133
|
-
"
|
|
133
|
+
"/v1/data-sync must NOT return hashedPass / hashedPassword / hashedInviteCode",
|
|
134
134
|
async () => ({
|
|
135
135
|
violationCount: violations.length,
|
|
136
136
|
violations: violations.slice(0, 10),
|
|
@@ -143,7 +143,7 @@ export const data_sync_redaction_bypass_tests = async ({ sdk, sdkNonAdmin } : {
|
|
|
143
143
|
// ========================================================================
|
|
144
144
|
// Additional coverage for applyRedactions code paths reachable via /v1/data-sync.
|
|
145
145
|
// Each of these is a distinct branch in applyRedactions (routing.ts:1165-1238)
|
|
146
|
-
// and could regress independently of
|
|
146
|
+
// and could regress independently of this fix.
|
|
147
147
|
// ========================================================================
|
|
148
148
|
|
|
149
149
|
// Case A: schema-level `redactions: ['all']` must apply to ADMIN sessions too.
|
|
@@ -153,7 +153,7 @@ export const data_sync_redaction_bypass_tests = async ({ sdk, sdkNonAdmin } : {
|
|
|
153
153
|
const adminSync = await sdk.sync({ from: new Date(0) })
|
|
154
154
|
const adminViolations = collectViolations(adminSync.results)
|
|
155
155
|
await async_test(
|
|
156
|
-
"
|
|
156
|
+
"coverage A: admin /v1/data-sync also strips redactions:['all'] fields (hashedPass etc.)",
|
|
157
157
|
async () => ({
|
|
158
158
|
violationCount: adminViolations.length,
|
|
159
159
|
violations: adminViolations.slice(0, 10),
|
|
@@ -180,7 +180,7 @@ export const data_sync_redaction_bypass_tests = async ({ sdk, sdkNonAdmin } : {
|
|
|
180
180
|
} catch {}
|
|
181
181
|
}
|
|
182
182
|
await async_test(
|
|
183
|
-
"
|
|
183
|
+
"coverage B: /v1/data-sync strips linkedAccountAccess from other users' records",
|
|
184
184
|
async () => ({
|
|
185
185
|
otherUserRecords: otherUsersInStream.length,
|
|
186
186
|
leakCount: linkedAccountLeaks.length,
|
|
@@ -226,11 +226,11 @@ if (require.main === module) {
|
|
|
226
226
|
|
|
227
227
|
runTests()
|
|
228
228
|
.then(() => {
|
|
229
|
-
console.log("✅
|
|
229
|
+
console.log("✅ data-sync redaction-bypass test suite completed successfully")
|
|
230
230
|
process.exit(0)
|
|
231
231
|
})
|
|
232
232
|
.catch((error) => {
|
|
233
|
-
console.error("❌
|
|
233
|
+
console.error("❌ data-sync redaction-bypass test suite failed:", error)
|
|
234
234
|
process.exit(1)
|
|
235
235
|
})
|
|
236
236
|
}
|
|
@@ -14,8 +14,7 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
|
|
|
14
14
|
const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.env.NON_ADMIN_PASSWORD]
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Regression test
|
|
18
|
-
* reopened 2026-08-17 for the `develop_health_run_benefit_verification` sub-item.
|
|
17
|
+
* Regression test: the `develop_health_run_benefit_verification` RBAC gate.
|
|
19
18
|
*
|
|
20
19
|
* `enduser_eligibility_results.develop_health_run_benefit_verification` is registered with
|
|
21
20
|
* `noAccessPermissions: true` (packages/private/api/api/v1/api.ts, ~line 24606). Before the fix,
|
|
@@ -39,7 +38,7 @@ const [nonAdminEmail, nonAdminPassword] = [process.env.NON_ADMIN_EMAIL, process.
|
|
|
39
38
|
* Post-fix: the handler throws 403 before touching `DB.endusers` at all. Test passes.
|
|
40
39
|
*/
|
|
41
40
|
export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkNonAdmin } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
42
|
-
log_header("
|
|
41
|
+
log_header("develop_health benefit verification RBAC regression")
|
|
43
42
|
|
|
44
43
|
const roleName = `f0006-develop-health-no-access-${Date.now()}`
|
|
45
44
|
let rbapId: string | undefined
|
|
@@ -74,7 +73,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
74
73
|
// Pre-fix: proceeds to DB.endusers.findById and either 400s on validation (fake id) or
|
|
75
74
|
// succeeds and forwards PHI to Develop Health (real id) — never a 403.
|
|
76
75
|
await async_test(
|
|
77
|
-
"
|
|
76
|
+
"enduser_eligibility_results.develop_health_run_benefit_verification must throw 403 when role denies endusers/enduser_eligibility_results",
|
|
78
77
|
() => sdkNonAdmin.api.enduser_eligibility_results.develop_health_run_benefit_verification({
|
|
79
78
|
enduserId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
80
79
|
providerUserId: new ObjectId().toHexString(), // fake id — access check should fire first
|
|
@@ -122,7 +121,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
122
121
|
await sdkNonAdmin.authenticate(nonAdminEmail!, nonAdminPassword!)
|
|
123
122
|
|
|
124
123
|
await async_test(
|
|
125
|
-
"
|
|
124
|
+
"a provider role with enduser access passes the gate (reaches 'Integration not found', not 403)",
|
|
126
125
|
() => sdkNonAdmin.api.enduser_eligibility_results.develop_health_run_benefit_verification({
|
|
127
126
|
enduserId: new ObjectId().toHexString(),
|
|
128
127
|
providerUserId: new ObjectId().toHexString(),
|
|
@@ -159,7 +158,7 @@ export const develop_health_benefit_verification_rbac_tests = async ({ sdk, sdkN
|
|
|
159
158
|
// the handler throws "Integration not found" BEFORE reaching the (now read-scoped) enduser load,
|
|
160
159
|
// and the enduser load is what the create>read fix governs. Exercising it would need either a real
|
|
161
160
|
// Develop Health integration or reordering the handler purely for the test. It is covered by code
|
|
162
|
-
// review +
|
|
161
|
+
// review + the systemic follow-up. If a Develop Health sandbox integration is ever available
|
|
163
162
|
// in the test org, add: role { endusers: create 'All', read 'Assigned' } → call with a real
|
|
164
163
|
// enduser NOT assigned to the caller → expect the enduser-not-found path, not a successful forward.
|
|
165
164
|
} finally {
|
|
@@ -194,11 +193,11 @@ if (require.main === module) {
|
|
|
194
193
|
|
|
195
194
|
runTests()
|
|
196
195
|
.then(() => {
|
|
197
|
-
console.log("✅
|
|
196
|
+
console.log("✅ develop_health_run_benefit_verification RBAC test suite completed successfully")
|
|
198
197
|
process.exit(0)
|
|
199
198
|
})
|
|
200
199
|
.catch((error) => {
|
|
201
|
-
console.error("❌
|
|
200
|
+
console.error("❌ develop_health_run_benefit_verification RBAC test suite failed:", error)
|
|
202
201
|
process.exit(1)
|
|
203
202
|
})
|
|
204
203
|
}
|
|
@@ -16,10 +16,10 @@ const CROSS_ENDUSER_MESSAGE = "enduserId does not match creator id for enduser s
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Regression test for the enduser cross-enduser CREATE gating gaps:
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
19
|
+
* enduser_observations
|
|
20
|
+
* enduser_orders
|
|
21
|
+
* managed_content_records
|
|
22
|
+
* chat_rooms (enduserIds-only gate; staff userIds targeting is by-design)
|
|
23
23
|
*
|
|
24
24
|
* Each model exposed enduserActions.create with an `enduserId`/`enduserIds` field that
|
|
25
25
|
* lacked a write-side gate, letting an authenticated enduser create records bound to a
|
|
@@ -30,7 +30,7 @@ const CROSS_ENDUSER_MESSAGE = "enduserId does not match creator id for enduser s
|
|
|
30
30
|
* legitimate path (self-create + staff-create) still works.
|
|
31
31
|
*/
|
|
32
32
|
export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
33
|
-
log_header("
|
|
33
|
+
log_header("enduser cross-enduser create gates")
|
|
34
34
|
|
|
35
35
|
let attackerId: string | undefined
|
|
36
36
|
let victimId: string | undefined
|
|
@@ -53,10 +53,10 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
53
53
|
await attackerSDK.authenticate(attackerEmail, ENDUSER_PASSWORD)
|
|
54
54
|
|
|
55
55
|
// ============================================================
|
|
56
|
-
//
|
|
56
|
+
// enduser_observations
|
|
57
57
|
// ============================================================
|
|
58
58
|
await async_test(
|
|
59
|
-
`
|
|
59
|
+
`enduser cannot create observation on another enduser (createOne)`,
|
|
60
60
|
() => attackerSDK.api.enduser_observations.createOne({
|
|
61
61
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
62
62
|
measurement: { unit: 'mmHg', value: 220 },
|
|
@@ -64,7 +64,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
64
64
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
65
65
|
)
|
|
66
66
|
await async_test(
|
|
67
|
-
`
|
|
67
|
+
`enduser cannot create observation on another enduser (createMany)`,
|
|
68
68
|
() => attackerSDK.api.enduser_observations.createSome([{
|
|
69
69
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
70
70
|
measurement: { unit: 'mmHg', value: 220 },
|
|
@@ -74,7 +74,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
74
74
|
|
|
75
75
|
// Positive control: enduser CAN create an observation on their OWN record
|
|
76
76
|
await async_test(
|
|
77
|
-
`
|
|
77
|
+
`enduser can still create observation on own record`,
|
|
78
78
|
() => attackerSDK.api.enduser_observations.createOne({
|
|
79
79
|
enduserId: attackerId!, category: 'vital-signs', status: 'final',
|
|
80
80
|
measurement: { unit: 'mmHg', value: 120 },
|
|
@@ -83,7 +83,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
83
83
|
)
|
|
84
84
|
// Positive control: staff CAN create an observation on any tenant enduser
|
|
85
85
|
await async_test(
|
|
86
|
-
`
|
|
86
|
+
`staff can still create observation on any enduser`,
|
|
87
87
|
() => sdk.api.enduser_observations.createOne({
|
|
88
88
|
enduserId: victimId!, category: 'vital-signs', status: 'final',
|
|
89
89
|
measurement: { unit: 'mmHg', value: 118 },
|
|
@@ -92,61 +92,61 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
// ============================================================
|
|
95
|
-
//
|
|
95
|
+
// enduser_orders
|
|
96
96
|
// ============================================================
|
|
97
97
|
const orderPayload = (enduserId: string) => ({
|
|
98
98
|
enduserId, externalId: `f0117-${Date.now()}`, source: 'f0117-source',
|
|
99
99
|
title: 'f0117 order', status: 'pending',
|
|
100
100
|
})
|
|
101
101
|
await async_test(
|
|
102
|
-
`
|
|
102
|
+
`enduser cannot create order on another enduser`,
|
|
103
103
|
() => attackerSDK.api.enduser_orders.createOne(orderPayload(victimId!) as any),
|
|
104
104
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
105
105
|
)
|
|
106
106
|
await async_test(
|
|
107
|
-
`
|
|
107
|
+
`enduser can still create order on own record`,
|
|
108
108
|
() => attackerSDK.api.enduser_orders.createOne(orderPayload(attackerId!) as any),
|
|
109
109
|
{ onResult: (o: any) => { if (o?.id) createdOrderIds.push(o.id); return o?.enduserId === attackerId } },
|
|
110
110
|
)
|
|
111
111
|
await async_test(
|
|
112
|
-
`
|
|
112
|
+
`staff can still create order on any enduser`,
|
|
113
113
|
() => sdk.api.enduser_orders.createOne(orderPayload(victimId!) as any),
|
|
114
114
|
{ onResult: (o: any) => { if (o?.id) createdOrderIds.push(o.id); return o?.enduserId === victimId } },
|
|
115
115
|
)
|
|
116
116
|
|
|
117
117
|
// ============================================================
|
|
118
|
-
//
|
|
118
|
+
// managed_content_records
|
|
119
119
|
// ============================================================
|
|
120
120
|
await async_test(
|
|
121
|
-
`
|
|
121
|
+
`enduser cannot create content with allowUnauthenticatedAccess`,
|
|
122
122
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
123
123
|
title: 'f0119 phishing', textContent: 'x', allowUnauthenticatedAccess: true,
|
|
124
124
|
} as any),
|
|
125
125
|
{ shouldError: true, onError: e => e.message === "allowUnauthenticatedAccess cannot be set by endusers" },
|
|
126
126
|
)
|
|
127
127
|
await async_test(
|
|
128
|
-
`
|
|
128
|
+
`enduser cannot create content with publicRead`,
|
|
129
129
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
130
130
|
title: 'f0119 broadcast', textContent: 'x', publicRead: true,
|
|
131
131
|
} as any),
|
|
132
132
|
{ shouldError: true, onError: e => e.message === "publicRead cannot be set by endusers" },
|
|
133
133
|
)
|
|
134
134
|
await async_test(
|
|
135
|
-
`
|
|
135
|
+
`enduser cannot create content bound to another enduser`,
|
|
136
136
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
137
137
|
title: 'f0119 cross', textContent: 'x', enduserId: victimId!,
|
|
138
138
|
} as any),
|
|
139
139
|
{ shouldError: true, onError: e => e.message === CROSS_ENDUSER_MESSAGE },
|
|
140
140
|
)
|
|
141
141
|
await async_test(
|
|
142
|
-
`
|
|
142
|
+
`enduser can still create ordinary content`,
|
|
143
143
|
() => attackerSDK.api.managed_content_records.createOne({
|
|
144
144
|
title: 'f0119 ok', textContent: 'hello',
|
|
145
145
|
} as any),
|
|
146
146
|
{ onResult: (o: any) => { if (o?.id) createdContentIds.push(o.id); return !o?.publicRead && !o?.allowUnauthenticatedAccess } },
|
|
147
147
|
)
|
|
148
148
|
await async_test(
|
|
149
|
-
`
|
|
149
|
+
`staff can still create public content`,
|
|
150
150
|
() => sdk.api.managed_content_records.createOne({
|
|
151
151
|
title: 'f0119 staff public', textContent: 'x', publicRead: true,
|
|
152
152
|
} as any),
|
|
@@ -154,11 +154,11 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
154
154
|
)
|
|
155
155
|
|
|
156
156
|
// ============================================================
|
|
157
|
-
//
|
|
157
|
+
// chat_rooms (enduserIds-only gate; staff userIds targeting is by-design)
|
|
158
158
|
// ============================================================
|
|
159
159
|
const staffId = sdk.userInfo.id
|
|
160
160
|
await async_test(
|
|
161
|
-
`
|
|
161
|
+
`enduser cannot add another patient to a chat room (enduserIds)`,
|
|
162
162
|
() => attackerSDK.api.chat_rooms.createOne({
|
|
163
163
|
type: 'internal', enduserIds: [attackerId!, victimId!], userIds: [staffId],
|
|
164
164
|
} as any),
|
|
@@ -166,7 +166,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
166
166
|
)
|
|
167
167
|
// Positive control: patient CAN create a room with care-team staff + self (intended feature)
|
|
168
168
|
await async_test(
|
|
169
|
-
`
|
|
169
|
+
`enduser can still create a room with staff + self`,
|
|
170
170
|
() => attackerSDK.api.chat_rooms.createOne({
|
|
171
171
|
type: 'internal', enduserIds: [attackerId!], userIds: [staffId],
|
|
172
172
|
} as any),
|
|
@@ -174,7 +174,7 @@ export const enduser_cross_create_tests = async ({ sdk } : { sdk: Session, sdkNo
|
|
|
174
174
|
)
|
|
175
175
|
// Positive control: staff can still create multi-patient rooms
|
|
176
176
|
await async_test(
|
|
177
|
-
`
|
|
177
|
+
`staff can still create a room with multiple endusers`,
|
|
178
178
|
() => sdk.api.chat_rooms.createOne({
|
|
179
179
|
type: 'internal', enduserIds: [attackerId!, victimId!], userIds: [staffId],
|
|
180
180
|
} as any),
|
|
@@ -211,7 +211,7 @@ if (require.main === module) {
|
|
|
211
211
|
|
|
212
212
|
runTests()
|
|
213
213
|
.then(() => {
|
|
214
|
-
console.log("✅
|
|
214
|
+
console.log("✅ enduser cross-create test suite completed successfully")
|
|
215
215
|
process.exit(0)
|
|
216
216
|
})
|
|
217
217
|
.catch((error) => {
|
|
@@ -71,9 +71,7 @@ const restrictedFormResponseUpdates = (staffId: string, otherEnduserId: string):
|
|
|
71
71
|
})
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Regression test
|
|
75
|
-
* (security-audit/findings/F-0106-enduser-self-update-admin-only-fields.md,
|
|
76
|
-
* security-audit/findings/F-0110-form-responses-enduser-update-admin-only-fields.md).
|
|
74
|
+
* Regression test: enduser self-updates must not write staff-only fields on `endusers` or `form_responses`.
|
|
77
75
|
*
|
|
78
76
|
* Endusers could PATCH admin-only / access-bearing / attribution-bearing fields on
|
|
79
77
|
* their own endusers record (assignedTo, tags, references, ...) and their own
|
|
@@ -88,7 +86,7 @@ const restrictedFormResponseUpdates = (staffId: string, otherEnduserId: string):
|
|
|
88
86
|
* - staff sessions can still update the restricted fields
|
|
89
87
|
*/
|
|
90
88
|
export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
|
|
91
|
-
log_header("
|
|
89
|
+
log_header("enduser write restrictions (enduserUpdatesDisabled)")
|
|
92
90
|
|
|
93
91
|
let enduserId: string | undefined
|
|
94
92
|
let otherEnduserId: string | undefined
|
|
@@ -111,7 +109,7 @@ export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session,
|
|
|
111
109
|
const enduserSDK = new EnduserSession({ host, businessId })
|
|
112
110
|
await enduserSDK.authenticate(enduserEmail, ENDUSER_PASSWORD)
|
|
113
111
|
|
|
114
|
-
const form = await sdk.api.forms.createOne({ title: '
|
|
112
|
+
const form = await sdk.api.forms.createOne({ title: 'Write Restriction Test Form' })
|
|
115
113
|
formId = form.id
|
|
116
114
|
const { response: formResponse } = await sdk.api.form_responses.prepare_form_response({
|
|
117
115
|
formId: form.id,
|
|
@@ -119,34 +117,34 @@ export const enduser_write_restrictions_tests = async ({ sdk } : { sdk: Session,
|
|
|
119
117
|
})
|
|
120
118
|
formResponseId = formResponse.id
|
|
121
119
|
|
|
122
|
-
// ----
|
|
120
|
+
// ---- enduser self-update of restricted endusers fields must 400 ----
|
|
123
121
|
for (const [field, value] of Object.entries(restrictedEnduserUpdates(sdk.userInfo.id, enduser.id))) {
|
|
124
122
|
await async_test(
|
|
125
|
-
`
|
|
123
|
+
`enduser cannot self-update endusers.${field}`,
|
|
126
124
|
() => enduserSDK.api.endusers.updateOne(enduser.id, { [field]: value } as any),
|
|
127
125
|
{ shouldError: true, onError: e => e.message === `${field} cannot be updated by endusers` },
|
|
128
126
|
)
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
//
|
|
129
|
+
// Variant A persistence check: the rejected assignedTo write must not
|
|
132
130
|
// have granted the staff read-filter match.
|
|
133
131
|
await async_test(
|
|
134
|
-
'
|
|
132
|
+
'rejected assignedTo write did not persist',
|
|
135
133
|
() => sdk.api.endusers.getOne(enduser.id),
|
|
136
134
|
{ onResult: e => !e.assignedTo?.length && !e.tags?.length && e.externalId === undefined },
|
|
137
135
|
)
|
|
138
136
|
|
|
139
|
-
// ----
|
|
137
|
+
// ---- enduser self-update of restricted form_responses fields must 400 ----
|
|
140
138
|
for (const [field, value] of Object.entries(restrictedFormResponseUpdates(sdk.userInfo.id, otherEnduser.id))) {
|
|
141
139
|
await async_test(
|
|
142
|
-
`
|
|
140
|
+
`enduser cannot self-update form_responses.${field}`,
|
|
143
141
|
() => enduserSDK.api.form_responses.updateOne(formResponse.id, { [field]: value } as any),
|
|
144
142
|
{ shouldError: true, onError: e => e.message === `${field} cannot be updated by endusers` },
|
|
145
143
|
)
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
await async_test(
|
|
149
|
-
'
|
|
147
|
+
'rejected writes did not persist (markedAsSubmitted, procedureCodes, submittedBy, enduserId)',
|
|
150
148
|
() => sdk.api.form_responses.getOne(formResponse.id),
|
|
151
149
|
{ onResult: fr => (
|
|
152
150
|
!fr.markedAsSubmitted && !fr.procedureCodes?.length && fr.submittedBy === undefined
|
|
@@ -238,11 +236,11 @@ if (require.main === module) {
|
|
|
238
236
|
|
|
239
237
|
runTests()
|
|
240
238
|
.then(() => {
|
|
241
|
-
console.log("✅
|
|
239
|
+
console.log("✅ enduser write-restriction test suite completed successfully")
|
|
242
240
|
process.exit(0)
|
|
243
241
|
})
|
|
244
242
|
.catch((error) => {
|
|
245
|
-
console.error("❌
|
|
243
|
+
console.error("❌ enduser write-restriction test suite failed:", error)
|
|
246
244
|
process.exit(1)
|
|
247
245
|
})
|
|
248
246
|
}
|