@proteinjs/user-server 1.18.0 → 1.20.0

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 (55) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +3 -1
  4. package/dist/generated/index.js.map +1 -1
  5. package/dist/src/authorization/UserActivityStamp.d.ts +17 -15
  6. package/dist/src/authorization/UserActivityStamp.d.ts.map +1 -1
  7. package/dist/src/authorization/UserActivityStamp.js +21 -19
  8. package/dist/src/authorization/UserActivityStamp.js.map +1 -1
  9. package/dist/src/authorization/userCache.d.ts +9 -0
  10. package/dist/src/authorization/userCache.d.ts.map +1 -1
  11. package/dist/src/authorization/userCache.js +9 -9
  12. package/dist/src/authorization/userCache.js.map +1 -1
  13. package/dist/src/routes/DevBootstrapRoles.d.ts +21 -0
  14. package/dist/src/routes/DevBootstrapRoles.d.ts.map +1 -0
  15. package/dist/src/routes/DevBootstrapRoles.js +64 -0
  16. package/dist/src/routes/DevBootstrapRoles.js.map +1 -0
  17. package/dist/src/routes/devLogin.d.ts +11 -0
  18. package/dist/src/routes/devLogin.d.ts.map +1 -1
  19. package/dist/src/routes/devLogin.js +23 -3
  20. package/dist/src/routes/devLogin.js.map +1 -1
  21. package/dist/src/services/Roles.d.ts +29 -1
  22. package/dist/src/services/Roles.d.ts.map +1 -1
  23. package/dist/src/services/Roles.js +88 -14
  24. package/dist/src/services/Roles.js.map +1 -1
  25. package/dist/src/services/UserPresence.d.ts +16 -0
  26. package/dist/src/services/UserPresence.d.ts.map +1 -0
  27. package/dist/src/services/UserPresence.js +75 -0
  28. package/dist/src/services/UserPresence.js.map +1 -0
  29. package/dist/test/DevLogin.test.js +5 -2
  30. package/dist/test/DevLogin.test.js.map +1 -1
  31. package/dist/test/DevLoginBootstrapAdmin.test.js +2 -0
  32. package/dist/test/DevLoginBootstrapAdmin.test.js.map +1 -1
  33. package/dist/test/DevLoginBootstrapRoles.test.d.ts +2 -0
  34. package/dist/test/DevLoginBootstrapRoles.test.d.ts.map +1 -0
  35. package/dist/test/DevLoginBootstrapRoles.test.js +491 -0
  36. package/dist/test/DevLoginBootstrapRoles.test.js.map +1 -0
  37. package/dist/test/UserActivityStamp.integration.test.js +57 -90
  38. package/dist/test/UserActivityStamp.integration.test.js.map +1 -1
  39. package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts +2 -0
  40. package/dist/test/UserCacheDoesNotStampPresence.integration.test.d.ts.map +1 -0
  41. package/dist/test/UserCacheDoesNotStampPresence.integration.test.js +117 -0
  42. package/dist/test/UserCacheDoesNotStampPresence.integration.test.js.map +1 -0
  43. package/generated/index.ts +3 -1
  44. package/package.json +3 -3
  45. package/src/authorization/UserActivityStamp.ts +22 -20
  46. package/src/authorization/userCache.ts +9 -9
  47. package/src/routes/DevBootstrapRoles.ts +50 -0
  48. package/src/routes/devLogin.ts +18 -0
  49. package/src/services/Roles.ts +61 -1
  50. package/src/services/UserPresence.ts +26 -0
  51. package/test/DevLogin.test.ts +5 -2
  52. package/test/DevLoginBootstrapAdmin.test.ts +2 -0
  53. package/test/DevLoginBootstrapRoles.test.ts +248 -0
  54. package/test/UserActivityStamp.integration.test.ts +38 -50
  55. package/test/UserCacheDoesNotStampPresence.integration.test.ts +44 -0
