@@ -95,6 +95,25 @@ def dev_deployment_config():
9595 return DeploymentConfig .from_dict (dev_env , TEST_CONFIG )
9696
9797
98+ @pytest .fixture
99+ def prod_cdk_app ():
100+ """Fixture for CDK App using PROD environment."""
101+ account_id = "588077357019"
102+ region = "eu-west-2"
103+ vpc_id = TEST_CONFIG ["vpc_id" ]
104+ domain_name = TEST_CONFIG ["domain_name" ]
105+
106+ app = App (context = _build_cdk_context (account_id , region , vpc_id , domain_name ))
107+ return app
108+
109+
110+ @pytest .fixture
111+ def prod_deployment_config ():
112+ """Fixture for PROD DeploymentConfig using from_dict."""
113+ prod_env = CdkEnvironment (account = "588077357019" , region = "eu-west-2" )
114+ return DeploymentConfig .from_dict (prod_env , TEST_CONFIG )
115+
116+
98117@pytest .fixture
99118def webapp_no_auth (cdk_app , deployment_config , app_config ):
100119 """Fixture for WebApp with NoAuth."""
@@ -581,3 +600,124 @@ def test_web_app_stack_invalid_authentication_raises_error(
581600 docker_context_path = "tests/fixtures" ,
582601 dockerfile_path = "Dockerfile" ,
583602 )
603+
604+
605+ # Cross-account access tests
606+
607+
608+ def test_web_app_stack_cross_account_access_in_dev (
609+ dev_cdk_app , dev_deployment_config , app_config
610+ ):
611+ """Test that cross_account_access=True adds IAM policy and env var in dev."""
612+ stack = WebApp (
613+ dev_cdk_app ,
614+ dev_deployment_config ,
615+ app_config ,
616+ authentication = AuthType .NONE ,
617+ docker_context_path = "tests/fixtures" ,
618+ dockerfile_path = "Dockerfile" ,
619+ cross_account_access = True ,
620+ )
621+ template = Template .from_stack (stack )
622+
623+ # Task role should have sts:AssumeRole policy
624+ template .has_resource_properties (
625+ "AWS::IAM::Policy" ,
626+ {
627+ "PolicyDocument" : {
628+ "Statement" : Match .array_with (
629+ [
630+ Match .object_like (
631+ {
632+ "Action" : "sts:AssumeRole" ,
633+ "Effect" : "Allow" ,
634+ "Resource" : Match .string_like_regexp (
635+ r".*assume_role_for_development_account"
636+ ),
637+ }
638+ )
639+ ]
640+ )
641+ }
642+ },
643+ )
644+
645+ # Container should have CROSS_ACCOUNT_ROLE_ARN env var
646+ template .has_resource_properties (
647+ "AWS::ECS::TaskDefinition" ,
648+ {
649+ "ContainerDefinitions" : Match .array_with (
650+ [
651+ Match .object_like (
652+ {
653+ "Environment" : Match .array_with (
654+ [
655+ {
656+ "Name" : "CROSS_ACCOUNT_ROLE_ARN" ,
657+ "Value" : Match .string_like_regexp (
658+ r".*assume_role_for_development_account"
659+ ),
660+ }
661+ ]
662+ )
663+ }
664+ )
665+ ]
666+ )
667+ },
668+ )
669+
670+
671+ def test_web_app_stack_cross_account_access_disabled_by_default (
672+ cdk_app , deployment_config , app_config
673+ ):
674+ """Test that cross_account_access defaults to False and adds nothing."""
675+ stack = WebApp (
676+ cdk_app ,
677+ deployment_config ,
678+ app_config ,
679+ authentication = AuthType .NONE ,
680+ docker_context_path = "tests/fixtures" ,
681+ dockerfile_path = "Dockerfile" ,
682+ )
683+ template = Template .from_stack (stack )
684+
685+ # Should have no IAM policy with sts:AssumeRole for cross-account role
686+ # (the only policies should be for logging, not sts:AssumeRole)
687+ policies = template .find_resources ("AWS::IAM::Policy" )
688+ for _policy_id , policy in policies .items ():
689+ statements = (
690+ policy .get ("Properties" , {}).get ("PolicyDocument" , {}).get ("Statement" , [])
691+ )
692+ for stmt in statements :
693+ if stmt .get ("Action" ) == "sts:AssumeRole" :
694+ resource = stmt .get ("Resource" , "" )
695+ assert "assume_role_for_development_account" not in str (resource )
696+
697+
698+ def test_web_app_stack_cross_account_access_true_in_prod (
699+ prod_cdk_app , prod_deployment_config , app_config
700+ ):
701+ """Test that cross_account_access=True in production adds no AssumeRole policy."""
702+ stack = WebApp (
703+ prod_cdk_app ,
704+ prod_deployment_config ,
705+ app_config ,
706+ authentication = AuthType .NONE ,
707+ docker_context_path = "tests/fixtures" ,
708+ dockerfile_path = "Dockerfile" ,
709+ cross_account_access = True ,
710+ )
711+ template = Template .from_stack (stack )
712+
713+ # Even with cross_account_access=True, production should have no
714+ # sts:AssumeRole policy for the cross-account role
715+ policies = template .find_resources ("AWS::IAM::Policy" )
716+ for _policy_id , policy in policies .items ():
717+ statements = (
718+ policy .get ("Properties" , {}).get ("PolicyDocument" , {}).get ("Statement" , [])
719+ )
720+ for stmt in statements :
721+ if stmt .get ("Action" ) == "sts:AssumeRole" :
722+ resource = stmt .get ("Resource" , "" )
723+ assert "assume_role_for_development_account" not in str (resource )
0 commit comments