@cloud-copilot/iam-lens 0.1.76 → 0.1.78

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 (42) hide show
  1. package/dist/cjs/utils/workerScript.d.ts +2 -2
  2. package/dist/cjs/utils/workerScript.d.ts.map +1 -1
  3. package/dist/cjs/utils/workerScript.js +7 -2
  4. package/dist/cjs/utils/workerScript.js.map +1 -1
  5. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts +4 -3
  6. package/dist/cjs/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -1
  7. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js +49 -4
  8. package/dist/cjs/whoCan/WhoCanMainThreadWorker.js.map +1 -1
  9. package/dist/cjs/whoCan/WhoCanWorker.d.ts +23 -2
  10. package/dist/cjs/whoCan/WhoCanWorker.d.ts.map +1 -1
  11. package/dist/cjs/whoCan/WhoCanWorker.js +23 -13
  12. package/dist/cjs/whoCan/WhoCanWorker.js.map +1 -1
  13. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js +68 -3
  14. package/dist/cjs/whoCan/WhoCanWorkerThreadWorker.js.map +1 -1
  15. package/dist/cjs/whoCan/requestAnalysis.d.ts +22 -0
  16. package/dist/cjs/whoCan/requestAnalysis.d.ts.map +1 -0
  17. package/dist/cjs/whoCan/requestAnalysis.js +27 -0
  18. package/dist/cjs/whoCan/requestAnalysis.js.map +1 -0
  19. package/dist/cjs/whoCan/whoCan.d.ts +35 -0
  20. package/dist/cjs/whoCan/whoCan.d.ts.map +1 -1
  21. package/dist/cjs/whoCan/whoCan.js +57 -16
  22. package/dist/cjs/whoCan/whoCan.js.map +1 -1
  23. package/dist/esm/utils/workerScript.d.ts.map +1 -1
  24. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts +4 -3
  25. package/dist/esm/whoCan/WhoCanMainThreadWorker.d.ts.map +1 -1
  26. package/dist/esm/whoCan/WhoCanMainThreadWorker.js +49 -4
  27. package/dist/esm/whoCan/WhoCanMainThreadWorker.js.map +1 -1
  28. package/dist/esm/whoCan/WhoCanWorker.d.ts +23 -2
  29. package/dist/esm/whoCan/WhoCanWorker.d.ts.map +1 -1
  30. package/dist/esm/whoCan/WhoCanWorker.js +23 -13
  31. package/dist/esm/whoCan/WhoCanWorker.js.map +1 -1
  32. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js +68 -3
  33. package/dist/esm/whoCan/WhoCanWorkerThreadWorker.js.map +1 -1
  34. package/dist/esm/whoCan/requestAnalysis.d.ts +22 -0
  35. package/dist/esm/whoCan/requestAnalysis.d.ts.map +1 -0
  36. package/dist/esm/whoCan/requestAnalysis.js +24 -0
  37. package/dist/esm/whoCan/requestAnalysis.js.map +1 -0
  38. package/dist/esm/whoCan/whoCan.d.ts +35 -0
  39. package/dist/esm/whoCan/whoCan.d.ts.map +1 -1
  40. package/dist/esm/whoCan/whoCan.js +57 -16
  41. package/dist/esm/whoCan/whoCan.js.map +1 -1
  42. package/package.json +2 -2
@@ -2,7 +2,7 @@
2
2
  * Get the path to a worker script, adjusted for the build output location.
3
3
  *
4
4
  * @param path the relative path to the worker script from the project src directory and with a .js extension
5
- * @returns the absolute path to the worker script
5
+ * @returns the absolute path to the worker script, or undefined if the worker script path does not exist
6
6
  */
7
- export declare function getWorkerScriptPath(path: string): string;
7
+ export declare function getWorkerScriptPath(path: string): string | undefined;
8
8
  //# sourceMappingURL=workerScript.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workerScript.d.ts","sourceRoot":"","sources":["../../../src/utils/workerScript.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD"}