@@ -0,0 +1,491 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ var db_1 = require("@proteinjs/db");
40
+ var logger_1 = require("@proteinjs/logger");
41
+ var reflection_1 = require("@proteinjs/reflection");
42
+ var user_1 = require("@proteinjs/user");
43
+ var devLoginHarness_1 = require("./devLoginHarness");
44
+ var UserServerTestEnvironment_1 = require("./UserServerTestEnvironment");
45
+ var testEnv = new UserServerTestEnvironment_1.UserServerTestEnvironment();
46
+ /**
47
+ * `DEV_BOOTSTRAP_ROLES` — the dev role-bootstrap door INSIDE `/dev/login`. A fresh development
48
+ * database has one admin at most (the first-admin door) and every other account is role-less —
49
+ * so a consumer's `adminGrantOnly` roles needed a manual admin act on every fresh database. The
50
+ * same door, the same two gates, one more variable: `email:role[,role];email:role…` — on a hit
51
+ * whose resolved address is listed, the listed roles the account does not hold are granted, once
52
+ * each:
53
+ * - behind the door's existing two gates (DEVELOPMENT AND DEV_AUTO_LOGIN_EMAIL): closed = 404 as
54
+ * before, and the variable changes nothing;
55
+ * - only for the request whose resolved address equals a listed address exactly (case-normalized
56
+ * the way every account email is) — every other address is untouched;
57
+ * - idempotent: a role the account holds is reported `held`, never re-granted, never re-audited;
58
+ * nothing is EVER revoked (a role the list does not name stays);
59
+ * - admin-grant-only roles are granted (that is the point — a fresh development database has no
60
+ * admin to grant them); break-glass and roles the catalog does not know are REFUSED and named;
61
+ * - each grant is audited like any grant (a role_grant_event row; actor = the account itself);
62
+ * - the outcome is ONE marker line, `[dev-bootstrap] <email>: granted …; held …; refused …`, the
63
+ * line provisioning tooling reads back from the server log as its proof.
64
+ * Outcomes are asserted on the rows (roles, audit), the marker line on the logger (it IS the
65
+ * contract its readers parse).
66
+ */
67
+ var ENV_EMAIL = 'dev@test.local';
68
+ var TEAM_EMAIL = 'team@test.local';
69
+ var OPS_EMAIL = 'ops@test.local';
70
+ var ROLES_ENV = "".concat(TEAM_EMAIL, ":staff,dev;").concat(OPS_EMAIL, ":ops");
71
+ var userRow = function (email) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
72
+ switch (_a.label) {
73
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().get(user_1.tables.User, { email: email })];
74
+ case 1: return [2 /*return*/, _a.sent()];
75
+ }
76
+ }); }); };
77
+ var auditRows = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
78
+ switch (_a.label) {
79
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.RoleGrantEvent, {})];
80
+ case 1: return [2 /*return*/, _a.sent()];
81
+ }
82
+ }); }); };
83
+ var adminRows = function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
84
+ switch (_a.label) {
85
+ case 0: return [4 /*yield*/, (0, db_1.getDbAsSystem)().query(user_1.tables.User, {})];
86
+ case 1: return [2 /*return*/, (_a.sent()).filter(function (user) { var _a; return ((_a = user.roles) !== null && _a !== void 0 ? _a : []).includes('admin'); })];
87
+ }
88
+ }); }); };
89
+ describe('devLogin — the DEV_BOOTSTRAP_ROLES role-bootstrap door', function () {
90
+ var originalEnv = {
91
+ DEVELOPMENT: process.env.DEVELOPMENT,
92
+ DEV_AUTO_LOGIN_EMAIL: process.env.DEV_AUTO_LOGIN_EMAIL,
93
+ DEV_BOOTSTRAP_ADMIN_EMAIL: process.env.DEV_BOOTSTRAP_ADMIN_EMAIL,
94
+ DEV_BOOTSTRAP_ROLES: process.env.DEV_BOOTSTRAP_ROLES,
95
+ };
96
+ var infoSpy;
97
+ var markerLines = function () {
98
+ return infoSpy.mock.calls
99
+ .map(function (call) { var _a, _b; return String((_b = (_a = call[0]) === null || _a === void 0 ? void 0 : _a.message) !== null && _b !== void 0 ? _b : ''); })
100
+ .filter(function (message) { return message.startsWith('[dev-bootstrap]'); });
101
+ };
102
+ beforeAll(function () { return __awaiter(void 0, void 0, void 0, function () {
103
+ return __generator(this, function (_a) {
104
+ switch (_a.label) {
105
+ case 0: return [4 /*yield*/, testEnv.beforeAll()];
106
+ case 1:
107
+ _a.sent();
108
+ // A consumer's catalog shape: 'staff' is admin-grant-only, 'dev'/'ops' plain.
109
+ reflection_1.SourceRepository.get().objectCache['@proteinjs/user/RoleCatalogEntry'] = [
110
+ { role: 'staff', description: 'Staff member', adminGrantOnly: true },
111
+ { role: 'dev', description: 'Developer tooling' },
112
+ { role: 'ops', description: 'Operations' },
113
+ ];
114
+ return [2 /*return*/];
115
+ }
116
+ });
117
+ }); });
118
+ afterAll(function () { return __awaiter(void 0, void 0, void 0, function () {
119
+ return __generator(this, function (_a) {
120
+ switch (_a.label) {
121
+ case 0: return [4 /*yield*/, testEnv.afterAll()];
122
+ case 1:
123
+ _a.sent();
124
+ return [2 /*return*/];
125
+ }
126
+ });
127
+ }); });
128
+ beforeEach(function () { return __awaiter(void 0, void 0, void 0, function () {
129
+ var db;
130
+ return __generator(this, function (_a) {
131
+ switch (_a.label) {
132
+ case 0:
133
+ process.env.DEVELOPMENT = 'true';
134
+ process.env.DEV_AUTO_LOGIN_EMAIL = ENV_EMAIL;
135
+ delete process.env.DEV_BOOTSTRAP_ADMIN_EMAIL;
136
+ process.env.DEV_BOOTSTRAP_ROLES = ROLES_ENV;
137
+ infoSpy = jest.spyOn(logger_1.Logger.prototype, 'info');
138
+ db = (0, db_1.getDbAsSystem)();
139
+ return [4 /*yield*/, db.delete(user_1.tables.RoleGrantEvent, {})];
140
+ case 1:
141
+ _a.sent();
142
+ return [4 /*yield*/, db.delete(user_1.tables.User, {})];
143
+ case 2:
144
+ _a.sent();
145
+ return [2 /*return*/];
146
+ }
147
+ });
148
+ }); });
149
+ afterEach(function () {
150
+ infoSpy.mockRestore();
151
+ for (var _i = 0, _a = Object.entries(originalEnv); _i < _a.length; _i++) {
152
+ var _b = _a[_i], key = _b[0], value = _b[1];
153
+ if (value === undefined) {
154
+ delete process.env[key];
155
+ }
156
+ else {
157
+ process.env[key] = value;
158
+ }
159
+ }
160
+ });
161
+ it('a fresh database + a listed address: the account is created carrying the listed roles (the admin-grant-only one included), one audit row per role, logged in, and the marker line names the grants', function () { return __awaiter(void 0, void 0, void 0, function () {
162
+ var _a, outcome, team, events;
163
+ return __generator(this, function (_b) {
164
+ switch (_b.label) {
165
+ case 0:
166
+ _a = expect;
167
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
168
+ case 1:
169
+ _a.apply(void 0, [_b.sent()]).toBeUndefined();
170
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
171
+ case 2:
172
+ outcome = _b.sent();
173
+ expect(outcome.loggedInAs).toBe(TEAM_EMAIL);
174
+ expect(outcome.sessionSaved).toBe(true);
175
+ expect(outcome.redirect).toBe('/');
176
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
177
+ case 3:
178
+ team = _b.sent();
179
+ expect(team.roles).toEqual(['staff', 'dev']);
180
+ return [4 /*yield*/, auditRows()];
181
+ case 4:
182
+ events = _b.sent();
183
+ expect(events.map(function (e) { return ({ actor: e.actor, target: e.target, role: e.role, action: e.action }); })).toEqual(expect.arrayContaining([
184
+ { actor: team.id, target: team.id, role: 'staff', action: 'grant' },
185
+ { actor: team.id, target: team.id, role: 'dev', action: 'grant' },
186
+ ]));
187
+ expect(events).toHaveLength(2);
188
+ expect(markerLines()).toEqual([
189
+ "[dev-bootstrap] ".concat(TEAM_EMAIL, ": granted staff, dev; held (none); refused (none)"),
190
+ ]);
191
+ return [2 /*return*/];
192
+ }
193
+ });
194
+ }); });
195
+ it('a second hit for the same address writes nothing: the roles stand, the audit trail is unchanged, the marker line reports them held', function () { return __awaiter(void 0, void 0, void 0, function () {
196
+ var outcome, _a, _b;
197
+ return __generator(this, function (_c) {
198
+ switch (_c.label) {
199
+ case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
200
+ case 1:
201
+ _c.sent();
202
+ infoSpy.mockClear();
203
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
204
+ case 2:
205
+ outcome = _c.sent();
206
+ expect(outcome.loggedInAs).toBe(TEAM_EMAIL);
207
+ _a = expect;
208
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
209
+ case 3:
210
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual(['staff', 'dev']);
211
+ _b = expect;
212
+ return [4 /*yield*/, auditRows()];
213
+ case 4:
214
+ _b.apply(void 0, [_c.sent()]).toHaveLength(2);
215
+ expect(markerLines()).toEqual([
216
+ "[dev-bootstrap] ".concat(TEAM_EMAIL, ": granted (none); held staff, dev; refused (none)"),
217
+ ]);
218
+ return [2 /*return*/];
219
+ }
220
+ });
221
+ }); });
222
+ it('an existing account holding one listed role and one unlisted role: only the missing role is granted, the unlisted one stays — the door never revokes', function () { return __awaiter(void 0, void 0, void 0, function () {
223
+ var _a, events;
224
+ return __generator(this, function (_b) {
225
+ switch (_b.label) {
226
+ case 0: return [4 /*yield*/, testEnv.createUser({ name: 'Team', email: TEAM_EMAIL, roles: ['dev', 'sessions'] })];
227
+ case 1:
228
+ _b.sent();
229
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
230
+ case 2:
231
+ _b.sent();
232
+ _a = expect;
233
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
234
+ case 3:
235
+ _a.apply(void 0, [(_b.sent()).roles]).toEqual(['dev', 'sessions', 'staff']);
236
+ return [4 /*yield*/, auditRows()];
237
+ case 4:
238
+ events = _b.sent();
239
+ expect(events).toHaveLength(1);
240
+ expect(events[0]).toMatchObject({ role: 'staff', action: 'grant' });
241
+ expect(markerLines()).toEqual(["[dev-bootstrap] ".concat(TEAM_EMAIL, ": granted staff; held dev; refused (none)")]);
242
+ return [2 /*return*/];
243
+ }
244
+ });
245
+ }); });
246
+ it('an address the list does not name: an ordinary account, no grant, no audit row, no marker line — and the listed addresses stay uncreated', function () { return __awaiter(void 0, void 0, void 0, function () {
247
+ var outcome, _a, _b, _c, _d;
248
+ return __generator(this, function (_e) {
249
+ switch (_e.label) {
250
+ case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'agent@test.local' })];
251
+ case 1:
252
+ outcome = _e.sent();
253
+ expect(outcome.loggedInAs).toBe('agent@test.local');
254
+ _a = expect;
255
+ return [4 /*yield*/, userRow('agent@test.local')];
256
+ case 2:
257
+ _a.apply(void 0, [(_e.sent()).roles]).toEqual([]);
258
+ _b = expect;
259
+ return [4 /*yield*/, auditRows()];
260
+ case 3:
261
+ _b.apply(void 0, [_e.sent()]).toHaveLength(0);
262
+ expect(markerLines()).toEqual([]);
263
+ _c = expect;
264
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
265
+ case 4:
266
+ _c.apply(void 0, [_e.sent()]).toBeUndefined();
267
+ _d = expect;
268
+ return [4 /*yield*/, userRow(OPS_EMAIL)];
269
+ case 5:
270
+ _d.apply(void 0, [_e.sent()]).toBeUndefined();
271
+ return [2 /*return*/];
272
+ }
273
+ });
274
+ }); });
275
+ it('each listed address gets ITS roles only — the second entry never inherits the first', function () { return __awaiter(void 0, void 0, void 0, function () {
276
+ var _a, _b;
277
+ return __generator(this, function (_c) {
278
+ switch (_c.label) {
279
+ case 0: return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: OPS_EMAIL })];
280
+ case 1:
281
+ _c.sent();
282
+ _a = expect;
283
+ return [4 /*yield*/, userRow(OPS_EMAIL)];
284
+ case 2:
285
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual(['ops']);
286
+ _b = expect;
287
+ return [4 /*yield*/, auditRows()];
288
+ case 3:
289
+ _b.apply(void 0, [_c.sent()]).toHaveLength(1);
290
+ expect(markerLines()).toEqual(["[dev-bootstrap] ".concat(OPS_EMAIL, ": granted ops; held (none); refused (none)")]);
291
+ return [2 /*return*/];
292
+ }
293
+ });
294
+ }); });
295
+ it('the match is case-normalized like every account email, and the grammar tolerates whitespace around every token', function () { return __awaiter(void 0, void 0, void 0, function () {
296
+ var _a, _b;
297
+ return __generator(this, function (_c) {
298
+ switch (_c.label) {
299
+ case 0:
300
+ process.env.DEV_BOOTSTRAP_ROLES = " Team@Test.local : staff , dev ; ".concat(OPS_EMAIL, ": ops ");
301
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: 'team@test.local' })];
302
+ case 1:
303
+ _c.sent();
304
+ _a = expect;
305
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
306
+ case 2:
307
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual(['staff', 'dev']);
308
+ _b = expect;
309
+ return [4 /*yield*/, auditRows()];
310
+ case 3:
311
+ _b.apply(void 0, [_c.sent()]).toHaveLength(2);
312
+ return [2 /*return*/];
313
+ }
314
+ });
315
+ }); });
316
+ it('a role the catalog does not know is refused and named; the known roles in the same entry are still granted', function () { return __awaiter(void 0, void 0, void 0, function () {
317
+ var _a, _b;
318
+ return __generator(this, function (_c) {
319
+ switch (_c.label) {
320
+ case 0:
321
+ process.env.DEV_BOOTSTRAP_ROLES = "".concat(TEAM_EMAIL, ":staff,no-such-role");
322
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
323
+ case 1:
324
+ _c.sent();
325
+ _a = expect;
326
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
327
+ case 2:
328
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual(['staff']);
329
+ _b = expect;
330
+ return [4 /*yield*/, auditRows()];
331
+ case 3:
332
+ _b.apply(void 0, [_c.sent()]).toHaveLength(1);
333
+ expect(markerLines()).toEqual([
334
+ "[dev-bootstrap] ".concat(TEAM_EMAIL, ": granted staff; held (none); refused no-such-role (unknown role)"),
335
+ ]);
336
+ return [2 /*return*/];
337
+ }
338
+ });
339
+ }); });
340
+ it("break-glass is never this door's to grant: 'admin' in the list is refused and named (the first-admin door is the one path)", function () { return __awaiter(void 0, void 0, void 0, function () {
341
+ var _a, _b, _c;
342
+ return __generator(this, function (_d) {
343
+ switch (_d.label) {
344
+ case 0:
345
+ process.env.DEV_BOOTSTRAP_ROLES = "".concat(TEAM_EMAIL, ":admin,dev");
346
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
347
+ case 1:
348
+ _d.sent();
349
+ _a = expect;
350
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
351
+ case 2:
352
+ _a.apply(void 0, [(_d.sent()).roles]).toEqual(['dev']);
353
+ _b = expect;
354
+ return [4 /*yield*/, adminRows()];
355
+ case 3:
356
+ _b.apply(void 0, [_d.sent()]).toHaveLength(0);
357
+ _c = expect;
358
+ return [4 /*yield*/, auditRows()];
359
+ case 4:
360
+ _c.apply(void 0, [(_d.sent()).map(function (e) { return e.role; })]).toEqual(['dev']);
361
+ expect(markerLines()).toEqual([
362
+ "[dev-bootstrap] ".concat(TEAM_EMAIL, ": granted dev; held (none); refused admin (break-glass)"),
363
+ ]);
364
+ return [2 /*return*/];
365
+ }
366
+ });
367
+ }); });
368
+ it('the default path is a request for DEV_AUTO_LOGIN_EMAIL: when that address is listed, the default account carries the roles', function () { return __awaiter(void 0, void 0, void 0, function () {
369
+ var outcome, _a, _b;
370
+ return __generator(this, function (_c) {
371
+ switch (_c.label) {
372
+ case 0:
373
+ process.env.DEV_BOOTSTRAP_ROLES = "".concat(ENV_EMAIL, ":dev");
374
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)()];
375
+ case 1:
376
+ outcome = _c.sent();
377
+ expect(outcome.loggedInAs).toBe(ENV_EMAIL);
378
+ _a = expect;
379
+ return [4 /*yield*/, userRow(ENV_EMAIL)];
380
+ case 2:
381
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual(['dev']);
382
+ _b = expect;
383
+ return [4 /*yield*/, auditRows()];
384
+ case 3:
385
+ _b.apply(void 0, [_c.sent()]).toHaveLength(1);
386
+ return [2 /*return*/];
387
+ }
388
+ });
389
+ }); });
390
+ it('composes with the first-admin door: the same address listed in both gets admin first, then its roles — three audited grants, one account', function () { return __awaiter(void 0, void 0, void 0, function () {
391
+ var _a, _b, _c;
392
+ return __generator(this, function (_d) {
393
+ switch (_d.label) {
394
+ case 0:
395
+ process.env.DEV_BOOTSTRAP_ADMIN_EMAIL = TEAM_EMAIL;
396
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
397
+ case 1:
398
+ _d.sent();
399
+ _a = expect;
400
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
401
+ case 2:
402
+ _a.apply(void 0, [(_d.sent()).roles]).toEqual(['admin', 'staff', 'dev']);
403
+ _b = expect;
404
+ return [4 /*yield*/, auditRows()];
405
+ case 3:
406
+ _b.apply(void 0, [_d.sent()]).toHaveLength(3);
407
+ _c = expect;
408
+ return [4 /*yield*/, adminRows()];
409
+ case 4:
410
+ _c.apply(void 0, [_d.sent()]).toHaveLength(1);
411
+ return [2 /*return*/];
412
+ }
413
+ });
414
+ }); });
415
+ it('with the variable unset a listed address is an ordinary account — the omission is the safety (a deployment outside development never sets it)', function () { return __awaiter(void 0, void 0, void 0, function () {
416
+ var _a, _b;
417
+ return __generator(this, function (_c) {
418
+ switch (_c.label) {
419
+ case 0:
420
+ delete process.env.DEV_BOOTSTRAP_ROLES;
421
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
422
+ case 1:
423
+ _c.sent();
424
+ _a = expect;
425
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
426
+ case 2:
427
+ _a.apply(void 0, [(_c.sent()).roles]).toEqual([]);
428
+ _b = expect;
429
+ return [4 /*yield*/, auditRows()];
430
+ case 3:
431
+ _b.apply(void 0, [_c.sent()]).toHaveLength(0);
432
+ expect(markerLines()).toEqual([]);
433
+ return [2 /*return*/];
434
+ }
435
+ });
436
+ }); });
437
+ it('malformed entries (no colon, no roles) are ignored; the well-formed entries beside them are honored', function () { return __awaiter(void 0, void 0, void 0, function () {
438
+ var _a, _b, _c;
439
+ return __generator(this, function (_d) {
440
+ switch (_d.label) {
441
+ case 0:
442
+ process.env.DEV_BOOTSTRAP_ROLES = "garbage;".concat(OPS_EMAIL, ":;").concat(TEAM_EMAIL, ":dev;:ops");
443
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
444
+ case 1:
445
+ _d.sent();
446
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: OPS_EMAIL })];
447
+ case 2:
448
+ _d.sent();
449
+ _a = expect;
450
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
451
+ case 3:
452
+ _a.apply(void 0, [(_d.sent()).roles]).toEqual(['dev']);
453
+ _b = expect;
454
+ return [4 /*yield*/, userRow(OPS_EMAIL)];
455
+ case 4:
456
+ _b.apply(void 0, [(_d.sent()).roles]).toEqual([]);
457
+ _c = expect;
458
+ return [4 /*yield*/, auditRows()];
459
+ case 5:
460
+ _c.apply(void 0, [_d.sent()]).toHaveLength(1);
461
+ return [2 /*return*/];
462
+ }
463
+ });
464
+ }); });
465
+ it.each([['DEVELOPMENT'], ['DEV_AUTO_LOGIN_EMAIL']])('gate closed (%s unset): 404 exactly as before — no session, no account, no grant; the variable changes nothing', function (gate) { return __awaiter(void 0, void 0, void 0, function () {
466
+ var outcome, _a, _b;
467
+ return __generator(this, function (_c) {
468
+ switch (_c.label) {
469
+ case 0:
470
+ delete process.env[gate];
471
+ return [4 /*yield*/, (0, devLoginHarness_1.invokeDevLogin)({ email: TEAM_EMAIL })];
472
+ case 1:
473
+ outcome = _c.sent();
474
+ expect(outcome.status).toBe(404);
475
+ expect(outcome.loggedInAs).toBeUndefined();
476
+ expect(outcome.sessionSaved).toBe(false);
477
+ _a = expect;
478
+ return [4 /*yield*/, userRow(TEAM_EMAIL)];
479
+ case 2:
480
+ _a.apply(void 0, [_c.sent()]).toBeUndefined();
481
+ _b = expect;
482
+ return [4 /*yield*/, auditRows()];
483
+ case 3:
484
+ _b.apply(void 0, [_c.sent()]).toHaveLength(0);
485
+ expect(markerLines()).toEqual([]);
486
+ return [2 /*return*/];
487
+ }
488
+ });
489
+ }); });
490
+ });
491
+ //# sourceMappingURL=DevLoginBootstrapRoles.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevLoginBootstrapRoles.test.js","sourceRoot":"","sources":["../../test/DevLoginBootstrapRoles.test.ts"],"names":[],"mappings":"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"}