@tellescope/sdk 1.256.13 → 1.256.14

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 (106) hide show
  1. package/lib/cjs/tests/api_tests/organization_signup.test.d.ts +20 -0
  2. package/lib/cjs/tests/api_tests/organization_signup.test.d.ts.map +1 -0
  3. package/lib/cjs/tests/api_tests/organization_signup.test.js +272 -0
  4. package/lib/cjs/tests/api_tests/organization_signup.test.js.map +1 -0
  5. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
  6. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
  7. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +336 -0
  8. package/lib/cjs/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
  9. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  10. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  11. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +354 -0
  12. package/lib/cjs/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  13. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
  14. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
  15. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +389 -0
  16. package/lib/cjs/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
  17. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
  18. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
  19. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +324 -0
  20. package/lib/cjs/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
  21. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
  22. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  23. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +282 -0
  24. package/lib/cjs/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
  25. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
  26. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
  27. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js +329 -0
  28. package/lib/cjs/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
  29. package/lib/cjs/tests/setup_isolated.d.ts +68 -0
  30. package/lib/cjs/tests/setup_isolated.d.ts.map +1 -0
  31. package/lib/cjs/tests/setup_isolated.js +232 -0
  32. package/lib/cjs/tests/setup_isolated.js.map +1 -0
  33. package/lib/cjs/tests/tests.d.ts.map +1 -1
  34. package/lib/cjs/tests/tests.js +257 -209
  35. package/lib/cjs/tests/tests.js.map +1 -1
  36. package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
  37. package/lib/cjs/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
  38. package/lib/cjs/tests/unit_tests/do_not_send_address.test.js +89 -0
  39. package/lib/cjs/tests/unit_tests/do_not_send_address.test.js.map +1 -0
  40. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
  41. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
  42. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js +140 -0
  43. package/lib/cjs/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
  44. package/lib/esm/enduser.d.ts +1 -0
  45. package/lib/esm/enduser.d.ts.map +1 -1
  46. package/lib/esm/sdk.d.ts +3 -2
  47. package/lib/esm/sdk.d.ts.map +1 -1
  48. package/lib/esm/session.d.ts +1 -0
  49. package/lib/esm/session.d.ts.map +1 -1
  50. package/lib/esm/tests/api_tests/organization_signup.test.d.ts +20 -0
  51. package/lib/esm/tests/api_tests/organization_signup.test.d.ts.map +1 -0
  52. package/lib/esm/tests/api_tests/organization_signup.test.js +264 -0
  53. package/lib/esm/tests/api_tests/organization_signup.test.js.map +1 -0
  54. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts +30 -0
  55. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.d.ts.map +1 -0
  56. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js +332 -0
  57. package/lib/esm/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.js.map +1 -0
  58. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts +6 -0
  59. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.d.ts.map +1 -0
  60. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js +350 -0
  61. package/lib/esm/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.js.map +1 -0
  62. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts +46 -0
  63. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.d.ts.map +1 -0
  64. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js +382 -0
  65. package/lib/esm/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.js.map +1 -0
  66. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts +43 -0
  67. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.d.ts.map +1 -0
  68. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js +317 -0
  69. package/lib/esm/tests/api_tests/security/F-0192-automated-actions-process-gate.test.js.map +1 -0
  70. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts +43 -0
  71. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.d.ts.map +1 -0
  72. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js +277 -0
  73. package/lib/esm/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.js.map +1 -0
  74. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts +5 -0
  75. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.d.ts.map +1 -0
  76. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js +324 -0
  77. package/lib/esm/tests/api_tests/tickets_bulk_assign_from_queue.test.js.map +1 -0
  78. package/lib/esm/tests/setup_isolated.d.ts +68 -0
  79. package/lib/esm/tests/setup_isolated.d.ts.map +1 -0
  80. package/lib/esm/tests/setup_isolated.js +221 -0
  81. package/lib/esm/tests/setup_isolated.js.map +1 -0
  82. package/lib/esm/tests/tests.d.ts.map +1 -1
  83. package/lib/esm/tests/tests.js +257 -209
  84. package/lib/esm/tests/tests.js.map +1 -1
  85. package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts +2 -0
  86. package/lib/esm/tests/unit_tests/do_not_send_address.test.d.ts.map +1 -0
  87. package/lib/esm/tests/unit_tests/do_not_send_address.test.js +85 -0
  88. package/lib/esm/tests/unit_tests/do_not_send_address.test.js.map +1 -0
  89. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts +17 -0
  90. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.d.ts.map +1 -0
  91. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js +113 -0
  92. package/lib/esm/tests/unit_tests/openapi_spec_freshness.test.js.map +1 -0
  93. package/lib/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +10 -10
  95. package/src/tests/api_tests/organization_signup.test.ts +240 -0
  96. package/src/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.ts +225 -0
  97. package/src/tests/api_tests/security/F-0185-startlinktoken-enduser-staff-escalation.test.ts +162 -0
  98. package/src/tests/api_tests/security/F-0191-schema-adminonly-enforcement.test.ts +288 -0
  99. package/src/tests/api_tests/security/F-0192-automated-actions-process-gate.test.ts +238 -0
  100. package/src/tests/api_tests/security/F-0196-add-to-journey-foreign-enduserid.test.ts +208 -0
  101. package/src/tests/api_tests/tickets_bulk_assign_from_queue.test.ts +279 -0
  102. package/src/tests/setup_isolated.ts +170 -0
  103. package/src/tests/tests.ts +25 -0
  104. package/src/tests/unit_tests/do_not_send_address.test.ts +60 -0
  105. package/src/tests/unit_tests/openapi_spec_freshness.test.ts +88 -0
  106. package/test_generated.pdf +0 -0
