@positronic/spec 0.0.67 → 0.0.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/brains.d.ts.map +1 -1
- package/dist/api/brains.js +108 -299
- package/dist/api/brains.js.map +1 -1
- package/dist/api/helpers.d.ts +12 -0
- package/dist/api/helpers.d.ts.map +1 -0
- package/dist/api/helpers.js +68 -0
- package/dist/api/helpers.js.map +1 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/schedules.d.ts.map +1 -1
- package/dist/api/schedules.js.map +1 -1
- package/dist/api/scoping.d.ts +39 -0
- package/dist/api/scoping.d.ts.map +1 -0
- package/dist/api/scoping.js +265 -0
- package/dist/api/scoping.js.map +1 -0
- package/dist/api/types.d.ts +4 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/api/brains.js +192 -581
- package/dist/src/api/helpers.js +280 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/api/scoping.js +756 -0
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
2
|
+
try {
|
|
3
|
+
var info = gen[key](arg);
|
|
4
|
+
var value = info.value;
|
|
5
|
+
} catch (error) {
|
|
6
|
+
reject(error);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (info.done) {
|
|
10
|
+
resolve(value);
|
|
11
|
+
} else {
|
|
12
|
+
Promise.resolve(value).then(_next, _throw);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function _async_to_generator(fn) {
|
|
16
|
+
return function() {
|
|
17
|
+
var self = this, args = arguments;
|
|
18
|
+
return new Promise(function(resolve, reject) {
|
|
19
|
+
var gen = fn.apply(self, args);
|
|
20
|
+
function _next(value) {
|
|
21
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
22
|
+
}
|
|
23
|
+
function _throw(err) {
|
|
24
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
25
|
+
}
|
|
26
|
+
_next(undefined);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function _ts_generator(thisArg, body) {
|
|
31
|
+
var f, y, t, _ = {
|
|
32
|
+
label: 0,
|
|
33
|
+
sent: function() {
|
|
34
|
+
if (t[0] & 1) throw t[1];
|
|
35
|
+
return t[1];
|
|
36
|
+
},
|
|
37
|
+
trys: [],
|
|
38
|
+
ops: []
|
|
39
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
40
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() {
|
|
41
|
+
return this;
|
|
42
|
+
}), g;
|
|
43
|
+
function verb(n) {
|
|
44
|
+
return function(v) {
|
|
45
|
+
return step([
|
|
46
|
+
n,
|
|
47
|
+
v
|
|
48
|
+
]);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function step(op) {
|
|
52
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
53
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
54
|
+
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;
|
|
55
|
+
if (y = 0, t) op = [
|
|
56
|
+
op[0] & 2,
|
|
57
|
+
t.value
|
|
58
|
+
];
|
|
59
|
+
switch(op[0]){
|
|
60
|
+
case 0:
|
|
61
|
+
case 1:
|
|
62
|
+
t = op;
|
|
63
|
+
break;
|
|
64
|
+
case 4:
|
|
65
|
+
_.label++;
|
|
66
|
+
return {
|
|
67
|
+
value: op[1],
|
|
68
|
+
done: false
|
|
69
|
+
};
|
|
70
|
+
case 5:
|
|
71
|
+
_.label++;
|
|
72
|
+
y = op[1];
|
|
73
|
+
op = [
|
|
74
|
+
0
|
|
75
|
+
];
|
|
76
|
+
continue;
|
|
77
|
+
case 7:
|
|
78
|
+
op = _.ops.pop();
|
|
79
|
+
_.trys.pop();
|
|
80
|
+
continue;
|
|
81
|
+
default:
|
|
82
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
83
|
+
_ = 0;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
87
|
+
_.label = op[1];
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
91
|
+
_.label = t[1];
|
|
92
|
+
t = op;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
if (t && _.label < t[2]) {
|
|
96
|
+
_.label = t[2];
|
|
97
|
+
_.ops.push(op);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
if (t[2]) _.ops.pop();
|
|
101
|
+
_.trys.pop();
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
op = body.call(thisArg, _);
|
|
105
|
+
} catch (e) {
|
|
106
|
+
op = [
|
|
107
|
+
6,
|
|
108
|
+
e
|
|
109
|
+
];
|
|
110
|
+
y = 0;
|
|
111
|
+
} finally{
|
|
112
|
+
f = t = 0;
|
|
113
|
+
}
|
|
114
|
+
if (op[0] & 5) throw op[1];
|
|
115
|
+
return {
|
|
116
|
+
value: op[0] ? op[1] : void 0,
|
|
117
|
+
done: true
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
import { BRAIN_EVENTS } from '@positronic/core';
|
|
122
|
+
import { startBrainRun, readSseUntil } from './helpers.js';
|
|
123
|
+
/**
|
|
124
|
+
* Helper: start a brain run as a specific user's fetch, wait for completion,
|
|
125
|
+
* and return the brainRunId.
|
|
126
|
+
*/ function runBrainAndWait(fetchFn, brainIdentifier) {
|
|
127
|
+
return _async_to_generator(function() {
|
|
128
|
+
var brainRunId, watchResponse, error;
|
|
129
|
+
return _ts_generator(this, function(_state) {
|
|
130
|
+
switch(_state.label){
|
|
131
|
+
case 0:
|
|
132
|
+
_state.trys.push([
|
|
133
|
+
0,
|
|
134
|
+
4,
|
|
135
|
+
,
|
|
136
|
+
5
|
|
137
|
+
]);
|
|
138
|
+
return [
|
|
139
|
+
4,
|
|
140
|
+
startBrainRun(fetchFn, brainIdentifier)
|
|
141
|
+
];
|
|
142
|
+
case 1:
|
|
143
|
+
brainRunId = _state.sent();
|
|
144
|
+
if (!brainRunId) return [
|
|
145
|
+
2,
|
|
146
|
+
null
|
|
147
|
+
];
|
|
148
|
+
return [
|
|
149
|
+
4,
|
|
150
|
+
fetchFn(new Request("http://example.com/brains/runs/".concat(brainRunId, "/watch")))
|
|
151
|
+
];
|
|
152
|
+
case 2:
|
|
153
|
+
watchResponse = _state.sent();
|
|
154
|
+
if (!watchResponse.ok || !watchResponse.body) {
|
|
155
|
+
console.error("GET /brains/runs/".concat(brainRunId, "/watch returned ").concat(watchResponse.status));
|
|
156
|
+
return [
|
|
157
|
+
2,
|
|
158
|
+
null
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
return [
|
|
162
|
+
4,
|
|
163
|
+
readSseUntil(watchResponse.body, function(event) {
|
|
164
|
+
return event.type === BRAIN_EVENTS.COMPLETE || event.type === BRAIN_EVENTS.ERROR;
|
|
165
|
+
})
|
|
166
|
+
];
|
|
167
|
+
case 3:
|
|
168
|
+
_state.sent();
|
|
169
|
+
return [
|
|
170
|
+
2,
|
|
171
|
+
brainRunId
|
|
172
|
+
];
|
|
173
|
+
case 4:
|
|
174
|
+
error = _state.sent();
|
|
175
|
+
console.error('Failed to run brain and wait:', error);
|
|
176
|
+
return [
|
|
177
|
+
2,
|
|
178
|
+
null
|
|
179
|
+
];
|
|
180
|
+
case 5:
|
|
181
|
+
return [
|
|
182
|
+
2
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
})();
|
|
187
|
+
}
|
|
188
|
+
export var scoping = {
|
|
189
|
+
brainRunIsolation: /**
|
|
190
|
+
* Test that brain runs are isolated between users.
|
|
191
|
+
*
|
|
192
|
+
* userA creates a run and waits for completion. Then:
|
|
193
|
+
* - userB gets 404 on GET /runs/:runId
|
|
194
|
+
* - root gets 200 on GET /runs/:runId
|
|
195
|
+
* - userA's history has the run
|
|
196
|
+
* - userB's history is empty
|
|
197
|
+
*/ function brainRunIsolation(rootFetch, fetchFactory, brainIdentifier) {
|
|
198
|
+
return _async_to_generator(function() {
|
|
199
|
+
var userA, userB, brainRunId, responseB, responseRoot, rootRun, historyA, historyDataA, historyB, historyDataB, error;
|
|
200
|
+
return _ts_generator(this, function(_state) {
|
|
201
|
+
switch(_state.label){
|
|
202
|
+
case 0:
|
|
203
|
+
_state.trys.push([
|
|
204
|
+
0,
|
|
205
|
+
11,
|
|
206
|
+
,
|
|
207
|
+
12
|
|
208
|
+
]);
|
|
209
|
+
return [
|
|
210
|
+
4,
|
|
211
|
+
fetchFactory('scoping-alice-run')
|
|
212
|
+
];
|
|
213
|
+
case 1:
|
|
214
|
+
userA = _state.sent();
|
|
215
|
+
return [
|
|
216
|
+
4,
|
|
217
|
+
fetchFactory('scoping-bob-run')
|
|
218
|
+
];
|
|
219
|
+
case 2:
|
|
220
|
+
userB = _state.sent();
|
|
221
|
+
return [
|
|
222
|
+
4,
|
|
223
|
+
runBrainAndWait(userA.fetch, brainIdentifier)
|
|
224
|
+
];
|
|
225
|
+
case 3:
|
|
226
|
+
brainRunId = _state.sent();
|
|
227
|
+
if (!brainRunId) {
|
|
228
|
+
console.error('Failed to create and complete brain run as userA');
|
|
229
|
+
return [
|
|
230
|
+
2,
|
|
231
|
+
false
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
return [
|
|
235
|
+
4,
|
|
236
|
+
userB.fetch(new Request("http://example.com/brains/runs/".concat(brainRunId)))
|
|
237
|
+
];
|
|
238
|
+
case 4:
|
|
239
|
+
responseB = _state.sent();
|
|
240
|
+
if (responseB.status !== 404) {
|
|
241
|
+
console.error("Expected userB to get 404 for userA's run, got ".concat(responseB.status));
|
|
242
|
+
return [
|
|
243
|
+
2,
|
|
244
|
+
false
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
return [
|
|
248
|
+
4,
|
|
249
|
+
rootFetch(new Request("http://example.com/brains/runs/".concat(brainRunId)))
|
|
250
|
+
];
|
|
251
|
+
case 5:
|
|
252
|
+
responseRoot = _state.sent();
|
|
253
|
+
if (responseRoot.status !== 200) {
|
|
254
|
+
console.error("Expected root to get 200 for userA's run, got ".concat(responseRoot.status));
|
|
255
|
+
return [
|
|
256
|
+
2,
|
|
257
|
+
false
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
return [
|
|
261
|
+
4,
|
|
262
|
+
responseRoot.json()
|
|
263
|
+
];
|
|
264
|
+
case 6:
|
|
265
|
+
rootRun = _state.sent();
|
|
266
|
+
if (rootRun.brainRunId !== brainRunId) {
|
|
267
|
+
console.error("Root returned wrong brainRunId: expected ".concat(brainRunId, ", got ").concat(rootRun.brainRunId));
|
|
268
|
+
return [
|
|
269
|
+
2,
|
|
270
|
+
false
|
|
271
|
+
];
|
|
272
|
+
}
|
|
273
|
+
return [
|
|
274
|
+
4,
|
|
275
|
+
userA.fetch(new Request("http://example.com/brains/".concat(encodeURIComponent(brainIdentifier), "/history?limit=50")))
|
|
276
|
+
];
|
|
277
|
+
case 7:
|
|
278
|
+
historyA = _state.sent();
|
|
279
|
+
if (historyA.status !== 200) {
|
|
280
|
+
console.error("Expected userA history to return 200, got ".concat(historyA.status));
|
|
281
|
+
return [
|
|
282
|
+
2,
|
|
283
|
+
false
|
|
284
|
+
];
|
|
285
|
+
}
|
|
286
|
+
return [
|
|
287
|
+
4,
|
|
288
|
+
historyA.json()
|
|
289
|
+
];
|
|
290
|
+
case 8:
|
|
291
|
+
historyDataA = _state.sent();
|
|
292
|
+
if (historyDataA.runs.length === 0) {
|
|
293
|
+
console.error("userA's history is empty but should have the run");
|
|
294
|
+
return [
|
|
295
|
+
2,
|
|
296
|
+
false
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
return [
|
|
300
|
+
4,
|
|
301
|
+
userB.fetch(new Request("http://example.com/brains/".concat(encodeURIComponent(brainIdentifier), "/history?limit=50")))
|
|
302
|
+
];
|
|
303
|
+
case 9:
|
|
304
|
+
historyB = _state.sent();
|
|
305
|
+
if (historyB.status !== 200) {
|
|
306
|
+
console.error("Expected userB history to return 200, got ".concat(historyB.status));
|
|
307
|
+
return [
|
|
308
|
+
2,
|
|
309
|
+
false
|
|
310
|
+
];
|
|
311
|
+
}
|
|
312
|
+
return [
|
|
313
|
+
4,
|
|
314
|
+
historyB.json()
|
|
315
|
+
];
|
|
316
|
+
case 10:
|
|
317
|
+
historyDataB = _state.sent();
|
|
318
|
+
if (historyDataB.runs.length !== 0) {
|
|
319
|
+
console.error("userB's history should be empty but has ".concat(historyDataB.runs.length, " runs"));
|
|
320
|
+
return [
|
|
321
|
+
2,
|
|
322
|
+
false
|
|
323
|
+
];
|
|
324
|
+
}
|
|
325
|
+
return [
|
|
326
|
+
2,
|
|
327
|
+
true
|
|
328
|
+
];
|
|
329
|
+
case 11:
|
|
330
|
+
error = _state.sent();
|
|
331
|
+
console.error('Failed brain run isolation spec:', error);
|
|
332
|
+
return [
|
|
333
|
+
2,
|
|
334
|
+
false
|
|
335
|
+
];
|
|
336
|
+
case 12:
|
|
337
|
+
return [
|
|
338
|
+
2
|
|
339
|
+
];
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
})();
|
|
343
|
+
},
|
|
344
|
+
activeRunIsolation: /**
|
|
345
|
+
* Test that active runs are isolated between users.
|
|
346
|
+
*
|
|
347
|
+
* userA starts a delayed brain (will remain running).
|
|
348
|
+
* - userA sees it in active-runs
|
|
349
|
+
* - userB does not see it in active-runs
|
|
350
|
+
*/ function activeRunIsolation(rootFetch, fetchFactory, delayedBrainIdentifier) {
|
|
351
|
+
return _async_to_generator(function() {
|
|
352
|
+
var userA, userB, brainRunId, responseB, activeB, responseA, activeA, error;
|
|
353
|
+
return _ts_generator(this, function(_state) {
|
|
354
|
+
switch(_state.label){
|
|
355
|
+
case 0:
|
|
356
|
+
_state.trys.push([
|
|
357
|
+
0,
|
|
358
|
+
8,
|
|
359
|
+
,
|
|
360
|
+
9
|
|
361
|
+
]);
|
|
362
|
+
return [
|
|
363
|
+
4,
|
|
364
|
+
fetchFactory('scoping-alice-active')
|
|
365
|
+
];
|
|
366
|
+
case 1:
|
|
367
|
+
userA = _state.sent();
|
|
368
|
+
return [
|
|
369
|
+
4,
|
|
370
|
+
fetchFactory('scoping-bob-active')
|
|
371
|
+
];
|
|
372
|
+
case 2:
|
|
373
|
+
userB = _state.sent();
|
|
374
|
+
return [
|
|
375
|
+
4,
|
|
376
|
+
startBrainRun(userA.fetch, delayedBrainIdentifier)
|
|
377
|
+
];
|
|
378
|
+
case 3:
|
|
379
|
+
brainRunId = _state.sent();
|
|
380
|
+
if (!brainRunId) return [
|
|
381
|
+
2,
|
|
382
|
+
false
|
|
383
|
+
];
|
|
384
|
+
return [
|
|
385
|
+
4,
|
|
386
|
+
userB.fetch(new Request("http://example.com/brains/".concat(encodeURIComponent(delayedBrainIdentifier), "/active-runs")))
|
|
387
|
+
];
|
|
388
|
+
case 4:
|
|
389
|
+
responseB = _state.sent();
|
|
390
|
+
if (responseB.status !== 200) {
|
|
391
|
+
console.error("Expected userB active-runs to return 200, got ".concat(responseB.status));
|
|
392
|
+
return [
|
|
393
|
+
2,
|
|
394
|
+
false
|
|
395
|
+
];
|
|
396
|
+
}
|
|
397
|
+
return [
|
|
398
|
+
4,
|
|
399
|
+
responseB.json()
|
|
400
|
+
];
|
|
401
|
+
case 5:
|
|
402
|
+
activeB = _state.sent();
|
|
403
|
+
if (activeB.runs.length !== 0) {
|
|
404
|
+
console.error("userB should see 0 active runs but sees ".concat(activeB.runs.length));
|
|
405
|
+
return [
|
|
406
|
+
2,
|
|
407
|
+
false
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
return [
|
|
411
|
+
4,
|
|
412
|
+
userA.fetch(new Request("http://example.com/brains/".concat(encodeURIComponent(delayedBrainIdentifier), "/active-runs")))
|
|
413
|
+
];
|
|
414
|
+
case 6:
|
|
415
|
+
responseA = _state.sent();
|
|
416
|
+
if (responseA.status !== 200) {
|
|
417
|
+
console.error("Expected userA active-runs to return 200, got ".concat(responseA.status));
|
|
418
|
+
return [
|
|
419
|
+
2,
|
|
420
|
+
false
|
|
421
|
+
];
|
|
422
|
+
}
|
|
423
|
+
return [
|
|
424
|
+
4,
|
|
425
|
+
responseA.json()
|
|
426
|
+
];
|
|
427
|
+
case 7:
|
|
428
|
+
activeA = _state.sent();
|
|
429
|
+
if (activeA.runs.length === 0) {
|
|
430
|
+
console.error('userA should see at least 1 active run but sees 0');
|
|
431
|
+
return [
|
|
432
|
+
2,
|
|
433
|
+
false
|
|
434
|
+
];
|
|
435
|
+
}
|
|
436
|
+
return [
|
|
437
|
+
2,
|
|
438
|
+
true
|
|
439
|
+
];
|
|
440
|
+
case 8:
|
|
441
|
+
error = _state.sent();
|
|
442
|
+
console.error('Failed active run isolation spec:', error);
|
|
443
|
+
return [
|
|
444
|
+
2,
|
|
445
|
+
false
|
|
446
|
+
];
|
|
447
|
+
case 9:
|
|
448
|
+
return [
|
|
449
|
+
2
|
|
450
|
+
];
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
})();
|
|
454
|
+
},
|
|
455
|
+
scheduleIsolation: /**
|
|
456
|
+
* Test that schedules are isolated between users.
|
|
457
|
+
*
|
|
458
|
+
* userA creates a schedule. Then:
|
|
459
|
+
* - userB can't see it in GET /schedules
|
|
460
|
+
* - userA can see it in GET /schedules
|
|
461
|
+
* - root can see it in GET /schedules
|
|
462
|
+
* - userB can't see runs for it in GET /schedules/runs
|
|
463
|
+
*/ function scheduleIsolation(rootFetch, fetchFactory, brainIdentifier) {
|
|
464
|
+
return _async_to_generator(function() {
|
|
465
|
+
var userA, userB, createResponse, schedule, listResponseB, listB, listResponseA, listA, listResponseRoot, listRoot, runsResponseB, runsB, error;
|
|
466
|
+
return _ts_generator(this, function(_state) {
|
|
467
|
+
switch(_state.label){
|
|
468
|
+
case 0:
|
|
469
|
+
_state.trys.push([
|
|
470
|
+
0,
|
|
471
|
+
13,
|
|
472
|
+
,
|
|
473
|
+
14
|
|
474
|
+
]);
|
|
475
|
+
return [
|
|
476
|
+
4,
|
|
477
|
+
fetchFactory('scoping-alice-sched')
|
|
478
|
+
];
|
|
479
|
+
case 1:
|
|
480
|
+
userA = _state.sent();
|
|
481
|
+
return [
|
|
482
|
+
4,
|
|
483
|
+
fetchFactory('scoping-bob-sched')
|
|
484
|
+
];
|
|
485
|
+
case 2:
|
|
486
|
+
userB = _state.sent();
|
|
487
|
+
return [
|
|
488
|
+
4,
|
|
489
|
+
userA.fetch(new Request('http://example.com/brains/schedules', {
|
|
490
|
+
method: 'POST',
|
|
491
|
+
headers: {
|
|
492
|
+
'Content-Type': 'application/json'
|
|
493
|
+
},
|
|
494
|
+
body: JSON.stringify({
|
|
495
|
+
identifier: brainIdentifier,
|
|
496
|
+
cronExpression: '0 6 * * *'
|
|
497
|
+
})
|
|
498
|
+
}))
|
|
499
|
+
];
|
|
500
|
+
case 3:
|
|
501
|
+
createResponse = _state.sent();
|
|
502
|
+
if (createResponse.status !== 201) {
|
|
503
|
+
console.error("POST /brains/schedules returned ".concat(createResponse.status, ", expected 201"));
|
|
504
|
+
return [
|
|
505
|
+
2,
|
|
506
|
+
false
|
|
507
|
+
];
|
|
508
|
+
}
|
|
509
|
+
return [
|
|
510
|
+
4,
|
|
511
|
+
createResponse.json()
|
|
512
|
+
];
|
|
513
|
+
case 4:
|
|
514
|
+
schedule = _state.sent();
|
|
515
|
+
if (schedule.runAsUserId !== userA.userId) {
|
|
516
|
+
console.error("Expected runAsUserId to be '".concat(userA.userId, "', got '").concat(schedule.runAsUserId, "'"));
|
|
517
|
+
return [
|
|
518
|
+
2,
|
|
519
|
+
false
|
|
520
|
+
];
|
|
521
|
+
}
|
|
522
|
+
return [
|
|
523
|
+
4,
|
|
524
|
+
userB.fetch(new Request('http://example.com/brains/schedules'))
|
|
525
|
+
];
|
|
526
|
+
case 5:
|
|
527
|
+
listResponseB = _state.sent();
|
|
528
|
+
if (listResponseB.status !== 200) {
|
|
529
|
+
console.error("Expected userB schedule list to return 200, got ".concat(listResponseB.status));
|
|
530
|
+
return [
|
|
531
|
+
2,
|
|
532
|
+
false
|
|
533
|
+
];
|
|
534
|
+
}
|
|
535
|
+
return [
|
|
536
|
+
4,
|
|
537
|
+
listResponseB.json()
|
|
538
|
+
];
|
|
539
|
+
case 6:
|
|
540
|
+
listB = _state.sent();
|
|
541
|
+
if (listB.schedules.some(function(s) {
|
|
542
|
+
return s.id === schedule.id;
|
|
543
|
+
})) {
|
|
544
|
+
console.error("userB should not see userA's schedule in list");
|
|
545
|
+
return [
|
|
546
|
+
2,
|
|
547
|
+
false
|
|
548
|
+
];
|
|
549
|
+
}
|
|
550
|
+
return [
|
|
551
|
+
4,
|
|
552
|
+
userA.fetch(new Request('http://example.com/brains/schedules'))
|
|
553
|
+
];
|
|
554
|
+
case 7:
|
|
555
|
+
listResponseA = _state.sent();
|
|
556
|
+
if (listResponseA.status !== 200) {
|
|
557
|
+
console.error("Expected userA schedule list to return 200, got ".concat(listResponseA.status));
|
|
558
|
+
return [
|
|
559
|
+
2,
|
|
560
|
+
false
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
return [
|
|
564
|
+
4,
|
|
565
|
+
listResponseA.json()
|
|
566
|
+
];
|
|
567
|
+
case 8:
|
|
568
|
+
listA = _state.sent();
|
|
569
|
+
if (!listA.schedules.some(function(s) {
|
|
570
|
+
return s.id === schedule.id;
|
|
571
|
+
})) {
|
|
572
|
+
console.error("userA should see their own schedule in list");
|
|
573
|
+
return [
|
|
574
|
+
2,
|
|
575
|
+
false
|
|
576
|
+
];
|
|
577
|
+
}
|
|
578
|
+
return [
|
|
579
|
+
4,
|
|
580
|
+
rootFetch(new Request('http://example.com/brains/schedules'))
|
|
581
|
+
];
|
|
582
|
+
case 9:
|
|
583
|
+
listResponseRoot = _state.sent();
|
|
584
|
+
if (listResponseRoot.status !== 200) {
|
|
585
|
+
console.error("Expected root schedule list to return 200, got ".concat(listResponseRoot.status));
|
|
586
|
+
return [
|
|
587
|
+
2,
|
|
588
|
+
false
|
|
589
|
+
];
|
|
590
|
+
}
|
|
591
|
+
return [
|
|
592
|
+
4,
|
|
593
|
+
listResponseRoot.json()
|
|
594
|
+
];
|
|
595
|
+
case 10:
|
|
596
|
+
listRoot = _state.sent();
|
|
597
|
+
if (!listRoot.schedules.some(function(s) {
|
|
598
|
+
return s.id === schedule.id;
|
|
599
|
+
})) {
|
|
600
|
+
console.error("root should see userA's schedule in list");
|
|
601
|
+
return [
|
|
602
|
+
2,
|
|
603
|
+
false
|
|
604
|
+
];
|
|
605
|
+
}
|
|
606
|
+
return [
|
|
607
|
+
4,
|
|
608
|
+
userB.fetch(new Request("http://example.com/brains/schedules/runs?scheduleId=".concat(schedule.id)))
|
|
609
|
+
];
|
|
610
|
+
case 11:
|
|
611
|
+
runsResponseB = _state.sent();
|
|
612
|
+
if (runsResponseB.status !== 200) {
|
|
613
|
+
console.error("Expected userB schedule runs to return 200, got ".concat(runsResponseB.status));
|
|
614
|
+
return [
|
|
615
|
+
2,
|
|
616
|
+
false
|
|
617
|
+
];
|
|
618
|
+
}
|
|
619
|
+
return [
|
|
620
|
+
4,
|
|
621
|
+
runsResponseB.json()
|
|
622
|
+
];
|
|
623
|
+
case 12:
|
|
624
|
+
runsB = _state.sent();
|
|
625
|
+
if (runsB.runs.length !== 0) {
|
|
626
|
+
console.error("userB should see 0 schedule runs but sees ".concat(runsB.runs.length));
|
|
627
|
+
return [
|
|
628
|
+
2,
|
|
629
|
+
false
|
|
630
|
+
];
|
|
631
|
+
}
|
|
632
|
+
return [
|
|
633
|
+
2,
|
|
634
|
+
true
|
|
635
|
+
];
|
|
636
|
+
case 13:
|
|
637
|
+
error = _state.sent();
|
|
638
|
+
console.error('Failed schedule isolation spec:', error);
|
|
639
|
+
return [
|
|
640
|
+
2,
|
|
641
|
+
false
|
|
642
|
+
];
|
|
643
|
+
case 14:
|
|
644
|
+
return [
|
|
645
|
+
2
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
})();
|
|
650
|
+
},
|
|
651
|
+
secretsRequireRoot: /**
|
|
652
|
+
* Test that non-root users get 403 on secrets endpoints.
|
|
653
|
+
*
|
|
654
|
+
* A non-root user calling GET/POST/DELETE /secrets gets 403.
|
|
655
|
+
* (Root access to secrets is already tested by secrets.list spec.)
|
|
656
|
+
*/ function secretsRequireRoot(rootFetch, fetchFactory) {
|
|
657
|
+
return _async_to_generator(function() {
|
|
658
|
+
var user, getResponse, getBody, postResponse, deleteResponse, error;
|
|
659
|
+
return _ts_generator(this, function(_state) {
|
|
660
|
+
switch(_state.label){
|
|
661
|
+
case 0:
|
|
662
|
+
_state.trys.push([
|
|
663
|
+
0,
|
|
664
|
+
6,
|
|
665
|
+
,
|
|
666
|
+
7
|
|
667
|
+
]);
|
|
668
|
+
return [
|
|
669
|
+
4,
|
|
670
|
+
fetchFactory('scoping-user-secrets')
|
|
671
|
+
];
|
|
672
|
+
case 1:
|
|
673
|
+
user = _state.sent();
|
|
674
|
+
return [
|
|
675
|
+
4,
|
|
676
|
+
user.fetch(new Request('http://example.com/secrets'))
|
|
677
|
+
];
|
|
678
|
+
case 2:
|
|
679
|
+
getResponse = _state.sent();
|
|
680
|
+
if (getResponse.status !== 403) {
|
|
681
|
+
console.error("Expected non-root GET /secrets to return 403, got ".concat(getResponse.status));
|
|
682
|
+
return [
|
|
683
|
+
2,
|
|
684
|
+
false
|
|
685
|
+
];
|
|
686
|
+
}
|
|
687
|
+
return [
|
|
688
|
+
4,
|
|
689
|
+
getResponse.json()
|
|
690
|
+
];
|
|
691
|
+
case 3:
|
|
692
|
+
getBody = _state.sent();
|
|
693
|
+
if (getBody.error !== 'Root access required') {
|
|
694
|
+
console.error("Expected error 'Root access required', got '".concat(getBody.error, "'"));
|
|
695
|
+
return [
|
|
696
|
+
2,
|
|
697
|
+
false
|
|
698
|
+
];
|
|
699
|
+
}
|
|
700
|
+
return [
|
|
701
|
+
4,
|
|
702
|
+
user.fetch(new Request('http://example.com/secrets', {
|
|
703
|
+
method: 'POST',
|
|
704
|
+
headers: {
|
|
705
|
+
'Content-Type': 'application/json'
|
|
706
|
+
},
|
|
707
|
+
body: JSON.stringify({
|
|
708
|
+
name: 'MY_SECRET',
|
|
709
|
+
value: 'secret-value'
|
|
710
|
+
})
|
|
711
|
+
}))
|
|
712
|
+
];
|
|
713
|
+
case 4:
|
|
714
|
+
postResponse = _state.sent();
|
|
715
|
+
if (postResponse.status !== 403) {
|
|
716
|
+
console.error("Expected non-root POST /secrets to return 403, got ".concat(postResponse.status));
|
|
717
|
+
return [
|
|
718
|
+
2,
|
|
719
|
+
false
|
|
720
|
+
];
|
|
721
|
+
}
|
|
722
|
+
return [
|
|
723
|
+
4,
|
|
724
|
+
user.fetch(new Request('http://example.com/secrets/MY_SECRET', {
|
|
725
|
+
method: 'DELETE'
|
|
726
|
+
}))
|
|
727
|
+
];
|
|
728
|
+
case 5:
|
|
729
|
+
deleteResponse = _state.sent();
|
|
730
|
+
if (deleteResponse.status !== 403) {
|
|
731
|
+
console.error("Expected non-root DELETE /secrets to return 403, got ".concat(deleteResponse.status));
|
|
732
|
+
return [
|
|
733
|
+
2,
|
|
734
|
+
false
|
|
735
|
+
];
|
|
736
|
+
}
|
|
737
|
+
return [
|
|
738
|
+
2,
|
|
739
|
+
true
|
|
740
|
+
];
|
|
741
|
+
case 6:
|
|
742
|
+
error = _state.sent();
|
|
743
|
+
console.error('Failed secrets require root spec:', error);
|
|
744
|
+
return [
|
|
745
|
+
2,
|
|
746
|
+
false
|
|
747
|
+
];
|
|
748
|
+
case 7:
|
|
749
|
+
return [
|
|
750
|
+
2
|
|
751
|
+
];
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
})();
|
|
755
|
+
}
|
|
756
|
+
};
|