@cloud-copilot/iam-shrink 0.1.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 (85) hide show
  1. package/LICENSE.txt +674 -0
  2. package/README.md +187 -0
  3. package/dist/cjs/cli.d.ts +2 -0
  4. package/dist/cjs/cli.d.ts.map +1 -0
  5. package/dist/cjs/cli.js +78 -0
  6. package/dist/cjs/cli.js.map +1 -0
  7. package/dist/cjs/cli_utils.d.ts +30 -0
  8. package/dist/cjs/cli_utils.d.ts.map +1 -0
  9. package/dist/cjs/cli_utils.js +75 -0
  10. package/dist/cjs/cli_utils.js.map +1 -0
  11. package/dist/cjs/errors.d.ts +13 -0
  12. package/dist/cjs/errors.d.ts.map +1 -0
  13. package/dist/cjs/errors.js +56 -0
  14. package/dist/cjs/errors.js.map +1 -0
  15. package/dist/cjs/index.d.ts +3 -0
  16. package/dist/cjs/index.d.ts.map +1 -0
  17. package/dist/cjs/index.js +8 -0
  18. package/dist/cjs/index.js.map +1 -0
  19. package/dist/cjs/package.json +3 -0
  20. package/dist/cjs/shrink.d.ts +131 -0
  21. package/dist/cjs/shrink.d.ts.map +1 -0
  22. package/dist/cjs/shrink.js +358 -0
  23. package/dist/cjs/shrink.js.map +1 -0
  24. package/dist/cjs/shrink_file.d.ts +12 -0
  25. package/dist/cjs/shrink_file.d.ts.map +1 -0
  26. package/dist/cjs/shrink_file.js +38 -0
  27. package/dist/cjs/shrink_file.js.map +1 -0
  28. package/dist/cjs/stdin.d.ts +7 -0
  29. package/dist/cjs/stdin.d.ts.map +1 -0
  30. package/dist/cjs/stdin.js +34 -0
  31. package/dist/cjs/stdin.js.map +1 -0
  32. package/dist/cjs/validate.d.ts +11 -0
  33. package/dist/cjs/validate.d.ts.map +1 -0
  34. package/dist/cjs/validate.js +30 -0
  35. package/dist/cjs/validate.js.map +1 -0
  36. package/dist/esm/cli.d.ts +2 -0
  37. package/dist/esm/cli.d.ts.map +1 -0
  38. package/dist/esm/cli.js +76 -0
  39. package/dist/esm/cli.js.map +1 -0
  40. package/dist/esm/cli_utils.d.ts +30 -0
  41. package/dist/esm/cli_utils.d.ts.map +1 -0
  42. package/dist/esm/cli_utils.js +69 -0
  43. package/dist/esm/cli_utils.js.map +1 -0
  44. package/dist/esm/errors.d.ts +13 -0
  45. package/dist/esm/errors.d.ts.map +1 -0
  46. package/dist/esm/errors.js +50 -0
  47. package/dist/esm/errors.js.map +1 -0
  48. package/dist/esm/index.d.ts +3 -0
  49. package/dist/esm/index.d.ts.map +1 -0
  50. package/dist/esm/index.js +3 -0
  51. package/dist/esm/index.js.map +1 -0
  52. package/dist/esm/package.json +3 -0
  53. package/dist/esm/shrink.d.ts +131 -0
  54. package/dist/esm/shrink.d.ts.map +1 -0
  55. package/dist/esm/shrink.js +343 -0
  56. package/dist/esm/shrink.js.map +1 -0
  57. package/dist/esm/shrink_file.d.ts +12 -0
  58. package/dist/esm/shrink_file.d.ts.map +1 -0
  59. package/dist/esm/shrink_file.js +35 -0
  60. package/dist/esm/shrink_file.js.map +1 -0
  61. package/dist/esm/stdin.d.ts +7 -0
  62. package/dist/esm/stdin.d.ts.map +1 -0
  63. package/dist/esm/stdin.js +31 -0
  64. package/dist/esm/stdin.js.map +1 -0
  65. package/dist/esm/validate.d.ts +11 -0
  66. package/dist/esm/validate.d.ts.map +1 -0
  67. package/dist/esm/validate.js +27 -0
  68. package/dist/esm/validate.js.map +1 -0
  69. package/package.json +43 -0
  70. package/postbuild.sh +13 -0
  71. package/src/cli.ts +83 -0
  72. package/src/cli_utils.test.ts +117 -0
  73. package/src/cli_utils.ts +82 -0
  74. package/src/errors.ts +52 -0
  75. package/src/index.ts +3 -0
  76. package/src/shrink.test.ts +594 -0
  77. package/src/shrink.ts +385 -0
  78. package/src/shrink_file.test.ts +72 -0
  79. package/src/shrink_file.ts +38 -0
  80. package/src/stdin.ts +34 -0
  81. package/src/validate.test.ts +55 -0
  82. package/src/validate.ts +29 -0
  83. package/tsconfig.cjs.json +12 -0
  84. package/tsconfig.esm.json +15 -0
  85. package/tsconfig.json +23 -0
