@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.
Files changed (352) hide show
  1. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js +1 -1
  2. package/lib/cjs/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
  3. package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
  4. package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
  5. package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js +388 -0
  6. package/lib/cjs/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
  7. package/lib/cjs/tests/api_tests/integrations_redacted.test.js +3 -3
  8. package/lib/cjs/tests/api_tests/integrations_redacted.test.js.map +1 -1
  9. package/lib/cjs/tests/api_tests/organization_signup.test.d.ts +20 -0
  10. package/lib/cjs/tests/api_tests/organization_signup.test.d.ts.map +1 -0
  11. package/lib/cjs/tests/api_tests/organization_signup.test.js +272 -0
  12. package/lib/cjs/tests/api_tests/organization_signup.test.js.map +1 -0
  13. package/lib/cjs/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
  14. package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js +103 -162
  15. package/lib/cjs/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
  16. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
  17. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
  18. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +336 -0
  19. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
  20. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  21. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  22. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +354 -0
  23. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  24. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
  25. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
  26. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +389 -0
  27. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
  28. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
  29. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
  30. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +324 -0
  31. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
  32. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
  33. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  34. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +282 -0
  35. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
  36. package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
  37. package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
  38. package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +249 -0
  39. package/lib/cjs/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
  40. package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
  41. package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  42. package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +281 -0
  43. package/lib/cjs/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
  44. package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
  45. package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
  46. package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js +390 -0
  47. package/lib/cjs/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
  48. package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
  49. package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
  50. package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js +1003 -0
  51. package/lib/cjs/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
  52. package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
  53. package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
  54. package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js +323 -0
  55. package/lib/cjs/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
  56. package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
  57. package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
  58. package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js +335 -0
  59. package/lib/cjs/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
  60. package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
  61. package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
  62. package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +237 -0
  63. package/lib/cjs/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
  64. package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
  65. package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
  66. package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js +349 -0
  67. package/lib/cjs/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
  68. package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
  69. package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
  70. package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +314 -0
  71. package/lib/cjs/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
  72. package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
  73. package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
  74. package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js +362 -0
  75. package/lib/cjs/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
  76. package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
  77. package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
  78. package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js +366 -0
  79. package/lib/cjs/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
  80. package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
  81. package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
  82. package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js +248 -0
  83. package/lib/cjs/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
  84. package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
  85. package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
  86. package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js +138 -0
  87. package/lib/cjs/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
  88. package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
  89. package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
  90. package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +201 -0
  91. package/lib/cjs/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
  92. package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
  93. package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
  94. package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js +278 -0
  95. package/lib/cjs/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
  96. package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
  97. package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
  98. package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js +155 -0
  99. package/lib/cjs/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
  100. package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
  101. package/lib/cjs/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
  102. package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js +88 -0
  103. package/lib/cjs/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
  104. package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
  105. package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
  106. package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +230 -0
  107. package/lib/cjs/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
  108. package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
  109. package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
  110. package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +242 -0
  111. package/lib/cjs/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
  112. package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
  113. package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
  114. package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js +148 -0
  115. package/lib/cjs/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
  116. package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
  117. package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
  118. package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js +388 -0
  119. package/lib/cjs/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
  120. package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
  121. package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
  122. package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js +222 -0
  123. package/lib/cjs/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
  124. package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  125. package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  126. package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +354 -0
  127. package/lib/cjs/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  128. package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
  129. package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
  130. package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js +442 -0
  131. package/lib/cjs/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
  132. package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
  133. package/lib/cjs/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
  134. package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js +156 -0
  135. package/lib/cjs/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
  136. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
  137. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
  138. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js +329 -0
  139. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
  140. package/lib/cjs/tests/api_tests/webhook_error_handling.test.js +2 -2
  141. package/lib/cjs/tests/api_tests/webhook_error_handling.test.js.map +1 -1
  142. package/lib/cjs/tests/setup_isolated.d.ts +68 -0
  143. package/lib/cjs/tests/setup_isolated.d.ts.map +1 -0
  144. package/lib/cjs/tests/setup_isolated.js +232 -0
  145. package/lib/cjs/tests/setup_isolated.js.map +1 -0
  146. package/lib/cjs/tests/tests.d.ts.map +1 -1
  147. package/lib/cjs/tests/tests.js +287 -227
  148. package/lib/cjs/tests/tests.js.map +1 -1
  149. package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
  150. package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
  151. package/lib/cjs/tests/unit_tests/do_not_send_address.test.js +89 -0
  152. package/lib/cjs/tests/unit_tests/do_not_send_address.test.js.map +1 -0
  153. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
  154. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
  155. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +140 -0
  156. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
  157. package/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -0
  158. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js +1 -1
  159. package/lib/esm/tests/api_tests/auto_merge_form_submission.test.js.map +1 -1
  160. package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts +5 -0
  161. package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.d.ts.map +1 -0
  162. package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js +383 -0
  163. package/lib/esm/tests/api_tests/enduser_observations_auto_review.test.js.map +1 -0
  164. package/lib/esm/tests/api_tests/integrations_redacted.test.js +3 -3
  165. package/lib/esm/tests/api_tests/integrations_redacted.test.js.map +1 -1
  166. package/lib/esm/tests/api_tests/organization_signup.test.d.ts +20 -0
  167. package/lib/esm/tests/api_tests/organization_signup.test.d.ts.map +1 -0
  168. package/lib/esm/tests/api_tests/organization_signup.test.js +264 -0
  169. package/lib/esm/tests/api_tests/organization_signup.test.js.map +1 -0
  170. package/lib/esm/tests/api_tests/purchase_made_trigger.test.d.ts.map +1 -1
  171. package/lib/esm/tests/api_tests/purchase_made_trigger.test.js +104 -163
  172. package/lib/esm/tests/api_tests/purchase_made_trigger.test.js.map +1 -1
  173. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
  174. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
  175. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +332 -0
  176. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
  177. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  178. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  179. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +350 -0
  180. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  181. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
  182. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
  183. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +382 -0
  184. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
  185. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
  186. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
  187. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +317 -0
  188. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
  189. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
  190. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  191. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +277 -0
  192. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
  193. package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts +33 -0
  194. package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.d.ts.map +1 -0
  195. package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js +244 -0
  196. package/lib/esm/tests/api_tests/security/F-0200-form-logic-js-execution.test.js.map +1 -0
  197. package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts +42 -0
  198. package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  199. package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js +276 -0
  200. package/lib/esm/tests/api_tests/security/add-to-journey-foreign-enduserid.test.js.map +1 -0
  201. package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts +38 -0
  202. package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.d.ts.map +1 -0
  203. package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js +386 -0
  204. package/lib/esm/tests/api_tests/security/ai-conversations-rbac.test.js.map +1 -0
  205. package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts +6 -0
  206. package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.d.ts.map +1 -0
  207. package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js +996 -0
  208. package/lib/esm/tests/api_tests/security/allowed-paths-confinement.test.js.map +1 -0
  209. package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts +42 -0
  210. package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.d.ts.map +1 -0
  211. package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js +316 -0
  212. package/lib/esm/tests/api_tests/security/automated-actions-process-gate.test.js.map +1 -0
  213. package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts +29 -0
  214. package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.d.ts.map +1 -0
  215. package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js +331 -0
  216. package/lib/esm/tests/api_tests/security/booking-info-idor-token-mint.test.js.map +1 -0
  217. package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts +32 -0
  218. package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.d.ts.map +1 -0
  219. package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js +233 -0
  220. package/lib/esm/tests/api_tests/security/cascade-role-rename-cross-tenant.test.js.map +1 -0
  221. package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts +28 -0
  222. package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.d.ts.map +1 -0
  223. package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js +345 -0
  224. package/lib/esm/tests/api_tests/security/data-sync-redaction-bypass.test.js.map +1 -0
  225. package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts +30 -0
  226. package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.d.ts.map +1 -0
  227. package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js +310 -0
  228. package/lib/esm/tests/api_tests/security/develop-health-benefit-verification-rbac.test.js.map +1 -0
  229. package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts +21 -0
  230. package/lib/esm/tests/api_tests/security/enduser-cross-create.test.d.ts.map +1 -0
  231. package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js +358 -0
  232. package/lib/esm/tests/api_tests/security/enduser-cross-create.test.js.map +1 -0
  233. package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts +21 -0
  234. package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.d.ts.map +1 -0
  235. package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js +362 -0
  236. package/lib/esm/tests/api_tests/security/enduser-write-restrictions.test.js.map +1 -0
  237. package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts +32 -0
  238. package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.d.ts.map +1 -0
  239. package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js +243 -0
  240. package/lib/esm/tests/api_tests/security/form-logic-js-execution.test.js.map +1 -0
  241. package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts +19 -0
  242. package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.d.ts.map +1 -0
  243. package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js +134 -0
  244. package/lib/esm/tests/api_tests/security/globalunique-conflict-redaction.test.js.map +1 -0
  245. package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts +24 -0
  246. package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.d.ts.map +1 -0
  247. package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js +194 -0
  248. package/lib/esm/tests/api_tests/security/handle-incoming-communication-cross-tenant.test.js.map +1 -0
  249. package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts +29 -0
  250. package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.d.ts.map +1 -0
  251. package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js +271 -0
  252. package/lib/esm/tests/api_tests/security/invite-user-enumeration.test.js.map +1 -0
  253. package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts +17 -0
  254. package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.d.ts.map +1 -0
  255. package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js +151 -0
  256. package/lib/esm/tests/api_tests/security/load-inbox-redaction.test.js.map +1 -0
  257. package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts +2 -0
  258. package/lib/esm/tests/api_tests/security/prototype-pollution.test.d.ts.map +1 -0
  259. package/lib/esm/tests/api_tests/security/prototype-pollution.test.js +84 -0
  260. package/lib/esm/tests/api_tests/security/prototype-pollution.test.js.map +1 -0
  261. package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts +34 -0
  262. package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.d.ts.map +1 -0
  263. package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js +223 -0
  264. package/lib/esm/tests/api_tests/security/proxy-image-unauth-ssrf.test.js.map +1 -0
  265. package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts +2 -0
  266. package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.d.ts.map +1 -0
  267. package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js +238 -0
  268. package/lib/esm/tests/api_tests/security/sanitize-user-html-with-iframes.test.js.map +1 -0
  269. package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts +2 -0
  270. package/lib/esm/tests/api_tests/security/sanitize-user-html.test.d.ts.map +1 -0
  271. package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js +144 -0
  272. package/lib/esm/tests/api_tests/security/sanitize-user-html.test.js.map +1 -0
  273. package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts +45 -0
  274. package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.d.ts.map +1 -0
  275. package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js +381 -0
  276. package/lib/esm/tests/api_tests/security/schema-adminonly-enforcement.test.js.map +1 -0
  277. package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts +38 -0
  278. package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.d.ts.map +1 -0
  279. package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js +218 -0
  280. package/lib/esm/tests/api_tests/security/self-admin-role-assignment.test.js.map +1 -0
  281. package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  282. package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  283. package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js +350 -0
  284. package/lib/esm/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  285. package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts +28 -0
  286. package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.d.ts.map +1 -0
  287. package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js +435 -0
  288. package/lib/esm/tests/api_tests/security/webhook-outbound-ssrf.test.js.map +1 -0
  289. package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts +19 -0
  290. package/lib/esm/tests/api_tests/security/webhook-timeout.test.d.ts.map +1 -0
  291. package/lib/esm/tests/api_tests/security/webhook-timeout.test.js +149 -0
  292. package/lib/esm/tests/api_tests/security/webhook-timeout.test.js.map +1 -0
  293. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
  294. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
  295. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js +324 -0
  296. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
  297. package/lib/esm/tests/api_tests/webhook_error_handling.test.js +2 -2
  298. package/lib/esm/tests/api_tests/webhook_error_handling.test.js.map +1 -1
  299. package/lib/esm/tests/setup_isolated.d.ts +68 -0
  300. package/lib/esm/tests/setup_isolated.d.ts.map +1 -0
  301. package/lib/esm/tests/setup_isolated.js +221 -0
  302. package/lib/esm/tests/setup_isolated.js.map +1 -0
  303. package/lib/esm/tests/tests.d.ts.map +1 -1
  304. package/lib/esm/tests/tests.js +287 -227
  305. package/lib/esm/tests/tests.js.map +1 -1
  306. package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
  307. package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
  308. package/lib/esm/tests/unit_tests/do_not_send_address.test.js +85 -0
  309. package/lib/esm/tests/unit_tests/do_not_send_address.test.js.map +1 -0
  310. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
  311. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
  312. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +113 -0
  313. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
  314. package/lib/tsconfig.tsbuildinfo +1 -1
  315. package/package.json +10 -10
  316. package/src/tests/api_tests/auto_merge_form_submission.test.ts +1 -1
  317. package/src/tests/api_tests/enduser_observations_auto_review.test.ts +358 -0
  318. package/src/tests/api_tests/integrations_redacted.test.ts +1 -1
  319. package/src/tests/api_tests/organization_signup.test.ts +240 -0
  320. package/src/tests/api_tests/purchase_made_trigger.test.ts +29 -41
  321. package/src/tests/api_tests/security/add-to-journey-foreign-enduserid.test.ts +207 -0
  322. package/src/tests/api_tests/security/{F-0005-ai-conversations-rbac.test.ts → ai-conversations-rbac.test.ts} +14 -14
  323. package/src/tests/api_tests/security/{F-0166-allowed-paths-wildcard-bypass.test.ts → allowed-paths-confinement.test.ts} +11 -11
  324. package/src/tests/api_tests/security/automated-actions-process-gate.test.ts +237 -0
  325. package/src/tests/api_tests/security/booking-info-idor-token-mint.test.ts +224 -0
  326. package/src/tests/api_tests/security/{F-0053-cascade-role-rename-cross-tenant.test.ts → cascade-role-rename-cross-tenant.test.ts} +10 -10
  327. package/src/tests/api_tests/security/{F-0001-data-sync-redaction-bypass.test.ts → data-sync-redaction-bypass.test.ts} +9 -9
  328. package/src/tests/api_tests/security/{F-0006-develop-health-benefit-verification-rbac.test.ts → develop-health-benefit-verification-rbac.test.ts} +7 -8
  329. package/src/tests/api_tests/security/{F-0116-F-0119-enduser-cross-create.test.ts → enduser-cross-create.test.ts} +25 -25
  330. package/src/tests/api_tests/security/{F-0106-F-0110-enduser-write-restrictions.test.ts → enduser-write-restrictions.test.ts} +12 -14
  331. package/src/tests/api_tests/security/form-logic-js-execution.test.ts +183 -0
  332. package/src/tests/api_tests/security/{F-0145-globalunique-leak.test.ts → globalunique-conflict-redaction.test.ts} +5 -6
  333. package/src/tests/api_tests/security/{F-0008-handle-incoming-communication-cross-tenant.test.ts → handle-incoming-communication-cross-tenant.test.ts} +8 -8
  334. package/src/tests/api_tests/security/{F-0007-invite-user-enumeration.test.ts → invite-user-enumeration.test.ts} +8 -8
  335. package/src/tests/api_tests/security/{F-0151-load-inbox-redaction.test.ts → load-inbox-redaction.test.ts} +5 -6
  336. package/src/tests/api_tests/security/{F-0016-prototype-pollution.test.ts → prototype-pollution.test.ts} +4 -4
  337. package/src/tests/api_tests/security/{F-0025-proxy-image-unauth-ssrf.test.ts → proxy-image-unauth-ssrf.test.ts} +11 -12
  338. package/src/tests/api_tests/security/{F-0013-sanitize-user-html-with-iframes.test.ts → sanitize-user-html-with-iframes.test.ts} +5 -5
  339. package/src/tests/api_tests/security/{F-0013-sanitize-user-html.test.ts → sanitize-user-html.test.ts} +4 -4
  340. package/src/tests/api_tests/security/schema-adminonly-enforcement.test.ts +287 -0
  341. package/src/tests/api_tests/security/{F-0076-self-admin-role-assignment.test.ts → self-admin-role-assignment.test.ts} +13 -13
  342. package/src/tests/api_tests/security/startlinktoken-enduser-staff-escalation.test.ts +162 -0
  343. package/src/tests/api_tests/security/{F-0015-webhook-outbound-ssrf.test.ts → webhook-outbound-ssrf.test.ts} +13 -14
  344. package/src/tests/api_tests/security/{F-0155-webhook-timeout.test.ts → webhook-timeout.test.ts} +6 -7
  345. package/src/tests/api_tests/tickets_bulk_assign_from_queue.test.ts +279 -0
  346. package/src/tests/api_tests/webhook_error_handling.test.ts +1 -1
  347. package/src/tests/setup_isolated.ts +170 -0
  348. package/src/tests/tests.ts +60 -18
  349. package/src/tests/unit_tests/do_not_send_address.test.ts +60 -0
  350. package/src/tests/unit_tests/openapi_spec_freshness.test.ts +88 -0
  351. package/test_generated.pdf +0 -0
  352. package/src/tests/api_tests/security/readonly-enduser-preview.test.ts +0 -301
