Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integration/config/code_key_to_file_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"codeuri": "code.zip",
"contenturi": "layer1.zip",
"definitionuri": "swagger1.json",
"microvmcodeuri": "microvm_code.zip",
"mtlsuri": "MTLSCert.pem",
"templateurl": "template.yaml"
}
4 changes: 4 additions & 0 deletions integration/config/file_to_s3_map.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
"type": "s3",
"uri": ""
},
"microvm_code.zip": {
"type": "s3",
"uri": ""
},
"swagger1.json": {
"type": "s3",
"uri": ""
Expand Down
1 change: 1 addition & 0 deletions integration/config/service_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
STATE_MACHINE_WITH_APIS = "StateMachineWithApis"
LAMBDA_URL = "LambdaUrl"
LAMBDA_MANAGED_INSTANCES = "LambdaManagedInstances"
MICROVM_IMAGE = "MicrovmImage"
LAMBDA_ENV_VARS = "LambdaEnvVars"
EVENT_INVOKE_CONFIG = "EventInvokeConfig"
API_KEY = "ApiKey"
Expand Down
Binary file added integration/resources/code/microvm_code.zip
Binary file not shown.
10 changes: 10 additions & 0 deletions integration/resources/expected/single/basic_microvm_image.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"LogicalResourceId": "MyMicroVMImage",
"ResourceType": "AWS::Lambda::MicrovmImage"
},
{
"LogicalResourceId": "MyMicroVMImageBuildRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"LogicalResourceId": "MyMinimalMicroVMImage",
"ResourceType": "AWS::Lambda::MicrovmImage"
},
{
"LogicalResourceId": "MyMinimalMicroVMImageBuildRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"LogicalResourceId": "MyMicroVMImageWithBuildRole",
"ResourceType": "AWS::Lambda::MicrovmImage"
},
{
"LogicalResourceId": "CustomBuildRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"LogicalResourceId": "MyNetworkConnector",
"ResourceType": "AWS::Lambda::NetworkConnector"
},
{
"LogicalResourceId": "MyNetworkConnectorOperatorRole",
"ResourceType": "AWS::IAM::Role"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"LogicalResourceId": "MyNetworkConnectorWithRole",
"ResourceType": "AWS::Lambda::NetworkConnector"
},
{
"LogicalResourceId": "CustomOperatorRole",
"ResourceType": "AWS::IAM::Role"
}
]
23 changes: 23 additions & 0 deletions integration/resources/templates/single/basic_microvm_image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Resources:
MyMicroVMImage:
Type: AWS::Serverless::MicrovmImage
Properties:
Name:
Fn::Select:
- 2
- Fn::Split:
- /
- !Ref AWS::StackId
CodeUri: ${microvmcodeuri}
BaseImageArn: !Sub arn:aws:lambda:${AWS::Region}:aws:microvm-image:al2023-0
BaseImageVersion: '0'
Resources:
- MinimumMemoryInMiB: 512
CpuConfigurations:
- Architecture: ARM_64
Hooks:
Port: 9000
Tags:
Environment: IntegTest
Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Resources:
MyMinimalMicroVMImage:
Type: AWS::Serverless::MicrovmImage
Properties:
Name:
Fn::Select:
- 2
- Fn::Split:
- /
- !Ref AWS::StackId
CodeUri: ${microvmcodeuri}
BaseImageArn: !Sub arn:aws:lambda:${AWS::Region}:aws:microvm-image:al2023-0
BaseImageVersion: '0'
Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Resources:
MyMicroVMImageWithBuildRole:
Type: AWS::Serverless::MicrovmImage
Properties:
Name:
Fn::Select:
- 2
- Fn::Split:
- /
- !Ref AWS::StackId
CodeUri: ${microvmcodeuri}
BaseImageArn: !Sub arn:aws:lambda:${AWS::Region}:aws:microvm-image:al2023-0
BaseImageVersion: '0'
BuildRoleArn: !GetAtt CustomBuildRole.Arn
Resources:
- MinimumMemoryInMiB: 512
CpuConfigurations:
- Architecture: ARM_64
Hooks:
Port: 9000

CustomBuildRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
- sts:TagSession
Policies:
- PolicyName: CustomBuildPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:GetObject
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'
Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Resources:
MyNetworkConnector:
Type: AWS::Serverless::NetworkConnector
Properties:
VpcConfig:
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroup
NetworkProtocol: IPv4
Tags:
Environment: IntegTest

Parameters:
SubnetId:
Type: String
SecurityGroup:
Type: String

Metadata:
SamTransformTest: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Resources:
MyNetworkConnectorWithRole:
Type: AWS::Serverless::NetworkConnector
Properties:
VpcConfig:
SubnetIds:
- !Ref SubnetId
SecurityGroupIds:
- !Ref SecurityGroup
NetworkProtocol: IPv4
OperatorRole: !GetAtt CustomOperatorRole.Arn

CustomOperatorRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CustomOperatorPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:CreateTags
Resource: '*'

Parameters:
SubnetId:
Type: String
SecurityGroup:
Type: String

Metadata:
SamTransformTest: true
81 changes: 81 additions & 0 deletions integration/single/test_basic_microvm_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import logging
from unittest.case import skipIf

from integration.helpers.base_test import BaseTest

LOG = logging.getLogger(__name__)


@skipIf(True, "MicroVMImage is not yet GA - enable when RIP feature flag is available")
class TestBasicMicroVMImage(BaseTest):
"""
Basic AWS::Serverless::MicroVMImage tests
"""

def test_basic_microvm_image(self):
"""
Creates a MicroVMImage with auto-generated BuildRole
"""
self.create_and_verify_stack("single/basic_microvm_image")

