@go-to-k/cdkd 0.0.3 → 0.0.4
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/dist/cli.js +124 -1
- package/dist/cli.js.map +2 -2
- package/dist/go-to-k-cdkd-0.0.4.tgz +0 -0
- package/dist/index.js +123 -0
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.0.3.tgz +0 -0
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -3132,6 +3132,11 @@ var TemplateParser = class {
|
|
|
3132
3132
|
// src/analyzer/dag-builder.ts
|
|
3133
3133
|
import graphlib from "graphlib";
|
|
3134
3134
|
var { Graph, alg } = graphlib;
|
|
3135
|
+
var IAM_ROLE_POLICY_TYPES = /* @__PURE__ */ new Set([
|
|
3136
|
+
"AWS::IAM::Policy",
|
|
3137
|
+
"AWS::IAM::RolePolicy",
|
|
3138
|
+
"AWS::IAM::ManagedPolicy"
|
|
3139
|
+
]);
|
|
3135
3140
|
var DagBuilder = class {
|
|
3136
3141
|
logger = getLogger().child("DagBuilder");
|
|
3137
3142
|
parser = new TemplateParser();
|
|
@@ -3172,6 +3177,7 @@ var DagBuilder = class {
|
|
|
3172
3177
|
}
|
|
3173
3178
|
}
|
|
3174
3179
|
this.logger.debug(`Dependency graph built: ${resourceIds.length} nodes, ${edgeCount} edges`);
|
|
3180
|
+
edgeCount += this.addCustomResourcePolicyEdges(graph, template);
|
|
3175
3181
|
if (!alg.isAcyclic(graph)) {
|
|
3176
3182
|
const cycles = this.findCycles(graph);
|
|
3177
3183
|
throw new DependencyError(
|
|
@@ -3314,6 +3320,123 @@ var DagBuilder = class {
|
|
|
3314
3320
|
const deps = this.getAllDependencies(graph, resourceA);
|
|
3315
3321
|
return deps.has(resourceB);
|
|
3316
3322
|
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Add implicit edges from IAM::Policy resources to Custom Resources whose
|
|
3325
|
+
* ServiceToken Lambda's execution role those policies attach to.
|
|
3326
|
+
*
|
|
3327
|
+
* Returns the number of edges added.
|
|
3328
|
+
*/
|
|
3329
|
+
addCustomResourcePolicyEdges(graph, template) {
|
|
3330
|
+
const rolePolicies = this.buildRolePoliciesMap(template);
|
|
3331
|
+
if (rolePolicies.size === 0) {
|
|
3332
|
+
return 0;
|
|
3333
|
+
}
|
|
3334
|
+
let added = 0;
|
|
3335
|
+
for (const logicalId of this.parser.getResourceIds(template)) {
|
|
3336
|
+
const resource = this.parser.getResource(template, logicalId);
|
|
3337
|
+
if (!resource || !this.isCustomResourceType(resource.Type)) {
|
|
3338
|
+
continue;
|
|
3339
|
+
}
|
|
3340
|
+
const serviceToken = (resource.Properties ?? {})["ServiceToken"];
|
|
3341
|
+
const lambdaId = this.extractLogicalIdFromReference(serviceToken);
|
|
3342
|
+
if (!lambdaId)
|
|
3343
|
+
continue;
|
|
3344
|
+
const lambdaResource = this.parser.getResource(template, lambdaId);
|
|
3345
|
+
if (!lambdaResource || lambdaResource.Type !== "AWS::Lambda::Function") {
|
|
3346
|
+
continue;
|
|
3347
|
+
}
|
|
3348
|
+
const roleId = this.extractLogicalIdFromReference((lambdaResource.Properties ?? {})["Role"]);
|
|
3349
|
+
if (!roleId)
|
|
3350
|
+
continue;
|
|
3351
|
+
const policies = rolePolicies.get(roleId);
|
|
3352
|
+
if (!policies)
|
|
3353
|
+
continue;
|
|
3354
|
+
for (const policyId of policies) {
|
|
3355
|
+
if (policyId === logicalId)
|
|
3356
|
+
continue;
|
|
3357
|
+
if (!graph.hasNode(policyId))
|
|
3358
|
+
continue;
|
|
3359
|
+
if (graph.hasEdge(policyId, logicalId))
|
|
3360
|
+
continue;
|
|
3361
|
+
graph.setEdge(policyId, logicalId);
|
|
3362
|
+
added++;
|
|
3363
|
+
this.logger.debug(
|
|
3364
|
+
`Added implicit edge (custom resource policy): ${policyId} -> ${logicalId}`
|
|
3365
|
+
);
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
if (added > 0) {
|
|
3369
|
+
this.logger.debug(`Added ${added} implicit edges for custom resource policies`);
|
|
3370
|
+
}
|
|
3371
|
+
return added;
|
|
3372
|
+
}
|
|
3373
|
+
isCustomResourceType(type) {
|
|
3374
|
+
return type === "AWS::CloudFormation::CustomResource" || type.startsWith("Custom::");
|
|
3375
|
+
}
|
|
3376
|
+
/**
|
|
3377
|
+
* Build a map of roleLogicalId -> Set<policyLogicalId> by scanning the
|
|
3378
|
+
* template for IAM::Policy / IAM::RolePolicy / IAM::ManagedPolicy resources
|
|
3379
|
+
* that attach to a role by Ref/GetAtt.
|
|
3380
|
+
*/
|
|
3381
|
+
buildRolePoliciesMap(template) {
|
|
3382
|
+
const map = /* @__PURE__ */ new Map();
|
|
3383
|
+
for (const [policyId, resource] of Object.entries(template.Resources)) {
|
|
3384
|
+
if (!IAM_ROLE_POLICY_TYPES.has(resource.Type))
|
|
3385
|
+
continue;
|
|
3386
|
+
for (const roleId of this.extractAttachedRoleIds(resource)) {
|
|
3387
|
+
let set = map.get(roleId);
|
|
3388
|
+
if (!set) {
|
|
3389
|
+
set = /* @__PURE__ */ new Set();
|
|
3390
|
+
map.set(roleId, set);
|
|
3391
|
+
}
|
|
3392
|
+
set.add(policyId);
|
|
3393
|
+
}
|
|
3394
|
+
}
|
|
3395
|
+
return map;
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* Extract the logical IDs of IAM::Role resources that a policy resource
|
|
3399
|
+
* attaches to. Supports both `Roles: [Ref]` (IAM::Policy / IAM::ManagedPolicy)
|
|
3400
|
+
* and `RoleName: Ref` (IAM::RolePolicy) shapes.
|
|
3401
|
+
*/
|
|
3402
|
+
extractAttachedRoleIds(resource) {
|
|
3403
|
+
const ids = [];
|
|
3404
|
+
const props = resource.Properties ?? {};
|
|
3405
|
+
const roles = props["Roles"];
|
|
3406
|
+
if (Array.isArray(roles)) {
|
|
3407
|
+
for (const entry of roles) {
|
|
3408
|
+
const id = this.extractLogicalIdFromReference(entry);
|
|
3409
|
+
if (id)
|
|
3410
|
+
ids.push(id);
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
const roleName = props["RoleName"];
|
|
3414
|
+
const roleNameId = this.extractLogicalIdFromReference(roleName);
|
|
3415
|
+
if (roleNameId)
|
|
3416
|
+
ids.push(roleNameId);
|
|
3417
|
+
return ids;
|
|
3418
|
+
}
|
|
3419
|
+
/**
|
|
3420
|
+
* Extract a resource logical ID from a direct Ref or Fn::GetAtt expression.
|
|
3421
|
+
* Returns undefined for literals or intrinsics we can't statically resolve
|
|
3422
|
+
* (Fn::Join, Fn::ImportValue, etc.) — callers should skip in that case.
|
|
3423
|
+
*/
|
|
3424
|
+
extractLogicalIdFromReference(value) {
|
|
3425
|
+
if (typeof value !== "object" || value === null)
|
|
3426
|
+
return void 0;
|
|
3427
|
+
const obj = value;
|
|
3428
|
+
if ("Ref" in obj && typeof obj["Ref"] === "string") {
|
|
3429
|
+
const ref = obj["Ref"];
|
|
3430
|
+
return ref.startsWith("AWS::") ? void 0 : ref;
|
|
3431
|
+
}
|
|
3432
|
+
if ("Fn::GetAtt" in obj) {
|
|
3433
|
+
const getAtt = obj["Fn::GetAtt"];
|
|
3434
|
+
if (Array.isArray(getAtt) && typeof getAtt[0] === "string") {
|
|
3435
|
+
return getAtt[0];
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
return void 0;
|
|
3439
|
+
}
|
|
3317
3440
|
};
|
|
3318
3441
|
|
|
3319
3442
|
// src/analyzer/replacement-rules.ts
|