@@ -11,10 +11,10 @@ import { setup_tests } from "../../setup"
11
11
  const host = process.env.API_URL || 'http://localhost:8080' as const
12
12
 
13
13
  /**
14
- * Self-role privilege-escalation guard (relates to security-audit finding F-0076, which was
14
+ * Self-role privilege-escalation guard (relates to a prior internal review, which was
15
15
  * investigated and closed as a FALSE POSITIVE — see that file for the full code trace).
16
16
  *
17
- * F-0076 hypothesized that a non-admin staff user could `PATCH /v1/users/{their-own-id}` with
17
+ * An earlier review hypothesized that a non-admin staff user could `PATCH /v1/users/{their-own-id}` with
18
18
  * `{ roles: ['Admin'] }` and self-promote to Admin, because the FIRST `users` relationship
19
19
  * constraint ("Only admin users can set the admin role",
20
20
  * [schema.ts:3446](packages/public/schema/src/schema.ts#L3446)) has a self-exception
@@ -43,7 +43,7 @@ const host = process.env.API_URL || 'http://localhost:8080' as const
43
43
  * path role-writable by non-admins would flip the step-3/step-4 assertions to red.
44
44
  */
45
45
  export const self_admin_role_assignment_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
46
- log_header("F-0076: self-admin role assignment privilege-escalation regression")
46
+ log_header("self-admin role assignment privilege-escalation regression")
47
47
 
