AWS parity E2E audit — bugs & enhancements (issue draft)
Method. Ran the standalone binary cloudemu serve --providers aws --aws-port 4566 and drove real aws-sdk-go-v2 clients (BaseEndpoint=http://127.0.0.1:4566) through dependency-ordered lifecycles per resource family — create → describe (with field assertions) → modify/associate → list → tag → sub-resources → delete → error paths. Every non-pass was hand-verified to separate real defects from bad test inputs.
Coverage. All 30 AWS service handlers exercised E2E (~250 operation calls): ec2, s3, iam, sts, dynamodb, lambda, rds, redshift, sqs, sns, eventbridge, secretsmanager, ssm, cloudwatch, cloudwatchlogs, ecr, ecs, eks, elbv2, elasticache, memorydb, keyspaces, route53, networkfirewall, resourcegroupstaggingapi, sagemaker, bedrock, bedrockagent, bedrockagentruntime, resourceexplorer2. Depth = representative dependency-ordered lifecycle per service (not literally every one of each service's SDK operations; EC2 additionally got a full 150-action reachability sweep). Runtime data-planes (model inference) not exercised.
Overall the emulator is strong — the vast majority of core CRUD + error paths pass, and it correctly enforces dependency violations, resource state, and CIDR overlaps.
Parity coverage vs full AWS API (implemented ops ÷ total SDK ops)
High-level breadth (denominator = the entire AWS API for the service, incl. many niche ops an emulator need not cover, so low % is expected for large services):
| Service |
impl/SDK |
Service |
impl/SDK |
Service |
impl/SDK |
| ec2 |
150/773 |
rds |
79/168 |
sagemaker |
113/403 |
| iam |
39/176 |
ecs |
37/77 |
memorydb |
33/45 |
| keyspaces |
18/19 |
elbv2 |
18/51 |
dynamodb |
15/57 |
| eventbridge |
14/57 |
cloudwatch |
10/46 |
elasticache |
10/75 |
| sns |
9/42 |
redshift |
9/141 |
cloudwatchlogs |
9/118 |
| ssm |
11/152 |
sqs |
7/23 |
secretsmanager |
7/23 |
| ecr |
7/58 |
networkfirewall |
20/84 |
resourcegroupstaggingapi |
9/9 |
| s3 / lambda / route53 / eks / bedrock* |
path/target-dispatch (subset) |
|
|
|
|
Thinnest relative to common usage: redshift, cloudwatchlogs, ssm, elasticache, ecr, resourceexplorer2.
Cross-cutting themes (fix these first — highest leverage)
A. Tagging is systemically missing/inconsistent
The tag operations users rely on for every IaC tool are absent across many services:
- ec2
CreateTags / DeleteTags — InvalidAction
- dynamodb
TagResource — UnknownOperationException
- sns
TagResource — InvalidAction
- secretsmanager
TagResource — UnknownOperationException
- ssm
AddTagsToResource — UnknownOperationException
- sqs
TagQueue — UnknownOperationException
- lambda
TagResource — 405 + non-JSON body (SDK can't deserialize → wire bug)
Impact: Terraform/CloudFormation/CDK tag nearly everything; tag-on-create or post-create tagging fails. A shared tagging surface would close most of these at once.
B. Set*/Modify* attribute operations commonly missing
- sqs
GetQueueAttributes / SetQueueAttributes — High: GetQueueAttributes is how you read a queue ARN (event-source mappings, DLQ wiring, S3→SQS notifications). Its absence breaks many real flows.
- sqs
PurgeQueue
- sns
SetTopicAttributes
- elasticache
ModifyCacheCluster
- redshift
CreateClusterParameterGroup
- cloudwatchlogs
PutRetentionPolicy
- cloudwatch
SetAlarmState
- secretsmanager
UpdateSecret — High: updating a secret's metadata is a routine op
D. Unimplemented REST/JSON paths return a 405 HTML page (breaks SDK error handling) — Med
Some unimplemented operations on REST/JSON services return an HTTP 405 + an HTML error body instead of a structured JSON API error. The SDK then fails to deserialize the response (invalid character '<') rather than surfacing a clean "operation not supported". Seen on: lambda TagResource, resourceexplorer2 CreateIndex / GetDefaultView. Users get an opaque parse error instead of an actionable API error.
C. EC2 Describe* by nonexistent ID returns empty success (systemic) — High
Describe{Vpcs,Instances,Volumes,SecurityGroups} with an explicit missing ID returns an empty set with no error, where real AWS returns Invalid*.NotFound. Confirmed across 4 resource types → almost certainly the shared EC2 ID-filter path. Breaks existence checks, Terraform refresh/drift, and "wait-until-deleted" polls. One shared fix likely covers all EC2 types.
Per-service findings
| Service |
Operation(s) |
Type |
Sev |
Note |
| ec2 |
Describe{Vpcs,Instances,Volumes,SecurityGroups}(missing id) |
BUG |
High |
no Invalid*.NotFound (theme C) |
| ec2 |
CreateTags / DeleteTags |
GAP |
High |
tagging (theme A) |
| ec2 |
CreateNetworkInterface |
GAP |
Med |
ENI describe/detach/delete exist; create missing |
| ec2 |
MonitorInstances / DescribeInstanceStatus |
GAP |
Med |
common instance ops |
| ec2 |
DescribeRegions / DescribeInstanceTypes |
GAP |
Med |
bootstrap/validation calls |
| s3 |
HeadBucket (existing & missing) |
BUG |
Med |
HTTP HEAD /bucket verb not routed → 405; breaks bucket-exists check |
| s3 |
PutBucketTagging (PUT /bucket?tagging) |
BUG |
Med |
?tagging subresource mis-routed to CreateBucket (BucketAlreadyOwnedByYou) |
| sqs |
GetQueueAttributes / SetQueueAttributes |
GAP |
High |
queue ARN/config (theme B) |
| sqs |
PurgeQueue / TagQueue |
GAP |
Med |
|
| sqs |
GetQueueUrl(missing) |
ENH |
Low |
code QueueDoesNotExist vs AWS AWS.SimpleQueueService.NonExistentQueue |
| sns |
SetTopicAttributes / TagResource |
GAP |
Med |
|
| lambda |
UpdateFunctionConfiguration / PublishVersion / CreateAlias / AddPermission |
GAP |
High |
404 "unsupported Lambda path" — versioning/alias/permission/config |
| lambda |
TagResource |
BUG-WIRE |
Med |
405 + HTML body → SDK deserialize error |
| dynamodb |
TagResource / DescribeTimeToLive |
GAP |
Med |
|
| iam |
PutRolePolicy |
GAP |
Med |
inline role policies |
| secretsmanager |
UpdateSecret / TagResource |
GAP |
High/Med |
|
| ssm |
AddTagsToResource |
GAP |
Med |
|
| ecr |
GetAuthorizationToken |
GAP |
High |
required for image push/pull auth (docker login) |
| ecr |
SetRepositoryPolicy |
GAP |
Low |
|
| elasticache |
ModifyCacheCluster |
GAP |
Med |
|
| redshift |
CreateClusterParameterGroup |
GAP |
Med |
|
| cloudwatchlogs |
PutRetentionPolicy |
GAP |
Med |
|
| cloudwatch |
SetAlarmState |
GAP |
Low |
also returns UnknownError message |
| cloudwatch |
PutMetricData (empty MetricData) |
BUG |
Low |
rejects (correct) but message InvalidParameterValue: UnknownError unhelpful |
| resourceexplorer2 |
CreateIndex / GetDefaultView |
BUG-WIRE |
Med |
405 + HTML body → SDK deserialize error (theme D); Search/ListViews/ListIndexes/ListResources work |
| bedrock / bedrockagent / bedrockagentruntime |
list/get/create + Retrieve |
— |
— |
all passed (ListFoundationModels, GetFoundationModel, guardrails, CreateAgent, ListKnowledgeBases, Retrieve) |
Verified-correct behavior (NOT bugs — excluded)
- ec2
DeleteSubnet/DeleteVpc → DependencyViolation (I hadn't removed ENI/NAT) ✔ good FK enforcement
- ec2
ModifyInstanceAttribute (type) on a running instance → IncorrectInstanceState ✔ correct
- ec2
CreateVpcPeeringConnection self-peer → CIDR-overlap rejection ✔ correct
- s3
DeleteBucket on non-empty bucket → BucketNotEmpty ✔ correct
- eks
DeleteCluster with a live nodegroup → InvalidRequestException ✔ correct
Passed cleanly (solid)
rds (instances/snapshots/clusters/param+subnet groups), ecs (cluster/task-def/service/run-task), sagemaker (model/endpoint-config/endpoint/notebook/training-job), dynamodb data-plane (put/get/query/scan/update/batch), s3 object data-plane, iam roles/users/policies/instance-profiles/groups, route53 zones+record sets, keyspaces, memorydb, eks cluster+nodegroup, elbv2 LB/target-group/listener/register, redshift cluster lifecycle, bedrock list ops, and all non-EC2 missing-resource error paths (proper *NotFound).
AWS parity E2E audit — bugs & enhancements (issue draft)
Method. Ran the standalone binary
cloudemu serve --providers aws --aws-port 4566and drove realaws-sdk-go-v2clients (BaseEndpoint=http://127.0.0.1:4566) through dependency-ordered lifecycles per resource family — create → describe (with field assertions) → modify/associate → list → tag → sub-resources → delete → error paths. Every non-pass was hand-verified to separate real defects from bad test inputs.Coverage. All 30 AWS service handlers exercised E2E (~250 operation calls): ec2, s3, iam, sts, dynamodb, lambda, rds, redshift, sqs, sns, eventbridge, secretsmanager, ssm, cloudwatch, cloudwatchlogs, ecr, ecs, eks, elbv2, elasticache, memorydb, keyspaces, route53, networkfirewall, resourcegroupstaggingapi, sagemaker, bedrock, bedrockagent, bedrockagentruntime, resourceexplorer2. Depth = representative dependency-ordered lifecycle per service (not literally every one of each service's SDK operations; EC2 additionally got a full 150-action reachability sweep). Runtime data-planes (model inference) not exercised.
Overall the emulator is strong — the vast majority of core CRUD + error paths pass, and it correctly enforces dependency violations, resource state, and CIDR overlaps.
Parity coverage vs full AWS API (implemented ops ÷ total SDK ops)
High-level breadth (denominator = the entire AWS API for the service, incl. many niche ops an emulator need not cover, so low % is expected for large services):
Thinnest relative to common usage: redshift, cloudwatchlogs, ssm, elasticache, ecr, resourceexplorer2.
Cross-cutting themes (fix these first — highest leverage)
A. Tagging is systemically missing/inconsistent
The tag operations users rely on for every IaC tool are absent across many services:
CreateTags/DeleteTags—InvalidActionTagResource—UnknownOperationExceptionTagResource—InvalidActionTagResource—UnknownOperationExceptionAddTagsToResource—UnknownOperationExceptionTagQueue—UnknownOperationExceptionTagResource— 405 + non-JSON body (SDK can't deserialize → wire bug)Impact: Terraform/CloudFormation/CDK tag nearly everything; tag-on-create or post-create tagging fails. A shared tagging surface would close most of these at once.
B.
Set*/Modify*attribute operations commonly missingGetQueueAttributes/SetQueueAttributes— High:GetQueueAttributesis how you read a queue ARN (event-source mappings, DLQ wiring, S3→SQS notifications). Its absence breaks many real flows.PurgeQueueSetTopicAttributesModifyCacheClusterCreateClusterParameterGroupPutRetentionPolicySetAlarmStateUpdateSecret— High: updating a secret's metadata is a routine opD. Unimplemented REST/JSON paths return a 405 HTML page (breaks SDK error handling) — Med
Some unimplemented operations on REST/JSON services return an HTTP 405 + an HTML error body instead of a structured JSON API error. The SDK then fails to deserialize the response (
invalid character '<') rather than surfacing a clean "operation not supported". Seen on: lambdaTagResource, resourceexplorer2CreateIndex/GetDefaultView. Users get an opaque parse error instead of an actionable API error.C. EC2
Describe*by nonexistent ID returns empty success (systemic) — HighDescribe{Vpcs,Instances,Volumes,SecurityGroups}with an explicit missing ID returns an empty set with no error, where real AWS returnsInvalid*.NotFound. Confirmed across 4 resource types → almost certainly the shared EC2 ID-filter path. Breaks existence checks, Terraform refresh/drift, and "wait-until-deleted" polls. One shared fix likely covers all EC2 types.Per-service findings
Invalid*.NotFound(theme C)HEAD /bucketverb not routed → 405; breaks bucket-exists checkPUT /bucket?tagging)?taggingsubresource mis-routed to CreateBucket (BucketAlreadyOwnedByYou)QueueDoesNotExistvs AWSAWS.SimpleQueueService.NonExistentQueueUnknownErrormessageInvalidParameterValue: UnknownErrorunhelpfulVerified-correct behavior (NOT bugs — excluded)
DeleteSubnet/DeleteVpc→DependencyViolation(I hadn't removed ENI/NAT) ✔ good FK enforcementModifyInstanceAttribute(type) on a running instance →IncorrectInstanceState✔ correctCreateVpcPeeringConnectionself-peer → CIDR-overlap rejection ✔ correctDeleteBucketon non-empty bucket →BucketNotEmpty✔ correctDeleteClusterwith a live nodegroup →InvalidRequestException✔ correctPassed cleanly (solid)
rds (instances/snapshots/clusters/param+subnet groups), ecs (cluster/task-def/service/run-task), sagemaker (model/endpoint-config/endpoint/notebook/training-job), dynamodb data-plane (put/get/query/scan/update/batch), s3 object data-plane, iam roles/users/policies/instance-profiles/groups, route53 zones+record sets, keyspaces, memorydb, eks cluster+nodegroup, elbv2 LB/target-group/listener/register, redshift cluster lifecycle, bedrock list ops, and all non-EC2 missing-resource error paths (proper
*NotFound).