@cloud-copilot/iam-lens 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -1
- package/dist/cjs/cli.js +57 -8
- package/dist/cjs/cli.js.map +1 -1
- package/dist/cjs/collect/client.d.ts +37 -2
- package/dist/cjs/collect/client.d.ts.map +1 -1
- package/dist/cjs/collect/client.js +126 -27
- package/dist/cjs/collect/client.js.map +1 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/principals.d.ts +0 -5
- package/dist/cjs/principals.d.ts.map +1 -1
- package/dist/cjs/principals.js +0 -9
- package/dist/cjs/principals.js.map +1 -1
- package/dist/cjs/resources.js +1 -1
- package/dist/cjs/resources.js.map +1 -1
- package/dist/cjs/{contextKeys.d.ts → simulate/contextKeys.d.ts} +1 -1
- package/dist/cjs/simulate/contextKeys.d.ts.map +1 -0
- package/dist/cjs/{contextKeys.js → simulate/contextKeys.js} +1 -1
- package/dist/cjs/simulate/contextKeys.js.map +1 -0
- package/dist/cjs/{simulate.d.ts → simulate/simulate.d.ts} +4 -2
- package/dist/cjs/simulate/simulate.d.ts.map +1 -0
- package/dist/cjs/{simulate.js → simulate/simulate.js} +43 -22
- package/dist/cjs/simulate/simulate.js.map +1 -0
- package/dist/cjs/test-datasets/testClient.d.ts +9 -0
- package/dist/cjs/test-datasets/testClient.d.ts.map +1 -0
- package/dist/cjs/test-datasets/testClient.js +28 -0
- package/dist/cjs/test-datasets/testClient.js.map +1 -0
- package/dist/cjs/utils/arn.d.ts +22 -0
- package/dist/cjs/utils/arn.d.ts.map +1 -0
- package/dist/cjs/utils/arn.js +49 -0
- package/dist/cjs/utils/arn.js.map +1 -0
- package/dist/cjs/utils/packageVersion.d.ts +5 -0
- package/dist/cjs/utils/packageVersion.d.ts.map +1 -0
- package/dist/cjs/utils/packageVersion.js +25 -0
- package/dist/cjs/utils/packageVersion.js.map +1 -0
- package/dist/cjs/utils/readPackageFile.d.ts +2 -0
- package/dist/cjs/utils/readPackageFile.d.ts.map +1 -0
- package/dist/cjs/utils/readPackageFile.js +13 -0
- package/dist/cjs/utils/readPackageFile.js.map +1 -0
- package/dist/cjs/utils/sts.d.ts +2 -0
- package/dist/cjs/utils/sts.d.ts.map +1 -0
- package/dist/cjs/utils/sts.js +9 -0
- package/dist/cjs/utils/sts.js.map +1 -0
- package/dist/cjs/whoCan/whoCan.d.ts +54 -0
- package/dist/cjs/whoCan/whoCan.d.ts.map +1 -0
- package/dist/cjs/whoCan/whoCan.js +320 -0
- package/dist/cjs/whoCan/whoCan.js.map +1 -0
- package/dist/esm/cli.js +57 -8
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/collect/client.d.ts +37 -2
- package/dist/esm/collect/client.d.ts.map +1 -1
- package/dist/esm/collect/client.js +125 -27
- package/dist/esm/collect/client.js.map +1 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/principals.d.ts +0 -5
- package/dist/esm/principals.d.ts.map +1 -1
- package/dist/esm/principals.js +0 -8
- package/dist/esm/principals.js.map +1 -1
- package/dist/esm/resources.js +1 -1
- package/dist/esm/resources.js.map +1 -1
- package/dist/esm/{contextKeys.d.ts → simulate/contextKeys.d.ts} +1 -1
- package/dist/esm/simulate/contextKeys.d.ts.map +1 -0
- package/dist/esm/{contextKeys.js → simulate/contextKeys.js} +1 -1
- package/dist/esm/simulate/contextKeys.js.map +1 -0
- package/dist/esm/{simulate.d.ts → simulate/simulate.d.ts} +4 -2
- package/dist/esm/simulate/simulate.d.ts.map +1 -0
- package/dist/esm/{simulate.js → simulate/simulate.js} +44 -24
- package/dist/esm/simulate/simulate.js.map +1 -0
- package/dist/esm/test-datasets/testClient.d.ts +9 -0
- package/dist/esm/test-datasets/testClient.d.ts.map +1 -0
- package/dist/esm/test-datasets/testClient.js +25 -0
- package/dist/esm/test-datasets/testClient.js.map +1 -0
- package/dist/esm/utils/arn.d.ts +22 -0
- package/dist/esm/utils/arn.d.ts.map +1 -0
- package/dist/esm/utils/arn.js +43 -0
- package/dist/esm/utils/arn.js.map +1 -0
- package/dist/esm/utils/packageVersion.d.ts +5 -0
- package/dist/esm/utils/packageVersion.d.ts.map +1 -0
- package/dist/esm/utils/packageVersion.js +22 -0
- package/dist/esm/utils/packageVersion.js.map +1 -0
- package/dist/esm/utils/readPackageFile.d.ts +2 -0
- package/dist/esm/utils/readPackageFile.d.ts.map +1 -0
- package/dist/esm/utils/readPackageFile.js +12 -0
- package/dist/esm/utils/readPackageFile.js.map +1 -0
- package/dist/esm/utils/readPackageFileEsm.d.ts.map +1 -0
- package/dist/esm/utils/sts.d.ts +2 -0
- package/dist/esm/utils/sts.d.ts.map +1 -0
- package/dist/esm/utils/sts.js +6 -0
- package/dist/esm/utils/sts.js.map +1 -0
- package/dist/esm/whoCan/whoCan.d.ts +54 -0
- package/dist/esm/whoCan/whoCan.d.ts.map +1 -0
- package/dist/esm/whoCan/whoCan.js +311 -0
- package/dist/esm/whoCan/whoCan.js.map +1 -0
- package/package.json +1 -1
- package/dist/cjs/accounts.d.ts +0 -3
- package/dist/cjs/accounts.d.ts.map +0 -1
- package/dist/cjs/accounts.js +0 -8
- package/dist/cjs/accounts.js.map +0 -1
- package/dist/cjs/contextKeys.d.ts.map +0 -1
- package/dist/cjs/contextKeys.js.map +0 -1
- package/dist/cjs/simulate.d.ts.map +0 -1
- package/dist/cjs/simulate.js.map +0 -1
- package/dist/esm/accounts.d.ts +0 -3
- package/dist/esm/accounts.d.ts.map +0 -1
- package/dist/esm/accounts.js +0 -5
- package/dist/esm/accounts.js.map +0 -1
- package/dist/esm/contextKeys.d.ts.map +0 -1
- package/dist/esm/contextKeys.js.map +0 -1
- package/dist/esm/simulate.d.ts.map +0 -1
- package/dist/esm/simulate.js.map +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Arn = void 0;
|
|
4
|
+
const iam_utils_1 = require("@cloud-copilot/iam-utils");
|
|
5
|
+
class Arn {
|
|
6
|
+
arn;
|
|
7
|
+
parts;
|
|
8
|
+
constructor(arn) {
|
|
9
|
+
this.arn = arn;
|
|
10
|
+
this.parts = (0, iam_utils_1.splitArnParts)(arn);
|
|
11
|
+
}
|
|
12
|
+
get service() {
|
|
13
|
+
return this.parts.service;
|
|
14
|
+
}
|
|
15
|
+
get partition() {
|
|
16
|
+
return this.parts.partition;
|
|
17
|
+
}
|
|
18
|
+
get region() {
|
|
19
|
+
return this.parts.region;
|
|
20
|
+
}
|
|
21
|
+
get accountId() {
|
|
22
|
+
return this.parts.accountId;
|
|
23
|
+
}
|
|
24
|
+
get resourceType() {
|
|
25
|
+
return this.parts.resourceType;
|
|
26
|
+
}
|
|
27
|
+
get resourcePath() {
|
|
28
|
+
return this.parts.resourcePath;
|
|
29
|
+
}
|
|
30
|
+
get resource() {
|
|
31
|
+
return this.parts.resource || '';
|
|
32
|
+
}
|
|
33
|
+
get value() {
|
|
34
|
+
return this.arn;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check
|
|
38
|
+
*
|
|
39
|
+
* @param parts
|
|
40
|
+
* @returns
|
|
41
|
+
*/
|
|
42
|
+
matches(parts) {
|
|
43
|
+
return Object.entries(parts).every(([key, value]) => {
|
|
44
|
+
return this.parts[key] === value;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.Arn = Arn;
|
|
49
|
+
//# sourceMappingURL=arn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arn.js","sourceRoot":"","sources":["../../../src/utils/arn.ts"],"names":[],"mappings":";;;AAAA,wDAAkE;AAElE,MAAa,GAAG;IAGe;IAFZ,KAAK,CAAU;IAEhC,YAA6B,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QACtC,IAAI,CAAC,KAAK,GAAG,IAAA,yBAAa,EAAC,GAAG,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,OAAQ,CAAA;IAC5B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAU,CAAA;IAC9B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAA;IAC7B,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAA;IAChC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAA;IAChC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAA;IAClC,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,GAAG,CAAA;IACjB,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,KAAwB;QAC9B,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;YAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAqB,CAAC,KAAK,KAAK,CAAA;QACpD,CAAC,CAAC,CAAA;IACJ,CAAC;CACF;AAlDD,kBAkDC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../../../src/utils/packageVersion.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAGtD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.iamLensVersion = iamLensVersion;
|
|
4
|
+
const readPackageFile_js_1 = require("./readPackageFile.js");
|
|
5
|
+
let packageCache = undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Get the package data version
|
|
8
|
+
*
|
|
9
|
+
* @returns the package data version
|
|
10
|
+
*/
|
|
11
|
+
async function getPackageData() {
|
|
12
|
+
if (!packageCache) {
|
|
13
|
+
const packageJson = await (0, readPackageFile_js_1.readPackageFile)(['package.json']);
|
|
14
|
+
packageCache = JSON.parse(packageJson);
|
|
15
|
+
}
|
|
16
|
+
return packageCache;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the version of the package
|
|
20
|
+
*/
|
|
21
|
+
async function iamLensVersion() {
|
|
22
|
+
const data = await getPackageData();
|
|
23
|
+
return data.version;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../../../src/utils/packageVersion.ts"],"names":[],"mappings":";;AAwBA,wCAGC;AA3BD,6DAAsD;AAMtD,IAAI,YAAY,GAA4B,SAAS,CAAA;AAErD;;;;GAIG;AACH,KAAK,UAAU,cAAc;IAC3B,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,WAAW,GAAG,MAAM,IAAA,oCAAe,EAAC,CAAC,cAAc,CAAC,CAAC,CAAA;QAC3D,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,YAAa,CAAA;AACtB,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,cAAc;IAClC,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAA;IACnC,OAAO,IAAI,CAAC,OAAO,CAAA;AACrB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readPackageFile.d.ts","sourceRoot":"","sources":["../../../src/utils/readPackageFile.ts"],"names":[],"mappings":"AAOA,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAG1E"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readPackageFile = readPackageFile;
|
|
4
|
+
const cli_1 = require("@cloud-copilot/cli");
|
|
5
|
+
let levels = 3;
|
|
6
|
+
if (__filename.includes('src')) {
|
|
7
|
+
levels = 2;
|
|
8
|
+
}
|
|
9
|
+
async function readPackageFile(pathParts) {
|
|
10
|
+
const packageFile = await (0, cli_1.readRelativeFile)(__filename, levels, pathParts);
|
|
11
|
+
return packageFile;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=readPackageFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readPackageFile.js","sourceRoot":"","sources":["../../../src/utils/readPackageFile.ts"],"names":[],"mappings":";;AAOA,0CAGC;AAVD,4CAAqD;AAErD,IAAI,MAAM,GAAG,CAAC,CAAA;AACd,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAC/B,MAAM,GAAG,CAAC,CAAA;AACZ,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,SAAmB;IACvD,MAAM,WAAW,GAAG,MAAM,IAAA,sBAAgB,EAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACzE,OAAO,WAAW,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sts.d.ts","sourceRoot":"","sources":["../../../src/utils/sts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,aAI5B,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AssumeRoleActions = void 0;
|
|
4
|
+
exports.AssumeRoleActions = new Set([
|
|
5
|
+
'sts:assumerole',
|
|
6
|
+
'sts:assumerolewithwebidentity',
|
|
7
|
+
'sts:assumerolewithsaml'
|
|
8
|
+
]);
|
|
9
|
+
//# sourceMappingURL=sts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sts.js","sourceRoot":"","sources":["../../../src/utils/sts.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG,IAAI,GAAG,CAAC;IACvC,gBAAgB;IAChB,+BAA+B;IAC/B,wBAAwB;CACzB,CAAC,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ResourceType } from '@cloud-copilot/iam-data';
|
|
2
|
+
import { IamCollectClient } from '../collect/client.js';
|
|
3
|
+
export interface ResourceAccessRequest {
|
|
4
|
+
resource?: string;
|
|
5
|
+
resourceAccount?: string;
|
|
6
|
+
actions: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface WhoCanAllowed {
|
|
9
|
+
principal: string;
|
|
10
|
+
service: string;
|
|
11
|
+
action: string;
|
|
12
|
+
}
|
|
13
|
+
export interface WhoCanResponse {
|
|
14
|
+
allowed: WhoCanAllowed[];
|
|
15
|
+
allAccountsChecked: boolean;
|
|
16
|
+
accountsNotFound: string[];
|
|
17
|
+
organizationsNotFound: string[];
|
|
18
|
+
organizationalUnitsNotFound: string[];
|
|
19
|
+
principalsNotFound: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare function whoCan(collectClient: IamCollectClient, request: ResourceAccessRequest): Promise<WhoCanResponse>;
|
|
22
|
+
export declare function uniqueAccountsToCheck(collectClient: IamCollectClient, accountsToCheck: AccountsToCheck): Promise<{
|
|
23
|
+
accountsNotFound: string[];
|
|
24
|
+
organizationsNotFound: string[];
|
|
25
|
+
organizationalUnitsNotFound: string[];
|
|
26
|
+
accounts: string[];
|
|
27
|
+
}>;
|
|
28
|
+
export interface AccountsToCheck {
|
|
29
|
+
allAccounts: boolean;
|
|
30
|
+
specificAccounts: string[];
|
|
31
|
+
specificPrincipals: string[];
|
|
32
|
+
specificOrganizations: string[];
|
|
33
|
+
specificOrganizationalUnits: string[];
|
|
34
|
+
}
|
|
35
|
+
export declare function accountsToCheckBasedOnResourcePolicy(resourcePolicy: any, resourceAccount: string | undefined): Promise<AccountsToCheck>;
|
|
36
|
+
export declare function actionsForWhoCan(request: ResourceAccessRequest): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Get the the possible resource types for an action and resource
|
|
39
|
+
*
|
|
40
|
+
* @param service the service the action belongs to
|
|
41
|
+
* @param action the action to get the resource type for
|
|
42
|
+
* @param resourceArn the resource type matching the action, if any
|
|
43
|
+
* @throws an error if the service or action does not exist, or if the action is a wildcard only action
|
|
44
|
+
*/
|
|
45
|
+
export declare function lookupActionsForResourceArn(resourceArn: string): Promise<string[]>;
|
|
46
|
+
export declare function findResourceTypeForArn(resourceArn: string): Promise<[string, ResourceType]>;
|
|
47
|
+
/**
|
|
48
|
+
* Convert a resource pattern from iam-data to a regex pattern
|
|
49
|
+
*
|
|
50
|
+
* @param pattern the pattern to convert to a regex
|
|
51
|
+
* @returns the regex pattern
|
|
52
|
+
*/
|
|
53
|
+
export declare function convertResourcePatternToRegex(pattern: string): string;
|
|
54
|
+
//# sourceMappingURL=whoCan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoCan.d.ts","sourceRoot":"","sources":["../../../src/whoCan/whoCan.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,YAAY,EACb,MAAM,yBAAyB,CAAA;AAShC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,2BAA2B,EAAE,MAAM,EAAE,CAAA;IACrC,kBAAkB,EAAE,MAAM,EAAE,CAAA;CAC7B;AAED,wBAAsB,MAAM,CAC1B,aAAa,EAAE,gBAAgB,EAC/B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAmGzB;AAkCD,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,gBAAgB,EAC/B,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC;IACT,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,2BAA2B,EAAE,MAAM,EAAE,CAAA;IACrC,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB,CAAC,CAiDD;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,OAAO,CAAA;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,2BAA2B,EAAE,MAAM,EAAE,CAAA;CACtC;AAED,wBAAsB,oCAAoC,CACxD,cAAc,EAAE,GAAG,EACnB,eAAe,EAAE,MAAM,GAAG,SAAS,GAClC,OAAO,CAAC,eAAe,CAAC,CA2E1B;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BxF;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAsBxF;AAED,wBAAsB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAqBjG;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOrE"}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.whoCan = whoCan;
|
|
4
|
+
exports.uniqueAccountsToCheck = uniqueAccountsToCheck;
|
|
5
|
+
exports.accountsToCheckBasedOnResourcePolicy = accountsToCheckBasedOnResourcePolicy;
|
|
6
|
+
exports.actionsForWhoCan = actionsForWhoCan;
|
|
7
|
+
exports.lookupActionsForResourceArn = lookupActionsForResourceArn;
|
|
8
|
+
exports.findResourceTypeForArn = findResourceTypeForArn;
|
|
9
|
+
exports.convertResourcePatternToRegex = convertResourcePatternToRegex;
|
|
10
|
+
const iam_data_1 = require("@cloud-copilot/iam-data");
|
|
11
|
+
const iam_policy_1 = require("@cloud-copilot/iam-policy");
|
|
12
|
+
const iam_utils_1 = require("@cloud-copilot/iam-utils");
|
|
13
|
+
const resources_js_1 = require("../resources.js");
|
|
14
|
+
const simulate_js_1 = require("../simulate/simulate.js");
|
|
15
|
+
const arn_js_1 = require("../utils/arn.js");
|
|
16
|
+
const sts_js_1 = require("../utils/sts.js");
|
|
17
|
+
async function whoCan(collectClient, request) {
|
|
18
|
+
const { resource } = request;
|
|
19
|
+
if (!request.resourceAccount && !request.resource) {
|
|
20
|
+
throw new Error('Either resourceAccount or resource must be provided in the request.');
|
|
21
|
+
}
|
|
22
|
+
if (resource && !resource.startsWith('arn:')) {
|
|
23
|
+
throw new Error(`Invalid resource ARN: ${resource}. It must start with 'arn:'.`);
|
|
24
|
+
}
|
|
25
|
+
const resourceAccount = request.resourceAccount || (await (0, resources_js_1.getAccountIdForResource)(collectClient, resource));
|
|
26
|
+
if (!resourceAccount) {
|
|
27
|
+
throw new Error(`Could not determine account ID for resource ${resource}`);
|
|
28
|
+
}
|
|
29
|
+
const actions = await actionsForWhoCan(request);
|
|
30
|
+
if (!actions || actions.length === 0) {
|
|
31
|
+
throw new Error('No valid actions provided or found for the resource.');
|
|
32
|
+
}
|
|
33
|
+
let resourcePolicy = undefined;
|
|
34
|
+
if (resource) {
|
|
35
|
+
resourcePolicy = await (0, resources_js_1.getResourcePolicyForResource)(collectClient, resource);
|
|
36
|
+
const resourceArn = new arn_js_1.Arn(resource);
|
|
37
|
+
if ((resourceArn.matches({ service: 'iam', resourceType: 'role' }) ||
|
|
38
|
+
resourceArn.matches({ service: 'kms', resourceType: 'key' })) &&
|
|
39
|
+
!resourcePolicy) {
|
|
40
|
+
throw new Error(`Unable to find resource policy for ${resource}. Cannot determine who can access the resource.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const accountsToCheck = await accountsToCheckBasedOnResourcePolicy(resourcePolicy, resourceAccount);
|
|
44
|
+
const uniqueAccounts = await uniqueAccountsToCheck(collectClient, accountsToCheck);
|
|
45
|
+
const whoCanResults = [];
|
|
46
|
+
for (const account of uniqueAccounts.accounts) {
|
|
47
|
+
const principals = await collectClient.getAllPrincipalsInAccount(account);
|
|
48
|
+
for (const principal of principals) {
|
|
49
|
+
const principalResults = await runPrincipalForActions(collectClient, principal, resource, resourceAccount, actions);
|
|
50
|
+
whoCanResults.push(...principalResults);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const principalsNotFound = [];
|
|
54
|
+
for (const principal of accountsToCheck.specificPrincipals) {
|
|
55
|
+
if ((0, iam_utils_1.isServicePrincipal)(principal)) {
|
|
56
|
+
const principalResults = await runPrincipalForActions(collectClient, principal, resource, resourceAccount, actions);
|
|
57
|
+
whoCanResults.push(...principalResults);
|
|
58
|
+
}
|
|
59
|
+
else if ((0, iam_utils_1.isIamUserArn)(principal) || (0, iam_utils_1.isIamRoleArn)(principal) || (0, iam_utils_1.isAssumedRoleArn)(principal)) {
|
|
60
|
+
const principalExists = await collectClient.principalExists(principal);
|
|
61
|
+
if (!principalExists) {
|
|
62
|
+
principalsNotFound.push(principal);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const principalResults = await runPrincipalForActions(collectClient, principal, resource, resourceAccount, actions);
|
|
66
|
+
whoCanResults.push(...principalResults);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
principalsNotFound.push(principal);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
allowed: whoCanResults,
|
|
75
|
+
allAccountsChecked: accountsToCheck.allAccounts,
|
|
76
|
+
accountsNotFound: uniqueAccounts.accountsNotFound,
|
|
77
|
+
organizationsNotFound: uniqueAccounts.organizationsNotFound,
|
|
78
|
+
organizationalUnitsNotFound: uniqueAccounts.organizationalUnitsNotFound,
|
|
79
|
+
principalsNotFound: principalsNotFound
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function runPrincipalForActions(collectClient, principal, resource, resourceAccount, actions) {
|
|
83
|
+
const results = [];
|
|
84
|
+
for (const action of actions) {
|
|
85
|
+
const result = await (0, simulate_js_1.simulateRequest)({
|
|
86
|
+
principal: principal,
|
|
87
|
+
resourceArn: resource,
|
|
88
|
+
resourceAccount,
|
|
89
|
+
action,
|
|
90
|
+
customContextKeys: {}
|
|
91
|
+
}, collectClient);
|
|
92
|
+
if (result.analysis?.result === 'Allowed') {
|
|
93
|
+
const [service, serviceAction] = action.split(':');
|
|
94
|
+
results.push({
|
|
95
|
+
principal,
|
|
96
|
+
service: service,
|
|
97
|
+
action: serviceAction
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
102
|
+
}
|
|
103
|
+
async function uniqueAccountsToCheck(collectClient, accountsToCheck) {
|
|
104
|
+
const returnValue = {
|
|
105
|
+
accountsNotFound: [],
|
|
106
|
+
organizationsNotFound: [],
|
|
107
|
+
organizationalUnitsNotFound: [],
|
|
108
|
+
accounts: []
|
|
109
|
+
};
|
|
110
|
+
if (accountsToCheck.allAccounts) {
|
|
111
|
+
returnValue.accounts = await collectClient.allAccounts();
|
|
112
|
+
return returnValue;
|
|
113
|
+
}
|
|
114
|
+
const uniqueAccounts = new Set();
|
|
115
|
+
for (const account of accountsToCheck.specificAccounts || []) {
|
|
116
|
+
const accountExists = await collectClient.accountExists(account);
|
|
117
|
+
if (accountExists) {
|
|
118
|
+
uniqueAccounts.add(account);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
returnValue.accountsNotFound.push(account);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
for (const ouPath of accountsToCheck.specificOrganizationalUnits || []) {
|
|
125
|
+
const parts = ouPath.split('/');
|
|
126
|
+
const orgId = parts[0];
|
|
127
|
+
const pathParts = parts.slice(1);
|
|
128
|
+
const [found, accounts] = await collectClient.getAccountsForOrgPath(orgId, pathParts);
|
|
129
|
+
for (const account of accounts) {
|
|
130
|
+
uniqueAccounts.add(account);
|
|
131
|
+
}
|
|
132
|
+
if (!found) {
|
|
133
|
+
returnValue.organizationalUnitsNotFound.push(ouPath);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (const orgId of accountsToCheck.specificOrganizations || []) {
|
|
137
|
+
const [found, accounts] = await collectClient.getAccountsForOrganization(orgId);
|
|
138
|
+
for (const account of accounts) {
|
|
139
|
+
uniqueAccounts.add(account);
|
|
140
|
+
}
|
|
141
|
+
if (!found) {
|
|
142
|
+
returnValue.organizationsNotFound.push(orgId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
returnValue.accounts = Array.from(uniqueAccounts);
|
|
146
|
+
return returnValue;
|
|
147
|
+
}
|
|
148
|
+
async function accountsToCheckBasedOnResourcePolicy(resourcePolicy, resourceAccount) {
|
|
149
|
+
const accountsToCheck = {
|
|
150
|
+
allAccounts: false,
|
|
151
|
+
specificAccounts: [],
|
|
152
|
+
specificPrincipals: [],
|
|
153
|
+
specificOrganizations: [],
|
|
154
|
+
specificOrganizationalUnits: []
|
|
155
|
+
};
|
|
156
|
+
if (resourceAccount) {
|
|
157
|
+
accountsToCheck.specificAccounts.push(resourceAccount);
|
|
158
|
+
}
|
|
159
|
+
if (!resourcePolicy) {
|
|
160
|
+
return accountsToCheck;
|
|
161
|
+
}
|
|
162
|
+
const policy = (0, iam_policy_1.loadPolicy)(resourcePolicy);
|
|
163
|
+
for (const statement of policy.statements()) {
|
|
164
|
+
if (statement.isAllow() && statement.isNotPrincipalStatement()) {
|
|
165
|
+
accountsToCheck.allAccounts = true;
|
|
166
|
+
}
|
|
167
|
+
if (statement.isAllow() && statement.isPrincipalStatement()) {
|
|
168
|
+
const principals = statement.principals();
|
|
169
|
+
let hasWildcardPrincipal = false;
|
|
170
|
+
for (const principal of principals) {
|
|
171
|
+
if (principal.isWildcardPrincipal()) {
|
|
172
|
+
hasWildcardPrincipal = true;
|
|
173
|
+
}
|
|
174
|
+
else if (principal.isAccountPrincipal()) {
|
|
175
|
+
accountsToCheck.specificAccounts.push(principal.accountId());
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
accountsToCheck.specificPrincipals.push(principal.value());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (hasWildcardPrincipal) {
|
|
182
|
+
const specificOrgs = [];
|
|
183
|
+
const specificOus = [];
|
|
184
|
+
const specificAccounts = [];
|
|
185
|
+
const conditions = statement.conditions();
|
|
186
|
+
for (const cond of conditions) {
|
|
187
|
+
if (cond.conditionKey().toLowerCase() === 'aws:principalorgid' &&
|
|
188
|
+
cond.operation().value().toLowerCase().startsWith('stringequals') &&
|
|
189
|
+
!cond.conditionValues().some((v) => v.includes('$')) // Ignore dynamic values for now
|
|
190
|
+
) {
|
|
191
|
+
specificOrgs.push(...cond.conditionValues());
|
|
192
|
+
}
|
|
193
|
+
if (cond.conditionKey().toLowerCase() === 'aws:principalorgpaths' &&
|
|
194
|
+
cond.operation().baseOperator().toLowerCase().startsWith('stringequals') &&
|
|
195
|
+
!cond.conditionValues().some((v) => v.includes('$')) // Ignore dynamic values for now
|
|
196
|
+
) {
|
|
197
|
+
specificOus.push(...cond.conditionValues());
|
|
198
|
+
}
|
|
199
|
+
if (cond.conditionKey().toLowerCase() === 'aws:principalaccount' &&
|
|
200
|
+
cond.operation().value().toLowerCase().startsWith('stringequals') &&
|
|
201
|
+
!cond.conditionValues().some((v) => v.includes('$')) // Ignore dynamic values for now
|
|
202
|
+
) {
|
|
203
|
+
specificAccounts.push(...cond.conditionValues());
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (specificAccounts.length > 0) {
|
|
207
|
+
accountsToCheck.specificAccounts.push(...specificAccounts);
|
|
208
|
+
}
|
|
209
|
+
else if (specificOus.length > 0) {
|
|
210
|
+
accountsToCheck.specificOrganizationalUnits.push(...specificOus);
|
|
211
|
+
}
|
|
212
|
+
else if (specificOrgs.length > 0) {
|
|
213
|
+
accountsToCheck.specificOrganizations.push(...specificOrgs);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
accountsToCheck.allAccounts = true;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return accountsToCheck;
|
|
222
|
+
}
|
|
223
|
+
async function actionsForWhoCan(request) {
|
|
224
|
+
const { actions } = request;
|
|
225
|
+
if (actions && actions.length > 0) {
|
|
226
|
+
const validActions = [];
|
|
227
|
+
for (const action of actions) {
|
|
228
|
+
const parts = action.split(':');
|
|
229
|
+
if (parts.length !== 2) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const [service, actionName] = parts;
|
|
233
|
+
const serviceExists = await (0, iam_data_1.iamServiceExists)(service);
|
|
234
|
+
if (!serviceExists) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const actionExists = await (0, iam_data_1.iamActionExists)(service, actionName);
|
|
238
|
+
if (!actionExists) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
validActions.push(action);
|
|
242
|
+
}
|
|
243
|
+
return validActions;
|
|
244
|
+
}
|
|
245
|
+
if (!request.resource) {
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
return lookupActionsForResourceArn(request.resource);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get the the possible resource types for an action and resource
|
|
252
|
+
*
|
|
253
|
+
* @param service the service the action belongs to
|
|
254
|
+
* @param action the action to get the resource type for
|
|
255
|
+
* @param resourceArn the resource type matching the action, if any
|
|
256
|
+
* @throws an error if the service or action does not exist, or if the action is a wildcard only action
|
|
257
|
+
*/
|
|
258
|
+
async function lookupActionsForResourceArn(resourceArn) {
|
|
259
|
+
const [service, resourceType] = await findResourceTypeForArn(resourceArn);
|
|
260
|
+
const resourceTypeKey = resourceType.key;
|
|
261
|
+
const selectedActions = [];
|
|
262
|
+
const serviceActions = await (0, iam_data_1.iamActionsForService)(service);
|
|
263
|
+
for (const action of serviceActions) {
|
|
264
|
+
const actionDetails = await (0, iam_data_1.iamActionDetails)(service, action);
|
|
265
|
+
for (const rt of actionDetails.resourceTypes) {
|
|
266
|
+
if (rt.name == resourceTypeKey) {
|
|
267
|
+
selectedActions.push(`${service}:${action}`);
|
|
268
|
+
break; // No need to check other resource types for this action
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const isRole = new arn_js_1.Arn(resourceArn).matches({ service: 'iam', resourceType: 'role' });
|
|
273
|
+
if (isRole) {
|
|
274
|
+
selectedActions.push(...sts_js_1.AssumeRoleActions.values());
|
|
275
|
+
}
|
|
276
|
+
return selectedActions;
|
|
277
|
+
}
|
|
278
|
+
async function findResourceTypeForArn(resourceArn) {
|
|
279
|
+
const arnParts = (0, iam_utils_1.splitArnParts)(resourceArn);
|
|
280
|
+
const service = arnParts.service.toLowerCase();
|
|
281
|
+
const serviceExists = await (0, iam_data_1.iamServiceExists)(service);
|
|
282
|
+
if (!serviceExists) {
|
|
283
|
+
throw new Error(`Unable to find service ${service} for resource ${resourceArn}`);
|
|
284
|
+
}
|
|
285
|
+
const sortedResourceTypes = await allResourceTypesByArnLength(service);
|
|
286
|
+
for (const rt of sortedResourceTypes) {
|
|
287
|
+
const pattern = convertResourcePatternToRegex(rt.arn);
|
|
288
|
+
const match = resourceArn.match(new RegExp(pattern));
|
|
289
|
+
if (match) {
|
|
290
|
+
return [service, rt];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
throw new Error(`Unable to find resource type for service ${service} and resource ${resourceArn}.`);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Convert a resource pattern from iam-data to a regex pattern
|
|
297
|
+
*
|
|
298
|
+
* @param pattern the pattern to convert to a regex
|
|
299
|
+
* @returns the regex pattern
|
|
300
|
+
*/
|
|
301
|
+
function convertResourcePatternToRegex(pattern) {
|
|
302
|
+
const regex = pattern.replace(/\$\{.*?\}/g, (match, position) => {
|
|
303
|
+
const name = match.substring(2, match.length - 1);
|
|
304
|
+
const camelName = name.at(0)?.toLowerCase() + name.substring(1);
|
|
305
|
+
return `(?<${camelName}>(.+?))`;
|
|
306
|
+
});
|
|
307
|
+
return `^${regex}$`;
|
|
308
|
+
}
|
|
309
|
+
async function allResourceTypesByArnLength(service) {
|
|
310
|
+
const resourceTypeKeys = await (0, iam_data_1.iamResourceTypesForService)(service);
|
|
311
|
+
const sortedResourceTypes = [];
|
|
312
|
+
for (const key of resourceTypeKeys) {
|
|
313
|
+
const details = await (0, iam_data_1.iamResourceTypeDetails)(service, key);
|
|
314
|
+
sortedResourceTypes.push(details);
|
|
315
|
+
}
|
|
316
|
+
return sortedResourceTypes.sort((a, b) => {
|
|
317
|
+
return b.arn.length - a.arn.length;
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=whoCan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoCan.js","sourceRoot":"","sources":["../../../src/whoCan/whoCan.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/cli.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseCliArguments } from '@cloud-copilot/cli';
|
|
3
3
|
import { getCollectClient, loadCollectConfigs } from './collect/collect.js';
|
|
4
|
-
import { simulateRequest } from './simulate.js';
|
|
4
|
+
import { resultMatchesExpectation, simulateRequest } from './simulate/simulate.js';
|
|
5
|
+
import { iamLensVersion } from './utils/packageVersion.js';
|
|
6
|
+
import { whoCan } from './whoCan/whoCan.js';
|
|
5
7
|
const main = async () => {
|
|
6
|
-
|
|
8
|
+
const version = await iamLensVersion();
|
|
7
9
|
const cli = parseCliArguments('iam-lens', {
|
|
8
10
|
simulate: {
|
|
9
11
|
description: 'Simulate an IAM request',
|
|
@@ -21,12 +23,12 @@ const main = async () => {
|
|
|
21
23
|
resourceAccountId: {
|
|
22
24
|
type: 'string',
|
|
23
25
|
values: 'single',
|
|
24
|
-
description: 'The account ID of the resource, only required if it cannot be determined from the resource ARN.
|
|
26
|
+
description: 'The account ID of the resource, only required if it cannot be determined from the resource ARN.'
|
|
25
27
|
},
|
|
26
28
|
action: {
|
|
27
29
|
type: 'string',
|
|
28
30
|
values: 'single',
|
|
29
|
-
description: 'The action to simulate; must be a valid IAM service and action such as `s3:
|
|
31
|
+
description: 'The action to simulate; must be a valid IAM service and action such as `s3:ListBucket`'
|
|
30
32
|
},
|
|
31
33
|
context: {
|
|
32
34
|
type: 'string',
|
|
@@ -37,6 +39,32 @@ const main = async () => {
|
|
|
37
39
|
type: 'boolean',
|
|
38
40
|
description: 'Enable verbose output for the simulation',
|
|
39
41
|
character: 'v'
|
|
42
|
+
},
|
|
43
|
+
expect: {
|
|
44
|
+
type: 'enum',
|
|
45
|
+
values: 'single',
|
|
46
|
+
validValues: ['Allowed', 'ImplicitlyDenied', 'ExplicitlyDenied', 'AnyDeny'],
|
|
47
|
+
description: 'The expected result of the simulation, if the result does not match the expected response a non-zero exit code will be returned'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
'who-can': {
|
|
52
|
+
description: 'Find who can perform an action on a resource',
|
|
53
|
+
options: {
|
|
54
|
+
resource: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
values: 'single',
|
|
57
|
+
description: 'The ARN of the resource to check permissions for. Ignore for wildcard actions'
|
|
58
|
+
},
|
|
59
|
+
resourceAccount: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
values: 'single',
|
|
62
|
+
description: 'The account ID of the resource, only required if it cannot be determined from the resource ARN. Required for wildcard actions'
|
|
63
|
+
},
|
|
64
|
+
actions: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
values: 'multiple',
|
|
67
|
+
description: 'The action to check permissions for; must be a valid IAM service and action such as `s3:GetObject`'
|
|
40
68
|
}
|
|
41
69
|
}
|
|
42
70
|
}
|
|
@@ -54,16 +82,16 @@ const main = async () => {
|
|
|
54
82
|
}, {
|
|
55
83
|
envPrefix: 'IAM_LENS',
|
|
56
84
|
showHelpIfNoArgs: true,
|
|
57
|
-
requireSubcommand: true
|
|
58
|
-
|
|
85
|
+
requireSubcommand: true,
|
|
86
|
+
version
|
|
59
87
|
});
|
|
60
88
|
if (cli.args.collectConfigs.length === 0) {
|
|
61
89
|
cli.args.collectConfigs.push('./iam-collect.jsonc');
|
|
62
90
|
}
|
|
63
91
|
const thePartition = cli.args.partition || 'aws';
|
|
92
|
+
const collectConfigs = await loadCollectConfigs(cli.args.collectConfigs);
|
|
93
|
+
const collectClient = getCollectClient(collectConfigs, thePartition);
|
|
64
94
|
if (cli.subcommand === 'simulate') {
|
|
65
|
-
const collectConfigs = await loadCollectConfigs(cli.args.collectConfigs);
|
|
66
|
-
const collectClient = getCollectClient(collectConfigs, thePartition);
|
|
67
95
|
const { principal, resource, resourceAccountId, action, context } = cli.args;
|
|
68
96
|
const contextKeys = convertContextKeysToMap(context);
|
|
69
97
|
const result = await simulateRequest({
|
|
@@ -73,10 +101,31 @@ const main = async () => {
|
|
|
73
101
|
action: action,
|
|
74
102
|
customContextKeys: contextKeys
|
|
75
103
|
}, collectClient);
|
|
104
|
+
if (result.errors) {
|
|
105
|
+
console.error('Simulation Errors:');
|
|
106
|
+
console.log(JSON.stringify(result.errors, null, 2));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
76
109
|
console.log(`Simulation Result: ${result.analysis?.result}`);
|
|
77
110
|
if (cli.args.verbose) {
|
|
78
111
|
console.log(JSON.stringify(result, null, 2));
|
|
79
112
|
}
|
|
113
|
+
if (!resultMatchesExpectation(cli.args.expect, result.analysis?.result)) {
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (cli.subcommand === 'who-can') {
|
|
118
|
+
const { resource, resourceAccount, actions } = cli.args;
|
|
119
|
+
if (!resourceAccount && !resource && actions.length === 0) {
|
|
120
|
+
console.error('Error: At least 1) resource or 2) resource-account and actions must be provided for who-can command');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
const results = await whoCan(collectClient, {
|
|
124
|
+
resource: cli.args.resource,
|
|
125
|
+
actions: cli.args.actions,
|
|
126
|
+
resourceAccount: cli.args.resourceAccount
|
|
127
|
+
});
|
|
128
|
+
console.log(JSON.stringify(results, null, 2));
|
|
80
129
|
}
|
|
81
130
|
};
|
|
82
131
|
main()
|