@vltpkg/vsr 0.2.0 → 0.2.1
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/README.md +1 -1
- package/package.json +6 -2
- package/test/README.md +0 -91
- package/test/access.test.js +0 -760
- package/test/cloudflare-waituntil.test.js +0 -141
- package/test/db.test.js +0 -447
- package/test/dist-tag.test.js +0 -415
- package/test/e2e.test.js +0 -904
- package/test/hono-context.test.js +0 -250
- package/test/integrity-validation.test.js +0 -183
- package/test/json-response.test.js +0 -76
- package/test/manifest-slimming.test.js +0 -449
- package/test/packument-consistency.test.js +0 -351
- package/test/packument-version-range.test.js +0 -144
- package/test/performance.test.js +0 -162
- package/test/route-with-waituntil.test.js +0 -298
- package/test/run-tests.js +0 -151
- package/test/setup-cache-tests.js +0 -190
- package/test/setup.js +0 -64
- package/test/stale-while-revalidate.test.js +0 -273
- package/test/static-assets.test.js +0 -85
- package/test/upstream-routing.test.js +0 -86
- package/test/utils/test-helpers.js +0 -84
- package/test/waituntil-correct.test.js +0 -208
- package/test/waituntil-demo.test.js +0 -138
- package/test/waituntil-readme.md +0 -113
package/test/access.test.js
DELETED
|
@@ -1,760 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { createContext } from './utils/test-helpers.js';
|
|
3
|
-
|
|
4
|
-
// Mock the database client
|
|
5
|
-
const mockDb = {
|
|
6
|
-
getPackage: vi.fn(),
|
|
7
|
-
upsertToken: vi.fn(),
|
|
8
|
-
query: {
|
|
9
|
-
tokens: {
|
|
10
|
-
findMany: vi.fn()
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
// Mock auth utilities
|
|
16
|
-
vi.mock('../src/utils/auth.js', async () => {
|
|
17
|
-
const actual = await vi.importActual('../src/utils/auth.js');
|
|
18
|
-
return {
|
|
19
|
-
...actual,
|
|
20
|
-
verifyToken: vi.fn().mockImplementation(() => true),
|
|
21
|
-
getTokenFromHeader: vi.fn().mockImplementation(() => 'test-token'),
|
|
22
|
-
getAuthedUser: vi.fn()
|
|
23
|
-
};
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// Mock utils
|
|
27
|
-
import { getTokenFromHeader, getAuthedUser, verifyToken, parseTokenAccess } from '../src/utils/auth.ts';
|
|
28
|
-
|
|
29
|
-
// Import functions to test
|
|
30
|
-
import {
|
|
31
|
-
listPackagesAccess,
|
|
32
|
-
getPackageAccessStatus,
|
|
33
|
-
setPackageAccessStatus,
|
|
34
|
-
grantPackageAccess,
|
|
35
|
-
revokePackageAccess
|
|
36
|
-
} from '../src/routes/access.js';
|
|
37
|
-
|
|
38
|
-
describe('Access Management API', () => {
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
vi.clearAllMocks();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
afterEach(() => {
|
|
44
|
-
vi.resetAllMocks();
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('listPackagesAccess', () => {
|
|
48
|
-
it('should list packages a user has access to', async () => {
|
|
49
|
-
// Mock authentication
|
|
50
|
-
getAuthedUser.mockResolvedValue({
|
|
51
|
-
uuid: 'test-user',
|
|
52
|
-
scope: [
|
|
53
|
-
{
|
|
54
|
-
values: ['package-1', 'package-2'],
|
|
55
|
-
types: { pkg: { read: true, write: true } }
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
values: ['package-3'],
|
|
59
|
-
types: { pkg: { read: true, write: false } }
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Mock DB response
|
|
65
|
-
mockDb.query.tokens.findMany.mockResolvedValue([
|
|
66
|
-
{
|
|
67
|
-
token: 'test-token',
|
|
68
|
-
uuid: 'test-user',
|
|
69
|
-
scope: JSON.stringify([
|
|
70
|
-
{
|
|
71
|
-
values: ['package-1', 'package-2'],
|
|
72
|
-
types: { pkg: { read: true, write: true } }
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
values: ['package-3'],
|
|
76
|
-
types: { pkg: { read: true, write: false } }
|
|
77
|
-
}
|
|
78
|
-
])
|
|
79
|
-
}
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
// Create test context
|
|
83
|
-
const c = createContext({
|
|
84
|
-
req: {
|
|
85
|
-
method: 'GET',
|
|
86
|
-
query: new Map([['user', 'test-user']])
|
|
87
|
-
},
|
|
88
|
-
db: mockDb
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// Execute function
|
|
92
|
-
const response = await listPackagesAccess(c);
|
|
93
|
-
|
|
94
|
-
// Verify mock calls
|
|
95
|
-
expect(verifyToken).toHaveBeenCalledWith('test-token', expect.anything());
|
|
96
|
-
expect(getAuthedUser).toHaveBeenCalledWith({ c, token: 'test-token' });
|
|
97
|
-
expect(mockDb.query.tokens.findMany).toHaveBeenCalled();
|
|
98
|
-
|
|
99
|
-
// Verify response
|
|
100
|
-
expect(response.status).toBe(200);
|
|
101
|
-
const body = await response.json();
|
|
102
|
-
expect(body).toEqual({
|
|
103
|
-
'package-1': { read: true, write: true },
|
|
104
|
-
'package-2': { read: true, write: true },
|
|
105
|
-
'package-3': { read: true, write: false }
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('should return unauthorized if not authenticated', async () => {
|
|
110
|
-
// Mock failed authentication
|
|
111
|
-
verifyToken.mockResolvedValue(false);
|
|
112
|
-
|
|
113
|
-
// Create test context
|
|
114
|
-
const c = createContext({
|
|
115
|
-
req: { method: 'GET' },
|
|
116
|
-
db: mockDb
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Execute function
|
|
120
|
-
const response = await listPackagesAccess(c);
|
|
121
|
-
|
|
122
|
-
// Verify response
|
|
123
|
-
expect(response.status).toBe(401);
|
|
124
|
-
const body = await response.json();
|
|
125
|
-
expect(body).toEqual({ error: 'Unauthorized' });
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should return empty result if user has no tokens', async () => {
|
|
129
|
-
// Mock authentication
|
|
130
|
-
getAuthedUser.mockResolvedValue({
|
|
131
|
-
uuid: 'test-user',
|
|
132
|
-
scope: []
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// Mock DB response - no tokens
|
|
136
|
-
mockDb.query.tokens.findMany.mockResolvedValue([]);
|
|
137
|
-
|
|
138
|
-
// Create test context
|
|
139
|
-
const c = createContext({
|
|
140
|
-
req: { method: 'GET' },
|
|
141
|
-
db: mockDb
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
// Execute function
|
|
145
|
-
const response = await listPackagesAccess(c);
|
|
146
|
-
|
|
147
|
-
// Verify response
|
|
148
|
-
expect(response.status).toBe(200);
|
|
149
|
-
const body = await response.json();
|
|
150
|
-
expect(body).toEqual({});
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
describe('getPackageAccessStatus', () => {
|
|
155
|
-
it('should return private status for existing package', async () => {
|
|
156
|
-
// Mock package data
|
|
157
|
-
mockDb.getPackage.mockResolvedValue({
|
|
158
|
-
name: 'test-package',
|
|
159
|
-
tags: { latest: '1.0.0' }
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Create test context with package param
|
|
163
|
-
const c = createContext({
|
|
164
|
-
req: { method: 'GET' },
|
|
165
|
-
db: mockDb,
|
|
166
|
-
// Mock packageSpec functionality
|
|
167
|
-
pkg: 'test-package'
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
// Execute function
|
|
171
|
-
const response = await getPackageAccessStatus(c);
|
|
172
|
-
|
|
173
|
-
// Verify mock calls
|
|
174
|
-
expect(mockDb.getPackage).toHaveBeenCalledWith('test-package');
|
|
175
|
-
|
|
176
|
-
// Verify response
|
|
177
|
-
expect(response.status).toBe(200);
|
|
178
|
-
const body = await response.json();
|
|
179
|
-
expect(body).toEqual({ status: 'private' });
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('should return private status for non-existent package', async () => {
|
|
183
|
-
// Mock package data - not found
|
|
184
|
-
mockDb.getPackage.mockResolvedValue(null);
|
|
185
|
-
|
|
186
|
-
// Create test context with package param
|
|
187
|
-
const c = createContext({
|
|
188
|
-
req: { method: 'GET' },
|
|
189
|
-
db: mockDb,
|
|
190
|
-
// Mock packageSpec functionality
|
|
191
|
-
pkg: 'non-existent-package'
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
// Execute function
|
|
195
|
-
const response = await getPackageAccessStatus(c);
|
|
196
|
-
|
|
197
|
-
// Verify response
|
|
198
|
-
expect(response.status).toBe(200);
|
|
199
|
-
const body = await response.json();
|
|
200
|
-
expect(body).toEqual({ status: 'private' });
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
describe('setPackageAccessStatus', () => {
|
|
205
|
-
it('should accept setting a package to private', async () => {
|
|
206
|
-
// Mock package data
|
|
207
|
-
mockDb.getPackage.mockResolvedValue({
|
|
208
|
-
name: 'test-package',
|
|
209
|
-
tags: { latest: '1.0.0' }
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
// Mock authentication with write access
|
|
213
|
-
getAuthedUser.mockResolvedValue({
|
|
214
|
-
uuid: 'test-user',
|
|
215
|
-
scope: [
|
|
216
|
-
{
|
|
217
|
-
values: ['test-package'],
|
|
218
|
-
types: { pkg: { read: true, write: true } }
|
|
219
|
-
}
|
|
220
|
-
]
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
// Mock the token access parsing
|
|
224
|
-
vi.mock('../src/utils/auth.js', async () => {
|
|
225
|
-
const actual = await vi.importActual('../src/utils/auth.js');
|
|
226
|
-
return {
|
|
227
|
-
...actual,
|
|
228
|
-
verifyToken: vi.fn().mockImplementation(() => true),
|
|
229
|
-
getTokenFromHeader: vi.fn().mockImplementation(() => 'test-token'),
|
|
230
|
-
getAuthedUser: vi.fn(),
|
|
231
|
-
parseTokenAccess: vi.fn().mockImplementation(() => ({
|
|
232
|
-
readAccess: true,
|
|
233
|
-
writeAccess: true
|
|
234
|
-
}))
|
|
235
|
-
};
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
// Create test context
|
|
239
|
-
const c = createContext({
|
|
240
|
-
req: {
|
|
241
|
-
method: 'PUT',
|
|
242
|
-
body: { status: 'private' }
|
|
243
|
-
},
|
|
244
|
-
db: mockDb,
|
|
245
|
-
pkg: 'test-package'
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
// Execute function
|
|
249
|
-
const response = await setPackageAccessStatus(c);
|
|
250
|
-
|
|
251
|
-
// Verify response
|
|
252
|
-
expect(response.status).toBe(200);
|
|
253
|
-
const body = await response.json();
|
|
254
|
-
expect(body.success).toBe(true);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('should reject setting a package to public', async () => {
|
|
258
|
-
// Mock package data
|
|
259
|
-
mockDb.getPackage.mockResolvedValue({
|
|
260
|
-
name: 'test-package',
|
|
261
|
-
tags: { latest: '1.0.0' }
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
// Mock admin user with write access
|
|
265
|
-
getAuthedUser.mockResolvedValue({
|
|
266
|
-
uuid: 'admin',
|
|
267
|
-
scope: [
|
|
268
|
-
{
|
|
269
|
-
values: ['*'],
|
|
270
|
-
types: { pkg: { read: true, write: true } }
|
|
271
|
-
}
|
|
272
|
-
]
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Create test context
|
|
276
|
-
const c = createContext({
|
|
277
|
-
req: {
|
|
278
|
-
method: 'PUT',
|
|
279
|
-
json: async () => ({ status: 'public' })
|
|
280
|
-
},
|
|
281
|
-
db: mockDb,
|
|
282
|
-
// Mock packageSpec functionality
|
|
283
|
-
pkg: 'test-package'
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
// Execute function
|
|
287
|
-
const response = await setPackageAccessStatus(c);
|
|
288
|
-
|
|
289
|
-
// Verify response
|
|
290
|
-
expect(response.status).toBe(400);
|
|
291
|
-
const body = await response.json();
|
|
292
|
-
expect(body).toEqual({
|
|
293
|
-
error: 'Public packages are not supported by this registry at this time'
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('should reject if user lacks write access', async () => {
|
|
298
|
-
// Mock package data
|
|
299
|
-
mockDb.getPackage.mockResolvedValue({
|
|
300
|
-
name: 'test-package',
|
|
301
|
-
tags: { latest: '1.0.0' }
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
// Mock user with only read access
|
|
305
|
-
getAuthedUser.mockResolvedValue({
|
|
306
|
-
uuid: 'regular-user',
|
|
307
|
-
scope: [
|
|
308
|
-
{
|
|
309
|
-
values: ['test-package'],
|
|
310
|
-
types: { pkg: { read: true, write: false } }
|
|
311
|
-
}
|
|
312
|
-
]
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
// Create test context
|
|
316
|
-
const c = createContext({
|
|
317
|
-
req: {
|
|
318
|
-
method: 'PUT',
|
|
319
|
-
json: async () => ({ status: 'private' })
|
|
320
|
-
},
|
|
321
|
-
db: mockDb,
|
|
322
|
-
// Mock packageSpec functionality
|
|
323
|
-
pkg: 'test-package'
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
// Execute function
|
|
327
|
-
const response = await setPackageAccessStatus(c);
|
|
328
|
-
|
|
329
|
-
// Verify response
|
|
330
|
-
expect(response.status).toBe(403);
|
|
331
|
-
const body = await response.json();
|
|
332
|
-
expect(body).toEqual({
|
|
333
|
-
error: 'Unauthorized - you do not have write access to this package'
|
|
334
|
-
});
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe('grantPackageAccess', () => {
|
|
339
|
-
it('should grant read-only access to a user', async () => {
|
|
340
|
-
// Mock package data
|
|
341
|
-
mockDb.getPackage.mockResolvedValue({
|
|
342
|
-
name: 'test-package',
|
|
343
|
-
tags: { latest: '1.0.0' }
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// Mock authentication
|
|
347
|
-
getAuthedUser.mockResolvedValue({
|
|
348
|
-
uuid: 'admin-user',
|
|
349
|
-
scope: [
|
|
350
|
-
{
|
|
351
|
-
values: ['*'],
|
|
352
|
-
types: {
|
|
353
|
-
user: { read: true, write: true },
|
|
354
|
-
pkg: { read: true, write: true }
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
]
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
// Create test context
|
|
361
|
-
const c = createContext({
|
|
362
|
-
req: {
|
|
363
|
-
method: 'PUT',
|
|
364
|
-
body: { permission: 'read-only' }
|
|
365
|
-
},
|
|
366
|
-
db: mockDb,
|
|
367
|
-
pkg: 'test-package',
|
|
368
|
-
username: 'test-user'
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
// Execute function
|
|
372
|
-
const response = await grantPackageAccess(c);
|
|
373
|
-
|
|
374
|
-
// Verify mock calls
|
|
375
|
-
expect(mockDb.upsertToken).toHaveBeenCalled();
|
|
376
|
-
|
|
377
|
-
// Verify the arguments manually since the deep comparison isn't working in tests
|
|
378
|
-
const callArgs = mockDb.upsertToken.mock.calls[0];
|
|
379
|
-
expect(callArgs[0]).toBe('user-token'); // First arg: token
|
|
380
|
-
expect(callArgs[1]).toBe('test-user'); // Second arg: username
|
|
381
|
-
|
|
382
|
-
// Third arg - scope object validation
|
|
383
|
-
const scope = callArgs[2];
|
|
384
|
-
expect(Array.isArray(scope)).toBe(true);
|
|
385
|
-
expect(scope.length).toBe(1);
|
|
386
|
-
expect(scope[0].values).toContain('test-package');
|
|
387
|
-
expect(scope[0].types.pkg.read).toBe(true);
|
|
388
|
-
expect(scope[0].types.pkg.write).toBe(false);
|
|
389
|
-
|
|
390
|
-
// Verify response
|
|
391
|
-
expect(response.status).toBe(200);
|
|
392
|
-
const body = await response.json();
|
|
393
|
-
expect(body.success).toBe(true);
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
it('should grant read-write access to a user', async () => {
|
|
397
|
-
// Mock package data
|
|
398
|
-
mockDb.getPackage.mockResolvedValue({
|
|
399
|
-
name: 'test-package',
|
|
400
|
-
tags: { latest: '1.0.0' }
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
// Mock admin user with write access to users and packages
|
|
404
|
-
getAuthedUser.mockResolvedValue({
|
|
405
|
-
uuid: 'admin',
|
|
406
|
-
scope: [
|
|
407
|
-
{
|
|
408
|
-
values: ['*'],
|
|
409
|
-
types: {
|
|
410
|
-
pkg: { read: true, write: true },
|
|
411
|
-
user: { read: true, write: true }
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
]
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// Mock existing user tokens
|
|
418
|
-
mockDb.query.tokens.findMany.mockResolvedValue([
|
|
419
|
-
{
|
|
420
|
-
token: 'user-token',
|
|
421
|
-
uuid: 'test-user',
|
|
422
|
-
scope: JSON.stringify([])
|
|
423
|
-
}
|
|
424
|
-
]);
|
|
425
|
-
|
|
426
|
-
// Create test context
|
|
427
|
-
const c = createContext({
|
|
428
|
-
req: {
|
|
429
|
-
method: 'PUT',
|
|
430
|
-
param: new Map([['username', 'test-user']]),
|
|
431
|
-
json: async () => ({ permission: 'read-write' })
|
|
432
|
-
},
|
|
433
|
-
db: mockDb,
|
|
434
|
-
// Mock packageSpec functionality
|
|
435
|
-
pkg: 'test-package'
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
// Execute function
|
|
439
|
-
const response = await grantPackageAccess(c);
|
|
440
|
-
|
|
441
|
-
// Verify mock calls
|
|
442
|
-
expect(mockDb.upsertToken).toHaveBeenCalledWith(
|
|
443
|
-
'user-token',
|
|
444
|
-
'test-user',
|
|
445
|
-
[
|
|
446
|
-
{
|
|
447
|
-
values: ['test-package'],
|
|
448
|
-
types: { pkg: { read: true, write: true } }
|
|
449
|
-
}
|
|
450
|
-
],
|
|
451
|
-
'test-token'
|
|
452
|
-
);
|
|
453
|
-
|
|
454
|
-
// Verify response
|
|
455
|
-
expect(response.status).toBe(200);
|
|
456
|
-
const body = await response.json();
|
|
457
|
-
expect(body).toEqual({
|
|
458
|
-
success: true,
|
|
459
|
-
message: 'Added read-write permission for test-user on test-package'
|
|
460
|
-
});
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
it('should update existing package access', async () => {
|
|
464
|
-
// Mock package data
|
|
465
|
-
mockDb.getPackage.mockResolvedValue({
|
|
466
|
-
name: 'test-package',
|
|
467
|
-
tags: { latest: '1.0.0' }
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
// Mock admin user with write access to users and packages
|
|
471
|
-
getAuthedUser.mockResolvedValue({
|
|
472
|
-
uuid: 'admin',
|
|
473
|
-
scope: [
|
|
474
|
-
{
|
|
475
|
-
values: ['*'],
|
|
476
|
-
types: {
|
|
477
|
-
pkg: { read: true, write: true },
|
|
478
|
-
user: { read: true, write: true }
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
]
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
// Mock existing user tokens with existing access
|
|
485
|
-
mockDb.query.tokens.findMany.mockResolvedValue([
|
|
486
|
-
{
|
|
487
|
-
token: 'user-token',
|
|
488
|
-
uuid: 'test-user',
|
|
489
|
-
scope: JSON.stringify([
|
|
490
|
-
{
|
|
491
|
-
values: ['test-package'],
|
|
492
|
-
types: { pkg: { read: true, write: false } }
|
|
493
|
-
}
|
|
494
|
-
])
|
|
495
|
-
}
|
|
496
|
-
]);
|
|
497
|
-
|
|
498
|
-
// Create test context
|
|
499
|
-
const c = createContext({
|
|
500
|
-
req: {
|
|
501
|
-
method: 'PUT',
|
|
502
|
-
param: new Map([['username', 'test-user']]),
|
|
503
|
-
json: async () => ({ permission: 'read-write' })
|
|
504
|
-
},
|
|
505
|
-
db: mockDb,
|
|
506
|
-
// Mock packageSpec functionality
|
|
507
|
-
pkg: 'test-package'
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
// Execute function
|
|
511
|
-
const response = await grantPackageAccess(c);
|
|
512
|
-
|
|
513
|
-
// Verify mock calls - should update to read-write
|
|
514
|
-
expect(mockDb.upsertToken).toHaveBeenCalledWith(
|
|
515
|
-
'user-token',
|
|
516
|
-
'test-user',
|
|
517
|
-
[
|
|
518
|
-
{
|
|
519
|
-
values: ['test-package'],
|
|
520
|
-
types: { pkg: { read: true, write: true } }
|
|
521
|
-
}
|
|
522
|
-
],
|
|
523
|
-
'test-token'
|
|
524
|
-
);
|
|
525
|
-
|
|
526
|
-
// Verify response
|
|
527
|
-
expect(response.status).toBe(200);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
it('should reject if admin user lacks user write access', async () => {
|
|
531
|
-
// Mock package data
|
|
532
|
-
mockDb.getPackage.mockResolvedValue({
|
|
533
|
-
name: 'test-package',
|
|
534
|
-
tags: { latest: '1.0.0' }
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
// Mock user with only package write access but no user write access
|
|
538
|
-
getAuthedUser.mockResolvedValue({
|
|
539
|
-
uuid: 'package-admin',
|
|
540
|
-
scope: [
|
|
541
|
-
{
|
|
542
|
-
values: ['*'],
|
|
543
|
-
types: { pkg: { read: true, write: true } }
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
values: ['*'],
|
|
547
|
-
types: { user: { read: true, write: false } }
|
|
548
|
-
}
|
|
549
|
-
]
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
// Create test context
|
|
553
|
-
const c = createContext({
|
|
554
|
-
req: {
|
|
555
|
-
method: 'PUT',
|
|
556
|
-
param: new Map([['username', 'test-user']]),
|
|
557
|
-
json: async () => ({ permission: 'read-only' })
|
|
558
|
-
},
|
|
559
|
-
db: mockDb,
|
|
560
|
-
// Mock packageSpec functionality
|
|
561
|
-
pkg: 'test-package'
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
// Execute function
|
|
565
|
-
const response = await grantPackageAccess(c);
|
|
566
|
-
|
|
567
|
-
// Verify response
|
|
568
|
-
expect(response.status).toBe(403);
|
|
569
|
-
const body = await response.json();
|
|
570
|
-
expect(body).toEqual({
|
|
571
|
-
error: 'Unauthorized - you do not have permission to manage user access'
|
|
572
|
-
});
|
|
573
|
-
});
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
describe('revokePackageAccess', () => {
|
|
577
|
-
it('should revoke access to a package', async () => {
|
|
578
|
-
// Mock package data
|
|
579
|
-
mockDb.getPackage.mockResolvedValue({
|
|
580
|
-
name: 'test-package',
|
|
581
|
-
tags: { latest: '1.0.0' }
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
// Mock admin user with write access to users and packages
|
|
585
|
-
getAuthedUser.mockResolvedValue({
|
|
586
|
-
uuid: 'admin',
|
|
587
|
-
scope: [
|
|
588
|
-
{
|
|
589
|
-
values: ['*'],
|
|
590
|
-
types: {
|
|
591
|
-
pkg: { read: true, write: true },
|
|
592
|
-
user: { read: true, write: true }
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
]
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
// Mock existing user tokens with access to be revoked
|
|
599
|
-
mockDb.query.tokens.findMany.mockResolvedValue([
|
|
600
|
-
{
|
|
601
|
-
token: 'user-token',
|
|
602
|
-
uuid: 'test-user',
|
|
603
|
-
scope: JSON.stringify([
|
|
604
|
-
{
|
|
605
|
-
values: ['test-package'],
|
|
606
|
-
types: { pkg: { read: true, write: true } }
|
|
607
|
-
},
|
|
608
|
-
{
|
|
609
|
-
values: ['other-package'],
|
|
610
|
-
types: { pkg: { read: true, write: false } }
|
|
611
|
-
}
|
|
612
|
-
])
|
|
613
|
-
}
|
|
614
|
-
]);
|
|
615
|
-
|
|
616
|
-
// Create test context
|
|
617
|
-
const c = createContext({
|
|
618
|
-
req: {
|
|
619
|
-
method: 'DELETE',
|
|
620
|
-
param: new Map([['username', 'test-user']])
|
|
621
|
-
},
|
|
622
|
-
db: mockDb,
|
|
623
|
-
// Mock packageSpec functionality
|
|
624
|
-
pkg: 'test-package'
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
// Execute function
|
|
628
|
-
const response = await revokePackageAccess(c);
|
|
629
|
-
|
|
630
|
-
// Verify mock calls - should update to remove the package
|
|
631
|
-
expect(mockDb.upsertToken).toHaveBeenCalledWith(
|
|
632
|
-
'user-token',
|
|
633
|
-
'test-user',
|
|
634
|
-
[
|
|
635
|
-
{
|
|
636
|
-
values: ['other-package'],
|
|
637
|
-
types: { pkg: { read: true, write: false } }
|
|
638
|
-
}
|
|
639
|
-
],
|
|
640
|
-
'test-token'
|
|
641
|
-
);
|
|
642
|
-
|
|
643
|
-
// Verify response
|
|
644
|
-
expect(response.status).toBe(200);
|
|
645
|
-
const body = await response.json();
|
|
646
|
-
expect(body).toEqual({
|
|
647
|
-
success: true,
|
|
648
|
-
message: 'Removed access for test-user to test-package'
|
|
649
|
-
});
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
it('should handle when user has no access to revoke', async () => {
|
|
653
|
-
// Mock package data
|
|
654
|
-
mockDb.getPackage.mockResolvedValue({
|
|
655
|
-
name: 'test-package',
|
|
656
|
-
tags: { latest: '1.0.0' }
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
// Mock admin user with write access to users and packages
|
|
660
|
-
getAuthedUser.mockResolvedValue({
|
|
661
|
-
uuid: 'admin',
|
|
662
|
-
scope: [
|
|
663
|
-
{
|
|
664
|
-
values: ['*'],
|
|
665
|
-
types: {
|
|
666
|
-
pkg: { read: true, write: true },
|
|
667
|
-
user: { read: true, write: true }
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
]
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
// Mock existing user tokens with no access to the package
|
|
674
|
-
mockDb.query.tokens.findMany.mockResolvedValue([
|
|
675
|
-
{
|
|
676
|
-
token: 'user-token',
|
|
677
|
-
uuid: 'test-user',
|
|
678
|
-
scope: JSON.stringify([
|
|
679
|
-
{
|
|
680
|
-
values: ['other-package'],
|
|
681
|
-
types: { pkg: { read: true, write: false } }
|
|
682
|
-
}
|
|
683
|
-
])
|
|
684
|
-
}
|
|
685
|
-
]);
|
|
686
|
-
|
|
687
|
-
// Create test context
|
|
688
|
-
const c = createContext({
|
|
689
|
-
req: {
|
|
690
|
-
method: 'DELETE',
|
|
691
|
-
param: new Map([['username', 'test-user']])
|
|
692
|
-
},
|
|
693
|
-
db: mockDb,
|
|
694
|
-
// Mock packageSpec functionality
|
|
695
|
-
pkg: 'test-package'
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
// Execute function
|
|
699
|
-
const response = await revokePackageAccess(c);
|
|
700
|
-
|
|
701
|
-
// Verify that token was not updated
|
|
702
|
-
expect(mockDb.upsertToken).not.toHaveBeenCalled();
|
|
703
|
-
|
|
704
|
-
// Verify response
|
|
705
|
-
expect(response.status).toBe(200);
|
|
706
|
-
const body = await response.json();
|
|
707
|
-
expect(body).toEqual({
|
|
708
|
-
success: true,
|
|
709
|
-
message: 'User test-user did not have access to test-package'
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
it('should handle when user has no tokens', async () => {
|
|
714
|
-
// Mock package data
|
|
715
|
-
mockDb.getPackage.mockResolvedValue({
|
|
716
|
-
name: 'test-package',
|
|
717
|
-
tags: { latest: '1.0.0' }
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
// Mock admin user with write access to users and packages
|
|
721
|
-
getAuthedUser.mockResolvedValue({
|
|
722
|
-
uuid: 'admin',
|
|
723
|
-
scope: [
|
|
724
|
-
{
|
|
725
|
-
values: ['*'],
|
|
726
|
-
types: {
|
|
727
|
-
pkg: { read: true, write: true },
|
|
728
|
-
user: { read: true, write: true }
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
]
|
|
732
|
-
});
|
|
733
|
-
|
|
734
|
-
// Mock no existing user tokens
|
|
735
|
-
mockDb.query.tokens.findMany.mockResolvedValue([]);
|
|
736
|
-
|
|
737
|
-
// Create test context
|
|
738
|
-
const c = createContext({
|
|
739
|
-
req: {
|
|
740
|
-
method: 'DELETE',
|
|
741
|
-
param: new Map([['username', 'test-user']])
|
|
742
|
-
},
|
|
743
|
-
db: mockDb,
|
|
744
|
-
// Mock packageSpec functionality
|
|
745
|
-
pkg: 'test-package'
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
// Execute function
|
|
749
|
-
const response = await revokePackageAccess(c);
|
|
750
|
-
|
|
751
|
-
// Verify response
|
|
752
|
-
expect(response.status).toBe(200);
|
|
753
|
-
const body = await response.json();
|
|
754
|
-
expect(body).toEqual({
|
|
755
|
-
success: true,
|
|
756
|
-
message: 'User test-user did not have access to test-package'
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
});
|
|
760
|
-
});
|