@cloud-copilot/iam-simulate 0.1.102 → 0.1.104

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 (80) hide show
  1. package/README.md +22 -7
  2. package/dist/cjs/index.d.ts +1 -1
  3. package/dist/cjs/index.d.ts.map +1 -1
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/request/requestResource.d.ts +12 -0
  6. package/dist/cjs/request/requestResource.d.ts.map +1 -1
  7. package/dist/cjs/request/requestResource.js +6 -0
  8. package/dist/cjs/request/requestResource.js.map +1 -1
  9. package/dist/cjs/resource/resource.d.ts +11 -2
  10. package/dist/cjs/resource/resource.d.ts.map +1 -1
  11. package/dist/cjs/resource/resource.js +170 -8
  12. package/dist/cjs/resource/resource.js.map +1 -1
  13. package/dist/cjs/simulation_engine/contextKeys.d.ts +2 -1
  14. package/dist/cjs/simulation_engine/contextKeys.d.ts.map +1 -1
  15. package/dist/cjs/simulation_engine/contextKeys.js +13 -8
  16. package/dist/cjs/simulation_engine/contextKeys.js.map +1 -1
  17. package/dist/cjs/simulation_engine/overallResult.d.ts +13 -0
  18. package/dist/cjs/simulation_engine/overallResult.d.ts.map +1 -0
  19. package/dist/cjs/simulation_engine/overallResult.js +35 -0
  20. package/dist/cjs/simulation_engine/overallResult.js.map +1 -0
  21. package/dist/cjs/simulation_engine/policyResources.d.ts +41 -0
  22. package/dist/cjs/simulation_engine/policyResources.d.ts.map +1 -0
  23. package/dist/cjs/simulation_engine/policyResources.js +112 -0
  24. package/dist/cjs/simulation_engine/policyResources.js.map +1 -0
  25. package/dist/cjs/simulation_engine/resourceTypes.d.ts +18 -0
  26. package/dist/cjs/simulation_engine/resourceTypes.d.ts.map +1 -0
  27. package/dist/cjs/simulation_engine/resourceTypes.js +145 -0
  28. package/dist/cjs/simulation_engine/resourceTypes.js.map +1 -0
  29. package/dist/cjs/simulation_engine/simulationEngine.d.ts +92 -14
  30. package/dist/cjs/simulation_engine/simulationEngine.d.ts.map +1 -1
  31. package/dist/cjs/simulation_engine/simulationEngine.js +74 -16
  32. package/dist/cjs/simulation_engine/simulationEngine.js.map +1 -1
  33. package/dist/cjs/util/resourceStrings.d.ts +10 -0
  34. package/dist/cjs/util/resourceStrings.d.ts.map +1 -0
  35. package/dist/cjs/util/resourceStrings.js +81 -0
  36. package/dist/cjs/util/resourceStrings.js.map +1 -0
  37. package/dist/cjs/util.d.ts +0 -10
  38. package/dist/cjs/util.d.ts.map +1 -1
  39. package/dist/cjs/util.js +0 -25
  40. package/dist/cjs/util.js.map +1 -1
  41. package/dist/esm/index.d.ts +1 -1
  42. package/dist/esm/index.d.ts.map +1 -1
  43. package/dist/esm/index.js.map +1 -1
  44. package/dist/esm/request/requestResource.d.ts +12 -0
  45. package/dist/esm/request/requestResource.d.ts.map +1 -1
  46. package/dist/esm/request/requestResource.js +6 -0
  47. package/dist/esm/request/requestResource.js.map +1 -1
  48. package/dist/esm/resource/resource.d.ts +11 -2
  49. package/dist/esm/resource/resource.d.ts.map +1 -1
  50. package/dist/esm/resource/resource.js +169 -8
  51. package/dist/esm/resource/resource.js.map +1 -1
  52. package/dist/esm/simulation_engine/contextKeys.d.ts +2 -1
  53. package/dist/esm/simulation_engine/contextKeys.d.ts.map +1 -1
  54. package/dist/esm/simulation_engine/contextKeys.js +14 -9
  55. package/dist/esm/simulation_engine/contextKeys.js.map +1 -1
  56. package/dist/esm/simulation_engine/overallResult.d.ts +13 -0
  57. package/dist/esm/simulation_engine/overallResult.d.ts.map +1 -0
  58. package/dist/esm/simulation_engine/overallResult.js +32 -0
  59. package/dist/esm/simulation_engine/overallResult.js.map +1 -0
  60. package/dist/esm/simulation_engine/policyResources.d.ts +41 -0
  61. package/dist/esm/simulation_engine/policyResources.d.ts.map +1 -0
  62. package/dist/esm/simulation_engine/policyResources.js +106 -0
  63. package/dist/esm/simulation_engine/policyResources.js.map +1 -0
  64. package/dist/esm/simulation_engine/resourceTypes.d.ts +18 -0
  65. package/dist/esm/simulation_engine/resourceTypes.d.ts.map +1 -0
  66. package/dist/esm/simulation_engine/resourceTypes.js +141 -0
  67. package/dist/esm/simulation_engine/resourceTypes.js.map +1 -0
  68. package/dist/esm/simulation_engine/simulationEngine.d.ts +92 -14
  69. package/dist/esm/simulation_engine/simulationEngine.d.ts.map +1 -1
  70. package/dist/esm/simulation_engine/simulationEngine.js +75 -17
  71. package/dist/esm/simulation_engine/simulationEngine.js.map +1 -1
  72. package/dist/esm/util/resourceStrings.d.ts +10 -0
  73. package/dist/esm/util/resourceStrings.d.ts.map +1 -0
  74. package/dist/esm/util/resourceStrings.js +78 -0
  75. package/dist/esm/util/resourceStrings.js.map +1 -0
  76. package/dist/esm/util.d.ts +0 -10
  77. package/dist/esm/util.d.ts.map +1 -1
  78. package/dist/esm/util.js +1 -25
  79. package/dist/esm/util.js.map +1 -1
  80. package/package.json +2 -2
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMatchingResourceStringsForPolicies = getMatchingResourceStringsForPolicies;
4
+ exports.getResourceStringsFromStatement = getResourceStringsFromStatement;
5
+ exports.statementResourceStringsForResourceTypeAndPattern = statementResourceStringsForResourceTypeAndPattern;
6
+ exports.statementAllowsAction = statementAllowsAction;
7
+ const iam_utils_1 = require("@cloud-copilot/iam-utils");
8
+ const resourceStrings_js_1 = require("../util/resourceStrings.js");
9
+ const resourceTypes_js_1 = require("./resourceTypes.js");
10
+ /**
11
+ * Extracts matching resource strings from a set of policies for a given action and resource pattern.
12
+ *
13
+ * @param policies Array of policies to search through (undefined entries are skipped)
14
+ * @param action The action to match against policy statements
15
+ * @param resourceType The resource type to filter resource strings by
16
+ * @param resourceArnPattern The resource ARN pattern to match against
17
+ * @returns Array of unique resource strings that match the criteria
18
+ */
19
+ function getMatchingResourceStringsForPolicies(policies, action, resourceType, resourceArnPattern) {
20
+ const resourceStrings = new Set();
21
+ for (const policy of policies) {
22
+ if (!policy) {
23
+ continue;
24
+ }
25
+ for (const statement of policy.statements()) {
26
+ const stmtResourceStrings = getResourceStringsFromStatement(statement, action, resourceType, resourceArnPattern);
27
+ for (const rs of stmtResourceStrings) {
28
+ resourceStrings.add(rs);
29
+ }
30
+ }
31
+ }
32
+ return Array.from(resourceStrings);
33
+ }
34
+ /**
35
+ * Extracts resource strings from a single policy statement that allows the specified action.
36
+ *
37
+ * @param statement The policy statement to analyze
38
+ * @param action The action to check if the statement allows
39
+ * @param resourceType The resource type to filter by
40
+ * @param resourceArnPattern The resource ARN pattern to match
41
+ * @returns Array of resource strings from the statement, or empty array if statement doesn't allow the action
42
+ */
43
+ function getResourceStringsFromStatement(statement, action, resourceType, resourceArnPattern) {
44
+ if (statementAllowsAction(statement, action)) {
45
+ return statementResourceStringsForResourceTypeAndPattern(statement, resourceType, resourceArnPattern);
46
+ }
47
+ return [];
48
+ }
49
+ /**
50
+ * Extracts resource strings from a statement's Resource or NotResource elements that match the given criteria.
51
+ *
52
+ * @param statement The policy statement to analyze
53
+ * @param resourceType The resource type to filter by
54
+ * @param resourceArnPattern The resource ARN pattern to check for overlap
55
+ * @returns Array of matching resource strings, or ['*'] for certain NotResource cases
56
+ */
57
+ function statementResourceStringsForResourceTypeAndPattern(statement, resourceType, resourceArnPattern) {
58
+ if (statement.isResourceStatement() && statement.isAllow()) {
59
+ const resourceStrings = [];
60
+ for (const stmtResource of statement.resources()) {
61
+ if ((0, resourceTypes_js_1.resourceStringMatchesResourceTypePattern)(stmtResource.value(), resourceType.arn)) {
62
+ if ((0, resourceStrings_js_1.resourceArnsOverlap)(resourceArnPattern, stmtResource.value())) {
63
+ resourceStrings.push(stmtResource.value());
64
+ }
65
+ }
66
+ }
67
+ return resourceStrings;
68
+ }
69
+ if (statement.isNotResourceStatement() && statement.isAllow()) {
70
+ for (const stmtNotResource of statement.notResources()) {
71
+ // If any NotResource string equals or is a superset of the resource type pattern, then the statement does not apply to the string. Otherwise, it should return the string '*'
72
+ if (stmtNotResource.value() === resourceArnPattern ||
73
+ isResourceArnSuperset(stmtNotResource.value(), resourceArnPattern)) {
74
+ return [];
75
+ }
76
+ }
77
+ return ['*'];
78
+ }
79
+ // If it's a statement that has no Resource or NotResource such as a trust policy, just return the original pattern
80
+ return [resourceArnPattern];
81
+ }
82
+ /**
83
+ * Determines if a policy statement allows the specified action.
84
+ *
85
+ * @param statement The policy statement to check
86
+ * @param action The action to test against the statement
87
+ * @returns true if the statement allows the action, false otherwise
88
+ */
89
+ function statementAllowsAction(statement, action) {
90
+ if (statement.isActionStatement() && statement.isAllow()) {
91
+ for (const stmtAction of statement.actions()) {
92
+ if ((0, iam_utils_1.actionMatchesPattern)(action, stmtAction.value())) {
93
+ return true;
94
+ }
95
+ }
96
+ return false;
97
+ }
98
+ else if (statement.isNotActionStatement() && statement.isAllow()) {
99
+ for (const stmtAction of statement.notActions()) {
100
+ if ((0, iam_utils_1.actionMatchesPattern)(action, stmtAction.value())) {
101
+ return false;
102
+ }
103
+ }
104
+ return true;
105
+ }
106
+ return false;
107
+ }
108
+ function isResourceArnSuperset(arnSuperset, arnSubset) {
109
+ const regexSuperset = (0, iam_utils_1.resourceArnWithWildcardsToRegex)(arnSuperset);
110
+ return regexSuperset.test(arnSubset);
111
+ }
112
+ //# sourceMappingURL=policyResources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyResources.js","sourceRoot":"","sources":["../../../src/simulation_engine/policyResources.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { ResourceType } from '@cloud-copilot/iam-data';
2
+ /**
3
+ * Checks to see if a resource string ARN matches a resource pattern from the Service Authorization Reference
4
+ *
5
+ * @param resourceString
6
+ * @param resourcePattern
7
+ */
8
+ export declare function resourceStringMatchesResourceTypePattern(resourceString: string, resourcePattern: string): boolean;
9
+ /**
10
+ * Get the the possible resource types for an action and resource
11
+ *
12
+ * @param service the service the action belongs to
13
+ * @param action the action to get the resource type for
14
+ * @param resource the resource type matching the action, if any
15
+ * @throws an error if the service or action does not exist, or if the action is a wildcard only action
16
+ */
17
+ export declare function getResourceTypesForAction(service: string, action: string, resource: string): Promise<ResourceType[]>;
18
+ //# sourceMappingURL=resourceTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceTypes.d.ts","sourceRoot":"","sources":["../../../src/simulation_engine/resourceTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAGhG;;;;;GAKG;AACH,wBAAgB,wCAAwC,CACtD,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CA2GT;AAqCD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB"}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resourceStringMatchesResourceTypePattern = resourceStringMatchesResourceTypePattern;
4
+ exports.getResourceTypesForAction = getResourceTypesForAction;
5
+ const iam_data_1 = require("@cloud-copilot/iam-data");
6
+ const util_js_1 = require("../util.js");
7
+ /**
8
+ * Checks to see if a resource string ARN matches a resource pattern from the Service Authorization Reference
9
+ *
10
+ * @param resourceString
11
+ * @param resourcePattern
12
+ */
13
+ function resourceStringMatchesResourceTypePattern(resourceString, resourcePattern) {
14
+ if (resourceString === '*') {
15
+ return true;
16
+ }
17
+ const resourceParts = (0, util_js_1.splitArnParts)(resourceString);
18
+ const patternParts = (0, util_js_1.splitArnParts)(resourcePattern);
19
+ if (!resourceComponentMatchesResourceTypeComponent(resourceParts.partition, patternParts.partition)) {
20
+ return false;
21
+ }
22
+ if (!resourceComponentMatchesResourceTypeComponent(resourceParts.service, patternParts.service)) {
23
+ return false;
24
+ }
25
+ if (!resourceComponentMatchesResourceTypeComponent(resourceParts.region, patternParts.region)) {
26
+ return false;
27
+ }
28
+ if (!resourceComponentMatchesResourceTypeComponent(resourceParts.accountId, patternParts.accountId)) {
29
+ return false;
30
+ }
31
+ const [resourceResourcePartsSegments, resourceResourceParts] = splitResourceTypeComponent(resourceParts.resource);
32
+ const [patternResourcePartsSegments, patternResourceParts] = splitResourceTypeComponent(patternParts.resource);
33
+ // If there are more segments in the resource than the pattern, it cannot match,
34
+ // unless the final pattern component is a variable (e.g. ${ObjectName}) which
35
+ // can span multiple segments (like S3 object keys with slashes).
36
+ if (resourceResourcePartsSegments > patternResourcePartsSegments) {
37
+ const lastPatternComponent = patternResourceParts.at(-1);
38
+ if (!isResourceTypeVariable(lastPatternComponent) || patternResourcePartsSegments === 1) {
39
+ return false;
40
+ }
41
+ }
42
+ // If there are fewer segments with contents in the resource than the pattern, and the last segment of the resource
43
+ // does not end with a wildcard, it cannot match
44
+ if (resourceResourceParts.length < patternResourceParts.length &&
45
+ !resourceResourceParts.at(-1)?.endsWith('*')) {
46
+ return false;
47
+ }
48
+ const compareLen = Math.min(resourceResourceParts.length, patternResourceParts.length);
49
+ for (let i = 0; i < compareLen; i++) {
50
+ const resourceComponent = resourceResourceParts[i];
51
+ const isLastPattern = i === patternResourceParts.length - 1;
52
+ const patternComponent = patternResourceParts[i];
53
+ if (!patternComponent) {
54
+ return false;
55
+ }
56
+ if (isResourceTypeVariable(patternComponent)) {
57
+ if (isLastPattern &&
58
+ resourceResourcePartsSegments > patternResourcePartsSegments &&
59
+ patternResourcePartsSegments > 1) {
60
+ // Variable at the end can absorb additional segments.
61
+ return true;
62
+ }
63
+ if (isLastPattern && resourceComponent?.endsWith('*')) {
64
+ // If the resource component ends with a wildcard, it matches everything after
65
+ break;
66
+ }
67
+ // These match anything, move along.
68
+ continue;
69
+ }
70
+ if (!resourceComponent) {
71
+ return false;
72
+ }
73
+ const resourceComponentPattern = '^' + resourceComponent.replace(/\?/g, '.').replace(/\*/g, '.*?') + '$';
74
+ const regex = new RegExp(resourceComponentPattern);
75
+ const match = patternComponent.match(regex);
76
+ if (match) {
77
+ if (isLastPattern && resourceComponent.endsWith('*')) {
78
+ // If the resource component ends with a wildcard, it matches everything after
79
+ break;
80
+ }
81
+ continue;
82
+ }
83
+ else {
84
+ return false;
85
+ }
86
+ }
87
+ /*
88
+ Matching resource types.
89
+ If the pattern has a slash or colon in the resource portion, those need to exist in the pattern.
90
+ If the pattern ends with a wildcard, that matches everything.
91
+ */
92
+ return true;
93
+ }
94
+ function splitResourceTypeComponent(component) {
95
+ const parts = component?.split(/[:/]/) ?? [];
96
+ return [parts.length, parts.filter((p) => p && p !== '')];
97
+ }
98
+ function resourceComponentMatchesResourceTypeComponent(resourceComponent, resourceTypeComponent) {
99
+ if (resourceTypeComponent === '*' || resourceTypeComponent === resourceComponent) {
100
+ return true;
101
+ }
102
+ if (!resourceComponent || !resourceTypeComponent) {
103
+ return false;
104
+ }
105
+ if (isResourceTypeVariable(resourceTypeComponent)) {
106
+ // If the entire component is a single variable, it matches anything
107
+ return true;
108
+ }
109
+ const pattern = (0, util_js_1.convertResourcePatternToRegex)(resourceTypeComponent);
110
+ const regex = new RegExp(pattern);
111
+ const match = resourceComponent.match(regex);
112
+ return !!match;
113
+ }
114
+ function isResourceTypeVariable(component) {
115
+ if (!component) {
116
+ return false;
117
+ }
118
+ return component.match(/^\$\{[0-9a-zA-Z]+\}$/) !== null;
119
+ }
120
+ /**
121
+ * Get the the possible resource types for an action and resource
122
+ *
123
+ * @param service the service the action belongs to
124
+ * @param action the action to get the resource type for
125
+ * @param resource the resource type matching the action, if any
126
+ * @throws an error if the service or action does not exist, or if the action is a wildcard only action
127
+ */
128
+ async function getResourceTypesForAction(service, action, resource) {
129
+ const actionDetails = await (0, iam_data_1.iamActionDetails)(service, action);
130
+ if (actionDetails.resourceTypes.length === 0) {
131
+ throw new Error(`${service}:${action} does not have any resource types`);
132
+ }
133
+ const matchingResourceTypes = [];
134
+ for (const rt of actionDetails.resourceTypes) {
135
+ const resourceType = await (0, iam_data_1.iamResourceTypeDetails)(service, rt.name);
136
+ // const pattern = convertResourcePatternToRegex(resourceType.arn)
137
+ // const match = resource.match(new RegExp(pattern))
138
+ const match = resourceStringMatchesResourceTypePattern(resource, resourceType.arn);
139
+ if (match) {
140
+ matchingResourceTypes.push(resourceType);
141
+ }
142
+ }
143
+ return matchingResourceTypes;
144
+ }
145
+ //# sourceMappingURL=resourceTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceTypes.js","sourceRoot":"","sources":["../../../src/simulation_engine/resourceTypes.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
+ import { ResourceType } from '@cloud-copilot/iam-data';
1
2
  import { ValidationError } from '@cloud-copilot/iam-policy';
