@cloud-copilot/iam-shrink 0.1.3 → 0.1.4

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 (68) hide show
  1. package/.github/workflows/guarddog.yml +31 -0
  2. package/.github/workflows/pr-checks.yml +87 -0
  3. package/.github/workflows/release.yml +33 -0
  4. package/.vscode/settings.json +12 -0
  5. package/CHANGELOG.md +6 -0
  6. package/LICENSE.txt +68 -81
  7. package/README.md +45 -35
  8. package/dist/cjs/cli.js +37 -35
  9. package/dist/cjs/cli.js.map +1 -1
  10. package/dist/cjs/cli_utils.d.ts +3 -15
  11. package/dist/cjs/cli_utils.d.ts.map +1 -1
  12. package/dist/cjs/cli_utils.js +9 -42
  13. package/dist/cjs/cli_utils.js.map +1 -1
  14. package/dist/cjs/errors.d.ts.map +1 -1
  15. package/dist/cjs/errors.js +3 -3
  16. package/dist/cjs/errors.js.map +1 -1
  17. package/dist/cjs/index.d.ts.map +1 -1
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/shrink.d.ts.map +1 -1
  20. package/dist/cjs/shrink.js +26 -27
  21. package/dist/cjs/shrink.js.map +1 -1
  22. package/dist/cjs/shrink_file.d.ts +1 -1
  23. package/dist/cjs/shrink_file.d.ts.map +1 -1
  24. package/dist/cjs/shrink_file.js.map +1 -1
  25. package/dist/cjs/validate.d.ts.map +1 -1
  26. package/dist/cjs/validate.js.map +1 -1
  27. package/dist/esm/cli.js +40 -38
  28. package/dist/esm/cli.js.map +1 -1
  29. package/dist/esm/cli_utils.d.ts +3 -15
  30. package/dist/esm/cli_utils.d.ts.map +1 -1
  31. package/dist/esm/cli_utils.js +9 -41
  32. package/dist/esm/cli_utils.js.map +1 -1
  33. package/dist/esm/errors.d.ts.map +1 -1
  34. package/dist/esm/errors.js +3 -3
  35. package/dist/esm/errors.js.map +1 -1
  36. package/dist/esm/index.d.ts.map +1 -1
  37. package/dist/esm/index.js.map +1 -1
  38. package/dist/esm/shrink.d.ts.map +1 -1
  39. package/dist/esm/shrink.js +26 -27
  40. package/dist/esm/shrink.js.map +1 -1
  41. package/dist/esm/shrink_file.d.ts +1 -1
  42. package/dist/esm/shrink_file.d.ts.map +1 -1
  43. package/dist/esm/shrink_file.js +1 -1
  44. package/dist/esm/shrink_file.js.map +1 -1
  45. package/dist/esm/validate.d.ts.map +1 -1
  46. package/dist/esm/validate.js +1 -1
  47. package/dist/esm/validate.js.map +1 -1
  48. package/package.json +72 -3
  49. package/src/cli.ts +54 -46
  50. package/src/cli_utils.test.ts +20 -58
  51. package/src/cli_utils.ts +21 -55
  52. package/src/errors.ts +14 -10
  53. package/src/index.ts +3 -4
  54. package/src/shrink.test.ts +270 -270
  55. package/src/shrink.ts +164 -132
  56. package/src/shrink_file.test.ts +4 -4
  57. package/src/shrink_file.ts +14 -10
  58. package/src/validate.test.ts +19 -21
  59. package/src/validate.ts +15 -12
  60. package/dist/cjs/stdin.d.ts +0 -7
  61. package/dist/cjs/stdin.d.ts.map +0 -1
  62. package/dist/cjs/stdin.js +0 -36
  63. package/dist/cjs/stdin.js.map +0 -1
  64. package/dist/esm/stdin.d.ts +0 -7
  65. package/dist/esm/stdin.d.ts.map +0 -1
  66. package/dist/esm/stdin.js +0 -33
  67. package/dist/esm/stdin.js.map +0 -1
  68. package/src/stdin.ts +0 -36
@@ -1,14 +1,27 @@
1
- import { expandIamActions } from '@cloud-copilot/iam-expand';
2
- import { beforeEach } from 'node:test';
3
- import { describe, expect, it, vi } from 'vitest';
4
- import { consolidateWildcardPatterns, countSubstrings, findCommonSequences, groupActionsByService, mapActions, reduceAction, regexForWildcardAction, shrink, shrinkIteration, shrinkResolvedList, splitActionIntoParts, wildcardActionMatchesAnyString } from './shrink.js';
5
- import { validateShrinkResults } from './validate.js';
1
+ import { expandIamActions } from '@cloud-copilot/iam-expand'
2
+ import { beforeEach } from 'node:test'
3
+ import { describe, expect, it, vi } from 'vitest'
4
+ import {
5
+ consolidateWildcardPatterns,
6
+ countSubstrings,
7
+ findCommonSequences,
8
+ groupActionsByService,
9
+ mapActions,
10
+ reduceAction,
11
+ regexForWildcardAction,
12
+ shrink,
13
+ shrinkIteration,
14
+ shrinkResolvedList,
15
+ splitActionIntoParts,
16
+ wildcardActionMatchesAnyString
17
+ } from './shrink.js'
18
+ import { validateShrinkResults } from './validate.js'
6
19
 