# Verify the auto-generated BuildRole exists and has correct trust policy
role_name = self.get_physical_id_by_logical_id("MyMicroVMImageBuildRole")
iam_client = self.client_provider.iam_client
role = iam_client.get_role(RoleName=role_name)

# Verify trust policy principal
trust_policy = role["Role"]["AssumeRolePolicyDocument"]
principals = []
for stmt in trust_policy["Statement"]:
if stmt["Effect"] != "Allow":
continue
service = stmt["Principal"].get("Service", [])
if isinstance(service, str):
principals.append(service)
else:
principals.extend(service)
self.assertIn(
"lambda.amazonaws.com",
principals,
"BuildRole should trust lambda-microvms service",
)

# Verify inline policy exists with scoped S3 permissions
role_policy = iam_client.get_role_policy(RoleName=role_name, PolicyName="MicrovmImageBuildPolicy")
statements = role_policy["PolicyDocument"]["Statement"]
s3_statement = next((s for s in statements if "s3:GetObject" in s["Action"]), None)
logs_statement = next((s for s in statements if "logs:CreateLogGroup" in s["Action"]), None)

self.assertIsNotNone(s3_statement, "Should have s3:GetObject statement")
self.assertIsNotNone(logs_statement, "Should have logs statement")
# S3 should be scoped (not wildcard)
self.assertNotEqual(s3_statement["Resource"], "*", "s3:GetObject should not use wildcard resource")
# Logs uses wildcard (expected)
self.assertEqual(logs_statement["Resource"], "*", "logs should use wildcard resource")
# kms:Decrypt should NOT be present
all_actions = [action for stmt in statements for action in stmt["Action"]]
self.assertNotIn("kms:Decrypt", all_actions, "kms:Decrypt should not be in auto-generated role")

def test_microvm_image_with_custom_build_role(self):
"""
Creates a MicroVMImage with customer-provided BuildRole (no auto-generation)
"""
self.create_and_verify_stack("single/basic_microvm_image_with_build_role")

# Verify only the customer-provided role exists (no auto-generated role)
stack_resources = self.get_stack_resources("AWS::IAM::Role")
role_logical_ids = [r["LogicalResourceId"] for r in stack_resources]

self.assertIn("CustomBuildRole", role_logical_ids)
self.assertNotIn(
"MyMicroVMImageWithBuildRoleBuildRole",
role_logical_ids,
"Should NOT auto-generate BuildRole when BuildRoleArn is provided",
)

def test_basic_microvm_image_minimal(self):
"""
Creates a MicroVMImage with only required fields — all optional fields omitted.
Verifies SAM auto-injects defaults and generates BuildRole.
"""
self.create_and_verify_stack("single/basic_microvm_image_minimal")
73 changes: 73 additions & 0 deletions integration/single/test_basic_network_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import logging
from unittest.case import skipIf

import pytest

from integration.helpers.base_test import BaseTest

LOG = logging.getLogger(__name__)


@skipIf(True, "NetworkConnector is not yet GA - enable when RIP feature flag is available")
class TestBasicNetworkConnector(BaseTest):
"""
Basic AWS::Serverless::NetworkConnector tests
"""

@pytest.fixture(autouse=True)
def companion_stack_outputs(self, get_companion_stack_outputs):
self.companion_stack_outputs = get_companion_stack_outputs

def generate_nc_parameters(self):
return [
self.generate_parameter("SubnetId", self.companion_stack_outputs["LMISubnetId"]),
self.generate_parameter("SecurityGroup", self.companion_stack_outputs["LMISecurityGroupId"]),
]

def test_basic_network_connector(self):
"""
Creates a NetworkConnector with auto-generated OperatorRole
"""
parameters = self.generate_nc_parameters()
self.create_and_verify_stack("single/basic_network_connector", parameters)

# Verify the auto-generated OperatorRole exists and has correct trust policy
role_name = self.get_physical_id_by_logical_id("MyNetworkConnectorOperatorRole")
iam_client = self.client_provider.iam_client
role = iam_client.get_role(RoleName=role_name)

trust_policy = role["Role"]["AssumeRolePolicyDocument"]
principals = []
for stmt in trust_policy["Statement"]:
if stmt["Effect"] != "Allow":
continue
service = stmt["Principal"].get("Service", [])
if isinstance(service, str):
principals.append(service)
else:
principals.extend(service)
self.assertIn("lambda.amazonaws.com", principals)

# Verify inline policy
role_policy = iam_client.get_role_policy(RoleName=role_name, PolicyName="NetworkConnectorOperatorPolicy")
statements = role_policy["PolicyDocument"]["Statement"]
all_actions = [s["Action"] for s in statements]
self.assertIn("ec2:CreateNetworkInterface", all_actions)
self.assertIn("ec2:CreateTags", all_actions)

def test_network_connector_with_custom_role(self):
"""
Creates a NetworkConnector with customer-provided OperatorRole (no auto-generation)
"""
parameters = self.generate_nc_parameters()
self.create_and_verify_stack("single/basic_network_connector_with_role", parameters)

stack_resources = self.get_stack_resources("AWS::IAM::Role")
role_logical_ids = [r["LogicalResourceId"] for r in stack_resources]

self.assertIn("CustomOperatorRole", role_logical_ids)
self.assertNotIn(
"MyNetworkConnectorWithRoleOperatorRole",
role_logical_ids,
"Should NOT auto-generate OperatorRole when OperatorRole is provided",
)
2 changes: 1 addition & 1 deletion samtranslator/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.110.0"
__version__ = "1.111.0"
Loading