48
48
  const stamp = Date.now()
49
49
  const NON_ADMIN_ROLE = 'Provider'
@@ -84,7 +84,7 @@ export const self_admin_role_assignment_tests = async ({ sdk } : { sdk: Session,
84
84
  assert(
85
85
  JSON.stringify(attackerBefore.roles) === JSON.stringify([NON_ADMIN_ROLE]),
86
86
  `Setup failed: expected attacker to hold [${NON_ADMIN_ROLE}], got ${JSON.stringify(attackerBefore.roles)}`,
87
- 'F-0076 setup: attacker holds a non-admin role',
87
+ 'setup: attacker holds a non-admin role',
88
88
  )
89
89
 
90
90
  // 2. Authenticate AS the attacker (no password needed — admin mints an auth token).
@@ -96,25 +96,25 @@ export const self_admin_role_assignment_tests = async ({ sdk } : { sdk: Session,
96
96
  assert(
97
97
  sdkAttacker.userInfo.id === attackerId && !(sdkAttacker.userInfo.roles ?? []).includes('Admin'),
98
98
  `Setup failed: attacker session is not the expected non-admin user`,
99
- 'F-0076 setup: authenticated as the non-admin attacker',
99
+ 'setup: authenticated as the non-admin attacker',
100
100
  )
101
101
 
102
102
  // 3. SECURITY ASSERTIONS — every self-role mutation by the non-admin must be blocked.
103
103
  await expect_blocked(
104
104
  () => sdkAttacker.api.users.updateOne(attackerId!, { roles: ['Admin'] }, { replaceObjectFields: true }),
105
- 'F-0076: non-admin self-update to [Admin] is blocked',
105
+ 'non-admin self-update to [Admin] is blocked',
106
106
  )
107
107
  await expect_blocked(
108
108
  () => sdkAttacker.api.users.updateOne(attackerId!, { roles: [NON_ADMIN_ROLE, 'Admin'] }, { replaceObjectFields: true }),
109
- 'F-0076: non-admin self-update to [Provider, Admin] is blocked',
109
+ 'non-admin self-update to [Provider, Admin] is blocked',
110
110
  )
111
111
  await expect_blocked(
112
112
  () => sdkAttacker.api.users.updateOne(attackerId!, { roles: [`Arbitrary_${stamp}`] }, { replaceObjectFields: true }),
113
- 'F-0076: non-admin self-update to an arbitrary role is blocked',
113
+ 'non-admin self-update to an arbitrary role is blocked',
114
114
  )
115
115
  await expect_blocked(
116
116
  () => sdkAttacker.api.users.updateOne(attackerId!, { roles: [] }, { replaceObjectFields: true }),
117
- 'F-0076: non-admin self-update to [] (would grant defaults) is blocked',
117
+ 'non-admin self-update to [] (would grant defaults) is blocked',
118
118
  )
119
119
 
120
120
  // 4. STATE ASSERTION — nothing slipped through; roles are still the original non-admin role.
@@ -123,7 +123,7 @@ export const self_admin_role_assignment_tests = async ({ sdk } : { sdk: Session,
123
123
  JSON.stringify(attackerAfter.roles) === JSON.stringify([NON_ADMIN_ROLE]),
124
124
  `ESCALATION LEAK: attacker roles changed to ${JSON.stringify(attackerAfter.roles)} `
125
125
  + `after self-update attempts. Expected [${NON_ADMIN_ROLE}].`,
126
- 'F-0076: attacker roles unchanged after all self-escalation attempts',
126
+ 'attacker roles unchanged after all self-escalation attempts',
127
127
  )
128
128
 
129
129
  // 5. POSITIVE CONTROL — an Admin CAN update the user's roles (mechanism is not over-restricted).
@@ -132,7 +132,7 @@ export const self_admin_role_assignment_tests = async ({ sdk } : { sdk: Session,
132
132
  assert(
133
133
  JSON.stringify(afterAdminUpdate.roles) === JSON.stringify([NON_ADMIN_ROLE]),
134
134
  `Admin role update failed: roles are ${JSON.stringify(afterAdminUpdate.roles)}, expected [${NON_ADMIN_ROLE}]`,
135
- 'F-0076: admin can manage user roles (positive control)',
135
+ 'admin can manage user roles (positive control)',
136
136
  )
137
137
  } finally {
138
138
  // Cleanup: delete the throwaway attacker. Never touches pre-existing users.
@@ -155,11 +155,11 @@ if (require.main === module) {
155
155
 
156
156
  runTests()
157
157
  .then(() => {
158
- console.log("✅ F-0076 self-admin role assignment test suite completed successfully")
158
+ console.log("✅ self-admin role assignment test suite completed successfully")
159
159
  process.exit(0)
160
160
  })
161
161
  .catch((error) => {
162
- console.error("❌ F-0076 self-admin role assignment test suite failed:", error)
162
+ console.error("❌ self-admin role assignment test suite failed:", error)
163
163
  process.exit(1)
164
164
  })
165
165
  }
@@ -0,0 +1,162 @@
1
+ require('source-map-support').install();
2
+
3
+ import { Session, EnduserSession } from "../../../sdk"
4
+ import { assert, log_header } from "@tellescope/testing"
5
+ import { setup_tests, authenticate_enduser_via_token } from "../../setup"
6
+ import { PROVIDER_PERMISSIONS } from "@tellescope/constants"
7
+
8
+ const host = process.env.API_URL || 'http://localhost:8080' as const
9
+
10
+ /**
11
+ * Regression test — `calendar_events.startLinkToken` privilege escalation.
12
+ *
13
+ * startLinkToken is a DOCUMENTED feature ("Video Call Start Links"): a tenant's staff / API-key
14
+ * integration PATCHes a CalendarEvent to set a random token, then sends the host user the
15
+ * `/video/startlink?token=...` link, which `session_for_start_link` exchanges for a scope-limited
16
+ * User (staff) authToken for the first `type:'user'` attendee, MFA bypassed. Nothing in the codebase
17
+ * reads the token value back (the redeem matches server-side; the integration holds its own copy), so
18
+ * the field is write-only-by-design.
19
+ *
20
+ * TWO escalation vectors let a patient (or a low-privilege staff user) obtain the host's session:
21
+ * WRITE — `enduserActions.update` + no `enduserUpdatesDisabled` let an enduser attendee PATCH
22
+ * `startLinkToken` to a value they choose, then redeem it.
23
+ * READ — no `redactions` let an enduser attendee (or a non-admin staff user with calendar read)
24
+ * read a LEGITIMATELY staff-set token and redeem it, with no write.
25
+ *
26
+ * Complete fix = TWO flags on schema.ts `startLinkToken`:
27
+ * enduserUpdatesDisabled: true (closes WRITE; preserves the staff/API-key write the feature needs)
28
+ * redactions: ['all'] (closes READ for endusers AND non-admin users; safe — nothing reads
29
+ * the value back). NOT `readonly` (would break the staff write — A2).
30
+ *
31
+ * Checks (collected, then asserted, so a RED run shows every failing vector):
32
+ * A1 enduser attendee PATCH of startLinkToken is REJECTED (WRITE gate)
33
+ * A2 a staff-set token still redeems for the host's session (feature preserved)
34
+ * A3 an enduser-set token (if the write lands) does NOT redeem (defence-in-depth)
35
+ * A4 an enduser attendee does NOT receive startLinkToken on read (READ gate, endusers)
36
+ * A5 a non-admin staff user does NOT receive startLinkToken on read (READ gate, users)
37
+ *
38
+ * No vendor, no Bedrock; the "host" is a throwaway user. Cleans up every created record.
39
+ */
40
+ const RAND = () => Math.random().toString(36).slice(2, 10)
41
+
42
+ export const startlinktoken_escalation_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
43
+ log_header("startLinkToken enduser-writable / readable → staff session escalation")
44
+
45
+ const businessId = sdk.userInfo.businessId
46
+ const userIds: string[] = []
47
+ const enduserIds: string[] = []
48
+ const eventIds: string[] = []
49
+ const roleIds: string[] = []
50
+
51
+ const checks: { label: string, pass: boolean, detail: string }[] = []
52
+ const record = (label: string, pass: boolean, detail: string) => checks.push({ label, pass, detail })
53
+
54
+ try {
55
+ // Throwaway host staff user — the account an attacker would escalate INTO.
56
+ const host_user = await sdk.api.users.createOne({
57
+ email: `f0185-host-${RAND()}@tellescope.example`, fname: 'F0185', lname: 'Host',
58
+ verifiedEmail: true, notificationEmailsDisabled: true,
59
+ } as any)
60
+ userIds.push(host_user.id)
61
+
62
+ // The attacking patient, an attendee of the host's appointment.
63
+ const patient = await sdk.api.endusers.createOne({
64
+ email: `f0185-patient-${RAND()}@tellescope.example`, fname: 'F0185', lname: 'Patient',
65
+ })
66
+ enduserIds.push(patient.id)
67
+
68
+ const event = await sdk.api.calendar_events.createOne({
69
+ title: 'appointment', durationInMinutes: 30, startTimeInMS: Date.now() + 3600_000,
70
+ attendees: [{ type: 'user', id: host_user.id }, { type: 'enduser', id: patient.id }],
71
+ } as any)
72
+ eventIds.push(event.id)
73
+
74
+ const patientSDK = new EnduserSession({ host, businessId })
75
+ await authenticate_enduser_via_token(sdk, patientSDK, { id: patient.id })
76
+
77
+ // ---- A1: WRITE gate — enduser attendee cannot PATCH startLinkToken ----
78
+ const attackerToken = `f0185-attacker-${RAND()}${RAND()}`
79
+ let wrote = false, writeErr = ''
80
+ try {
81
+ await patientSDK.api.calendar_events.updateOne(event.id, { startLinkToken: attackerToken } as any)
82
+ wrote = true
83
+ } catch (err: any) { writeErr = err?.message ?? String(err) }
84
+ record('A1: enduser cannot write startLinkToken', !wrote,
85
+ wrote ? 'PATCH ACCEPTED — patient set a staff start-link token' : `rejected (${writeErr})`)
86
+
87
+ // ---- A3: defence-in-depth — an enduser-set token must not redeem ----
88
+ // Only lands when A1 failed (pre-fix). Read back as admin to see if the value stuck.
89
+ const adminView = await sdk.api.calendar_events.getOne(event.id)
90
+ if ((adminView as any).startLinkToken === attackerToken) {
91
+ let redeemed: any = null
92
+ try { redeemed = await new Session({ host }).api.calendar_events.session_for_start_link({ token: attackerToken }) } catch {}
93
+ record('A3: enduser-set token does not mint a staff session', !redeemed?.authToken,
94
+ redeemed?.authToken ? `minted a STAFF authToken for host ${host_user.id}` : 'not redeemable')
95
+ } else {
96
+ record('A3: enduser-set token does not mint a staff session', true, '(n/a — write blocked, value never landed)')
97
+ }
98
+
99
+ // ---- A2: feature pin — a STAFF-set token still redeems (write + redeem must both survive the fix) ----
100
+ const staffToken = `f0185-staff-${RAND()}${RAND()}`
101
+ let staffWriteErr = ''
102
+ try { await sdk.api.calendar_events.updateOne(event.id, { startLinkToken: staffToken } as any) }
103
+ catch (e: any) { staffWriteErr = e?.message ?? String(e) }
104
+ let legit: any = null
105
+ try { legit = await new Session({ host }).api.calendar_events.session_for_start_link({ token: staffToken }) }
106
+ catch (e: any) { legit = { error: e?.message ?? String(e) } }
107
+ record('A2: staff-set start link still works', !!legit?.authToken && legit.eventId === event.id,
108
+ `staffWrite=${staffWriteErr ? 'REJECTED(' + staffWriteErr + ')' : 'ok'} authToken=${!!legit?.authToken} eventId=${legit?.eventId} ${legit?.error ? '(' + legit.error + ')' : ''}`)
109
+
110
+ // ---- A4: READ gate (endusers) — patient attendee must not receive the token ----
111
+ let enduserRead: any = null
112
+ try { enduserRead = await patientSDK.api.calendar_events.getOne(event.id) } catch {}
113
+ record('A4: startLinkToken redacted from enduser reads',
114
+ !enduserRead || (enduserRead as any).startLinkToken === undefined,
115
+ `enduser read startLinkToken=${(enduserRead as any)?.startLinkToken ?? '(absent)'} — could redeem a staff-set token`)
116
+
117
+ // ---- A5: READ gate (non-admin users) — low-priv staff must not receive the token ----
118
+ const rbap = await sdk.api.role_based_access_permissions.createOne({
119
+ role: `F0185NonAdmin-${RAND()}`,
120
+ // Non-admin (non-Admin-role) staff with tenant-wide calendar READ — enough to load the event,
121
+ // so the assertion isolates redaction (not access). Spread a valid full permissions shape.
122
+ permissions: { ...PROVIDER_PERMISSIONS, calendar_events: { ...(PROVIDER_PERMISSIONS as any).calendar_events, read: 'All', readMany: 'All' } },
123
+ } as any).catch((e: any) => { console.warn('A5 role create failed:', e?.message ?? e); return null })
124
+ if (rbap) {
125
+ roleIds.push(rbap.id)
126
+ const nonAdmin = await sdk.api.users.createOne({
127
+ email: `f0185-nonadmin-${RAND()}@tellescope.example`, fname: 'F0185', lname: 'NonAdmin',
128
+ verifiedEmail: true, notificationEmailsDisabled: true, roles: [rbap.role],
129
+ } as any)
130
+ userIds.push(nonAdmin.id)
131
+ const { authToken } = await sdk.api.users.generate_auth_token({ id: nonAdmin.id })
132
+ const nonAdminSDK = new Session({ host, authToken })
133
+ let staffRead: any = null
134
+ try { staffRead = await nonAdminSDK.api.calendar_events.getOne(event.id) } catch {}
135
+ record('A5: startLinkToken redacted from non-admin user reads',
136
+ !staffRead || (staffRead as any).startLinkToken === undefined,
137
+ `non-admin user read startLinkToken=${(staffRead as any)?.startLinkToken ?? '(absent)'} — staff→host escalation via read`)
138
+ } else {
139
+ record('A5: startLinkToken redacted from non-admin user reads', true, '(n/a — could not create a non-admin role in this env)')
140
+ }
141
+
142
+ // Report the full table before asserting (the harness exits on the first failed assert).
143
+ console.log('\n check summary:')
144
+ for (const c of checks) console.log(` ${c.pass ? 'PASS' : 'FAIL'} ${c.label} — ${c.detail}`)
145
+ console.log('')
146
+ for (const c of checks) assert(c.pass, `${c.label} — ${c.detail}`, c.label)
147
+ } finally {
148
+ for (const id of eventIds) { try { await sdk.api.calendar_events.deleteOne(id) } catch {} }
149
+ for (const id of enduserIds) { try { await sdk.api.endusers.deleteOne(id) } catch {} }
150
+ for (const id of userIds) { try { await sdk.api.users.deleteOne(id) } catch {} }
151
+ for (const id of roleIds) { try { await sdk.api.role_based_access_permissions.deleteOne(id) } catch {} }
152
+ }
153
+ }
154
+
155
+ if (require.main === module) {
156
+ const sdk = new Session({ host })
157
+ const sdkNonAdmin = new Session({ host })
158
+ setup_tests(sdk, sdkNonAdmin)
159
+ .then(() => startlinktoken_escalation_tests({ sdk, sdkNonAdmin }))
160
+ .then(() => { console.log("✅ startLinkToken escalation test suite completed successfully"); process.exit(0) })
161
+ .catch((error) => { console.error("❌ startLinkToken escalation test suite failed:", error); process.exit(1) })
162
+ }
@@ -51,7 +51,7 @@ const assert_local_api = () => {
51
51
  const hostname = new URL(host).hostname
52
52
  if (!LOCAL_HOSTNAMES.includes(hostname)) {
53
53
  throw new Error(
54
- `F-0015 SSRF tests must run against a local API (got ${host}). `
54
+ `SSRF tests must run against a local API (got ${host}). `
55
55
  + `127.0.0.1 would resolve to the API server rather than this machine, and this test configures a webhook.`
56
56
  )
57
57
  }
@@ -76,8 +76,7 @@ const wait_until = async (predicate: () => boolean, ms: number) => {
76
76
  }
77
77
 
78
78
  /**
79
- * Regression tests for F-0015
80
- * (security-audit/findings/F-0015-webhook-outbound-ssrf.md).
79
+ * Regression tests: outbound webhook delivery must refuse internal destinations.
81
80
  *
82
81
  * Outbound webhooks request customer-configured URLs that are validated only for SYNTAX
83
82
  * (urlValidator -> validator.isURL, which happily accepts http://10.0.0.1/). Four call sites are
@@ -99,7 +98,7 @@ const wait_until = async (predicate: () => boolean, ms: number) => {
99
98
  * subscription. So each is paired with a positive control that proves the attempt really was made.
100
99
  */
101
100
  export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
102
- log_header("F-0015: outbound webhook SSRF")
101
+ log_header("outbound webhook SSRF")
103
102
  assert_local_api()
104
103
 
105
104
  const SENTINEL = `f0015-sentinel-${Date.now()}-${Math.random().toString(36).slice(2)}`
@@ -110,9 +109,9 @@ export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkN
110
109
  // guard refuses in every environment, and loopback does not qualify (see the note above).
111
110
  assert(
112
111
  false,
113
- 'F-0015 SKIPPED: no non-loopback RFC1918 interface on this host, so the SSRF sentinel cannot be '
112
+ 'SKIPPED: no non-loopback RFC1918 interface on this host, so the SSRF sentinel cannot be '
114
113
  + 'bound anywhere the guard refuses. Run on a host with a private network interface.',
115
- 'F-0015 outbound SSRF',
114
+ 'outbound SSRF',
116
115
  )
117
116
  return
118
117
  }
@@ -179,21 +178,21 @@ export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkN
179
178
  // webhook, every "sentinel not contacted" assertion below is meaningless.
180
179
  // ---------------------------------------------------------------------------------------------
181
180
  await async_test(
182
- 'F-0015: automation webhook to a permitted target still delivers (regression baseline)',
181
+ 'automation webhook to a permitted target still delivers (regression baseline)',
183
182
  () => send_automation_webhook_to(okURL),
184
183
  { onResult: (r: any) => r.okHits === 1 && r.sentinelHits === 0 },
185
184
  )
186
185
 
187
186
  // T3 — direct non-allowlisted private destination.
188
187
  await async_test(
189
- 'F-0015: automation webhook does not reach a private destination',
188
+ 'automation webhook does not reach a private destination',
190
189
  () => send_automation_webhook_to(sentinelURL),
191
190
  { onResult: (r: any) => r.sentinelHits === 0 },
192
191
  )
193
192
 
194
193
  // T4 — the redirect bypass. THE test that justifies a connect-time guard over a pre-flight check.
195
194
  await async_test(
196
- 'F-0015: automation webhook does not follow a redirect from a permitted host into a private one',
195
+ 'automation webhook does not follow a redirect from a permitted host into a private one',
197
196
  () => send_automation_webhook_to(redirectURL),
198
197
  {
199
198
  // redirectHits === 1 is the positive control: hop 1 was allowlisted and really was reached, so
@@ -212,7 +211,7 @@ export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkN
212
211
  templateEnduserId = templateEnduser.id
213
212
 
214
213
  await async_test(
215
- 'F-0015: automation webhook validates the URL after template interpolation, not before',
214
+ 'automation webhook validates the URL after template interpolation, not before',
216
215
  () => send_automation_webhook_to('http://{{enduser.ssrfTarget}}/ssrf-sentinel', templateEnduser.id),
217
216
  { onResult: (r: any) => r.sentinelHits === 0 },
218
217
  )
@@ -229,7 +228,7 @@ export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkN
229
228
  configuredWebhook = true
230
229
 
231
230
  await async_test(
232
- 'F-0015: configured webhook to a permitted target still delivers (positive control)',
231
+ 'configured webhook to a permitted target still delivers (positive control)',
233
232
  async () => {
234
233
  sentinelHits = 0; okHits = 0
235
234
  const e = await sdk.api.endusers.createOne({ email: `f0015-ok-${Date.now()}@example.com` })
@@ -244,7 +243,7 @@ export const webhook_outbound_ssrf_tests = async ({ sdk } : { sdk: Session, sdkN
244
243
  await sdk.api.webhooks.update({ url: sentinelURL })
245
244
 
246
245
  await async_test(
247
- 'F-0015: configured webhook does not deliver to a private destination',
246
+ 'configured webhook does not deliver to a private destination',
248
247
  async () => {
249
248
  sentinelHits = 0; okHits = 0
250
249
  const e = await sdk.api.endusers.createOne({ email: `f0015-blocked-${Date.now()}@example.com` })
@@ -282,11 +281,11 @@ if (require.main === module) {
282
281
 
283
282
  runTests()
284
283
  .then(() => {
285
- console.log("✅ F-0015 outbound webhook SSRF test suite completed successfully")
284
+ console.log("✅ outbound webhook SSRF test suite completed successfully")
286
285
  process.exit(0)
287
286
  })
288
287
  .catch((error) => {
289
- console.error("❌ F-0015 outbound webhook SSRF test suite failed:", error)
288
+ console.error("❌ outbound webhook SSRF test suite failed:", error)
290
289
  process.exit(1)
291
290
  })
292
291
  }
@@ -10,12 +10,11 @@ import { setup_tests } from "../../setup"
10
10
 
11
11
  const host = process.env.API_URL || 'http://localhost:8080' as const
12
12
 
13
- // The server-side axios timeout is 15s (F-0155 fix). We bound our own wait above that.
13
+ // The server-side axios timeout is 15s (the fix under test). We bound our own wait above that.
14
14
  const CLIENT_WAIT_MS = 20_000
15
15
 
16
16
  /**
17
- * Regression test for F-0155
18
- * (security-audit/findings/F-0155-outbound-webhook-no-timeout-slow-loris.md).
17
+ * Regression test: outbound webhook delivery must time out rather than hang.
19
18
  *
20
19
  * Outbound webhook delivery used axios.post(url, ...) with no `timeout` (axios default = infinite).
21
20
  * A tenant-controlled receiver that accepts the connection and never responds hangs the awaited
@@ -28,7 +27,7 @@ const CLIENT_WAIT_MS = 20_000
28
27
  * - red (unfixed): the call is still pending at 20s → client timer wins
29
28
  */
30
29
  export const webhook_timeout_tests = async ({ sdk } : { sdk: Session, sdkNonAdmin: Session }) => {
31
- log_header("F-0155: outbound webhook timeout")
30
+ log_header("outbound webhook timeout")
32
31
 
33
32
  let enduserId: string | undefined
34
33
  const slowServer = http.createServer(() => { /* accept connection, never respond */ })
@@ -42,7 +41,7 @@ export const webhook_timeout_tests = async ({ sdk } : { sdk: Session, sdkNonAdmi
42
41
  enduserId = enduser.id
43
42
 
44
43
  await async_test(
45
- 'F-0155: outbound webhook to a non-responding receiver times out server-side (does not hang)',
44
+ 'outbound webhook to a non-responding receiver times out server-side (does not hang)',
46
45
  async () => {
47
46
  const start = Date.now()
48
47
  const outcome = await Promise.race([
@@ -75,11 +74,11 @@ if (require.main === module) {
75
74
 
76
75
  runTests()
77
76
  .then(() => {
78
- console.log("✅ F-0155 webhook timeout test suite completed successfully")
77
+ console.log("✅ webhook timeout test suite completed successfully")
79
78
  process.exit(0)
80
79
  })
81
80
  .catch((error) => {
82
- console.error("❌ F-0155 webhook timeout test suite failed:", error)
81
+ console.error("❌ webhook timeout test suite failed:", error)
83
82
  process.exit(1)
84
83
  })
85
84
  }