@@ -0,0 +1,343 @@
1
+ import { expandIamActions } from '@cloud-copilot/iam-expand';
2
+ import { ShrinkValidationError } from './errors.js';
3
+ import { validateShrinkResults } from './validate.js';
4
+ const defaultOptions = {
5
+ iterations: 2
6
+ };
7
+ //TODO: Add stats for how many iterations were run?
8
+ /**
9
+ * Shrink the list of desired patterns minus the excluded patterns to the smallest list of patterns
10
+ * that still includes the actions you want and only the actions you want.
11
+ *
12
+ * This will create a Target Set of actions that match the patterns in {@link desiredPatterns}, and do
13
+ * not match any pattern in {@link excludedPatterns}.
14
+ *
15
+ * It will then derive the list of wildcard patterns that match the Target Set and no other actions.
16
+ *
17
+ * @param desiredPatterns the list of patterns you want to include, e.g. ['s3:Get*', 's3:PutObject', 's3:*Tag*']
18
+ * @param iterations the number of iterations to run the shrink operations
19
+ * @returns the smallest list of patterns that will match only the actions specified by desiredPatterns and not match any of the excludedPatterns or any actions not specified by desiredPatterns.
20
+ */
21
+ export async function shrink(desiredPatterns, shrinkOptions) {
22
+ //Check for an all actions wildcard
23
+ const wildCard = desiredPatterns.find(pattern => collapseAsterisks(pattern) === '*');
24
+ if (wildCard) {
25
+ return ["*"];
26
+ }
27
+ const options = { ...defaultOptions, ...shrinkOptions };
28
+ const targetActions = await expandIamActions(desiredPatterns, { expandServiceAsterisk: true });
29
+ const expandedActionsByService = groupActionsByService(targetActions);
30
+ const services = Array.from(expandedActionsByService.keys()).sort();
31
+ const reducedActions = [];
32
+ for (const service of services) {
33
+ const desiredActions = expandedActionsByService.get(service);
34
+ const possibleActions = mapActions(await expandIamActions(`${service}:*`, { expandServiceAsterisk: true }));
35
+ const reducedServiceActions = shrinkResolvedList(desiredActions.withoutService, possibleActions, options.iterations);
36
+ //Validation
37
+ const reducedServiceActionsWithService = reducedServiceActions.map(action => `${service}:${action}`);
38
+ const invalidMatch = await validateShrinkResults(desiredActions.withService, reducedServiceActionsWithService);
39
+ if (invalidMatch) {
40
+ throw new ShrinkValidationError(desiredPatterns, invalidMatch);
41
+ }
42
+ reducedActions.push(...reducedServiceActionsWithService);
43
+ }
44
+ return reducedActions;
45
+ }
46
+ /**
47
+ * Map an array of service:action strings to just the action
48
+ *
49
+ * @param actions the array of service:action strings such as ['s3:GetObject', 'ec2:DescribeInstances']
50
+ * @returns an array of just the action strings such as ['GetObject', 'DescribeInstances']
51
+ */
52
+ export function mapActions(actions) {
53
+ return actions.map(action => action.split(":")[1]);
54
+ }
55
+ /**
56
+ * Groups an array of service:action strings by service
57
+ *
58
+ * Returns a map of service to an object with two arrays: withService and withoutService
59
+ * * withService contains the full service:action strings
60
+ * * withoutService contains just the action strings
61
+ *
62
+ * @param actions the array of service:action strings such as ['s3:GetObject', 'ec2:DescribeInstances']
63
+ * @returns a map of service to an object with two arrays: withService and withoutService
64
+ */
65
+ export function groupActionsByService(actions) {
66
+ const serviceMap = new Map();
67
+ actions.forEach(actionString => {
68
+ const [service, action] = actionString.split(":");
69
+ if (!serviceMap.has(service)) {
70
+ serviceMap.set(service, { withService: [], withoutService: [] });
71
+ }
72
+ serviceMap.get(service).withService.push(actionString);
73
+ serviceMap.get(service).withoutService.push(action);
74
+ });
75
+ return serviceMap;
76
+ }
77
+ /**
78
+ * Shrink a list of desired actions to the smallest number of patterns that match the desired actions
79
+ * from the possible actions and no other actions.
80
+ *
81
+ * @param desiredActions the list of actions you want to include
82
+ * @param possibleActions the list of actions that are possible
83
+ * @param iterations the number of iterations to run the shrink operations
84
+ * @returns the smallest list of patterns that when compared to possibleActions will match only the desiredActions and no others
85
+ */
86
+ export function shrinkResolvedList(desiredActions, possibleActions, iterations) {
87
+ const desiredActionSet = new Set(desiredActions);
88
+ const undesiredActions = possibleActions.filter(action => !desiredActionSet.has(action));
89
+ if (undesiredActions.length === 0) {
90
+ // If there are no undesired actions, that means we want all actions
91
+ return ["*"];
92
+ }
93
+ // Iteratively shrink based on the most commmon sequence until we can't shrink anymore
94
+ let previousActionListLength = desiredActions.length;
95
+ let actionList = desiredActions.slice();
96
+ do {
97
+ previousActionListLength = actionList.length;
98
+ actionList = shrinkIteration(actionList, undesiredActions, false);
99
+ iterations = iterations - 1;
100
+ if (iterations <= 0) {
101
+ return actionList;
102
+ }
103
+ } while (actionList.length < previousActionListLength);
104
+ // Iteratively shrink based on all common sequences until we can't shrink anymore
105
+ do {
106
+ previousActionListLength = actionList.length;
107
+ actionList = shrinkIteration(actionList, undesiredActions, true);
108
+ iterations = iterations - 1;
109
+ if (iterations <= 0) {
110
+ return actionList;
111
+ }
112
+ } while (actionList.length < previousActionListLength);
113
+ return actionList;
114
+ }
115
+ /**
116
+ * Shrink the list of desired actions for while excluding the undesired actions
117
+ *
118
+ * @param desiredActions the list of actions you want to include, can be a mix of full actions and wildcards
119
+ * @param undesiredActions the list of actions you want to exclude no matter what
120
+ * @param deep if true, will shrink based on all common sequences, otherwise will only shrink based on the most common sequence
121
+ * @returns the smallest list of actions that will match only the desiredActions and not match any of the undesiredActions or any actions not specified by desiredActions.
122
+ */
123
+ export function shrinkIteration(desiredActions, undesiredActions, deep) {
124
+ // Find all common words in the strings in the desiredActions array
125
+ const commonSequences = findCommonSequences(desiredActions).filter(sequence => sequence.sequence != "*");
126
+ ;
127
+ commonSequences.sort((a, b) => {
128
+ return b.frequency - a.frequency;
129
+ });
130
+ const sequencesToProcess = deep ? commonSequences : commonSequences.slice(0, 1);
131
+ // Reduce the actions based on the common sequences
132
+ let reducedActions = desiredActions;
133
+ for (const sequence of sequencesToProcess) {
134
+ const reducedIteration = Array.from(new Set(reducedActions.map(action => reduceAction(action, sequence.sequence, undesiredActions))));
135
+ reducedActions = consolidateWildcardPatterns(reducedIteration);
136
+ }
137
+ return reducedActions;
138
+ }
139
+ /**
140
+ * Reduces a singele action into a smaller number of parts by replace one part at a time with an asterisk
141
+ * and validating that there are no undesired actions that match the new action
142
+ *
143
+ * @param desiredAction the action to reduce
144
+ * @param sequence the sequence to reduce the action by
145
+ * @param undesiredActions the list of actions that should not match the reduced action
146
+ * @returns the reduced action with as many parts replaced with asterisks as possible while still matching the desired actions and not matching any of the undesired actions
147
+ */
148
+ export function reduceAction(desiredAction, sequence, undesiredActions) {
149
+ const testArray = splitActionIntoParts(desiredAction);
150
+ if (testArray.length === 1) {
151
+ return desiredAction;
152
+ }
153
+ const indexOfSequence = testArray.indexOf(sequence);
154
+ let shorterValue = desiredAction;
155
+ if (indexOfSequence === 0) {
156
+ const tempArray = testArray.slice();
157
+ //Iterate though ever following element and see if replacing the sequence with the first common sequence results in a failure
158
+ for (let i = 1; i < testArray.length; i++) {
159
+ tempArray[i] = "*";
160
+ const tempString = collapseAsterisks(tempArray.join(""));
161
+ const problemMatch = wildcardActionMatchesAnyString(tempString, undesiredActions);
162
+ if (problemMatch) {
163
+ // Stopping here seems to work the best
164
+ break;
165
+ }
166
+ shorterValue = tempString;
167
+ }
168
+ //its at the beginning
169
+ }
170
+ else if (indexOfSequence === testArray.length - 1) {
171
+ //its at the end
172
+ const tempArray = testArray.slice();
173
+ //Iterate through the array backwards and see if replace the items with * results in a failure
174
+ for (let i = testArray.length - 2; i >= 0; i--) {
175
+ tempArray[i] = "*";
176
+ const tempString = collapseAsterisks(tempArray.join(""));
177
+ const problemMatch = wildcardActionMatchesAnyString(tempString, undesiredActions);
178
+ if (problemMatch) {
179
+ // Stopping here seems to work the best
180
+ break;
181
+ }
182
+ shorterValue = tempString;
183
+ }
184
+ }
185
+ else if (indexOfSequence > 0) {
186
+ //its in the middle
187
+ const tempArray = testArray.slice();
188
+ //Iterate forward through the array and see if replacing the items with * results in a failure
189
+ for (let i = indexOfSequence + 1; i < testArray.length; i++) {
190
+ tempArray[i] = "*";
191
+ const tempString = collapseAsterisks(tempArray.join(""));
192
+ const problemMatch = wildcardActionMatchesAnyString(tempString, undesiredActions);
193
+ if (problemMatch) {
194
+ //This replacement cased a prolem match, so revert it before going backwards in the strings
195
+ tempArray[i] = testArray[i];
196
+ // Stopping here seems to work the best
197
+ break;
198
+ }
199
+ shorterValue = tempString;
200
+ }
201
+ //Iterate through the array backwards and see if replace the items with * results in a failure
202
+ for (let i = indexOfSequence - 1; i >= 0; i--) {
203
+ tempArray[i] = "*";
204
+ const tempString = collapseAsterisks(tempArray.join(""));
205
+ const problemMatch = wildcardActionMatchesAnyString(tempString, undesiredActions);
206
+ if (problemMatch) {
207
+ // Stopping here seems to work the best
208
+ break;
209
+ }
210
+ shorterValue = tempString;
211
+ }
212
+ }
213
+ return shorterValue;
214
+ }
215
+ /**
216
+ * Consolidate multile consecutive asterisks into a single asterisk
217
+ *
218
+ * @param wildcardAction the action to collapse
219
+ * @returns the action with consecutive asterisks collapsed into a single asterisk
220
+ */
221
+ export function collapseAsterisks(wildcardAction) {
222
+ return wildcardAction.replace(/\*+/g, '*');
223
+ }
224
+ /**
225
+ * Convert a wildcard action into a regular expression
226
+ *
227
+ * @param wildcardAction the wildcard action to convert
228
+ * @returns a regular expression that will match the wildcard action
229
+ */
230
+ export function regexForWildcardAction(wildcardAction) {
231
+ wildcardAction = collapseAsterisks(wildcardAction);
232
+ const pattern = "^" + wildcardAction.replace(/\*/g, '.*?') + "$";
233
+ return new RegExp(pattern, 'i');
234
+ }
235
+ /**
236
+ * Checks to see if a wildcard action matches any of the strings in a list
237
+ *
238
+ * @param wildcardAction the wildcard action to check
239
+ * @param strings the list of strings to check against
240
+ * @returns true if the wildcard action matches any of the strings
241
+ */
242
+ export function wildcardActionMatchesAnyString(wildcardAction, strings) {
243
+ const regex = regexForWildcardAction(wildcardAction);
244
+ for (const string of strings) {
245
+ if (regex.test(string)) {
246
+ return true;
247
+ }
248
+ }
249
+ return false;
250
+ }
251
+ /**
252
+ * Split an IAM Action into parts based on capital letters and asterisks
253
+ * For a new part to start there must be a transition from a lowercase letter to an uppercase letter or an asterisk
254
+ * For example :
255
+ * * "CreateAccessPointForObjectLambda" would be split into ["Create", "Access", "Point", "For", "Object", "Lambda"]
256
+ * * "*ObjectTagging*" would be split into ["*", "Object", "Tagging", "*"]
257
+ *
258
+ * @param input the IAM Action to split
259
+ * @returns the parts of the IAM Action
260
+ */
261
+ export function splitActionIntoParts(input) {
262
+ // Split the string using a regex that finds transitions from lower to upper case or asterisks
263
+ // and keeps sequences of uppercase letters together
264
+ // return input.split(/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/);
265
+ return input.split(/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?=[*])|(?<=[*])/);
266
+ }
267
+ /**
268
+ * Given a list of strings and a list of strings those parts are in, count the number of times each part appears in the strings
269
+ *
270
+ * @param substrings the sub strings to count
271
+ * @param actions the list of strings to count the substrings in
272
+ * @returns Returns a map of the substring to the number of times it appears in the actions
273
+ */
274
+ export function countSubstrings(substrings, actions) {
275
+ const substringCount = new Map();
276
+ substrings.forEach(substring => {
277
+ let count = 0;
278
+ actions.forEach(action => {
279
+ if (action.includes(substring)) {
280
+ count++;
281
+ }
282
+ });
283
+ if (count > 0) {
284
+ substringCount.set(substring, count);
285
+ }
286
+ });
287
+ return substringCount;
288
+ }
289
+ /**
290
+ * Finds all the the common sequences in a list of actions strings and counts their frequency and length.
291
+ *
292
+ * @param actions the list of actions to find common sequences in
293
+ * @returns an array of objects with the sequence, frequency, and length of the common sequences
294
+ */
295
+ export function findCommonSequences(actions) {
296
+ const allSubstrings = new Set();
297
+ actions.forEach(action => {
298
+ splitActionIntoParts(action).forEach(substring => allSubstrings.add(substring));
299
+ });
300
+ const substringCount = countSubstrings(Array.from(allSubstrings), actions);
301
+ const result = [];
302
+ substringCount.forEach((frequency, sequence) => {
303
+ result.push({ sequence, frequency, length: sequence.length });
304
+ });
305
+ return result;
306
+ }
307
+ /**
308
+ * Consolidates overlapping wildcards into their most general form
309
+ *
310
+ * For example:
311
+ * ['*Object', 'Object*', '*Object*'] will be consolidated into ['*Object*']
312
+ * ['Get*', '*Get*'] will be consolidated into ['*Get*']
313
+ *
314
+ * @param patterns the list of patterns to consolidate
315
+ * @returns the consolidated list of patterns
316
+ */
317
+ export function consolidateWildcardPatterns(patterns) {
318
+ // Sort patterns to handle simpler cases first
319
+ patterns.sort((a, b) => b.length - a.length);
320
+ let consolidatedPatterns = [];
321
+ for (const pattern of patterns) {
322
+ //If it's already covered, skip it
323
+ const coveredByExistingPattern = consolidatedPatterns.some(consolidated => matchesPattern(consolidated, pattern));
324
+ if (coveredByExistingPattern) {
325
+ continue;
326
+ }
327
+ //If it subsumes any existing patterns, remove them
328
+ consolidatedPatterns = consolidatedPatterns.filter(consolidated => !matchesPattern(pattern, consolidated));
329
+ consolidatedPatterns.push(pattern);
330
+ }
331
+ return consolidatedPatterns;
332
+ }
333
+ /**
334
+ * Checks a specific string against a general pattern
335
+ * @param general the general pattern, e.g. 's3:Get*'
336
+ * @param specific the specific string, e.g. 's3:GetObject'
337
+ * @returns true if the specific string matches the general pattern
338
+ */
339
+ function matchesPattern(general, specific) {
340
+ const regex = new RegExp("^" + general.replace(/\*/g, ".*") + "$");
341
+ return regex.test(specific);
342
+ }
343
+ //# sourceMappingURL=shrink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shrink.js","sourceRoot":"","sources":["../../src/shrink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { ShrinkOptions } from "./shrink.js";
2
+ /**
3
+ * Takes any JSON document and shrinks any Action or NotAction array of strings in the document.
4
+ * *MODIFIES THE DOCUMENT IN PLACE*
5
+ *
6
+ * @param options the options to use when shrinking the actions
7
+ * @param document the JSON document to expand
8
+ * @param key the key of the current node in the document
9
+ * @returns the original JSON document with any actions expanded in place
10
+ */
11
+ export declare function shrinkJsonDocument(options: Partial<ShrinkOptions>, document: any, key?: string): Promise<any>;
12
+ //# sourceMappingURL=shrink_file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shrink_file.d.ts","sourceRoot":"","sources":["../../src/shrink_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAU,MAAM,aAAa,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA0BnH"}
@@ -0,0 +1,35 @@
1
+ import { shrink } from "./shrink.js";
2
+ /**
3
+ * Takes any JSON document and shrinks any Action or NotAction array of strings in the document.
4
+ * *MODIFIES THE DOCUMENT IN PLACE*
5
+ *
6
+ * @param options the options to use when shrinking the actions
7
+ * @param document the JSON document to expand
8
+ * @param key the key of the current node in the document
9
+ * @returns the original JSON document with any actions expanded in place
10
+ */
11
+ export async function shrinkJsonDocument(options, document, key) {
12
+ if (key === 'Action' || key === 'NotAction') {
13
+ // if (typeof document === 'string') {
14
+ // // return shrink([document], options);
15
+ // }
16
+ if (Array.isArray(document) && document.length > 0 && typeof document[0] === 'string') {
17
+ return shrink(document, options);
18
+ }
19
+ }
20
+ if (Array.isArray(document)) {
21
+ const results = [];
22
+ for (const item of document) {
23
+ results.push(await shrinkJsonDocument(options, item));
24
+ }
25
+ return results;
26
+ }
27
+ if (typeof document === 'object' && document !== null) {
28
+ for (const key of Object.keys(document)) {
29
+ document[key] = await shrinkJsonDocument(options, document[key], key);
30
+ }
31
+ return document;
32
+ }
33
+ return document;
34
+ }
35
+ //# sourceMappingURL=shrink_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shrink_file.js","sourceRoot":"","sources":["../../src/shrink_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,MAAM,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAA+B,EAAE,QAAa,EAAE,GAAY;IACnG,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;QAC5C,sCAAsC;QACtC,2CAA2C;QAC3C,IAAI;QACJ,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YACtF,OAAO,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,EAAE,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,kBAAkB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxC,QAAQ,CAAC,GAAG,CAAC,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Read from stdin until the stream ends, timeout, or an error occurs
3
+ *
4
+ * @returns the string input from stdin
5
+ */
6
+ export declare function readStdin(readWait: number | undefined): Promise<string>;
7
+ //# sourceMappingURL=stdin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../src/stdin.ts"],"names":[],"mappings":"AACA;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B7E"}
@@ -0,0 +1,31 @@
1
+ import { stdin } from 'process';
2
+ /**
3
+ * Read from stdin until the stream ends, timeout, or an error occurs
4
+ *
5
+ * @returns the string input from stdin
6
+ */
7
+ export async function readStdin(readWait) {
8
+ return new Promise((resolve, reject) => {
9
+ // If the input is not a TTY, we are most likely receiving data from a pipe.
10
+ const definitelyReceivingData = !process.stdin.isTTY;
11
+ if (!readWait || readWait <= 0) {
12
+ readWait = definitelyReceivingData ? 10000 : 20;
13
+ }
14
+ let data = '';
15
+ setTimeout(() => {
16
+ if (data.length === 0) {
17
+ resolve(data);
18
+ }
19
+ }, readWait);
20
+ stdin.on('data', (chunk) => {
21
+ data += chunk;
22
+ });
23
+ stdin.on('end', () => {
24
+ resolve(data);
25
+ });
26
+ stdin.on('error', (err) => {
27
+ reject(err);
28
+ });
29
+ });
30
+ }
31
+ //# sourceMappingURL=stdin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.js","sourceRoot":"","sources":["../../src/stdin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAA4B;IAC1D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,4EAA4E;QAC5E,MAAM,uBAAuB,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAA;QACpD,IAAG,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAC9B,QAAQ,GAAG,uBAAuB,CAAC,CAAC,CAAC,KAAM,CAAC,CAAC,CAAC,EAAE,CAAA;QAClD,CAAC;QAED,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,UAAU,CAAC,GAAG,EAAE;YACd,IAAG,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,OAAO,CAAC,IAAI,CAAC,CAAA;YACf,CAAC;QACH,CAAC,EAAE,QAAQ,CAAC,CAAA;QAEZ,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YACzB,IAAI,IAAI,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACnB,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Checks a list of patterns against a list of desired actions to validate:
3
+ * * All desired actions are matched by the patterns
4
+ * * No undesired actions are matched by the patterns
5
+ *
6
+ * @param desiredActions The actions that should be in the list
7
+ * @param patterns The list of patterns that the algorithm has derived
8
+ * @returns the first match error if any, otherwise undefined
9
+ */
10
+ export declare function validateShrinkResults(desiredActions: string[], patterns: string[]): Promise<string | undefined>;
11
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAAC,cAAc,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiBrH"}
@@ -0,0 +1,27 @@
1
+ import { expandIamActions } from "@cloud-copilot/iam-expand";
2
+ /**
3
+ * Checks a list of patterns against a list of desired actions to validate:
4
+ * * All desired actions are matched by the patterns
5
+ * * No undesired actions are matched by the patterns
6
+ *
7
+ * @param desiredActions The actions that should be in the list
8
+ * @param patterns The list of patterns that the algorithm has derived
9
+ * @returns the first match error if any, otherwise undefined
10
+ */
11
+ export async function validateShrinkResults(desiredActions, patterns) {
12
+ const desiredActionSet = new Set(desiredActions);
13
+ const expandedAfterActions = await expandIamActions(patterns, { expandServiceAsterisk: true });
14
+ const expandedAfterActionSet = new Set(expandedAfterActions);
15
+ for (const afterAction of expandedAfterActions) {
16
+ if (!desiredActionSet.has(afterAction)) {
17
+ return `Undesired action: ${afterAction}`;
18
+ }
19
+ }
20
+ for (const desiredAction of desiredActions) {
21
+ if (!expandedAfterActionSet.has(desiredAction)) {
22
+ return `Missing action ${desiredAction}`;
23
+ }
24
+ }
25
+ return undefined;
26
+ }
27
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,cAAwB,EAAE,QAAkB;IACtF,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;IACjD,MAAM,oBAAoB,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,EAAC,qBAAqB,EAAE,IAAI,EAAC,CAAC,CAAC;IAC7F,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC7D,KAAI,MAAM,WAAW,IAAI,oBAAoB,EAAE,CAAC;QAC9C,IAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACtC,OAAO,qBAAqB,WAAW,EAAE,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,KAAI,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC1C,IAAG,CAAC,sBAAsB,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YAC9C,OAAO,kBAAkB,aAAa,EAAE,CAAA;QAC1C,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@cloud-copilot/iam-shrink",
3
+ "version": "0.1.0",
4
+ "description": "Shrink IAM Policies",
5
+ "scripts": {
6
+ "build": "npx tsc -p tsconfig.cjs.json && npx tsc -p tsconfig.esm.json && ./postbuild.sh",
7
+ "test": "npx vitest --run --coverage"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/cloud-copilot/iam-shrink.git"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/esm/index.js",
16
+ "require": "./dist/cjs/index.js"
17
+ }
18
+ },
19
+ "types": "dist/cjs/index.d.ts",
20
+ "bin": {
21
+ "iam-shrink": "dist/esm/cli.js"
22
+ },
23
+ "keywords": [
24
+ "AWS",
25
+ "IAM"
26
+ ],
27
+ "author": "David Kerber <dave@cloudcopilot.io>",
28
+ "license": "GPL-3.0-or-later",
29
+ "bugs": {
30
+ "url": "https://github.com/cloud-copilot/iam-shrink/issues"
31
+ },
32
+ "homepage": "https://github.com/cloud-copilot/iam-shrink#readme",
33
+ "devDependencies": {
34
+ "@types/node": "^22.5.0",
35
+ "@vitest/coverage-v8": "^2.0.5",
36
+ "typescript": "^5.5.4",
37
+ "vitest": "^2.0.5"
38
+ },
39
+ "peerDependencies": {
40
+ "@cloud-copilot/iam-data": ">=0.5.0 <1.0.0",
41
+ "@cloud-copilot/iam-expand": ">=0.2.0 <1.0.0"
42
+ }
43
+ }
package/postbuild.sh ADDED
@@ -0,0 +1,13 @@
1
+ cat >dist/cjs/package.json <<!EOF
2
+ {
3
+ "type": "commonjs"
4
+ }
5
+ !EOF
6
+
7
+ cat >dist/esm/package.json <<!EOF
8
+ {
9
+ "type": "module"
10
+ }
11
+ !EOF
12
+
13
+ chmod +x dist/**/cli.js
package/src/cli.ts ADDED
@@ -0,0 +1,83 @@
1
+ import { iamDataUpdatedAt, iamDataVersion } from "@cloud-copilot/iam-data"
2
+ import { convertOptions, parseStdIn } from "./cli_utils.js"
3
+ import { shrink, ShrinkOptions } from "./shrink.js"
4
+
5
+ const commandName = 'iam-shrink'
6
+ const dataPackage = '@cloud-copilot/iam-data'
7
+
8
+ async function shrinkAandPrint(actions: string[], shrinkOptions: Partial<ShrinkOptions>) {
9
+ try {
10
+ const result = await shrink(actions, shrinkOptions)
11
+ for (const action of result) {
12
+ console.log(action)
13
+ }
14
+ } catch (e: any) {
15
+ console.error(e.message)
16
+ process.exit(1)
17
+ }
18
+ }
19
+
20
+ function printUsage() {
21
+ console.log('No arguments provided or input from stdin')
22
+ console.log('Usage:')
23
+ console.log(` ${commandName} [options] [action1] [action2] ...`)
24
+ console.log(` <input from stdout> | ${commandName} [options]`)
25
+ console.log('Shrink ActionOptions:')
26
+ console.log(' --iterations: How many iterations of shrinking should be executed, defaults to 2; zero or less means no limit')
27
+ console.log(' Example: --iterations=5')
28
+ console.log(' Example: --iterations=-1')
29
+ console.log('CLI Behavior Options:')
30
+ console.log(' --show-data-version: Print the version of the iam-data package being used and exit')
31
+ console.log(' --read-wait-ms: Millisenconds to wait for the first byte from stdin before timing out.')
32
+ console.log(' Example: --read-wait-ms=10_000')
33
+ process.exit(1)
34
+ }
35
+
36
+ const args = process.argv.slice(2); // Ignore the first two elements
37
+ const actionStrings: string[] = []
38
+ const optionStrings: string[] = []
39
+
40
+ for (const arg of args) {
41
+ if(arg.startsWith('--')) {
42
+ optionStrings.push(arg)
43
+ } else {
44
+ actionStrings.push(arg)
45
+ }
46
+ }
47
+
48
+ async function run() {
49
+ const options = convertOptions(optionStrings)
50
+ if(options.showDataVersion) {
51
+ const version = await iamDataVersion()
52
+ console.log(`${dataPackage} version: ${version}`)
53
+ console.log(`Data last updated: ${await iamDataUpdatedAt()}`)
54
+ console.log(`Update with either:`)
55
+ console.log(` npm update ${dataPackage}`)
56
+ console.log(` npm update -g ${dataPackage}`)
57
+ return
58
+ }
59
+
60
+ if(actionStrings.length === 0) {
61
+ //If no actions are provided, read from stdin
62
+ const stdInResult = await parseStdIn(options)
63
+ if(stdInResult.object) {
64
+ console.log(JSON.stringify(stdInResult.object, null, 2))
65
+ return
66
+ } else if (stdInResult.strings) {
67
+ actionStrings.push(...stdInResult.strings)
68
+ }
69
+ }
70
+
71
+ if(actionStrings.length > 0) {
72
+ await shrinkAandPrint(actionStrings, options)
73
+ return
74
+ }
75
+
76
+ printUsage()
77
+
78
+ }
79
+
80
+ run().catch((e) => {
81
+ console.error(e)
82
+ process.exit(1)
83
+ }).then(() => {}).finally(() => {})