@cloud-copilot/iam-expand 0.1.9 → 0.1.11

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.
@@ -1,147 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { convertOptions, dashToCamelCase, extractActionsFromLineOfInput, parseStdIn } from "./cli_utils";
3
- import { InvalidActionBehavior } from './expand.js';
4
- import { readStdin } from './stdin';
5
- vi.mock('./stdin')
6
-
7
- beforeEach(() => {
8
- vi.resetAllMocks()
9
- })
10
-
11
- const extractScenarios = [
12
- {input: ' s3:Get* ', expected: ['s3:Get*']},
13
- {input: ' s3:Get* s3:Put* ', expected: ['s3:Get*', 's3:Put*']},
14
- {input: ' "s3:Get*", "s3:Put*"', expected: ['s3:Get*', 's3:Put*']},
15
- {input: ' `s3:Get*`, `s3:Put*`', expected: ['s3:Get*', 's3:Put*']},
16
- {input: ` 's3:Get*', 's3:Put*'`, expected: ['s3:Get*', 's3:Put*']},
17
- {input: ` 'resource-Groups:Get*'`, expected: ['resource-Groups:Get*']},
18
- {input: `s3:Get*, s3:Put*`, expected: ['s3:Get*', 's3:Put*']},
19
- {input: "s3:Put*", expected: ['s3:Put*']},
20
- {input: ":s3:Put*", expected: []},
21
- {input: 'arn:aws:apigateway:*::/apis', expected: []},
22
- {input: 'hamburger', expected: []},
23
- ]
24
-
25
- const dashToCamelCaseScenarios = [
26
- {input: "--distinct", expected: "distinct"},
27
- {input: "--sort", expected: "sort"},
28
- {input: "--expand-asterisk", expected: "expandAsterisk"},
29
- {input: "--expand-service-asterisk", expected: "expandServiceAsterisk"},
30
- {input: "--error-on-missing-service", expected: "errorOnMissingService"},
31
- {input: "--error-on-invalid-format", expected: "errorOnInvalidFormat"},
32
- {input: "--show-data-version", expected: "showDataVersion"},
33
- ]
34
-
35
- describe('cli_utils', () => {
36
- describe('extractActionsFromLineOfInput', () => {
37
- extractScenarios.forEach((scenario, index) => {
38
- it(`should return for scenario ${index}: ${scenario.input} `, () => {
39
- // Given the input
40
- const input = scenario.input
41
-
42
- // When the actions are extracted
43
- const result = extractActionsFromLineOfInput(input)
44
-
45
- // Then I should get the expected result
46
- expect(result).toEqual(scenario.expected)
47
- })
48
- })
49
- })
50
-
51
- describe('dashToCamelCase', () => {
52
- dashToCamelCaseScenarios.forEach((scenario, index) => {
53
- it(`should return for scenario ${index}: ${scenario.input} `, () => {
54
- // Given the input
55
- const input = scenario.input
56
-
57
- // When the input is converted
58
- const result = dashToCamelCase(input)
59
-
60
- // Then I should get the expected result
61
- expect(result).toEqual(scenario.expected)
62
- })
63
- })
64
- })
65
-
66
- describe('convertOptions', () => {
67
- it('should convert the options to keys on an object', () => {
68
- // Given options as an array of strings
69
- const optionArgs = ['--distinct', '--sort', '--something-cool', '--key-with-value=10']
70
-
71
- // When the options are converted
72
- const result = convertOptions(optionArgs)
73
-
74
- // Then each option should be a key on the object
75
- expect(result).toEqual({
76
- distinct: true,
77
- sort: true,
78
- somethingCool: true,
79
- keyWithValue: "10",
80
- })
81
- })
82
-
83
- it('should convert the invalidActionBehavior to an enum', () => {
84
- // Given an invalid action behavior option
85
- const optionArgs = ['--invalid-action-behavior=error']
86
-
87
- // When the options are converted
88
- const result = convertOptions(optionArgs)
89
-
90
- // Then the invalidActionBehavior should be an enum
91
- expect(result).toEqual({
92
- invalidActionBehavior: InvalidActionBehavior.Error,
93
- })
94
- })
95
-
96
- it('should remove the invalidActionBehavior if the value is not valid', () => {
97
- // Given an invalid action behavior option
98
- const optionArgs = ['--invalid-action-behavior=not-a-real-value']
99
-
100
- // When the options are converted
101
- const result = convertOptions(optionArgs)
102
-
103
- // Then the invalidActionBehavior should be removed
104
- expect(result).toEqual({})
105
- })
106
- })
107
-
108
- describe('parseStdIn', () => {
109
- it('should return an empty object if no data is provided', async () => {
110
- // Given no data is provided
111
- vi.mocked(readStdin).mockResolvedValue('')
112
-
113
- // When the actions are parsed
114
- const result = await parseStdIn({})
115
-
116
- // Then I should get an empty object
117
- expect(result).toEqual({})
118
- })
119
-
120
- it('should return an array of actions from the data if it cannot be parsed', async () => {
121
- // Given there is data with actions in multiple lines
122
- vi.mocked(readStdin).mockResolvedValue('s3:GetObject\ns3:PutObject\ns3:DeleteObject\n')
123
-
124
- // When the actions are parsed
125
- const result = await parseStdIn({})
126
-
127
- // Then I should get the expected actions
128
- expect(result).toEqual({strings: ['s3:GetObject', 's3:PutObject', 's3:DeleteObject']})
129
- })
130
-
131
- it('should return an object if the data can be parsed', async () => {
132
- // Given there is data that can be parsed
133
- const dataValue = {
134
- Action: ["s3:GetObject"],
135
- Version: "2012-10-17"
136
- }
137
- vi.mocked(readStdin).mockResolvedValue(JSON.stringify(dataValue))
138
-
139
- // When the actions are parsed
140
- const result = await parseStdIn({})
141
-
142
- // Then I should get the expected object
143
- expect(result).toEqual({object: dataValue})
144
- })
145
- })
146
- })
147
-
package/src/cli_utils.ts DELETED
@@ -1,84 +0,0 @@
1
-
2
- import { ExpandIamActionsOptions, InvalidActionBehavior } from "./expand.js";
3
- import { expandJsonDocument } from "./expand_file.js";
4
- import { readStdin } from "./stdin.js";
5
-
6
- interface CliOptions extends ExpandIamActionsOptions {
7
- showDataVersion: boolean
8
- readWaitTime: string
9
- }
10
-
11
- /**
12
- * Convert a dash-case string to camelCase
13
- * @param str the string to convert
14
- * @returns the camelCase string
15
- */
16
- export function dashToCamelCase(str: string): string {
17
- str = str.substring(2)
18
- return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
19
- }
20
-
21
- /**
22
- * Convert an array of option strings to an object
23
- *
24
- * @param optionArgs the array of option strings to convert
25
- * @returns the object representation of the options
26
- */
27
- export function convertOptions(optionArgs: string[]): Partial<CliOptions> {
28
- const options: Record<string, string | boolean> = {} ;
29
-
30
- for(const option of optionArgs) {
31
- let key: string = option
32
- let value: boolean | string = true
33
- if(option.includes('=')) {
34
- [key,value] = option.split('=')
35
- }
36
-
37
- options[dashToCamelCase(key)] = value
38
- }
39
-
40
- if(typeof(options.invalidActionBehavior) === 'string') {
41
- const behaviorString = options.invalidActionBehavior as string
42
- const cleanedInput = behaviorString.charAt(0).toUpperCase() + behaviorString.slice(1).toLowerCase();
43
- const behavior = InvalidActionBehavior[cleanedInput as keyof typeof InvalidActionBehavior];
44
- if(behavior) {
45
- options.invalidActionBehavior = behavior
46
- } else {
47
- delete options['invalidActionBehavior']
48
- }
49
- }
50
-
51
- return options
52
- }
53
-
54
- const actionPattern = /\:?([a-zA-Z0-9-]+:[a-zA-Z0-9*]+)/g;
55
- export function extractActionsFromLineOfInput(line: string): string[] {
56
- const matches = line.matchAll(actionPattern)
57
-
58
- return Array.from(matches)
59
- .filter((match) => !match[0].startsWith('arn:') && !match[0].startsWith(':'))
60
- .map((match) => match[1])
61
- }
62
-
63
- /**
64
- * Parse the actions from stdin
65
- *
66
- * @returns an array of strings from stdin
67
- */
68
- export async function parseStdIn(options: Partial<CliOptions>): Promise<{strings?: string[], object?: any}> {
69
- const delay = options.readWaitTime ? parseInt(options.readWaitTime.replaceAll(/\D/g, '')) : undefined
70
- const data = await readStdin(delay)
71
- if(data.length === 0) {
72
- return {}
73
- }
74
-
75
- try {
76
- const object = await expandJsonDocument(options, JSON.parse(data))
77
- return {object}
78
- } catch (err: any) {}
79
-
80
-
81
- const lines = data.split('\n')
82
- const actions = lines.flatMap(line => extractActionsFromLineOfInput(line))
83
- return {strings: actions}
84
- }