@@ -0,0 +1,20 @@
1
+ import { Check } from "../setup_isolated";
2
+ /**
3
+ * Covers the self-service organization signup chain, which had ZERO test coverage:
4
+ * `users.register` -> `users.submit_email_verification` -> `organizations.create_and_join`.
5
+ *
6
+ * That gap is why F-0191 nearly shipped a schema `adminOnly` flag on create_and_join that would have
7
+ * 401'd every new organization — a freshly registered user has no `roles`, because create_and_join is
8
+ * itself what grants Admin. This test is the regression guard for that.
9
+ *
10
+ * It also covers the new test-support provisioning module, including the assertion that matters most:
11
+ * teardown refuses any organization it did not create.
12
+ *
13
+ * Uses a `dontsend...@tellescope.com` address so the verification email is dropped at
14
+ * forCommunications before it is ever enqueued (locally the worker consumes the same test queue the
15
+ * API writes to, so an unsuppressed registration really does send mail).
16
+ */
17
+ export declare const organization_signup_checks: () => Promise<Check[]>;
18
+ /** Asserting wrapper, for standalone runs and for sequential use in the suite. */
19
+ export declare const organization_signup_tests: () => Promise<void>;
20
+ //# sourceMappingURL=organization_signup.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization_signup.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/api_tests/organization_signup.test.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,EAIN,MAAM,mBAAmB,CAAA;AAS1B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,0BAA0B,QAAa,QAAQ,KAAK,EAAE,CAwLlE,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,qBAErC,CAAA"}
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.organization_signup_tests = exports.organization_signup_checks = void 0;
43
+ require('source-map-support').install();
44
+ var axios_1 = __importDefault(require("axios"));
45
+ var sdk_1 = require("../../sdk");
46
+ var testing_1 = require("@tellescope/testing");
47
+ var setup_isolated_1 = require("../setup_isolated");
48
+ var host = process.env.API_URL || 'http://localhost:8080';
49
+ var RAND = function () { return Math.random().toString(36).slice(2, 10); };
50
+ // legacy shared fixture — teardown must refuse it
51
+ var SEEDED_TEST_BUSINESS_ID = '60398b1131a295e64f084ff6';
52
+ /**
53
+ * Covers the self-service organization signup chain, which had ZERO test coverage:
54
+ * `users.register` -> `users.submit_email_verification` -> `organizations.create_and_join`.
55
+ *
56
+ * That gap is why F-0191 nearly shipped a schema `adminOnly` flag on create_and_join that would have
57
+ * 401'd every new organization — a freshly registered user has no `roles`, because create_and_join is
58
+ * itself what grants Admin. This test is the regression guard for that.
59
+ *
60
+ * It also covers the new test-support provisioning module, including the assertion that matters most:
61
+ * teardown refuses any organization it did not create.
62
+ *
63
+ * Uses a `dontsend...@tellescope.com` address so the verification email is dropped at
64
+ * forCommunications before it is ever enqueued (locally the worker consumes the same test queue the
65
+ * API writes to, so an unsuppressed registration really does send mail).
66
+ */
67
+ var organization_signup_checks = function () { return __awaiter(void 0, void 0, void 0, function () {
68
+ var checks, record, bootstrapUserId, createdBusinessId, provisioned, keyDetail, keyPass, keySession, e_1, enduser, refusal, email, password, registerResult, preVerifyLogin, unverifiedAttempt, code, verified, subdomain, joined, second, disposable, disposableKey, secondTeardown, revokedDetail, revokedPass, e_2, e_3, _a;
69
+ var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11;
70
+ return __generator(this, function (_12) {
71
+ switch (_12.label) {
72
+ case 0:
73
+ checks = [];
74
+ record = function (label, pass, detail) { return checks.push({ label: label, pass: pass, detail: detail }); };
75
+ bootstrapUserId = '';
76
+ createdBusinessId = '';
77
+ _12.label = 1;
78
+ case 1:
79
+ _12.trys.push([1, , 25, 34]);
80
+ return [4 /*yield*/, (0, setup_isolated_1.setup_isolated_tenant)()];
81
+ case 2:
82
+ /* ===== A: provisioning works with no seeded database ===== */
83
+ provisioned = _12.sent();
84
+ record('A1: provision-tenant returns a usable admin session', !!provisioned.businessId && ((_b = provisioned.sdk.userInfo) === null || _b === void 0 ? void 0 : _b.businessId) === provisioned.businessId, "businessId=".concat(provisioned.businessId, " session businessId=").concat((_c = provisioned.sdk.userInfo) === null || _c === void 0 ? void 0 : _c.businessId));
85
+ keyDetail = '';
86
+ keyPass = false;
87
+ _12.label = 3;
88
+ case 3:
89
+ _12.trys.push([3, 5, , 6]);
90
+ keySession = new sdk_1.Session({ host: host, apiKey: provisioned.apiKeys[0] });
91
+ return [4 /*yield*/, keySession.test_authenticated()];
92
+ case 4:
93
+ keyDetail = _12.sent();
94
+ keyPass = keyDetail === 'Authenticated!';
95
+ return [3 /*break*/, 6];
96
+ case 5:
97
+ e_1 = _12.sent();
98
+ keyDetail = "rejected: ".concat((e_1 === null || e_1 === void 0 ? void 0 : e_1.message) || (e_1 === null || e_1 === void 0 ? void 0 : e_1.toString()));
99
+ return [3 /*break*/, 6];
100
+ case 6:
101
+ record('A2: a provisioned API key authenticates', keyPass, "test_authenticated -> ".concat(keyDetail));
102
+ return [4 /*yield*/, provisioned.sdk.api.endusers.createOne({ fname: 'Provisioned', lname: 'Patient' })];
103
+ case 7:
104
+ enduser = _12.sent();
105
+ record('A3: the provisioned tenant accepts writes', !!enduser.id, "enduserId=".concat(enduser.id));
106
+ return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/teardown-tenant', { businessId: SEEDED_TEST_BUSINESS_ID })];
107
+ case 8:
108
+ refusal = _12.sent();
109
+ record('B1: teardown REFUSES an organization without the provenance marker', refusal.status === 403, "status=".concat(refusal.status, " ").concat(JSON.stringify(refusal.body), " (expected 403)"));
110
+ email = "dontsend-signup-".concat(RAND(), "@tellescope.com");
111
+ password = "Signup-".concat(RAND(), "-A1!");
112
+ return [4 /*yield*/, axios_1.default.request({
113
+ method: 'post', url: "".concat(host, "/v1/users/register"),
114
+ data: { email: email, password: password, termsVersion: '1' },
115
+ validateStatus: function () { return true; },
116
+ })];
117
+ case 9:
118
+ registerResult = _12.sent();
119
+ record('C1: register accepts a new org-less user', registerResult.status === 204, "status=".concat(registerResult.status, " ").concat(JSON.stringify((_d = registerResult.data) !== null && _d !== void 0 ? _d : '')));
120
+ return [4 /*yield*/, (0, testing_1.wait)(undefined, 1200)
121
+ // login works before verification, which is how a test learns the new user's id
122
+ ]; // register is IP-limited to ~1/sec
123
+ case 10:
124
+ _12.sent(); // register is IP-limited to ~1/sec
125
+ return [4 /*yield*/, axios_1.default.request({
126
+ method: 'post', url: "".concat(host, "/v1/users/login"),
127
+ data: { email: email, password: password },
128
+ validateStatus: function () { return true; },
129
+ })];
130
+ case 11:
131
+ preVerifyLogin = _12.sent();
132
+ bootstrapUserId = (_g = (_f = (_e = preVerifyLogin.data) === null || _e === void 0 ? void 0 : _e.user) === null || _f === void 0 ? void 0 : _f.id) !== null && _g !== void 0 ? _g : '';
133
+ record('C2: the unverified user can log in (and is org-less)', preVerifyLogin.status === 200 && !!bootstrapUserId && !((_j = (_h = preVerifyLogin.data) === null || _h === void 0 ? void 0 : _h.user) === null || _j === void 0 ? void 0 : _j.businessId), "status=".concat(preVerifyLogin.status, " id=").concat(bootstrapUserId, " businessId=").concat((_m = (_l = (_k = preVerifyLogin.data) === null || _k === void 0 ? void 0 : _k.user) === null || _l === void 0 ? void 0 : _l.businessId) !== null && _m !== void 0 ? _m : '(none)'));
134
+ return [4 /*yield*/, axios_1.default.request({
135
+ method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
136
+ data: { name: 'Should Not Work', subdomain: "nope-".concat(RAND()) },
137
+ headers: { Authorization: "Bearer ".concat((_o = preVerifyLogin.data) === null || _o === void 0 ? void 0 : _o.authToken) },
138
+ validateStatus: function () { return true; },
139
+ })];
140
+ case 12:
141
+ unverifiedAttempt = _12.sent();
142
+ record('C3: create_and_join is rejected before email verification', unverifiedAttempt.status === 400, "status=".concat(unverifiedAttempt.status, " ").concat(JSON.stringify((_p = unverifiedAttempt.data) !== null && _p !== void 0 ? _p : '')));
143
+ code = "verify-".concat(RAND());
144
+ return [4 /*yield*/, (0, setup_isolated_1.set_email_verification_code)(email, code)];
145
+ case 13:
146
+ _12.sent();
147
+ return [4 /*yield*/, axios_1.default.request({
148
+ method: 'post', url: "".concat(host, "/v1/users/submit-email-verification"),
149
+ data: { email: email, code: code },
150
+ validateStatus: function () { return true; },
151
+ })];
152
+ case 14:
153
+ verified = _12.sent();
154
+ record('C4: submit_email_verification accepts the code and mints a token', verified.status === 200 && !!((_q = verified.data) === null || _q === void 0 ? void 0 : _q.authToken), "status=".concat(verified.status, " authToken=").concat(!!((_r = verified.data) === null || _r === void 0 ? void 0 : _r.authToken)));
155
+ subdomain = "signup-".concat(RAND());
156
+ return [4 /*yield*/, axios_1.default.request({
157
+ method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
158
+ data: { name: "Signup Test ".concat(RAND()), subdomain: subdomain },
159
+ headers: { Authorization: "Bearer ".concat((_s = verified.data) === null || _s === void 0 ? void 0 : _s.authToken) },
160
+ validateStatus: function () { return true; },
161
+ })];
162
+ case 15:
163
+ joined = _12.sent();
164
+ createdBusinessId = (_v = (_u = (_t = joined.data) === null || _t === void 0 ? void 0 : _t.organization) === null || _u === void 0 ? void 0 : _u.id) !== null && _v !== void 0 ? _v : '';
165
+ record('D1: a freshly verified, org-less user can create and join an organization', joined.status === 200 && !!createdBusinessId, "status=".concat(joined.status, " organizationId=").concat(createdBusinessId, " ").concat(joined.status !== 200 ? JSON.stringify(joined.data) : ''));
166
+ record('D2: the handler grants Admin and sets businessId (the roles bootstrap)', ((_y = (_x = (_w = joined.data) === null || _w === void 0 ? void 0 : _w.user) === null || _x === void 0 ? void 0 : _x.roles) === null || _y === void 0 ? void 0 : _y.includes('Admin')) && ((_0 = (_z = joined.data) === null || _z === void 0 ? void 0 : _z.user) === null || _0 === void 0 ? void 0 : _0.businessId) === createdBusinessId, "roles=".concat(JSON.stringify((_2 = (_1 = joined.data) === null || _1 === void 0 ? void 0 : _1.user) === null || _2 === void 0 ? void 0 : _2.roles), " businessId=").concat((_4 = (_3 = joined.data) === null || _3 === void 0 ? void 0 : _3.user) === null || _4 === void 0 ? void 0 : _4.businessId));
167
+ record('D3: a fresh token is returned', !!((_5 = joined.data) === null || _5 === void 0 ? void 0 : _5.authToken) && joined.data.authToken !== ((_6 = verified.data) === null || _6 === void 0 ? void 0 : _6.authToken), "token returned=".concat(!!((_7 = joined.data) === null || _7 === void 0 ? void 0 : _7.authToken), ", rotated=").concat(((_8 = joined.data) === null || _8 === void 0 ? void 0 : _8.authToken) !== ((_9 = verified.data) === null || _9 === void 0 ? void 0 : _9.authToken)));
168
+ return [4 /*yield*/, axios_1.default.request({
169
+ method: 'post', url: "".concat(host, "/v1/organizations/create-and-join"),
170
+ data: { name: 'Second Org', subdomain: "signup-".concat(RAND()) },
171
+ headers: { Authorization: "Bearer ".concat((_10 = joined.data) === null || _10 === void 0 ? void 0 : _10.authToken) },
172
+ validateStatus: function () { return true; },
173
+ })];
174
+ case 16:
175
+ second = _12.sent();
176
+ record('D4: a user already in an organization cannot create another', second.status === 400, "status=".concat(second.status, " ").concat(JSON.stringify((_11 = second.data) !== null && _11 !== void 0 ? _11 : '')));
177
+ return [4 /*yield*/, (0, setup_isolated_1.setup_isolated_tenant)({ users: [{ isAdmin: true }], apiKeys: 1 })];
178
+ case 17:
179
+ disposable = _12.sent();
180
+ disposableKey = disposable.apiKeys[0];
181
+ return [4 /*yield*/, disposable.sdk.api.endusers.createOne({ fname: 'Disposable', lname: 'Patient' })];
182
+ case 18:
183
+ _12.sent();
184
+ return [4 /*yield*/, disposable.teardown()];
185
+ case 19:
186
+ _12.sent();
187
+ return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/teardown-tenant', { businessId: disposable.businessId })];
188
+ case 20:
189
+ secondTeardown = _12.sent();
190
+ record('E1: teardown removes the organization record itself', secondTeardown.status === 404, "re-teardown status=".concat(secondTeardown.status, " ").concat(JSON.stringify(secondTeardown.body), " (expected 404 \u2014 org gone)"));
191
+ revokedDetail = '';
192
+ revokedPass = false;
193
+ _12.label = 21;
194
+ case 21:
195
+ _12.trys.push([21, 23, , 24]);
196
+ return [4 /*yield*/, (new sdk_1.Session({ host: host, apiKey: disposableKey })).test_authenticated()];
197
+ case 22:
198
+ revokedDetail = _12.sent();
199
+ return [3 /*break*/, 24];
200
+ case 23:
201
+ e_2 = _12.sent();
202
+ revokedPass = true;
203
+ revokedDetail = "rejected: ".concat((e_2 === null || e_2 === void 0 ? void 0 : e_2.message) || (e_2 === null || e_2 === void 0 ? void 0 : e_2.toString()));
204
+ return [3 /*break*/, 24];
205
+ case 24:
206
+ record('E2: the torn-down tenant\'s API key no longer authenticates', revokedPass, revokedDetail);
207
+ return [3 /*break*/, 34];
208
+ case 25:
209
+ if (!provisioned) return [3 /*break*/, 29];
210
+ _12.label = 26;
211
+ case 26:
212
+ _12.trys.push([26, 28, , 29]);
213
+ return [4 /*yield*/, provisioned.teardown()];
214
+ case 27:
215
+ _12.sent();
216
+ return [3 /*break*/, 29];
217
+ case 28:
218
+ e_3 = _12.sent();
219
+ console.error('teardown failed', e_3);
220
+ return [3 /*break*/, 29];
221
+ case 29:
222
+ if (!bootstrapUserId) return [3 /*break*/, 33];
223
+ _12.label = 30;
224
+ case 30:
225
+ _12.trys.push([30, 32, , 33]);
226
+ return [4 /*yield*/, (0, setup_isolated_1.test_support_request)('/delete-user', { userId: bootstrapUserId })];
227
+ case 31:
228
+ _12.sent();
229
+ return [3 /*break*/, 33];
230
+ case 32:
231
+ _a = _12.sent();
232
+ return [3 /*break*/, 33];
233
+ case 33:
234
+ if (createdBusinessId) {
235
+ console.log(" note: organization ".concat(createdBusinessId, " was created by the signup flow and is left behind (nothing can delete an org record)"));
236
+ }
237
+ return [7 /*endfinally*/];
238
+ case 34: return [2 /*return*/, checks];
239
+ }
240
+ });
241
+ }); };
242
+ exports.organization_signup_checks = organization_signup_checks;
243
+ /** Asserting wrapper, for standalone runs and for sequential use in the suite. */
244
+ var organization_signup_tests = function () { return __awaiter(void 0, void 0, void 0, function () {
245
+ var _a, _b;
246
+ return __generator(this, function (_c) {
247
+ switch (_c.label) {
248
+ case 0:
249
+ _a = setup_isolated_1.assert_checks;
250
+ _b = ['Organization signup'];
251
+ return [4 /*yield*/, (0, exports.organization_signup_checks)()];
252
+ case 1:
253
+ _a.apply(void 0, _b.concat([_c.sent()]));
254
+ return [2 /*return*/];
255
+ }
256
+ });
257
+ }); };
258
+ exports.organization_signup_tests = organization_signup_tests;
259
+ // Allow running this test file independently
260
+ if (require.main === module) {
261
+ console.log("\uD83C\uDF10 Using API URL: ".concat(host));
262
+ (0, exports.organization_signup_tests)()
263
+ .then(function () {
264
+ console.log("✅ Organization signup test suite completed successfully");
265
+ process.exit(0);
266
+ })
267
+ .catch(function (error) {
268
+ console.error("❌ Organization signup test suite failed:", error);
269
+ process.exit(1);
270
+ });
271
+ }
272
+ //# sourceMappingURL=organization_signup.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization_signup.test.js","sourceRoot":"","sources":["../../../../src/tests/api_tests/organization_signup.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { Session } from "../../../sdk";
2
+ /**
3
+ * Regression test for F-0179
4
+ * (security-audit/findings/F-0179-booking-info-idor-token-mint.md).
5
+ *
6
+ * `form_fields.booking_info` resolved its target patient as
7
+ * `DB.endusers.findById(enduserId || req.session.id)` with no ownership check for enduser
8
+ * sessions. The enduser DB branch builds the endusers collection with `enduserAccess: true`
9
+ * (database.ts), so a FOREIGN in-tenant id resolves — and the handler then writes
10
+ * `enduserFields.state` onto that record and calls `login_enduser` with
11
+ * `sessionScopes: ['appointment-booking']`, returning a live 24h token for the victim inside
12
+ * `bookingURL`. booking_info is enduser-callable AND granted to the 'public-form' scope, so a
13
+ * portal patient or an anonymous form-filler could mint a working session as any co-tenant patient.
14
+ *
15
+ * The fix mirrors `prepare_form_response` (api.ts): reject when an enduser session supplies an
16
+ * `enduserId` other than its own, before the booking-page lookup and before the `state` write.
17
+ *
18
+ * RED (pre-fix): A1 and A2 fail — the exploit returns 200 with a bookingURL whose token decodes to
19
+ * the VICTIM's id, and the victim's `state` is overwritten. B/C (positive controls) pass pre-fix.
20
+ * GREEN (post-fix): all six checks pass.
21
+ *
22
+ * Checks are collected and printed before any assert runs: the testing harness has
23
+ * EXIT_ON_FIRST_ERROR, so asserting inline would kill the process before the evidence table and
24
+ * before `finally` cleanup.
25
+ */
26
+ export declare const booking_info_idor_tests: ({ sdk }: {
27
+ sdk: Session;
28
+ sdkNonAdmin: Session;
29
+ }) => Promise<void>;
30
+ //# sourceMappingURL=F-0179-booking-info-idor-token-mint.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"F-0179-booking-info-idor-token-mint.test.d.ts","sourceRoot":"","sources":["../../../../../src/tests/api_tests/security/F-0179-booking-info-idor-token-mint.test.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAkB,MAAM,cAAc,CAAA;AAqBtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,uBAAuB;SAA2B,OAAO;iBAAe,OAAO;mBA2J3F,CAAA"}