From fb739d0a6ba293339431f81812f8fe805b85649f Mon Sep 17 00:00:00 2001 From: Alon Gubkin Date: Sun, 30 Aug 2026 03:18:35 -0700 Subject: [PATCH 1/2] fix(aws): allow compute role policy reconciliation --- .../compute-cluster/management.jsonc | 17 +++++++++++ .../tests/aws_cloudformation.rs | 29 +++++++++++++++++++ crates/alien-permissions/tests/aws_runtime.rs | 26 +++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc b/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc index fda9e2303..f381545b5 100644 --- a/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc +++ b/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc @@ -410,6 +410,23 @@ } } }, + // The runtime controller keeps the setup-created compute role, but owns + // the generated execute policy attached to it. Capacity reconciliation + // must therefore be able to refresh that policy and remove its legacy + // predecessor without gaining authority over unrelated IAM roles. + { + "grant": { + "actions": ["iam:PutRolePolicy", "iam:DeleteRolePolicy"] + }, + "binding": { + "stack": { + "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*"] + }, + "resource": { + "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*"] + } + } + }, // Read-only inspection. AWS requires Resource: "*" for these Describe APIs. { "grant": { diff --git a/crates/alien-permissions/tests/aws_cloudformation.rs b/crates/alien-permissions/tests/aws_cloudformation.rs index 3cf9b8db2..727379a38 100644 --- a/crates/alien-permissions/tests/aws_cloudformation.rs +++ b/crates/alien-permissions/tests/aws_cloudformation.rs @@ -203,6 +203,35 @@ fn test_aws_cloudformation_compute_management_can_use_setup_security_group() { ); } +#[test] +fn test_aws_cloudformation_compute_management_can_reconcile_instance_role_policy() { + let generator = AwsCloudFormationPermissionsGenerator::new(); + let permission_set = + get_permission_set("compute-cluster/management").expect("permission set exists"); + let context = PermissionContext::new() + .with_stack_prefix("") + .with_aws_region("${AWS::Region}") + .with_aws_account_id("${AWS::AccountId}"); + + let result = generator + .generate_policy(permission_set, BindingTarget::Stack, &context) + .expect("Should generate AWS CloudFormation policy successfully"); + + let statement = result + .statement + .iter() + .find(|statement| statement.action.contains(&json!("iam:PutRolePolicy"))) + .expect("compute-cluster management should grant inline role policy reconciliation"); + + assert!(statement.action.contains(&json!("iam:DeleteRolePolicy"))); + assert_eq!( + statement.resource, + [json!({ + "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWS::StackName}-*" + })] + ); +} + #[test] fn test_aws_cloudformation_compute_management_can_terminate_only_tagged_stack_instances() { let generator = AwsCloudFormationPermissionsGenerator::new(); diff --git a/crates/alien-permissions/tests/aws_runtime.rs b/crates/alien-permissions/tests/aws_runtime.rs index 64a071ab6..cf09e3fd0 100644 --- a/crates/alien-permissions/tests/aws_runtime.rs +++ b/crates/alien-permissions/tests/aws_runtime.rs @@ -608,6 +608,32 @@ fn test_compute_cluster_management_can_pass_stack_prefixed_instance_roles() { ); } +#[test] +fn test_compute_cluster_management_can_reconcile_stack_prefixed_instance_role_policy() { + let generator = AwsRuntimePermissionsGenerator::new(); + let permission_set = + get_permission_set("compute-cluster/management").expect("permission set exists"); + let context = create_test_context(); + + let result = generator + .generate_policy(permission_set, BindingTarget::Stack, &context) + .expect("Should generate AWS policy successfully"); + + let role_policy_statement = result + .statement + .iter() + .find(|statement| statement.action.contains(&"iam:PutRolePolicy".to_string())) + .expect("compute-cluster management should grant inline role policy reconciliation"); + + assert!(role_policy_statement + .action + .contains(&"iam:DeleteRolePolicy".to_string())); + assert_eq!( + role_policy_statement.resource, + vec!["arn:aws:iam::123456789012:role/my-stack-*".to_string()] + ); +} + #[test] fn test_aws_statement_id_generation() { let generator = AwsRuntimePermissionsGenerator::new(); From 4845b4afc9215b2443d9e30603f5bb50b0b06996 Mon Sep 17 00:00:00 2001 From: Alon Gubkin Date: Sun, 30 Aug 2026 03:21:59 -0700 Subject: [PATCH 2/2] fix(aws): narrow compute role policy scope --- .../permission-sets/compute-cluster/management.jsonc | 4 ++-- crates/alien-permissions/tests/aws_cloudformation.rs | 2 +- crates/alien-permissions/tests/aws_runtime.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc b/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc index f381545b5..dc66e7677 100644 --- a/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc +++ b/crates/alien-permissions/permission-sets/compute-cluster/management.jsonc @@ -420,10 +420,10 @@ }, "binding": { "stack": { - "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*"] + "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*-role"] }, "resource": { - "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*"] + "resources": ["arn:aws:iam::${awsAccountId}:role/${stackPrefix}-*-role"] } } }, diff --git a/crates/alien-permissions/tests/aws_cloudformation.rs b/crates/alien-permissions/tests/aws_cloudformation.rs index 727379a38..4251a18ba 100644 --- a/crates/alien-permissions/tests/aws_cloudformation.rs +++ b/crates/alien-permissions/tests/aws_cloudformation.rs @@ -227,7 +227,7 @@ fn test_aws_cloudformation_compute_management_can_reconcile_instance_role_policy assert_eq!( statement.resource, [json!({ - "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWS::StackName}-*" + "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${AWS::StackName}-*-role" })] ); } diff --git a/crates/alien-permissions/tests/aws_runtime.rs b/crates/alien-permissions/tests/aws_runtime.rs index cf09e3fd0..5d6980719 100644 --- a/crates/alien-permissions/tests/aws_runtime.rs +++ b/crates/alien-permissions/tests/aws_runtime.rs @@ -630,7 +630,7 @@ fn test_compute_cluster_management_can_reconcile_stack_prefixed_instance_role_po .contains(&"iam:DeleteRolePolicy".to_string())); assert_eq!( role_policy_statement.resource, - vec!["arn:aws:iam::123456789012:role/my-stack-*".to_string()] + vec!["arn:aws:iam::123456789012:role/my-stack-*-role".to_string()] ); }