1
+ {"version":3,"file":"workerScript.d.ts","sourceRoot":"","sources":["../../../src/utils/workerScript.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMpE"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getWorkerScriptPath = getWorkerScriptPath;
4
+ const fs_1 = require("fs");
4
5
  const path_1 = require("path");
5
6
  let root = (0, path_1.resolve)(__dirname, '../');
6
7
  if (process.env.NODE_ENV === 'test') {
@@ -10,9 +11,13 @@ if (process.env.NODE_ENV === 'test') {
10
11
  * Get the path to a worker script, adjusted for the build output location.
11
12
  *
12
13
  * @param path the relative path to the worker script from the project src directory and with a .js extension
13
- * @returns the absolute path to the worker script
14
+ * @returns the absolute path to the worker script, or undefined if the worker script path does not exist
14
15
  */
15
16
  function getWorkerScriptPath(path) {
16
- return (0, path_1.join)(root, path);
17
+ const fullPath = (0, path_1.join)(root, path);
18
+ if (!(0, fs_1.existsSync)(fullPath)) {
19
+ return undefined;
20
+ }
21
+ return fullPath;
17
22
  }
18
23
  //# sourceMappingURL=workerScript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workerScript.js","sourceRoot":"","sources":["../../../src/utils/workerScript.ts"],"names":[],"mappings":";;AAaA,kDAEC;AAfD,+BAAoC;AAEpC,IAAI,IAAI,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,KAAK,CAAC,CAAA;AACpC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;IACpC,IAAI,GAAG,IAAA,cAAO,EAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAA;AACzB,CAAC"}
1
+ {"version":3,"file":"workerScript.js","sourceRoot":"","sources":["../../../src/utils/workerScript.ts"],"names":[],"mappings":";;AAcA,kDAMC;AApBD,2BAA+B;AAC/B,+BAAoC;AAEpC,IAAI,IAAI,GAAG,IAAA,cAAO,EAAC,SAAS,EAAE,KAAK,CAAC,CAAA;AACpC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;IACpC,IAAI,GAAG,IAAA,cAAO,EAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;AAC3C,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACjC,IAAI,CAAC,IAAA,eAAU,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC"}
@@ -4,7 +4,8 @@ import { S3AbacOverride } from '../utils/s3Abac.js';
4
4
  import { ArrayStreamingWorkQueue } from '../workers/ArrayStreamingWorkQueue.js';
5
5
  import { PullBasedJobRunner } from '../workers/JobRunner.js';
6
6
  import { StreamingWorkQueue } from '../workers/StreamingWorkQueue.js';
7
- import { WhoCanAllowed } from './whoCan.js';
8
- import { WhoCanWorkItem } from './WhoCanWorker.js';
9
- export declare function createMainThreadStreamingWorkQueue(queue: StreamingWorkQueue<WhoCanWorkItem> | ArrayStreamingWorkQueue<WhoCanWorkItem>, collectClient: IamCollectClient, s3AbacOverride: S3AbacOverride | undefined, onComplete: (result: JobResult<WhoCanAllowed | undefined, Record<string, unknown>>) => void): PullBasedJobRunner<WhoCanAllowed | undefined, Record<string, unknown>, WhoCanWorkItem>;
7
+ import { LightRequestAnalysis } from './requestAnalysis.js';
8
+ import { WhoCanAllowed, WhoCanDenyDetail } from './whoCan.js';
9
+ import { WhoCanExecutionResult, WhoCanWorkItem } from './WhoCanWorker.js';
10
+ export declare function createMainThreadStreamingWorkQueue(queue: StreamingWorkQueue<WhoCanWorkItem> | ArrayStreamingWorkQueue<WhoCanWorkItem>, collectClient: IamCollectClient, s3AbacOverride: S3AbacOverride | undefined, onComplete: (result: JobResult<WhoCanAllowed | undefined, Record<string, unknown>>) => void, denyDetailsCallback?: (details: LightRequestAnalysis) => boolean, onDenyDetail?: (detail: WhoCanDenyDetail) => void): PullBasedJobRunner<WhoCanExecutionResult, Record<string, unknown>, WhoCanWorkItem>;
10
11
  //# sourceMappingURL=WhoCanMainThreadWorker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WhoCanMainThreadWorker.d.ts","sourceRoot":"","sources":["../../../src/whoCan/WhoCanMainThreadWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAA8B,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAE9E,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,kBAAkB,CAAC,cAAc,CAAC,GAAG,uBAAuB,CAAC,cAAc,CAAC,EACnF,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,aAAa,GAAG,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,0FAiB5F"}
1
+ {"version":3,"file":"WhoCanMainThreadWorker.d.ts","sourceRoot":"","sources":["../../../src/whoCan/WhoCanMainThreadWorker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAA0B,MAAM,sBAAsB,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAEL,qBAAqB,EACrB,cAAc,EACf,MAAM,mBAAmB,CAAA;AAE1B,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,kBAAkB,CAAC,cAAc,CAAC,GAAG,uBAAuB,CAAC,cAAc,CAAC,EACnF,aAAa,EAAE,gBAAgB,EAC/B,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,aAAa,GAAG,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,EAC3F,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,EAChE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,sFA6DlD"}
@@ -1,18 +1,63 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createMainThreadStreamingWorkQueue = createMainThreadStreamingWorkQueue;
4
+ const iam_simulate_1 = require("@cloud-copilot/iam-simulate");
4
5
  const JobRunner_js_1 = require("../workers/JobRunner.js");
6
+ const requestAnalysis_js_1 = require("./requestAnalysis.js");
5
7
  const WhoCanWorker_js_1 = require("./WhoCanWorker.js");
6
- function createMainThreadStreamingWorkQueue(queue, collectClient, s3AbacOverride, onComplete) {
8
+ function createMainThreadStreamingWorkQueue(queue, collectClient, s3AbacOverride, onComplete, denyDetailsCallback, onDenyDetail) {
9
+ const collectDenyDetails = !!denyDetailsCallback;
7
10
  return new JobRunner_js_1.PullBasedJobRunner(50, async () => {
8
11
  return queue.dequeue();
9
12
  }, (workItem) => {
10
13
  return (0, WhoCanWorker_js_1.createJobForWhoCanWorkItem)(workItem, collectClient, {
11
- s3AbacOverride
14
+ s3AbacOverride,
15
+ collectDenyDetails
12
16
  });
13
17
  }, async (result) => {
14
- // no-op for now, results are handled by the caller of execute
15
- return onComplete(result);
18
+ if (result.status === 'fulfilled') {
19
+ const executionResult = result.value;
20
+ if (executionResult.allowed) {
21
+ // Simulation was allowed - pass through to onComplete
22
+ onComplete({
23
+ status: 'fulfilled',
24
+ value: executionResult.allowed,
25
+ properties: result.properties
26
+ });
27
+ }
28
+ else {
29
+ // Simulation was denied
30
+ onComplete({
31
+ status: 'fulfilled',
32
+ value: undefined,
33
+ properties: result.properties
34
+ });
35
+ // Check if we should include deny details
36
+ if (denyDetailsCallback && onDenyDetail && executionResult.denyAnalysis) {
37
+ const lightAnalysis = (0, requestAnalysis_js_1.toLightRequestAnalysis)(executionResult.denyAnalysis);
38
+ const shouldInclude = denyDetailsCallback(lightAnalysis);
39
+ if (shouldInclude) {
40
+ const denialReasons = (0, iam_simulate_1.getDenialReasons)(executionResult.denyAnalysis);
41
+ const { workItem } = executionResult;
42
+ const [service, action] = workItem.action.split(':');
43
+ onDenyDetail({
44
+ principal: workItem.principal,
45
+ service,
46
+ action,
47
+ details: denialReasons
48
+ });
49
+ }
50
+ }
51
+ }
52
+ }
53
+ else {
54
+ // Error case - pass through as rejected
55
+ onComplete({
56
+ status: 'rejected',
57
+ reason: result.reason,
58
+ properties: result.properties
59
+ });
60
+ }
16
61
  });
17
62
  }
18
63
  //# sourceMappingURL=WhoCanMainThreadWorker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WhoCanMainThreadWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanMainThreadWorker.ts"],"names":[],"mappings":";;AASA,gFAqBC;AA1BD,0DAA4D;AAG5D,uDAA8E;AAE9E,SAAgB,kCAAkC,CAChD,KAAmF,EACnF,aAA+B,EAC/B,cAA0C,EAC1C,UAA2F;IAE3F,OAAO,IAAI,iCAAkB,CAC3B,EAAE,EACF,KAAK,IAAI,EAAE;QACT,OAAO,KAAK,CAAC,OAAO,EAAE,CAAA;IACxB,CAAC,EACD,CAAC,QAAQ,EAAE,EAAE;QACX,OAAO,IAAA,4CAA0B,EAAC,QAAQ,EAAE,aAAa,EAAE;YACzD,cAAc;SACf,CAAC,CAAA;IACJ,CAAC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,8DAA8D;QAC9D,OAAO,UAAU,CAAC,MAAM,CAAC,CAAA;IAC3B,CAAC,CACF,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"WhoCanMainThreadWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanMainThreadWorker.ts"],"names":[],"mappings":";;AAeA,gFAmEC;AAlFD,8DAA8D;AAK9D,0DAA4D;AAE5D,6DAAmF;AAEnF,uDAI0B;AAE1B,SAAgB,kCAAkC,CAChD,KAAmF,EACnF,aAA+B,EAC/B,cAA0C,EAC1C,UAA2F,EAC3F,mBAAgE,EAChE,YAAiD;IAEjD,MAAM,kBAAkB,GAAG,CAAC,CAAC,mBAAmB,CAAA;IAEhD,OAAO,IAAI,iCAAkB,CAC3B,EAAE,EACF,KAAK,IAAI,EAAE;QACT,OAAO,KAAK,CAAC,OAAO,EAAE,CAAA;IACxB,CAAC,EACD,CAAC,QAAQ,EAAE,EAAE;QACX,OAAO,IAAA,4CAA0B,EAAC,QAAQ,EAAE,aAAa,EAAE;YACzD,cAAc;YACd,kBAAkB;SACnB,CAAC,CAAA;IACJ,CAAC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAA;YACpC,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;gBAC5B,sDAAsD;gBACtD,UAAU,CAAC;oBACT,MAAM,EAAE,WAAW;oBACnB,KAAK,EAAE,eAAe,CAAC,OAAO;oBAC9B,UAAU,EAAE,MAAM,CAAC,UAAU;iBAC9B,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,wBAAwB;gBACxB,UAAU,CAAC;oBACT,MAAM,EAAE,WAAW;oBACnB,KAAK,EAAE,SAAS;oBAChB,UAAU,EAAE,MAAM,CAAC,UAAU;iBAC9B,CAAC,CAAA;gBAEF,0CAA0C;gBAC1C,IAAI,mBAAmB,IAAI,YAAY,IAAI,eAAe,CAAC,YAAY,EAAE,CAAC;oBACxE,MAAM,aAAa,GAAG,IAAA,2CAAsB,EAAC,eAAe,CAAC,YAAY,CAAC,CAAA;oBAC1E,MAAM,aAAa,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAA;oBAExD,IAAI,aAAa,EAAE,CAAC;wBAClB,MAAM,aAAa,GAAG,IAAA,+BAAgB,EAAC,eAAe,CAAC,YAAY,CAAC,CAAA;wBACpE,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAA;wBACpC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;wBACpD,YAAY,CAAC;4BACX,SAAS,EAAE,QAAQ,CAAC,SAAS;4BAC7B,OAAO;4BACP,MAAM;4BACN,OAAO,EAAE,aAAa;yBACvB,CAAC,CAAA;oBACJ,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,wCAAwC;YACxC,UAAU,CAAC;gBACT,MAAM,EAAE,UAAU;gBAClB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,UAAU,EAAE,MAAM,CAAC,UAAU;aAC9B,CAAC,CAAA;QACJ,CAAC;IACH,CAAC,CACF,CAAA;AACH,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { RequestAnalysis } from '@cloud-copilot/iam-simulate';
1
2
  import { Job } from '@cloud-copilot/job';
2
3
  import { IamCollectClient } from '../collect/client.js';
3
4
  import { S3AbacOverride } from '../utils/s3Abac.js';
@@ -8,9 +9,29 @@ export interface WhoCanWorkItem {
8
9
  action: string;
9
10
  principal: string;
10
11
  }
11
- export declare function createJobForWhoCanWorkItem(workItem: WhoCanWorkItem, collectClient: IamCollectClient, whoCanOptions: WhoCanOptions): Job<WhoCanAllowed | undefined, Record<string, unknown>>;
12
+ /**
13
+ * The result of executing a whoCan work item.
14
+ * Contains either the allowed result or the deny analysis (but not both).
15
+ */
16
+ export interface WhoCanExecutionResult {
17
+ /**
18
+ * The allowed result if the simulation was successful
19
+ */
20
+ allowed?: WhoCanAllowed;
21
+ /**
22
+ * The deny analysis if the simulation was not allowed.
23
+ * Only populated when collectDenyDetails is true.
24
+ */
25
+ denyAnalysis?: RequestAnalysis;
26
+ /**
27
+ * The work item that was executed, for context in deny details
28
+ */
29
+ workItem: WhoCanWorkItem;
30
+ }
31
+ export declare function createJobForWhoCanWorkItem(workItem: WhoCanWorkItem, collectClient: IamCollectClient, whoCanOptions: WhoCanOptions): Job<WhoCanExecutionResult, Record<string, unknown>>;
12
32
  export interface WhoCanOptions {
13
33
  s3AbacOverride?: S3AbacOverride;
34
+ collectDenyDetails?: boolean;
14
35
  }
15
- export declare function executeWhoCan(workItem: WhoCanWorkItem, collectClient: IamCollectClient, whoCanOptions: WhoCanOptions): Promise<WhoCanAllowed | undefined>;
36
+ export declare function executeWhoCan(workItem: WhoCanWorkItem, collectClient: IamCollectClient, whoCanOptions: WhoCanOptions): Promise<WhoCanExecutionResult>;
16
37
  //# sourceMappingURL=WhoCanWorker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WhoCanWorker.d.ts","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,gBAAgB,EAC/B,aAAa,EAAE,aAAa,GAC3B,GAAG,CAAC,aAAa,GAAG,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAOzD;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,gBAAgB,EAC/B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAqDpC"}
1
+ {"version":3,"file":"WhoCanWorker.d.ts","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,eAAe,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,CAAA;IAEvB;;;OAGG;IACH,YAAY,CAAC,EAAE,eAAe,CAAA;IAE9B;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAA;CACzB;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,gBAAgB,EAC/B,aAAa,EAAE,aAAa,GAC3B,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAOrD;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,wBAAsB,aAAa,CACjC,QAAQ,EAAE,cAAc,EACxB,aAAa,EAAE,gBAAgB,EAC/B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CA+DhC"}
@@ -37,27 +37,37 @@ async function executeWhoCan(workItem, collectClient, whoCanOptions) {
37
37
  if (result?.result.analysis?.result === 'Allowed') {
38
38
  const actionType = await getActionLevel(service, serviceAction);
39
39
  return {
40
- principal,
41
- service,
42
- action: serviceAction,
43
- level: actionType.toLowerCase()
40
+ workItem,
41
+ allowed: {
42
+ principal,
43
+ service,
44
+ action: serviceAction,
45
+ level: actionType.toLowerCase()
46
+ }
44
47
  };
45
48
  }
46
49
  else {
47
50
  const actionType = await getActionLevel(service, serviceAction);
48
51
  return {
49
- principal,
50
- service: service,
51
- action: serviceAction,
52
- level: actionType.toLowerCase(),
53
- conditions: discoveryResult?.result.analysis.ignoredConditions,
54
- dependsOnSessionName: discoveryResult?.result.analysis.ignoredRoleSessionName
55
- ? true
56
- : undefined
52
+ workItem,
53
+ allowed: {
54
+ principal,
55
+ service: service,
56
+ action: serviceAction,
57
+ level: actionType.toLowerCase(),
58
+ conditions: discoveryResult?.result.analysis.ignoredConditions,
59
+ dependsOnSessionName: discoveryResult?.result.analysis.ignoredRoleSessionName
60
+ ? true
61
+ : undefined
62
+ }
57
63
  };
58
64
  }
59
65
  }
60
- return undefined;
66
+ // Not allowed - return deny analysis if requested
67
+ return {
68
+ workItem,
69
+ denyAnalysis: whoCanOptions.collectDenyDetails ? discoveryResult?.result.analysis : undefined
70
+ };
61
71
  }
62
72
  /**
63
73
  * Get the action level for a specific service action, will fail if the service or action does not exist.
@@ -1 +1 @@
1
- {"version":3,"file":"WhoCanWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorker.ts"],"names":[],"mappings":";;AAcA,gEAWC;AAMD,sCAyDC;AAxFD,sDAA0D;AAG1D,yDAAyD;AAWzD,SAAgB,0BAA0B,CACxC,QAAwB,EACxB,aAA+B,EAC/B,aAA4B;IAE5B,OAAO;QACL,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACzB,OAAO,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,aAAa,CAAC,CAAA;QAC9D,CAAC;KACF,CAAA;AACH,CAAC;AAMM,KAAK,UAAU,aAAa,CACjC,QAAwB,EACxB,aAA+B,EAC/B,aAA4B;IAE5B,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IACjE,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClD,MAAM,eAAe,GAAG,MAAM,IAAA,6BAAe,EAC3C;QACE,SAAS;QACT,WAAW,EAAE,QAAQ;QACrB,eAAe,EAAE,eAAe;QAChC,MAAM;QACN,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,WAAW;QAC3B,cAAc,EAAE,aAAa,CAAC,cAAc;KAC7C,EACD,aAAa,CACd,CAAA;IAED,IAAI,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAe,EAClC;YACE,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,eAAe;YACf,MAAM;YACN,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,QAAQ;YACxB,cAAc,EAAE,aAAa,CAAC,cAAc;SAC7C,EACD,aAAa,CACd,CAAA;QACD,IAAI,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAClD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;YAC/D,OAAO;gBACL,SAAS;gBACT,OAAO;gBACP,MAAM,EAAE,aAAa;gBACrB,KAAK,EAAE,UAAU,CAAC,WAAW,EAAE;aAChC,CAAA;QACH,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;YAC/D,OAAO;gBACL,SAAS;gBACT,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,aAAa;gBACrB,KAAK,EAAE,UAAU,CAAC,WAAW,EAAE;gBAC/B,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,iBAAiB;gBAC9D,oBAAoB,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB;oBAC3E,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,SAAS;aACd,CAAA;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,MAAc;IAC3D,MAAM,OAAO,GAAG,MAAM,IAAA,2BAAgB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACvD,OAAO,OAAO,CAAC,WAAW,CAAA;AAC5B,CAAC"}
1
+ {"version":3,"file":"WhoCanWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorker.ts"],"names":[],"mappings":";;AAqCA,gEAWC;AAOD,sCAmEC;AA1HD,sDAA0D;AAI1D,yDAAyD;AAiCzD,SAAgB,0BAA0B,CACxC,QAAwB,EACxB,aAA+B,EAC/B,aAA4B;IAE5B,OAAO;QACL,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACzB,OAAO,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,aAAa,CAAC,CAAA;QAC9D,CAAC;KACF,CAAA;AACH,CAAC;AAOM,KAAK,UAAU,aAAa,CACjC,QAAwB,EACxB,aAA+B,EAC/B,aAA4B;IAE5B,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IACjE,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClD,MAAM,eAAe,GAAG,MAAM,IAAA,6BAAe,EAC3C;QACE,SAAS;QACT,WAAW,EAAE,QAAQ;QACrB,eAAe,EAAE,eAAe;QAChC,MAAM;QACN,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,WAAW;QAC3B,cAAc,EAAE,aAAa,CAAC,cAAc;KAC7C,EACD,aAAa,CACd,CAAA;IAED,IAAI,eAAe,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAe,EAClC;YACE,SAAS;YACT,WAAW,EAAE,QAAQ;YACrB,eAAe;YACf,MAAM;YACN,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,QAAQ;YACxB,cAAc,EAAE,aAAa,CAAC,cAAc;SAC7C,EACD,aAAa,CACd,CAAA;QACD,IAAI,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YAClD,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;YAC/D,OAAO;gBACL,QAAQ;gBACR,OAAO,EAAE;oBACP,SAAS;oBACT,OAAO;oBACP,MAAM,EAAE,aAAa;oBACrB,KAAK,EAAE,UAAU,CAAC,WAAW,EAAE;iBAChC;aACF,CAAA;QACH,CAAC;aAAM,CAAC;YACN,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;YAC/D,OAAO;gBACL,QAAQ;gBACR,OAAO,EAAE;oBACP,SAAS;oBACT,OAAO,EAAE,OAAO;oBAChB,MAAM,EAAE,aAAa;oBACrB,KAAK,EAAE,UAAU,CAAC,WAAW,EAAE;oBAC/B,UAAU,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,iBAAiB;oBAC9D,oBAAoB,EAAE,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB;wBAC3E,CAAC,CAAC,IAAI;wBACN,CAAC,CAAC,SAAS;iBACd;aACF,CAAA;QACH,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,OAAO;QACL,QAAQ;QACR,YAAY,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC,CAAC,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;KAC9F,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,MAAc;IAC3D,MAAM,OAAO,GAAG,MAAM,IAAA,2BAAgB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACvD,OAAO,OAAO,CAAC,WAAW,CAAA;AAC5B,CAAC"}
@@ -1,16 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const iam_simulate_1 = require("@cloud-copilot/iam-simulate");
3
4
  const worker_threads_1 = require("worker_threads");
4
5
  const collect_js_1 = require("../collect/collect.js");
5
6
  const JobRunner_js_1 = require("../workers/JobRunner.js");
6
7
  const SharedArrayBufferWorkerCache_js_1 = require("../workers/SharedArrayBufferWorkerCache.js");
8
+ const requestAnalysis_js_1 = require("./requestAnalysis.js");
7
9
  const WhoCanWorker_js_1 = require("./WhoCanWorker.js");
8
10
  if (!worker_threads_1.parentPort) {
9
11
  throw new Error('Must be run as a worker thread');
10
12
  }
11
13
  // Get config from the main thread
12
- const { concurrency, collectConfigs, partition, s3AbacOverride } = worker_threads_1.workerData;
14
+ const { concurrency, collectConfigs, partition, s3AbacOverride, collectDenyDetails } = worker_threads_1.workerData;
13
15
  const taskPromises = {};
16
+ // Pending deny details checks - keyed by a unique id for each check
17
+ let denyDetailsCheckId = 0;
18
+ const pendingDenyDetailsChecks = {};
14
19
  worker_threads_1.parentPort.on('message', (msg) => {
15
20
  if (msg.type === 'task' && msg.workerId in taskPromises) {
16
21
  taskPromises[msg.workerId](msg.task);
@@ -24,6 +29,15 @@ worker_threads_1.parentPort.on('message', (msg) => {
24
29
  worker_threads_1.parentPort.postMessage({ type: 'finished' });
25
30
  });
26
31
  }
32
+ else if (msg.type === 'denyDetailsCheckResult') {
33
+ // Handle response from main thread about whether to include deny details
34
+ const checkId = msg.checkId;
35
+ const resolveFn = pendingDenyDetailsChecks[checkId];
36
+ if (resolveFn) {
37
+ resolveFn(msg.shouldInclude);
38
+ delete pendingDenyDetailsChecks[checkId];
39
+ }
40
+ }
27
41
  });
28
42
  const collectClient = (0, collect_js_1.getCollectClient)(collectConfigs, partition, {
29
43
  cacheProvider: new SharedArrayBufferWorkerCache_js_1.SharedArrayBufferWorkerCache(worker_threads_1.parentPort)
@@ -38,11 +52,62 @@ const jobRunner = new JobRunner_js_1.PullBasedJobRunner(concurrency, async (work
38
52
  properties: {},
39
53
  execute: async (context) => {
40
54
  return (0, WhoCanWorker_js_1.executeWhoCan)(taskDetails, collectClient, {
41
- s3AbacOverride
55
+ s3AbacOverride,
56
+ collectDenyDetails
42
57
  });
43
58
  }
44
59
  };
45
60
  }, async (result) => {
46
- worker_threads_1.parentPort.postMessage({ type: 'result', result });
61
+ if (result.status === 'fulfilled') {
62
+ const executionResult = result.value;
63
+ if (executionResult.allowed) {
64
+ // Allowed - send result back to main thread
65
+ worker_threads_1.parentPort.postMessage({
66
+ type: 'result',
67
+ result: {
68
+ status: 'fulfilled',
69
+ value: executionResult.allowed,
70
+ properties: result.properties
71
+ }
72
+ });
73
+ }
74
+ else {
75
+ // If we have deny analysis and collectDenyDetails is enabled, check with main thread
76
+ if (collectDenyDetails && executionResult.denyAnalysis) {
77
+ const lightAnalysis = (0, requestAnalysis_js_1.toLightRequestAnalysis)(executionResult.denyAnalysis);
78
+ const checkId = denyDetailsCheckId++;
79
+ // Send check request to main thread
80
+ worker_threads_1.parentPort.postMessage({
81
+ type: 'checkDenyDetails',
82
+ checkId,
83
+ workItem: executionResult.workItem,
84
+ lightAnalysis
85
+ });
86
+ // Wait for response from main thread
87
+ const shouldInclude = await new Promise((resolve) => {
88
+ pendingDenyDetailsChecks[checkId] = resolve;
89
+ });
90
+ if (shouldInclude) {
91
+ // Get full denial reasons and send to main thread
92
+ const denialReasons = (0, iam_simulate_1.getDenialReasons)(executionResult.denyAnalysis);
93
+ const { workItem } = executionResult;
94
+ const [service, action] = workItem.action.split(':');
95
+ worker_threads_1.parentPort.postMessage({
96
+ type: 'denyDetailsResult',
97
+ denyDetail: {
98
+ principal: workItem.principal,
99
+ service,
100
+ action,
101
+ details: denialReasons
102
+ }
103
+ });
104
+ }
105
+ }
106
+ }
107
+ }
108
+ else {
109
+ // Error case - pass through
110
+ worker_threads_1.parentPort.postMessage({ type: 'result', result });
111
+ }
47
112
  });
48
113
  //# sourceMappingURL=WhoCanWorkerThreadWorker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WhoCanWorkerThreadWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorkerThreadWorker.ts"],"names":[],"mappings":";;AAEA,mDAAuD;AACvD,sDAAwD;AAExD,0DAA4D;AAC5D,gGAAyF;AACzF,uDAAiE;AAGjE,IAAI,CAAC,2BAAU,EAAE,CAAC;IAChB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;AACnD,CAAC;AAED,kCAAkC;AAClC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,2BAKlE,CAAA;AAED,MAAM,YAAY,GAAuC,EAAE,CAAA;AAE3D,2BAAU,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;IAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC;QACxD,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACpC,OAAO,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnC,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACxC,SAAS,CAAC,mBAAmB,EAAE,CAAA;IACjC,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACrC,SAAS,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAClC,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACJ,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,aAAa,GAAG,IAAA,6BAAgB,EAAC,cAAc,EAAE,SAAS,EAAE;IAChE,aAAa,EAAE,IAAI,8DAA4B,CAAC,2BAAU,CAAC;CAC5D,CAAC,CAAA;AAEF,MAAM,SAAS,GAAG,IAAI,iCAAkB,CAKtC,WAAW,EACX,KAAK,EAAE,QAAQ,EAAE,EAAE;IACjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1D,YAAY,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC,EACD,CAAC,WAAW,EAAE,EAAE;IACd,OAAO;QACL,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACzB,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,aAAa,EAAE;gBAC/C,cAAc;aACf,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;IACf,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;AACrD,CAAC,CACF,CAAA"}
1
+ {"version":3,"file":"WhoCanWorkerThreadWorker.js","sourceRoot":"","sources":["../../../src/whoCan/WhoCanWorkerThreadWorker.ts"],"names":[],"mappings":";;AAEA,8DAA8D;AAC9D,mDAAuD;AACvD,sDAAwD;AAExD,0DAA4D;AAC5D,gGAAyF;AACzF,6DAA6D;AAC7D,uDAAwF;AAExF,IAAI,CAAC,2BAAU,EAAE,CAAC;IAChB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;AACnD,CAAC;AAED,kCAAkC;AAClC,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAClF,2BAMC,CAAA;AAEH,MAAM,YAAY,GAAuC,EAAE,CAAA;AAE3D,oEAAoE;AACpE,IAAI,kBAAkB,GAAG,CAAC,CAAA;AAC1B,MAAM,wBAAwB,GAAqD,EAAE,CAAA;AAErF,2BAAU,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;IAC/B,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC;QACxD,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACpC,OAAO,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnC,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;QACxC,SAAS,CAAC,mBAAmB,EAAE,CAAA;IACjC,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACrC,SAAS,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAClC,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACJ,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;QACjD,yEAAyE;QACzE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAiB,CAAA;QACrC,MAAM,SAAS,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAA;QACnD,IAAI,SAAS,EAAE,CAAC;YACd,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;YAC5B,OAAO,wBAAwB,CAAC,OAAO,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,MAAM,aAAa,GAAG,IAAA,6BAAgB,EAAC,cAAc,EAAE,SAAS,EAAE;IAChE,aAAa,EAAE,IAAI,8DAA4B,CAAC,2BAAU,CAAC;CAC5D,CAAC,CAAA;AAEF,MAAM,SAAS,GAAG,IAAI,iCAAkB,CAKtC,WAAW,EACX,KAAK,EAAE,QAAQ,EAAE,EAAE;IACjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC1D,YAAY,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC,EACD,CAAC,WAAW,EAAE,EAAE;IACd,OAAO;QACL,UAAU,EAAE,EAAE;QACd,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACzB,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,aAAa,EAAE;gBAC/C,cAAc;gBACd,kBAAkB;aACnB,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;IACf,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAA;QAEpC,IAAI,eAAe,CAAC,OAAO,EAAE,CAAC;YAC5B,4CAA4C;YAC5C,2BAAW,CAAC,WAAW,CAAC;gBACtB,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE;oBACN,MAAM,EAAE,WAAW;oBACnB,KAAK,EAAE,eAAe,CAAC,OAAO;oBAC9B,UAAU,EAAE,MAAM,CAAC,UAAU;iBAC9B;aACF,CAAC,CAAA;QACJ,CAAC;aAAM,CAAC;YACN,qFAAqF;YACrF,IAAI,kBAAkB,IAAI,eAAe,CAAC,YAAY,EAAE,CAAC;gBACvD,MAAM,aAAa,GAAG,IAAA,2CAAsB,EAAC,eAAe,CAAC,YAAY,CAAC,CAAA;gBAC1E,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAA;gBAEpC,oCAAoC;gBACpC,2BAAW,CAAC,WAAW,CAAC;oBACtB,IAAI,EAAE,kBAAkB;oBACxB,OAAO;oBACP,QAAQ,EAAE,eAAe,CAAC,QAAQ;oBAClC,aAAa;iBACd,CAAC,CAAA;gBAEF,qCAAqC;gBACrC,MAAM,aAAa,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;oBAC3D,wBAAwB,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;gBAC7C,CAAC,CAAC,CAAA;gBAEF,IAAI,aAAa,EAAE,CAAC;oBAClB,kDAAkD;oBAClD,MAAM,aAAa,GAAG,IAAA,+BAAgB,EAAC,eAAe,CAAC,YAAY,CAAC,CAAA;oBACpE,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAA;oBACpC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;oBACpD,2BAAW,CAAC,WAAW,CAAC;wBACtB,IAAI,EAAE,mBAAmB;wBACzB,UAAU,EAAE;4BACV,SAAS,EAAE,QAAQ,CAAC,SAAS;4BAC7B,OAAO;4BACP,MAAM;4BACN,OAAO,EAAE,aAAa;yBACvB;qBACF,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,4BAA4B;QAC5B,2BAAW,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;IACrD,CAAC;AACH,CAAC,CACF,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { RequestAnalysis } from '@cloud-copilot/iam-simulate';
2
+ /**
3
+ * A light version of RequestAnalysis containing only the result and sameAccount fields,
4
+ * along with the result fields of the various analyses.
5
+ */
6
+ export interface LightRequestAnalysis {
7
+ result: RequestAnalysis['result'];
8
+ sameAccount: RequestAnalysis['sameAccount'];
9
+ identityAnalysis?: Pick<NonNullable<RequestAnalysis['identityAnalysis']>, 'result'>;
10
+ resourceAnalysis?: Pick<NonNullable<RequestAnalysis['resourceAnalysis']>, 'result'>;
11
+ scpAnalysis?: Pick<NonNullable<RequestAnalysis['scpAnalysis']>, 'result'>;
12
+ rcpAnalysis?: Pick<NonNullable<RequestAnalysis['rcpAnalysis']>, 'result'>;
13
+ permissionBoundaryAnalysis?: Pick<NonNullable<RequestAnalysis['permissionBoundaryAnalysis']>, 'result'>;
14
+ }
15
+ /**
16
+ * Convert a full RequestAnalysis to a LightRequestAnalysis
17
+ *
18
+ * @param analysis the full RequestAnalysis to convert
19
+ * @returns a LightRequestAnalysis with only the essential fields
20
+ */
21
+ export declare function toLightRequestAnalysis(analysis: RequestAnalysis): LightRequestAnalysis;
22
+ //# sourceMappingURL=requestAnalysis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestAnalysis.d.ts","sourceRoot":"","sources":["../../../src/whoCan/requestAnalysis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IACjC,WAAW,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC3C,gBAAgB,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IACnF,gBAAgB,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,kBAAkB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IACnF,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IACzE,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;IACzE,0BAA0B,CAAC,EAAE,IAAI,CAC/B,WAAW,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,EAC1D,QAAQ,CACT,CAAA;CACF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,oBAAoB,CAgBtF"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toLightRequestAnalysis = toLightRequestAnalysis;
4
+ /**
5
+ * Convert a full RequestAnalysis to a LightRequestAnalysis
6
+ *
7
+ * @param analysis the full RequestAnalysis to convert
8
+ * @returns a LightRequestAnalysis with only the essential fields
9
+ */
10
+ function toLightRequestAnalysis(analysis) {
11
+ return {
12
+ result: analysis.result,
13
+ sameAccount: analysis.sameAccount,
14
+ identityAnalysis: analysis.identityAnalysis
15
+ ? { result: analysis.identityAnalysis.result }
16
+ : undefined,
17
+ resourceAnalysis: analysis.resourceAnalysis
18
+ ? { result: analysis.resourceAnalysis.result }
19
+ : undefined,
20
+ scpAnalysis: analysis.scpAnalysis ? { result: analysis.scpAnalysis.result } : undefined,
21
+ rcpAnalysis: analysis.rcpAnalysis ? { result: analysis.rcpAnalysis.result } : undefined,
22
+ permissionBoundaryAnalysis: analysis.permissionBoundaryAnalysis
23
+ ? { result: analysis.permissionBoundaryAnalysis.result }
24
+ : undefined
25
+ };
26
+ }
27
+ //# sourceMappingURL=requestAnalysis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestAnalysis.js","sourceRoot":"","sources":["../../../src/whoCan/requestAnalysis.ts"],"names":[],"mappings":";;AAyBA,wDAgBC;AAtBD;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,QAAyB;IAC9D,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;YACzC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE;YAC9C,CAAC,CAAC,SAAS;QACb,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB;YACzC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE;YAC9C,CAAC,CAAC,SAAS;QACb,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS;QACvF,WAAW,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS;QACvF,0BAA0B,EAAE,QAAQ,CAAC,0BAA0B;YAC7D,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,0BAA0B,CAAC,MAAM,EAAE;YACxD,CAAC,CAAC,SAAS;KACd,CAAA;AACH,CAAC"}
@@ -1,13 +1,41 @@
1
1
  import { TopLevelConfig } from '@cloud-copilot/iam-collect';
2
2
  import { ResourceType } from '@cloud-copilot/iam-data';
3
+ import { RequestDenial } from '@cloud-copilot/iam-simulate';
3
4
  import { IamCollectClient } from '../collect/client.js';
4
5
  import { S3AbacOverride } from '../utils/s3Abac.js';
6
+ import { LightRequestAnalysis } from './requestAnalysis.js';
5
7
  export interface ResourceAccessRequest {
8
+ /**
9
+ * The ARN of the resource to check access for. If not provided, actions must be specified.
10
+ */
6
11
  resource?: string;
12
+ /**
13
+ * The account ID the resource belongs to.
14
+ * By default this will be looked up based on the resource ARN, but that may
15
+ * not be possible for all actions, such as wildcard actions like `s3:ListAllMyBuckets`.
16
+ */
7
17
  resourceAccount?: string;
18
+ /**
19
+ * The actions to check access for. If not provided, actions will be looked up based on the resource ARN.
20
+ */
8
21
  actions: string[];
22
+ /**
23
+ * Whether to sort the results for consistent output.
24
+ */
9
25
  sort?: boolean;
26
+ /**
27
+ * An override for S3 ABAC being enabled when checking access to S3 Bucket resources.
28
+ */
10
29
  s3AbacOverride?: S3AbacOverride;
30
+ /**
31
+ * The number of worker threads to use for simulations beyond the main thread.
32
+ * If not provided, defaults to number of CPUs - 1.
33
+ */
34
+ workerThreads?: number;
35
+ /**
36
+ * Deny details callback for simulations. If the callback returns true, deny details will be included for that simulation.
37
+ */
38
+ denyDetailsCallback?: (details: LightRequestAnalysis) => boolean;
11
39
  }
12
40
  export interface WhoCanAllowed {
13
41
  principal: string;
@@ -17,6 +45,12 @@ export interface WhoCanAllowed {
17
45
  conditions?: any;
18
46
  dependsOnSessionName?: boolean;
19
47
  }
48
+ export interface WhoCanDenyDetail {
49
+ principal: string;
50
+ service: string;
51
+ action: string;
52
+ details: RequestDenial[];
53
+ }
20
54
  export interface WhoCanResponse {
21
55
  simulationCount: number;
22
56
  allowed: WhoCanAllowed[];
@@ -25,6 +59,7 @@ export interface WhoCanResponse {
25
59
  organizationsNotFound: string[];
26
60
  organizationalUnitsNotFound: string[];
27
61
  principalsNotFound: string[];
62
+ denyDetails?: WhoCanDenyDetail[] | undefined;
28
63
  }
29
64
  export declare function whoCan(collectConfigs: TopLevelConfig[], partition: string, request: ResourceAccessRequest): Promise<WhoCanResponse>;
30
65
  export declare function uniqueAccountsToCheck(collectClient: IamCollectClient, accountsToCheck: AccountsToCheck): Promise<{
@@ -1 +1 @@
1
- {"version":3,"file":"whoCan.d.ts","sourceRoot":"","sources":["../../../src/whoCan/whoCan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAOL,YAAY,EACb,MAAM,yBAAyB,CAAA;AAWhC,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAIvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AASnD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,cAAc,CAAC,EAAE,cAAc,CAAA;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,GAAG,CAAA;IAChB,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,eAAe,EAAE,MAAM,CAAA;IACvB,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;AASD,wBAAsB,MAAM,CAC1B,cAAc,EAAE,cAAc,EAAE,EAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,cAAc,CAAC,CAuOzB;AAoBD,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;AAcD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,cAAc,QAe/D"}
1
+ {"version":3,"file":"whoCan.d.ts","sourceRoot":"","sources":["../../../src/whoCan/whoCan.ts"],"names":[],"mappings":"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"}
@@ -21,26 +21,38 @@ const workerScript_js_1 = require("../utils/workerScript.js");
21
21
  const SharedArrayBufferMainCache_js_1 = require("../workers/SharedArrayBufferMainCache.js");
22
22
  const StreamingWorkQueue_js_1 = require("../workers/StreamingWorkQueue.js");
23
23
  const WhoCanMainThreadWorker_js_1 = require("./WhoCanMainThreadWorker.js");
24
- function getCpuCount() {
25
- if (process.env.NODE_ENV === 'test') {
26
- return 2;
24
+ /**
25
+ * Get the number of worker threads to use, defaulting to number of CPUs - 1
26
+ *
27
+ * @param overrideValue the override value, if any
28
+ * @returns the override value if provided, otherwise number of CPUs - 1
29
+ */
30
+ function getNumberOfWorkers(overrideValue) {
31
+ if (typeof overrideValue === 'number' && overrideValue >= 0) {
32
+ return Math.floor(overrideValue);
27
33
  }
28
- return (0, job_1.numberOfCpus)();
34
+ return Math.max(0, (0, job_1.numberOfCpus)() - 1);
29
35
  }
30
36
  async function whoCan(collectConfigs, partition, request) {
31
- const cpus = getCpuCount();
32
37
  const { resource } = request;
38
+ // Get the number of workers and the worker script path.
39
+ // It's possible in bundled environments that the worker script path may not be found, so handle that gracefully.
40
+ const numWorkers = getNumberOfWorkers(request.workerThreads);
33
41
  const workerPath = (0, workerScript_js_1.getWorkerScriptPath)('whoCan/WhoCanWorkerThreadWorker.js');
34
- const workers = new Array(cpus - 1).fill(undefined).map((val) => {
35
- return new worker_threads_1.Worker(workerPath, {
36
- workerData: {
37
- collectConfigs: collectConfigs,
38
- partition,
39
- concurrency: 50,
40
- s3AbacOverride: request.s3AbacOverride
41
- }
42
+ const collectDenyDetails = !!request.denyDetailsCallback;
43
+ const workers = !workerPath
44
+ ? []
45
+ : new Array(numWorkers).fill(undefined).map((val) => {
46
+ return new worker_threads_1.Worker(workerPath, {
47
+ workerData: {
48
+ collectConfigs: collectConfigs,
49
+ partition,
50
+ concurrency: 50,
51
+ s3AbacOverride: request.s3AbacOverride,
52
+ collectDenyDetails
53
+ }
54
+ });
42
55
  });
43
- });
44
56
  const collectClient = (0, collect_js_1.getCollectClient)(collectConfigs, partition, {
45
57
  cacheProvider: new SharedArrayBufferMainCache_js_1.SharedArrayBufferMainCache(workers)
46
58
  });
@@ -75,6 +87,7 @@ async function whoCan(collectConfigs, partition, request) {
75
87
  let simulationCount = 0;
76
88
  const simulateQueue = new StreamingWorkQueue_js_1.StreamingWorkQueue();
77
89
  const simulationErrors = [];
90
+ const denyDetails = [];
78
91
  const onComplete = (result) => {
79
92
  simulationCount++;
80
93
  if (result.status === 'fulfilled' && result.value) {
@@ -85,7 +98,7 @@ async function whoCan(collectConfigs, partition, request) {
85
98
  simulationErrors.push(result);
86
99
  }
87
100
  };
88
- const mainThreadWorker = (0, WhoCanMainThreadWorker_js_1.createMainThreadStreamingWorkQueue)(simulateQueue, collectClient, request.s3AbacOverride, onComplete);
101
+ const mainThreadWorker = (0, WhoCanMainThreadWorker_js_1.createMainThreadStreamingWorkQueue)(simulateQueue, collectClient, request.s3AbacOverride, onComplete, request.denyDetailsCallback, (detail) => denyDetails.push(detail));
89
102
  workers.forEach((worker) => {
90
103
  worker.on('message', (msg) => {
91
104
  if (msg.type === 'requestTask') {
@@ -95,6 +108,18 @@ async function whoCan(collectConfigs, partition, request) {
95
108
  if (msg.type === 'result') {
96
109
  onComplete(msg.result);
97
110
  }
111
+ if (msg.type === 'checkDenyDetails') {
112
+ // Run the callback on main thread to check if we should include deny details
113
+ const shouldInclude = request.denyDetailsCallback?.(msg.lightAnalysis) ?? false;
114
+ worker.postMessage({
115
+ type: 'denyDetailsCheckResult',
116
+ checkId: msg.checkId,
117
+ shouldInclude
118
+ });
119
+ }
120
+ if (msg.type === 'denyDetailsResult') {
121
+ denyDetails.push(msg.denyDetail);
122
+ }
98
123
  });
99
124
  });
100
125
  simulateQueue.setWorkAvailableCallback(() => {
@@ -183,7 +208,8 @@ async function whoCan(collectConfigs, partition, request) {
183
208
  accountsNotFound: uniqueAccounts.accountsNotFound,
184
209
  organizationsNotFound: uniqueAccounts.organizationsNotFound,
185
210
  organizationalUnitsNotFound: uniqueAccounts.organizationalUnitsNotFound,
186
- principalsNotFound: principalsNotFound
211
+ principalsNotFound: principalsNotFound,
212
+ denyDetails: request.denyDetailsCallback ? denyDetails : undefined
187
213
  };
188
214
  if (request.sort) {
189
215
  sortWhoCanResults(results);
@@ -438,6 +464,21 @@ function sortWhoCanResults(whoCanResponse) {
438
464
  return 1;
439
465
  return 0;
440
466
  });
467
+ whoCanResponse.denyDetails?.sort((a, b) => {
468
+ if (a.principal < b.principal)
469
+ return -1;
470
+ if (a.principal > b.principal)
471
+ return 1;
472
+ if (a.service < b.service)
473
+ return -1;
474
+ if (a.service > b.service)
475
+ return 1;
476
+ if (a.action < b.action)
477
+ return -1;
478
+ if (a.action > b.action)
479
+ return 1;
480
+ return 0;
481
+ });
441
482
  whoCanResponse.accountsNotFound.sort();
442
483
  whoCanResponse.organizationsNotFound.sort();
443
484
  whoCanResponse.organizationalUnitsNotFound.sort();