7
20
  vi.mock('@cloud-copilot/iam-expand')
8
21
  vi.mock('./validate.js')
9
22
 
10
- const mockExpandIamActions = vi.mocked(expandIamActions);
11
- const mockValidateShrinkResults = vi.mocked(validateShrinkResults);
23
+ const mockExpandIamActions = vi.mocked(expandIamActions)
24
+ const mockValidateShrinkResults = vi.mocked(validateShrinkResults)
12
25
 
13
26
  beforeEach(() => {
14
27
  vi.resetAllMocks()
@@ -18,47 +31,35 @@ describe('shrink.ts', () => {
18
31
  describe('splitActionIntoParts', () => {
19
32
  it('should split by capital letters', () => {
20
33
  //Given an action with capital letters
21
- const input = "CreateAccessPointForObjectLambda";
34
+ const input = 'CreateAccessPointForObjectLambda'
22
35
 
23
36
  //When we split the action into parts
24
- const result = splitActionIntoParts(input);
37
+ const result = splitActionIntoParts(input)
25
38
 
26
39
  //Then we should get an array of parts
27
- expect(result).toEqual([
28
- "Create",
29
- "Access",
30
- "Point",
31
- "For",
32
- "Object",
33
- "Lambda"
34
- ]);
40
+ expect(result).toEqual(['Create', 'Access', 'Point', 'For', 'Object', 'Lambda'])
35
41
  })
36
42
 
37
43
  it('should split by asterisks', () => {
38
44
  //Given an action with asterisks
39
- const input = "*ObjectTagging*";
45
+ const input = '*ObjectTagging*'
40
46
 
41
47
  //When we split the action into parts
42
- const result = splitActionIntoParts(input);
48
+ const result = splitActionIntoParts(input)
43
49
 
44
50
  //Then we should get an array of parts
45
- expect(result).toEqual([
46
- "*",
47
- "Object",
48
- "Tagging",
49
- "*"
50
- ]);
51
+ expect(result).toEqual(['*', 'Object', 'Tagging', '*'])
51
52
  })
52
53
 
53
54
  it('should not split on consecutive capital letters', () => {
54
55
  //Given an action with only capital letters
55
- const input = "GET";
56
+ const input = 'GET'
56
57
 
57
58
  //When we split the action into parts
58
- const result = splitActionIntoParts(input);
59
+ const result = splitActionIntoParts(input)
59
60
 
60
61
  //Then we should back the original string
61
- expect(result).toEqual([input]);
62
+ expect(result).toEqual([input])
62
63
  })
63
64
  })
64
65
 
@@ -68,10 +69,10 @@ describe('shrink.ts', () => {
68
69
  const actions = ['*Object', 'Object*', '*Object*']
69
70
 
70
71
  //When we consolidate the actions
71
- const result = consolidateWildcardPatterns(actions);
72
+ const result = consolidateWildcardPatterns(actions)
72
73
 
73
74
  //Then we should get an array of consolidated actions
74
- expect(result).toEqual(['*Object*']);
75
+ expect(result).toEqual(['*Object*'])
75
76
  })
76
77
 
77
78
  it('should not overconsolidate in the middle', () => {
@@ -86,63 +87,49 @@ describe('shrink.ts', () => {
86
87
  ]
87
88
 
88
89
  //When we consolidate the actions
89
- const result = consolidateWildcardPatterns(actions);
90
+ const result = consolidateWildcardPatterns(actions)
90
91
 
91
92
  //Then we should get an array of consolidated actions
92
- expect(result.sort()).toEqual([
93
+ expect(result.sort()).toEqual(
94
+ [
93
95
  'Delete*Tagging',
94
96
  'GetJobTagging',
95
97
  'GetObject*Tagging',
96
98
  'GetStorage*Tagging',
97
99
  'Put*Tagging'
98
100
  ].sort()
99
- );
101
+ )
100
102
  })
101
103
  })
102
104
 
103
105
  describe('countSubstrings', () => {
104
106
  it('will count strings that appear in the substrings', () => {
105
107
  //Given a set of substrings
106
- const substrings = [
107
- "Get",
108
- "Object",
109
- "Tagging",
110
- "Put"
111
- ]
112
- const actionStrings = [
113
- "GetObjectTagging",
114
- "PutObjectTagging"
115
- ]
116
-
108
+ const substrings = ['Get', 'Object', 'Tagging', 'Put']
109
+ const actionStrings = ['GetObjectTagging', 'PutObjectTagging']
117
110
 
118
111
  //When we count the substrings
119
- const result = countSubstrings(substrings, actionStrings);
112
+ const result = countSubstrings(substrings, actionStrings)
120
113
 
121
114
  //Then we should get the count of substrings
122
- expect(result.size).toEqual(4);
123
- expect(result.get("Get")).toBe(1);
124
- expect(result.get("Object")).toBe(2);
125
- expect(result.get("Tagging")).toBe(2);
126
- expect(result.get("Put")).toBe(1);
115
+ expect(result.size).toEqual(4)
116
+ expect(result.get('Get')).toBe(1)
117
+ expect(result.get('Object')).toBe(2)
118
+ expect(result.get('Tagging')).toBe(2)
119
+ expect(result.get('Put')).toBe(1)
127
120
  })
128
121
 
129
122
  it('does not count substrings that are not in the action strings', () => {
130
123
  //Given a set of substrings
131
- const substrings = [
132
- "Silliness",
133
- "Get",
134
- ]
135
- const actionStrings = [
136
- "GetObjectTagging",
137
- "PutObjectTagging"
138
- ]
124
+ const substrings = ['Silliness', 'Get']
125
+ const actionStrings = ['GetObjectTagging', 'PutObjectTagging']
139
126
 
140
127
  //When we count the substrings
141
- const result = countSubstrings(substrings, actionStrings);
128
+ const result = countSubstrings(substrings, actionStrings)
142
129
 
143
130
  //Then we should get the count of substrings
144
- expect(result.size).toEqual(1);
145
- expect(result.get("Get")).toBe(1);
131
+ expect(result.size).toEqual(1)
132
+ expect(result.get('Get')).toBe(1)
146
133
  })
147
134
  })
148
135
 
@@ -150,31 +137,31 @@ describe('shrink.ts', () => {
150
137
  it('counts up the common sequences', () => {
151
138
  //Given a set of actions
152
139
  const actions = [
153
- "GetObjectTagging",
154
- "PutObjectTagging",
155
- "GetBucketTagging",
156
- "GetObjectVersionAcl",
157
- "Get*"
140
+ 'GetObjectTagging',
141
+ 'PutObjectTagging',
142
+ 'GetBucketTagging',
143
+ 'GetObjectVersionAcl',
144
+ 'Get*'
158
145
  ]
159
146
 
160
147
  //When we find the common sequences
161
- const result = findCommonSequences(actions);
148
+ const result = findCommonSequences(actions)
162
149
 
163
150
  //And sort them
164
151
  result.sort((a, b) => {
165
- return a.sequence.localeCompare(b.sequence);
166
- });
152
+ return a.sequence.localeCompare(b.sequence)
153
+ })
167
154
 
168
155
  //Then we should get the common sequences
169
156
  expect(result).toEqual([
170
- {sequence: "*", frequency: 1, length: 1},
171
- {sequence: "Acl", frequency: 1, length: 3},
172
- {sequence: "Bucket", frequency: 1, length: 6},
173
- {sequence: "Get", frequency: 4, length: 3},
174
- {sequence: "Object", frequency: 3, length: 6},
175
- {sequence: "Put", frequency: 1, length: 3},
176
- {sequence: "Tagging", frequency: 3, length: 7},
177
- {sequence: "Version", frequency: 1, length: 7},
157
+ { sequence: '*', frequency: 1, length: 1 },
158
+ { sequence: 'Acl', frequency: 1, length: 3 },
159
+ { sequence: 'Bucket', frequency: 1, length: 6 },
160
+ { sequence: 'Get', frequency: 4, length: 3 },
161
+ { sequence: 'Object', frequency: 3, length: 6 },
162
+ { sequence: 'Put', frequency: 1, length: 3 },
163
+ { sequence: 'Tagging', frequency: 3, length: 7 },
164
+ { sequence: 'Version', frequency: 1, length: 7 }
178
165
  ])
179
166
  })
180
167
  })
@@ -182,167 +169,204 @@ describe('shrink.ts', () => {
182
169
  describe('regexForWildcardAction', () => {
183
170
  it('should create a regex for a wildcard action', () => {
184
171
  //Given a wildcard action
185
- const action = "*ObjectTagging*";
172
+ const action = '*ObjectTagging*'
186
173
 
187
174
  //When we create a regex for the action
188
- const result = regexForWildcardAction(action);
175
+ const result = regexForWildcardAction(action)
189
176
 
190
177
  //Then we should get a regex that matches the action
191
- expect(result.source).toBe("^.*?ObjectTagging.*?$");
192
- expect(result.flags).toBe("i");
178
+ expect(result.source).toBe('^.*?ObjectTagging.*?$')
179
+ expect(result.flags).toBe('i')
193
180
  })
194
181
 
195
182
  it('should collapse consecutive asterisks', () => {
196
183
  //Given a wildcard action with consecutive asterisks
197
- const action = "*Object****Tagging*";
184
+ const action = '*Object****Tagging*'
198
185
 
199
186
  //When we create a regex for the action
200
- const result = regexForWildcardAction(action);
187
+ const result = regexForWildcardAction(action)
201
188
 
202
189
  //Then we should get a regex that matches the action
203
- expect(result.source).toBe("^.*?Object.*?Tagging.*?$");
190
+ expect(result.source).toBe('^.*?Object.*?Tagging.*?$')
204
191
  })
205
192
  })
206
193
 
207
194
  describe('wildcardActionMatchesAnyString', () => {
208
195
  it('should match a string that matches the wildcard action', () => {
209
196
  //Given a wildcard action
210
- const wildcardAction = "*ObjectTagging*";
197
+ const wildcardAction = '*ObjectTagging*'
211
198
  //And a list of strings with one that matches the wildcard action
212
- const strings = [
213
- "GetObjectTagging",
214
- "PutObjectTagging",
215
- "GetObjectVersionAcl"
216
- ]
199
+ const strings = ['GetObjectTagging', 'PutObjectTagging', 'GetObjectVersionAcl']
217
200
 
218
201
  //When we match the strings against the action
219
- const result = wildcardActionMatchesAnyString(wildcardAction, strings);
202
+ const result = wildcardActionMatchesAnyString(wildcardAction, strings)
220
203
 
221
204
  //Then we should get a match
222
- expect(result).toBe(true);
205
+ expect(result).toBe(true)
223
206
  })
224
207
 
225
208
  it('should return false if there are no matches', () => {
226
209
  //Given a wildcard action
227
- const wildcardAction = "*ObjectTagging*";
210
+ const wildcardAction = '*ObjectTagging*'
228
211
  //And a list of strings with none that match the wildcard action
229
- const strings = [
230
- "GetObjectVersionAcl",
231
- "PutBucketTagging",
232
- ]
212
+ const strings = ['GetObjectVersionAcl', 'PutBucketTagging']
233
213
 
234
214
  //When we match the strings against the action
235
- const result = wildcardActionMatchesAnyString(wildcardAction, strings);
215
+ const result = wildcardActionMatchesAnyString(wildcardAction, strings)
236
216
 
237
217
  //Then we should not get a match
238
- expect(result).toBe(false);
218
+ expect(result).toBe(false)
239
219
  })
240
220
 
241
221
  it('should return false if for an empty list of strings', () => {
242
222
  //Given a wildcard action
243
- const wildcardAction = "*ObjectTagging*";
223
+ const wildcardAction = '*ObjectTagging*'
244
224
  //And an empty list of strings
245
225
  const strings: string[] = []
246
226
 
247
227
  //When we match the strings against the action
248
- const result = wildcardActionMatchesAnyString(wildcardAction, strings);
228
+ const result = wildcardActionMatchesAnyString(wildcardAction, strings)
249
229
 
250
230
  //Then the result should be false
251
- expect(result).toBe(false);
231
+ expect(result).toBe(false)
252
232
  })
253
233
  })
254
234
 
255
- const reduceActionCases: {action: string, sequence: string, undesiredActions: string[], expected: string, name?: string}[] = [
235
+ const reduceActionCases: {
236
+ action: string
237
+ sequence: string
238
+ undesiredActions: string[]
239
+ expected: string
240
+ name?: string
241
+ }[] = [
256
242
  //Sequence at the beginning
257
- {action: "GetObjectTagging", sequence: "Get", undesiredActions: ["GetObjectAcl"], expected: "Get*Tagging"},
258
- {action: "GetObjectTagging", sequence: "Get", undesiredActions: ["PutObjectTagging"], expected: "Get*"},
243
+ {
244
+ action: 'GetObjectTagging',
245
+ sequence: 'Get',
246
+ undesiredActions: ['GetObjectAcl'],
247
+ expected: 'Get*Tagging'
248
+ },
249
+ {
250
+ action: 'GetObjectTagging',
251
+ sequence: 'Get',
252
+ undesiredActions: ['PutObjectTagging'],
253
+ expected: 'Get*'
254
+ },
259
255
 
260
256
  //Sequence in the middle, remove beginning
261
- {action: "GetObjectTagging", sequence: "Object", undesiredActions: ["PutObjectVersion", "GetObjectVersion"], expected: "*ObjectTagging"},
262
- {action: "GetIntelligentTieringConfiguration", sequence: "Tiering", undesiredActions: ["GetIntelligentTieringStructure"], expected: "*TieringConfiguration"},
257
+ {
258
+ action: 'GetObjectTagging',
259
+ sequence: 'Object',
260
+ undesiredActions: ['PutObjectVersion', 'GetObjectVersion'],
261
+ expected: '*ObjectTagging'
262
+ },
263
+ {
264
+ action: 'GetIntelligentTieringConfiguration',
265
+ sequence: 'Tiering',
266
+ undesiredActions: ['GetIntelligentTieringStructure'],
267
+ expected: '*TieringConfiguration'
268
+ },
263
269
 
264
270
  //Sequence in the middle, remove end
265
- {action: "GetObjectTagging", sequence: "Object", undesiredActions: ["PutObjectTagging"], expected: "GetObject*"},
266
- {action: "GetObjectTaggingVersion", sequence: "Object", undesiredActions: ["PutObjectTagging"], expected: "GetObject*"},
271
+ {
272
+ action: 'GetObjectTagging',
273
+ sequence: 'Object',
274
+ undesiredActions: ['PutObjectTagging'],
275
+ expected: 'GetObject*'
276
+ },
277
+ {
278
+ action: 'GetObjectTaggingVersion',
279
+ sequence: 'Object',
280
+ undesiredActions: ['PutObjectTagging'],
281
+ expected: 'GetObject*'
282
+ },
267
283
 
268
284
  //Sequence in the middle, remove beginning and end
269
- {action: "GetObjectTagging", sequence: "Object", undesiredActions: ["ListBucketVersions"], expected: "*Object*"},
285
+ {
286
+ action: 'GetObjectTagging',
287
+ sequence: 'Object',
288
+ undesiredActions: ['ListBucketVersions'],
289
+ expected: '*Object*'
290
+ },
270
291
 
271
292
  //Sequence at the end
272
- {action: "GetObjectTagging", sequence: "Tagging", undesiredActions: ["PutObjectTagging"], expected: "Get*Tagging"},
273
- {action: "GetObjectTagging", sequence: "Tagging", undesiredActions: ["PutObjectTagging"], expected: "Get*Tagging"},
274
- {action: "GetObjectTagging", sequence: "Tagging", undesiredActions: ["GetObjectAcl"], expected: "*Tagging"},
293
+ {
294
+ action: 'GetObjectTagging',
295
+ sequence: 'Tagging',
296
+ undesiredActions: ['PutObjectTagging'],
297
+ expected: 'Get*Tagging'
298
+ },
299
+ {
300
+ action: 'GetObjectTagging',
301
+ sequence: 'Tagging',
302
+ undesiredActions: ['PutObjectTagging'],
303
+ expected: 'Get*Tagging'
304
+ },
305
+ {
306
+ action: 'GetObjectTagging',
307
+ sequence: 'Tagging',
308
+ undesiredActions: ['GetObjectAcl'],
309
+ expected: '*Tagging'
310
+ },
275
311
 
276
312
  //Action only Has One Part
277
- {action: "GET", sequence: "GET", undesiredActions: ["PUT"], expected: "GET"},
313
+ { action: 'GET', sequence: 'GET', undesiredActions: ['PUT'], expected: 'GET' }
278
314
  ]
279
315
 
280
316
  describe('reduceAction', () => {
281
- for(const {action, sequence, undesiredActions, expected, name} of reduceActionCases) {
317
+ for (const { action, sequence, undesiredActions, expected, name } of reduceActionCases) {
282
318
  it(name ?? `should reduce ${action} to ${expected}`, () => {
283
319
  //When we reduce the action
284
- const result = reduceAction(action, sequence, undesiredActions);
320
+ const result = reduceAction(action, sequence, undesiredActions)
285
321
 
286
322
  //Then we should get the reduced action
287
- expect(result).toBe(expected);
323
+ expect(result).toBe(expected)
288
324
  })
289
325
  }
290
326
 
291
- it('should replace parts after the sequence if it occurs at the beginning', () => {
292
-
293
- })
327
+ it('should replace parts after the sequence if it occurs at the beginning', () => {})
294
328
  })
295
329
 
296
330
  describe('shrinkIteration', () => {
297
331
  it('should shrink the actions, shallow', () => {
298
332
  //Given a list of actions
299
333
  const actions = [
300
- "GetObjectTagging",
301
- "PutObjectTagging",
302
- "GetBucketTagging",
303
- "GetObjectVersionAcl",
334
+ 'GetObjectTagging',
335
+ 'PutObjectTagging',
336
+ 'GetBucketTagging',
337
+ 'GetObjectVersionAcl'
304
338
  ]
305
339
  //And a set of undesired actions
306
- const undesiredActions = [
307
- "GetObjectAcl",
308
- "PutObjectTagging"
309
- ]
340
+ const undesiredActions = ['GetObjectAcl', 'PutObjectTagging']
310
341
 
311
342
  //When we shrink the actions
312
- const result = shrinkIteration(actions, undesiredActions, false);
343
+ const result = shrinkIteration(actions, undesiredActions, false)
313
344
 
314
345
  //Then we should get the reduced actions
315
346
  expect(result).toEqual([
316
347
  // "*ObjectTagging",
317
- "PutObjectTagging",
318
- "Get*VersionAcl",
319
- "Get*Tagging",
348
+ 'PutObjectTagging',
349
+ 'Get*VersionAcl',
350
+ 'Get*Tagging'
320
351
  ])
321
352
  })
322
353
 
323
354
  it('should shrink the actions, deep', () => {
324
355
  //Given a list of actions
325
356
  const actions = [
326
- "GetObjectTagging",
327
- "PutObjectTagging",
328
- "GetBucketTagging",
329
- "GetObjectVersionAcl",
357
+ 'GetObjectTagging',
358
+ 'PutObjectTagging',
359
+ 'GetBucketTagging',
360
+ 'GetObjectVersionAcl'
330
361
  ]
331
362
  //And a set of undesired actions
332
- const undesiredActions = [
333
- "GetObjectAcl",
334
- "PutObjectTagging"
335
- ]
363
+ const undesiredActions = ['GetObjectAcl', 'PutObjectTagging']
336
364
 
337
365
  //When we shrink the actions
338
- const result = shrinkIteration(actions, undesiredActions, true);
366
+ const result = shrinkIteration(actions, undesiredActions, true)
339
367
 
340
368
  //Then we should get the reduced actions
341
- expect(result).toEqual([
342
- "PutObjectTagging",
343
- "Get*Tagging",
344
- "*Version*",
345
- ])
369
+ expect(result).toEqual(['PutObjectTagging', 'Get*Tagging', '*Version*'])
346
370
  })
347
371
  })
348
372
 
@@ -350,75 +374,69 @@ describe('shrink.ts', () => {
350
374
  it('should return a wildcard if all actions are desired', () => {
351
375
  //Given a list of actions
352
376
  const actions = [
353
- "GetObjectTagging",
354
- "PutObjectTagging",
355
- "GetBucketTagging",
356
- "GetObjectVersionAcl",
377
+ 'GetObjectTagging',
378
+ 'PutObjectTagging',
379
+ 'GetBucketTagging',
380
+ 'GetObjectVersionAcl'
357
381
  ]
358
382
  //And an exact same list of possible actions
359
- const possibleActions = actions.slice(0);
383
+ const possibleActions = actions.slice(0)
360
384
 
361
385
  //When we shrink the actions
362
- const result = shrinkResolvedList(actions, possibleActions, Infinity);
386
+ const result = shrinkResolvedList(actions, possibleActions, Infinity)
363
387
 
364
388
  //Then we should get a wildcard
365
- expect(result).toEqual(["*"]);
389
+ expect(result).toEqual(['*'])
366
390
  })
367
391
 
368
392
  it('should shrink the list with two iterations', () => {
369
393
  //Given a list of actions
370
394
  const actions = [
371
- "GetObjectTagging",
372
- "PutObjectTagging",
373
- "GetBucketTagging",
374
- "GetObjectVersionAcl",
395
+ 'GetObjectTagging',
396
+ 'PutObjectTagging',
397
+ 'GetBucketTagging',
398
+ 'GetObjectVersionAcl'
375
399
  ]
376
400
  //And a set of undesired actions
377
401
  const possibleActions = [
378
- "GetObjectTagging",
379
- "PutObjectTagging",
380
- "GetBucketTagging",
381
- "GetObjectVersionAcl",
382
- "GetObjectAcl",
383
- "GetObjectVersion",
402
+ 'GetObjectTagging',
403
+ 'PutObjectTagging',
404
+ 'GetBucketTagging',
405
+ 'GetObjectVersionAcl',
406
+ 'GetObjectAcl',
407
+ 'GetObjectVersion'
384
408
  ]
385
409
 
386
410
  //When we shrink the actions
387
- const result = shrinkResolvedList(actions, possibleActions, 2);
411
+ const result = shrinkResolvedList(actions, possibleActions, 2)
388
412
 
389
413
  //Then we should get the reduced actions
390
- expect(result.sort()).toEqual([
391
- "*Tagging",
392
- "Get*VersionAcl"
393
- ])
414
+ expect(result.sort()).toEqual(['*Tagging', 'Get*VersionAcl'])
394
415
  })
395
416
 
396
417
  it('should shrink the list of actions aggressively', () => {
397
418
  //Given a list of actions
398
419
  const actions = [
399
- "GetObjectTagging",
400
- "PutObjectTagging",
401
- "GetBucketTagging",
402
- "GetObjectVersionAcl",
420
+ 'GetObjectTagging',
421
+ 'PutObjectTagging',
422
+ 'GetBucketTagging',
423
+ 'GetObjectVersionAcl'
403
424
  ]
404
425
  //And a set of undesired actions
405
426
  const possibleActions = [
406
- "GetObjectTagging",
407
- "PutObjectTagging",
408
- "GetBucketTagging",
409
- "GetObjectVersionAcl",
410
- "GetObjectAcl",
411
- "GetObjectVersion",
427
+ 'GetObjectTagging',
428
+ 'PutObjectTagging',
429
+ 'GetBucketTagging',
430
+ 'GetObjectVersionAcl',
431
+ 'GetObjectAcl',
432
+ 'GetObjectVersion'
412
433
  ]
413
434
 
414
435
  //When we shrink the actions
415
- const result = shrinkResolvedList(actions, possibleActions, Infinity);
436
+ const result = shrinkResolvedList(actions, possibleActions, Infinity)
416
437
 
417
438
  //Then we should get the reduced actions
418
- expect(result.sort()).toEqual([
419
- "*Tagging",
420
- "*VersionAcl"
421
- ])
439
+ expect(result.sort()).toEqual(['*Tagging', '*VersionAcl'])
422
440
  })
423
441
  })
424
442
 
@@ -426,47 +444,39 @@ describe('shrink.ts', () => {
426
444
  it('should group the actions by service', () => {
427
445
  //Given a list of actions
428
446
  const actions = [
429
- "s3:GetObjectTagging",
430
- "s3:PutObjectTagging",
431
- "s3:GetBucketTagging",
432
- "s3:GetObjectVersionAcl",
433
- "ec2:GetObjectTagging",
434
- "ec2:PutObjectTagging",
435
- "ec2:GetBucketTagging"
447
+ 's3:GetObjectTagging',
448
+ 's3:PutObjectTagging',
449
+ 's3:GetBucketTagging',
450
+ 's3:GetObjectVersionAcl',
451
+ 'ec2:GetObjectTagging',
452
+ 'ec2:PutObjectTagging',
453
+ 'ec2:GetBucketTagging'
436
454
  ]
437
455
 
438
456
  //When we group the actions by service
439
- const result = groupActionsByService(actions);
457
+ const result = groupActionsByService(actions)
440
458
 
441
459
  //Then we should get the actions grouped by service
442
- expect([...result.keys()]).toEqual(["s3", "ec2"]);
460
+ expect([...result.keys()]).toEqual(['s3', 'ec2'])
443
461
 
444
- expect(result.get("s3")).toEqual({
462
+ expect(result.get('s3')).toEqual({
445
463
  withService: [
446
- "s3:GetObjectTagging",
447
- "s3:PutObjectTagging",
448
- "s3:GetBucketTagging",
449
- "s3:GetObjectVersionAcl"
464
+ 's3:GetObjectTagging',
465
+ 's3:PutObjectTagging',
466
+ 's3:GetBucketTagging',
467
+ 's3:GetObjectVersionAcl'
450
468
  ],
451
469
  withoutService: [
452
- "GetObjectTagging",
453
- "PutObjectTagging",
454
- "GetBucketTagging",
455
- "GetObjectVersionAcl"
470
+ 'GetObjectTagging',
471
+ 'PutObjectTagging',
472
+ 'GetBucketTagging',
473
+ 'GetObjectVersionAcl'
456
474
  ]
457
475
  })
458
476
 
459
- expect(result.get("ec2")).toEqual({
460
- withService: [
461
- "ec2:GetObjectTagging",
462
- "ec2:PutObjectTagging",
463
- "ec2:GetBucketTagging"
464
- ],
465
- withoutService: [
466
- "GetObjectTagging",
467
- "PutObjectTagging",
468
- "GetBucketTagging"
469
- ]
477
+ expect(result.get('ec2')).toEqual({
478
+ withService: ['ec2:GetObjectTagging', 'ec2:PutObjectTagging', 'ec2:GetBucketTagging'],
479
+ withoutService: ['GetObjectTagging', 'PutObjectTagging', 'GetBucketTagging']
470
480
  })
471
481
  })
472
482
  })
@@ -475,27 +485,27 @@ describe('shrink.ts', () => {
475
485
  it('should map the actions with the service', () => {
476
486
  //Given a list of actions
477
487
  const actions = [
478
- "s3:GetObjectTagging",
479
- "s3:PutObjectTagging",
480
- "s3:GetBucketTagging",
481
- "s3:GetObjectVersionAcl",
482
- "ec2:GetObjectTagging",
483
- "ec2:PutObjectTagging",
484
- "ec2:GetBucketTagging"
488
+ 's3:GetObjectTagging',
489
+ 's3:PutObjectTagging',
490
+ 's3:GetBucketTagging',
491
+ 's3:GetObjectVersionAcl',
492
+ 'ec2:GetObjectTagging',
493
+ 'ec2:PutObjectTagging',
494
+ 'ec2:GetBucketTagging'
485
495
  ]
486
496
 
487
497
  //When we map the actions to services
488
- const result = mapActions(actions);
498
+ const result = mapActions(actions)
489
499
 
490
500
  //Then we should get the actions grouped by service
491
501
  expect(result).toEqual([
492
- "GetObjectTagging",
493
- "PutObjectTagging",
494
- "GetBucketTagging",
495
- "GetObjectVersionAcl",
496
- "GetObjectTagging",
497
- "PutObjectTagging",
498
- "GetBucketTagging"
502
+ 'GetObjectTagging',
503
+ 'PutObjectTagging',
504
+ 'GetBucketTagging',
505
+ 'GetObjectVersionAcl',
506
+ 'GetObjectTagging',
507
+ 'PutObjectTagging',
508
+ 'GetBucketTagging'
499
509
  ])
500
510
  })
501
511
  })
@@ -504,91 +514,81 @@ describe('shrink.ts', () => {
504
514
  it('should shrink the actions', async () => {
505
515
  //Given a list of actions
506
516
  const actions = [
507
- "s3:GetObjectTagging",
508
- "s3:PutObjectTagging",
509
- "s3:GetBucketTagging",
510
- "s3:GetObjectVersionAcl"
517
+ 's3:GetObjectTagging',
518
+ 's3:PutObjectTagging',
519
+ 's3:GetBucketTagging',
520
+ 's3:GetObjectVersionAcl'
511
521
  ]
512
522
 
513
523
  //And a set of available actions
514
524
  mockExpandIamActions.mockImplementation(async (actions: string | string[]) => {
515
- if(actions == "s3:*") {
525
+ if (actions == 's3:*') {
516
526
  return [
517
- "s3:GetObjectTagging",
518
- "s3:PutObjectTagging",
519
- "s3:GetBucketTagging",
520
- "s3:GetObjectVersionAcl",
521
- "s3:GetObjectAcl",
522
- "s3:GetObjectVersion"
527
+ 's3:GetObjectTagging',
528
+ 's3:PutObjectTagging',
529
+ 's3:GetBucketTagging',
530
+ 's3:GetObjectVersionAcl',
531
+ 's3:GetObjectAcl',
532
+ 's3:GetObjectVersion'
523
533
  ]
524
534
  }
525
535
 
526
536
  return [
527
- "s3:GetObjectTagging",
528
- "s3:PutObjectTagging",
529
- "s3:GetBucketTagging",
530
- "s3:GetObjectVersionAcl"
531
- ];
532
-
537
+ 's3:GetObjectTagging',
538
+ 's3:PutObjectTagging',
539
+ 's3:GetBucketTagging',
540
+ 's3:GetObjectVersionAcl'
541
+ ]
533
542
  })
534
543
 
535
544
  //When shrink is called
536
- const result = await shrink(actions, {});
545
+ const result = await shrink(actions, {})
537
546
 
538
547
  //Then we should get the reduced actions
539
- expect(result).toEqual([
540
- "s3:Get*VersionAcl",
541
- "s3:*Tagging"
542
- ])
548
+ expect(result).toEqual(['s3:Get*VersionAcl', 's3:*Tagging'])
543
549
  })
544
550
 
545
551
  it('should throw an error if the shrink does not validate', async () => {
546
552
  //Given a list of actions
547
553
  const actions = [
548
- "s3:GetObjectTagging",
549
- "s3:PutObjectTagging",
550
- "s3:GetBucketTagging",
551
- "s3:GetObjectVersionAcl"
554
+ 's3:GetObjectTagging',
555
+ 's3:PutObjectTagging',
556
+ 's3:GetBucketTagging',
557
+ 's3:GetObjectVersionAcl'
552
558
  ]
553
559
 
554
560
  //And the validation fails
555
- mockValidateShrinkResults.mockResolvedValueOnce("Undesired action: s3:DeleteObject")
561
+ mockValidateShrinkResults.mockResolvedValueOnce('Undesired action: s3:DeleteObject')
556
562
 
557
563
  //When shrink is called
558
- const result = shrink(actions, {});
564
+ const result = shrink(actions, {})
559
565
 
560
566
  //Then we should get the reduced actions
561
- await expect(result).rejects.toThrow(/@cloud-copilot\/iam-shrink has failed validation and this is a bug\./)
567
+ await expect(result).rejects.toThrow(
568
+ /@cloud-copilot\/iam-shrink has failed validation and this is a bug\./
569
+ )
562
570
  })
563
571
 
564
572
  it('should return an all actions wildcard if one is provided', async () => {
565
573
  //Given a list of actions that includes a global wildcard
566
- const actions = [
567
- "*",
568
- "s3:GetObjectTagging",
569
- "s3:PutObjectTagging",
570
- ]
574
+ const actions = ['*', 's3:GetObjectTagging', 's3:PutObjectTagging']
571
575
 
572
576
  //When shrink is called
573
- const result = await shrink(actions, {});
577
+ const result = await shrink(actions, {})
574
578
 
575
579
  //Then we should get back the single wildcard
576
- expect(result).toEqual(["*"])
580
+ expect(result).toEqual(['*'])
577
581
  })
578
582
 
579
583
  it('should return an all actions wildcard if a string of multiple asterisks is included', async () => {
580
584
  //Given a list of actions that includes a global wildcard
581
- const actions = [
582
- "***",
583
- "s3:GetObjectTagging",
584
- "s3:PutObjectTagging",
585
- ]
585
+ const actions = ['***', 's3:GetObjectTagging', 's3:PutObjectTagging']
586
586
 
587
587
  //When shrink is called
588
- const result = await shrink(actions);
588
+ const result = await shrink(actions)
589
589
 
590
590
  //Then we should get back the single wildcard
591
- expect(result).toEqual(["*"])
591
+ expect(result).toEqual(['*'])
592
592
  })
593
593
  })
594
594
  })