@cloud-copilot/iam-lens
Version:
Visibility in IAM in and across AWS accounts
81 lines • 3.93 kB
JavaScript
import {} from '@cloud-copilot/job';
import { IamCollectClient } from '../collect/client.js';
import {} from '../utils/s3Abac.js';
import { PullBasedJobRunner } from '../workers/JobRunner.js';
import { convertToDenialDetails, toLightRequestAnalysis } from './requestAnalysis.js';
import {} from './whoCan.js';
import { executeWhoCan } from './WhoCanWorker.js';
/**
* Creates a main-thread simulation runner that pulls tagged work items from
* the processor's FIFO scheduler and routes results back by requestId.
*
* The requestId is threaded through the job's properties so it is available
* in onComplete without needing the workerId.
*
* @param dequeueWork - Function to dequeue the next tagged work item.
* @param onSimulationResult - Callback for simulation results.
* @param onCheckDenyDetails - Callback to check whether to collect deny details.
* @param onDenyDetail - Callback for deny detail delivery.
* @param collectClient - The IAM collect client for fetching policy data.
* @param s3AbacOverride - Optional override for S3 ABAC when checking S3 Bucket access.
* @param collectGrantDetails - Whether to collect grant details for allowed simulations.
* @param concurrency - The number of concurrent simulations to run on the main thread. Defaults to 50.
* @returns a PullBasedJobRunner that processes tagged whoCan work items.
*/
export function createMainThreadStreamingWorkQueue(dequeueWork, onSimulationResult, onCheckDenyDetails, onDenyDetail, collectClient, s3AbacOverride, collectGrantDetails, concurrency = 50) {
return new PullBasedJobRunner(concurrency, async () => {
return dequeueWork();
}, (taggedItem) => {
const { requestId, ...workItem } = taggedItem;
return {
properties: { requestId, collectDenyDetails: workItem.collectDenyDetails },
execute: async (context) => {
return executeWhoCan(workItem, collectClient, {
s3AbacOverride,
collectDenyDetails: workItem.collectDenyDetails,
collectGrantDetails,
strictContextKeys: workItem.strictContextKeys
});
}
};
}, async (result) => {
const { requestId, collectDenyDetails } = result.properties;
if (result.status === 'fulfilled') {
const executionResult = result.value;
if (executionResult.type === 'allowed') {
onSimulationResult(requestId, {
status: 'fulfilled',
value: executionResult.allowed,
properties: {}
});
}
else {
// Denied — handle deny details BEFORE reporting the simulation result,
// because onSimulationResult may trigger request completion checks.
const hasDetails = executionResult.type === 'denied_single' || executionResult.type === 'denied_wildcard';
if (collectDenyDetails && hasDetails) {
const lightAnalysis = toLightRequestAnalysis(executionResult);
const shouldInclude = onCheckDenyDetails(requestId, lightAnalysis);
if (shouldInclude) {
onDenyDetail(requestId, convertToDenialDetails(executionResult));
}
}
// Now report the denied simulation result (may trigger completion check)
onSimulationResult(requestId, {
status: 'fulfilled',
value: undefined,
properties: {}
});
}
}
else {
// Error case
onSimulationResult(requestId, {
status: 'rejected',
reason: result.reason,
properties: {}
});
}
});
}
//# sourceMappingURL=WhoCanMainThreadWorker.js.map