2
- import { RequestAnalysis } from '../evaluate.js';
3
+ import { EvaluationResult, RequestAnalysis } from '../evaluate.js';
3
4
  import { Simulation } from './simulation.js';
4
5
  import { SimulationOptions } from './simulationOptions.js';
5
6
  export interface SimulationErrors {
@@ -12,16 +13,11 @@ export interface SimulationErrors {
12
13
  vpcEndpointErrors?: Record<string, ValidationError[]>;
13
14
  message: string;
14
15
  }
15
- export interface SimulationResult {
16
- errors?: SimulationErrors;
17
- analysis?: RequestAnalysis;
18
- /**
19
- * The resource type that was used for the simulation, if applicable.
20
- *
21
- * Will only be present if the request passes validation to reach the policy
22
- * evaluation stage and the action is not a wildcard-only action.
23
- */
24
- resourceType?: string;
16
+ /**
17
+ * Result of evaluating a single resource simulation, containing the analysis and any ignored context keys.
18
+ */
19
+ export interface SimulationResourceResult {
20
+ analysis: RequestAnalysis;
25
21
  /**
26
22
  * Any context keys provided in the request that were filtered out before
27
23
  * policy evaluation because they do not apply to the action/resource type.
@@ -33,15 +29,97 @@ export interface SimulationResult {
33
29
  */
34
30
  ignoredContextKeys?: string[];
35
31
  }
32
+ /**
33
+ * Extended simulation resource result that includes resource type and pattern information
34
+ * for wildcard resource simulations.
35
+ */
36
+ export interface WildcardSimulationResourceResult extends SimulationResourceResult {
37
+ /**
38
+ * The resource type that was used for the simulation, if applicable.
39
+ *
40
+ * Will only be present if the request passes validation to reach the policy
41
+ * evaluation stage and the action is not a wildcard-only action.
42
+ */
43
+ resourceType: string;
44
+ /**
45
+ * The resource pattern that was used for the simulation, if applicable. If a wildcard
46
+ * resource was provided and multiple simulations were run, this will indicate the
47
+ * specific resource string that was simulated.
48
+ */
49
+ resourcePattern: string;
50
+ }
51
+ /**
52
+ * Simulation result indicating that errors prevented the simulation from running.
53
+ */
54
+ export interface ErrorSimulationResult {
55
+ resultType: 'error';
56
+ /**
57
+ * Errors in the simulation input that prevented the simulation from being run.
58
+ */
59
+ errors: SimulationErrors;
60
+ }
61
+ /**
62
+ * Simulation result for a single resource (non-wildcard) evaluation.
63
+ */
64
+ export interface SingleResourceSimulationResult {
65
+ /**
66
+ * A single resource simulation result.
67
+ */
68
+ resultType: 'single';
69
+ /**
70
+ * The overall result of the one simulation that was run.
71
+ */
72
+ overallResult: EvaluationResult;
73
+ /**
74
+ * The detailed result of the simulation that was run and the request analysis
75
+ */
76
+ result: SimulationResourceResult;
77
+ }
78
+ /**
79
+ * Simulation results for wildcard resource evaluations, containing multiple individual results.
80
+ */
81
+ export interface WildcardResourceSimulationResults {
82
+ /**
83
+ * Whether a wildcard was detected in the resource ARN of the request and the
84
+ * simulation was not a wildcard-only action, which can cause multiple simulations to be run.
85
+ */
86
+ resultType: 'wildcard';
87
+ /**
88
+ * The overall result of the simulation, calculated based on the results of individual simulations if
89
+ * multiple were run.
90
+ */
91
+ overallResult: EvaluationResult;
92
+ /**
93
+ * The results of the simulation or simulations that were run.
94
+ * If it is a wildcard only action or the resource ARN contains no wildcards, this will contain a single result.
95
+ * If the resource ARN contains a wildcard and the action is not a wildcard-only action, this may contain no
96
+ * results, or one result for each matching pattern found in the provided identity and resource policies.
97
+ */
98
+ results: WildcardSimulationResourceResult[];
99
+ }
100
+ /**
101
+ * The result of running a simulation.
102
+ * Can be an error, a single result, or a wildcard result.
103
+ * Discriminated by the `resultType` field.
104
+ */
105
+ export type RunSimulationResults = ErrorSimulationResult | SingleResourceSimulationResult | WildcardResourceSimulationResults;
106
+ /**
107
+ * Union type representing successful simulation results (excluding error cases).
108
+ */
109
+ export type SuccessfulRunSimulationResults = SingleResourceSimulationResult | WildcardResourceSimulationResults;
110
+ /**
111
+ * Discriminant type for the different kinds of simulation results.
112
+ */
113
+ export type SimulationResultType = RunSimulationResults['resultType'];
36
114
  /**
37
115
  * Run a simulation with validation
38
116
  *
39
117
  * @param simulation The simulation to run
40
118
  * @param simulationOptions Options for the simulation
41
- * @returns
119
+ * @returns The results of the simulation, or errors if the simulation could not be run
42
120
  */
43
- export declare function runSimulation(simulation: Simulation, simulationOptions: Partial<SimulationOptions>): Promise<SimulationResult>;
44
- export declare function normalizeSimulationParameters(simulation: Simulation): Promise<{
121
+ export declare function runSimulation(simulation: Simulation, simulationOptions: Partial<SimulationOptions>): Promise<RunSimulationResults>;
122
+ export declare function normalizeSimulationParameters(simulation: Simulation, suggestedResourceType: ResourceType | undefined): Promise<{
45
123
  validContextValues: Record<string, string | string[]>;
46
124
  ignoredContextKeys: string[];
47
125
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"simulationEngine.d.ts","sourceRoot":"","sources":["../../../src/simulation_engine/simulationEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,eAAe,EAChB,MAAM,2BAA2B,CAAA;AAYlC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAKhD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAiB1D,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAA;IACvC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IACxD,0BAA0B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC9D,2BAA2B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC/D,wBAAwB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC5D,oBAAoB,CAAC,EAAE,eAAe,EAAE,CAAA;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IACrD,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,QAAQ,CAAC,EAAE,eAAe,CAAA;IAE1B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC5C,OAAO,CAAC,gBAAgB,CAAC,CA6O3B;AAED,wBAAsB,6BAA6B,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;IACnF,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACrD,kBAAkB,EAAE,MAAM,EAAE,CAAA;CAC7B,CAAC,CAyCD"}
1
+ {"version":3,"file":"simulationEngine.d.ts","sourceRoot":"","sources":["../../../src/simulation_engine/simulationEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACzF,OAAO,EAOL,eAAe,EAChB,MAAM,2BAA2B,CAAA;AAYlC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAQlE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAiB1D,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB,CAAC,EAAE,eAAe,EAAE,CAAA;IACvC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IACxD,0BAA0B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC9D,2BAA2B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC/D,wBAAwB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IAC5D,oBAAoB,CAAC,EAAE,eAAe,EAAE,CAAA;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAA;IACrD,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,eAAe,CAAA;IAEzB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,gCAAiC,SAAQ,wBAAwB;IAChF;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;IAEpB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,OAAO,CAAA;IAEnB;;OAEG;IACH,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,UAAU,EAAE,QAAQ,CAAA;IAEpB;;OAEG;IACH,aAAa,EAAE,gBAAgB,CAAA;IAE/B;;OAEG;IACH,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAChD;;;OAGG;IACH,UAAU,EAAE,UAAU,CAAA;IAEtB;;;OAGG;IACH,aAAa,EAAE,gBAAgB,CAAA;IAE/B;;;;;OAKG;IACH,OAAO,EAAE,gCAAgC,EAAE,CAAA;CAC5C;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAC5B,qBAAqB,GACrB,8BAA8B,GAC9B,iCAAiC,CAAA;AAErC;;GAEG;AACH,MAAM,MAAM,8BAA8B,GACtC,8BAA8B,GAC9B,iCAAiC,CAAA;AAErC;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,oBAAoB,CAAC,YAAY,CAAC,CAAA;AAErE;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,UAAU,EACtB,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAC5C,OAAO,CAAC,oBAAoB,CAAC,CA0T/B;AAED,wBAAsB,6BAA6B,CACjD,UAAU,EAAE,UAAU,EACtB,qBAAqB,EAAE,YAAY,GAAG,SAAS,GAC9C,OAAO,CAAC;IACT,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;IACrD,kBAAkB,EAAE,MAAM,EAAE,CAAA;CAC7B,CAAC,CA0CD"}
@@ -13,6 +13,9 @@ const request_js_1 = require("../request/request.js");
13
13
  const requestContext_js_1 = require("../requestContext.js");
14
14
  const util_js_1 = require("../util.js");
15
15
  const contextKeys_js_2 = require("./contextKeys.js");
16
+ const overallResult_js_1 = require("./overallResult.js");
17
+ const policyResources_js_1 = require("./policyResources.js");
18
+ const resourceTypes_js_1 = require("./resourceTypes.js");
16
19
  const DEFAULT_RCP = {
17
20
  name: 'RCPFullAWSAccess',
18
21
  policy: {
@@ -32,15 +35,18 @@ const DEFAULT_RCP = {
32
35
  *
33
36
  * @param simulation The simulation to run
34
37
  * @param simulationOptions Options for the simulation
35
- * @returns
38
+ * @returns The results of the simulation, or errors if the simulation could not be run
36
39
  */
37
40
  async function runSimulation(simulation, simulationOptions) {
38
41
  const principal = simulation.request.principal;
42
+ const resourceArn = simulation.request.resource.resource;
43
+ const resourceHasWildcard = resourceArn.includes('*');
39
44
  if (simulation.sessionPolicy) {
40
45
  if (!(0, iam_utils_1.isIamRoleArn)(principal) &&
41
46
  !(0, iam_utils_1.isAssumedRoleArn)(principal) &&
42
47
  !(0, iam_utils_1.isFederatedUserArn)(principal)) {
43
48
  return {
49
+ resultType: 'error',
44
50
  errors: {
45
51
  message: 'session.policy.invalid.principal'
46
52
  }
@@ -143,6 +149,7 @@ async function runSimulation(simulation, simulationOptions) {
143
149
  resourcePolicyErrors.length > 0 ||
144
150
  sessionPolicyErrors.length > 0) {
145
151
  return {
152
+ resultType: 'error',
146
153
  errors: {
147
154
  sessionPolicyErrors,
148
155
  identityPolicyErrors,
@@ -160,6 +167,7 @@ async function runSimulation(simulation, simulationOptions) {
160
167
  : undefined;
161
168
  if (simulation.request.action.split(':').length != 2) {
162
169
  return {
170
+ resultType: 'error',
163
171
  errors: {
164
172
  message: 'invalid.action'
165
173
  }
@@ -169,6 +177,7 @@ async function runSimulation(simulation, simulationOptions) {
169
177
  const validService = await (0, iam_data_1.iamServiceExists)(service);
170
178
  if (!validService) {
171
179
  return {
180
+ resultType: 'error',
172
181
  errors: {
173
182
  message: 'invalid.service'
174
183
  }
@@ -177,17 +186,19 @@ async function runSimulation(simulation, simulationOptions) {
177
186
  const validAction = await (0, iam_data_1.iamActionExists)(service, action);
178
187
  if (!validAction) {
179
188
  return {
189
+ resultType: 'error',
180
190
  errors: {
181
191
  message: 'invalid.action'
182
192
  }
183
193
  };
184
194
  }
185
- const resourceArn = simulation.request.resource.resource;
186
195
  const isWildCardOnlyAction = await (0, util_js_1.isWildcardOnlyAction)(service, action);
187
- let resourceType = undefined;
196
+ const runMultipleSimulations = resourceHasWildcard && !isWildCardOnlyAction;
197
+ let resourceTypes = undefined;
188
198
  if (isWildCardOnlyAction) {
189
199
  if (resourceArn !== '*') {
190
200
  return {
201
+ resultType: 'error',
191
202
  errors: {
192
203
  message: 'must.use.wildcard'
193
204
  }
@@ -195,37 +206,39 @@ async function runSimulation(simulation, simulationOptions) {
195
206
  }
196
207
  }
197
208
  else {
198
- const resourceTypes = await (0, util_js_1.getResourceTypesForAction)(service, action, resourceArn);
199
- if (resourceTypes.length === 0) {
209
+ const actionResourceTypes = await (0, resourceTypes_js_1.getResourceTypesForAction)(service, action, resourceArn);
210
+ if (actionResourceTypes.length === 0) {
200
211
  return {
212
+ resultType: 'error',
201
213
  errors: {
202
214
  message: 'no.resource.types'
203
215
  }
204
216
  };
205
217
  }
206
- else if (resourceTypes.length > 1) {
218
+ else if (actionResourceTypes.length > 1 && !resourceHasWildcard) {
207
219
  return {
220
+ resultType: 'error',
208
221
  errors: {
209
222
  message: 'multiple.resource.types'
210
223
  }
211
224
  };
212
225
  }
213
226
  else {
214
- resourceType = resourceTypes[0].key;
227
+ resourceTypes = actionResourceTypes.map((item) => item);
215
228
  }
216
229
  }
217
- const { validContextValues, ignoredContextKeys } = await normalizeSimulationParameters(simulation);
218
230
  const simulationMode = CoreSimulatorEngine_js_1.validSimulationModes.includes(simulationOptions.simulationMode)
219
231
  ? simulationOptions.simulationMode
220
232
  : 'Strict';
233
+ // For each resource type, find the resource patterns, for each pattern, run a simulation
221
234
  const strictConditionKeys = simulationMode === 'Discovery'
222
235
  ? new strictContextKeys_js_1.StrictContextKeys(simulationOptions.strictConditionKeys || [])
223
236
  : new strictContextKeys_js_1.StrictContextKeys([]);
224
- const simulationResult = (0, CoreSimulatorEngine_js_1.authorize)({
237
+ const curriedAuthorize = (curriedResourceString, curriedContextValues) => (0, CoreSimulatorEngine_js_1.authorize)({
225
238
  request: new request_js_1.AwsRequestImpl(principal, {
226
- resource: simulation.request.resource.resource,
239
+ resource: curriedResourceString,
227
240
  accountId: simulation.request.resource.accountId
228
- }, simulation.request.action, new requestContext_js_1.RequestContextImpl(validContextValues)),
241
+ }, simulation.request.action, new requestContext_js_1.RequestContextImpl(curriedContextValues)),
229
242
  sessionPolicy,
230
243
  identityPolicies,
231
244
  serviceControlPolicies,
@@ -238,16 +251,61 @@ async function runSimulation(simulation, simulationOptions) {
238
251
  strictConditionKeys: strictConditionKeys
239
252
  }
240
253
  });
254
+ const policiesThatGrantAccess = [resourcePolicy, ...identityPolicies];
255
+ // If there is only one simulation to run, run it
256
+ if (!runMultipleSimulations) {
257
+ const { validContextValues, ignoredContextKeys } = await normalizeSimulationParameters(simulation, undefined);
258
+ const singleResult = curriedAuthorize(resourceArn, validContextValues);
259
+ return {
260
+ resultType: 'single',
261
+ overallResult: singleResult.result,
262
+ result: {
263
+ analysis: singleResult,
264
+ ignoredContextKeys
265
+ }
266
+ };
267
+ }
268
+ // Here, we know it is a wildcard resource and not a wildcard-only action, so we need to run multiple simulations
269
+ const simulationResults = [];
270
+ const resourceTypesToSimulate = resourceTypes && resourceTypes.length > 0 ? resourceTypes : [];
271
+ for (const resourceType of resourceTypesToSimulate) {
272
+ // If "run multiple" get the resource strings that match the wildcard pattern, otherwise, just run the one.
273
+ const { validContextValues, ignoredContextKeys } = await normalizeSimulationParameters(simulation, resourceType);
274
+ //Run the pattern directly first.
275
+ const exactPatternResult = curriedAuthorize(resourceArn, validContextValues);
276
+ if (exactPatternResult.result === 'ExplicitlyDenied') {
277
+ simulationResults.push({
278
+ analysis: exactPatternResult,
279
+ ignoredContextKeys,
280
+ resourceType: resourceType.key,
281
+ resourcePattern: resourceArn
282
+ });
283
+ }
284
+ else {
285
+ let resourceStrings = [simulation.request.resource.resource];
286
+ resourceStrings = (0, policyResources_js_1.getMatchingResourceStringsForPolicies)(policiesThatGrantAccess, simulation.request.action, resourceType, simulation.request.resource.resource);
287
+ for (const resourceString of resourceStrings) {
288
+ const simulationResult = curriedAuthorize(resourceString, validContextValues);
289
+ simulationResults.push({
290
+ analysis: simulationResult,
291
+ ignoredContextKeys,
292
+ resourceType: resourceType.key,
293
+ resourcePattern: resourceString
294
+ });
295
+ }
296
+ }
297
+ }
298
+ const overallResult = (0, overallResult_js_1.calculateOverallResult)(simulationResults);
241
299
  return {
242
- analysis: simulationResult,
243
- ignoredContextKeys,
244
- resourceType
300
+ resultType: 'wildcard',
301
+ overallResult,
302
+ results: simulationResults
245
303
  };
246
304
  }
247
- async function normalizeSimulationParameters(simulation) {
305
+ async function normalizeSimulationParameters(simulation, suggestedResourceType) {
248
306
  const [service, action] = simulation.request.action.split(':');
249
307
  const resourceArn = simulation.request.resource.resource;
250
- const contextVariablesForAction = new Set(await (0, contextKeys_js_2.allowedContextKeysForRequest)(service, action, resourceArn, !!simulation.additionalSettings?.s3?.bucketAbacEnabled));
308
+ const contextVariablesForAction = new Set(await (0, contextKeys_js_2.allowedContextKeysForRequest)(service, action, resourceArn, !!simulation.additionalSettings?.s3?.bucketAbacEnabled, suggestedResourceType));
251
309
  //Get the types of the context variables and set a string or array of strings based on that.
252
310
  const validContextValues = {};
253
311
  const ignoredContextKeys = [];