feat(ec2): implement IPAM internet-registry associations and routing policy registrations - #2511
Conversation
There was a problem hiding this comment.
8 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="website/static/llms-full.txt">
<violation number="1" location="website/static/llms-full.txt:9">
P3: The updated operation count is paired with the old aggregate conformance total, so this page now reports an internally inconsistent coverage claim. Update the aggregate pass/total to the post-change conformance result and keep the other generated documentation in sync.</violation>
</file>
<file name="crates/fakecloud-conformance/tests/ec2.rs">
<violation number="1" location="crates/fakecloud-conformance/tests/ec2.rs:13051">
P2: The routing-policy lifecycle creates a registration through a `pending-enable` association. Enable the association before creating the registration, otherwise this test will preserve and hide an invalid lifecycle and fail to catch enforcement of the enable prerequisite.</violation>
</file>
<file name="crates/fakecloud-testkit/src/lib.rs">
<violation number="1" location="crates/fakecloud-testkit/src/lib.rs:528">
P2: If `try_wait` returns an error, `wait_bounded` leaves the CLI child running and callers drop it without cleanup. Kill and reap the child before returning `false` from this branch.</violation>
</file>
<file name="crates/fakecloud-ec2/src/service/ipam_registry.rs">
<violation number="1" location="crates/fakecloud-ec2/src/service/ipam_registry.rs:68">
P2: Associations returned from China, GovCloud, or isolated regions contain the wrong ARN partition. Use `partition_for(&a.region)` when constructing this ARN.
(Based on your team's feedback about regional ARN partitioning.)</violation>
<violation number="2" location="crates/fakecloud-ec2/src/service/ipam_registry.rs:239">
P2: When an enable parameter contains XML metacharacters, the returned `childRequestXml` is not a well-formed document after XML decoding. Escape each attribute value before assembling the child request.</violation>
<violation number="3" location="crates/fakecloud-ec2/src/service/ipam_registry.rs:299">
P2: These handlers ignore the modeled `Filters` parameter, so callers cannot restrict associations or derived route views. Parse and apply the supported filters before paginating the results.</violation>
<violation number="4" location="crates/fakecloud-ec2/src/service/ipam_registry.rs:315">
P2: These listing operations validate `MaxResults` but never apply it or return `nextToken`. Large associations, registrations, deltas, and derived views therefore cannot be paginated and clients receive incorrect pages; apply `paginate` and emit the returned token.</violation>
</file>
<file name="website/content/docs/parity.md">
<violation number="1" location="website/content/docs/parity.md:107">
P3: The EC2 row now advertises 791 operations but still says `Full 776-op control plane`, making the parity matrix internally contradictory. Update the stale description to 791 so readers do not get conflicting coverage information.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| let c = s.ec2_client().await; | ||
| let q = Ec2Query::new(&s); | ||
|
|
||
| let id = make_ir_association(&c, &q).await; |
There was a problem hiding this comment.
P2: The routing-policy lifecycle creates a registration through a pending-enable association. Enable the association before creating the registration, otherwise this test will preserve and hide an invalid lifecycle and fail to catch enforcement of the enable prerequisite.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-conformance/tests/ec2.rs, line 13051:
<comment>The routing-policy lifecycle creates a registration through a `pending-enable` association. Enable the association before creating the registration, otherwise this test will preserve and hide an invalid lifecycle and fail to catch enforcement of the enable prerequisite.</comment>
<file context>
@@ -12936,3 +12936,488 @@ async fn ec2_detach_image_watermark() {
+ let c = s.ec2_client().await;
+ let q = Ec2Query::new(&s);
+
+ let id = make_ir_association(&c, &q).await;
+ assert!(id.starts_with("ipam-ir-assoc-"), "{id}");
+
</file context>
| match child.try_wait() { | ||
| Ok(Some(_)) => return true, | ||
| Ok(None) => {} | ||
| Err(_) => return false, |
There was a problem hiding this comment.
P2: If try_wait returns an error, wait_bounded leaves the CLI child running and callers drop it without cleanup. Kill and reap the child before returning false from this branch.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-testkit/src/lib.rs, line 528:
<comment>If `try_wait` returns an error, `wait_bounded` leaves the CLI child running and callers drop it without cleanup. Kill and reap the child before returning `false` from this branch.</comment>
<file context>
@@ -471,23 +471,68 @@ fn sweep_instance_containers(cli: &str, pid: u32) {
+ match child.try_wait() {
+ Ok(Some(_)) => return true,
+ Ok(None) => {}
+ Err(_) => return false,
+ }
+ if std::time::Instant::now() >= deadline {
</file context>
| Err(_) => return false, | |
| Err(_) => { | |
| let _ = child.kill(); | |
| let _ = child.wait(); | |
| return false; | |
| } |
| s.push_str(&ec2_elem( | ||
| "ipamInternetRegistryAssociationArn", | ||
| &format!( | ||
| "arn:aws:ec2::{owner}:ipam-internet-registry-association/{}", |
There was a problem hiding this comment.
P2: Associations returned from China, GovCloud, or isolated regions contain the wrong ARN partition. Use partition_for(&a.region) when constructing this ARN.
(Based on your team's feedback about regional ARN partitioning.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-ec2/src/service/ipam_registry.rs, line 68:
<comment>Associations returned from China, GovCloud, or isolated regions contain the wrong ARN partition. Use `partition_for(&a.region)` when constructing this ARN.
(Based on your team's feedback about regional ARN partitioning.) </comment>
<file context>
@@ -0,0 +1,786 @@
+ s.push_str(&ec2_elem(
+ "ipamInternetRegistryAssociationArn",
+ &format!(
+ "arn:aws:ec2::{owner}:ipam-internet-registry-association/{}",
+ a.id
+ ),
</file context>
| req: &AwsRequest, | ||
| ) -> Result<AwsResponse, AwsServiceError> { | ||
| mr(req)?; | ||
| let ids = indexed_list(&req.query_params, "IpamInternetRegistryAssociationId"); |
There was a problem hiding this comment.
P2: These handlers ignore the modeled Filters parameter, so callers cannot restrict associations or derived route views. Parse and apply the supported filters before paginating the results.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-ec2/src/service/ipam_registry.rs, line 299:
<comment>These handlers ignore the modeled `Filters` parameter, so callers cannot restrict associations or derived route views. Parse and apply the supported filters before paginating the results.</comment>
<file context>
@@ -0,0 +1,786 @@
+ req: &AwsRequest,
+) -> Result<AwsResponse, AwsServiceError> {
+ mr(req)?;
+ let ids = indexed_list(&req.query_params, "IpamInternetRegistryAssociationId");
+ let owner = req.account_id.clone();
+ let accounts = svc.state.read();
</file context>
| Ok(Ec2Service::respond( | ||
| "DescribeIpamInternetRegistryAssociations", | ||
| &req.request_id, | ||
| &ec2_list("ipamInternetRegistryAssociationSet", &items), |
There was a problem hiding this comment.
P2: These listing operations validate MaxResults but never apply it or return nextToken. Large associations, registrations, deltas, and derived views therefore cannot be paginated and clients receive incorrect pages; apply paginate and emit the returned token.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-ec2/src/service/ipam_registry.rs, line 315:
<comment>These listing operations validate `MaxResults` but never apply it or return `nextToken`. Large associations, registrations, deltas, and derived views therefore cannot be paginated and clients receive incorrect pages; apply `paginate` and emit the returned token.</comment>
<file context>
@@ -0,0 +1,786 @@
+ Ok(Ec2Service::respond(
+ "DescribeIpamInternetRegistryAssociations",
+ &req.request_id,
+ &ec2_list("ipamInternetRegistryAssociationSet", &items),
+ ))
+}
</file context>
| let a = get_association(state, &id)?; | ||
| // The child request is the RPKI provisioning document the registry needs; | ||
| // it is what the caller takes to the RIR to finish setup. | ||
| a.child_request_xml = Some(format!( |
There was a problem hiding this comment.
P2: When an enable parameter contains XML metacharacters, the returned childRequestXml is not a well-formed document after XML decoding. Escape each attribute value before assembling the child request.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At crates/fakecloud-ec2/src/service/ipam_registry.rs, line 239:
<comment>When an enable parameter contains XML metacharacters, the returned `childRequestXml` is not a well-formed document after XML decoding. Escape each attribute value before assembling the child request.</comment>
<file context>
@@ -0,0 +1,786 @@
+ let a = get_association(state, &id)?;
+ // The child request is the RPKI provisioning document the registry needs;
+ // it is what the caller takes to the RIR to finish setup.
+ a.child_request_xml = Some(format!(
+ "<publisher_request version=\"{rpki_version}\" \
+ service_uri=\"{service_uri}\" \
</file context>
| fakecloud emulates AWS locally for integration testing and development. It is a single Rust binary (~19 MB, ~300ms startup, ~10 MiB idle memory) — no Docker required to run fakecloud itself, no signup. Point any AWS SDK or the AWS CLI at `http://localhost:4566` with dummy credentials. | ||
|
|
||
| **Coverage goal:** 100% of AWS services, each at 100% behavioral conformance, with 100% of cross-service integrations. Approach is depth-first — a service lands when it passes the full Smithy-model test variants and the cross-service wire-ups that matter for it, not when the API surface looks filled in. 105 services (7,408 operations) are shipped today, all at true 100% conformance — 248,557/248,557 generated Smithy variants pass on every commit; more land progressively as they hit the bar. | ||
| **Coverage goal:** 100% of AWS services, each at 100% behavioral conformance, with 100% of cross-service integrations. Approach is depth-first — a service lands when it passes the full Smithy-model test variants and the cross-service wire-ups that matter for it, not when the API surface looks filled in. 105 services (7,423 operations) are shipped today, all at true 100% conformance — 248,557/248,557 generated Smithy variants pass on every commit; more land progressively as they hit the bar. |
There was a problem hiding this comment.
P3: The updated operation count is paired with the old aggregate conformance total, so this page now reports an internally inconsistent coverage claim. Update the aggregate pass/total to the post-change conformance result and keep the other generated documentation in sync.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/static/llms-full.txt, line 9:
<comment>The updated operation count is paired with the old aggregate conformance total, so this page now reports an internally inconsistent coverage claim. Update the aggregate pass/total to the post-change conformance result and keep the other generated documentation in sync.</comment>
<file context>
@@ -6,7 +6,7 @@
fakecloud emulates AWS locally for integration testing and development. It is a single Rust binary (~19 MB, ~300ms startup, ~10 MiB idle memory) — no Docker required to run fakecloud itself, no signup. Point any AWS SDK or the AWS CLI at `http://localhost:4566` with dummy credentials.
-**Coverage goal:** 100% of AWS services, each at 100% behavioral conformance, with 100% of cross-service integrations. Approach is depth-first — a service lands when it passes the full Smithy-model test variants and the cross-service wire-ups that matter for it, not when the API surface looks filled in. 105 services (7,408 operations) are shipped today, all at true 100% conformance — 248,557/248,557 generated Smithy variants pass on every commit; more land progressively as they hit the bar.
+**Coverage goal:** 100% of AWS services, each at 100% behavioral conformance, with 100% of cross-service integrations. Approach is depth-first — a service lands when it passes the full Smithy-model test variants and the cross-service wire-ups that matter for it, not when the API surface looks filled in. 105 services (7,423 operations) are shipped today, all at true 100% conformance — 248,557/248,557 generated Smithy variants pass on every commit; more land progressively as they hit the bar.
Key design principles:
</file context>
| | [Glue](@/docs/services/glue.md) | 269 | JSON 1.1 | Full | Partial | Full control plane: Data Catalog (databases, tables, partitions with `GetPartitions` `Expression` pruning), jobs, crawlers, classifiers, connections, triggers, workflows, blueprints, dev endpoints, schema registry, interactive sessions, ML transforms, data quality, user-defined functions, usage profiles, column statistics, and tagging. Status transitions are real (crawler `READY`↔`RUNNING`, trigger/workflow/run lifecycles). Job/crawler/Spark *execution* itself is synthesized — fakecloud is not a Spark engine. | | ||
| | [Organizations](@/docs/services/organizations.md) | 63 | JSON 1.1 | Full | Full | Full org tree (roots, OUs, accounts), policies with SCP enforcement, handshakes, delegated administrators, service access, tagging, and a resource policy. Billing responsibility transfers ride handshake-backed records. `CreateAccount` transitions `IN_PROGRESS` -> `SUCCEEDED` after a short synthetic delay. | | ||
| | [EC2](@/docs/services/ec2.md) | 776 | ec2Query | Full | Partial | Full 776-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. | | ||
| | [EC2](@/docs/services/ec2.md) | 791 | ec2Query | Full | Partial | Full 776-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. | |
There was a problem hiding this comment.
P3: The EC2 row now advertises 791 operations but still says Full 776-op control plane, making the parity matrix internally contradictory. Update the stale description to 791 so readers do not get conflicting coverage information.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At website/content/docs/parity.md, line 107:
<comment>The EC2 row now advertises 791 operations but still says `Full 776-op control plane`, making the parity matrix internally contradictory. Update the stale description to 791 so readers do not get conflicting coverage information.</comment>
<file context>
@@ -104,7 +104,7 @@ fakecloud implements **105 AWS services** with **7,408 operations**. **248,557/2
| [Glue](@/docs/services/glue.md) | 269 | JSON 1.1 | Full | Partial | Full control plane: Data Catalog (databases, tables, partitions with `GetPartitions` `Expression` pruning), jobs, crawlers, classifiers, connections, triggers, workflows, blueprints, dev endpoints, schema registry, interactive sessions, ML transforms, data quality, user-defined functions, usage profiles, column statistics, and tagging. Status transitions are real (crawler `READY`↔`RUNNING`, trigger/workflow/run lifecycles). Job/crawler/Spark *execution* itself is synthesized — fakecloud is not a Spark engine. |
| [Organizations](@/docs/services/organizations.md) | 63 | JSON 1.1 | Full | Full | Full org tree (roots, OUs, accounts), policies with SCP enforcement, handshakes, delegated administrators, service access, tagging, and a resource policy. Billing responsibility transfers ride handshake-backed records. `CreateAccount` transitions `IN_PROGRESS` -> `SUCCEEDED` after a short synthetic delay. |
-| [EC2](@/docs/services/ec2.md) | 776 | ec2Query | Full | Partial | Full 776-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. |
+| [EC2](@/docs/services/ec2.md) | 791 | ec2Query | Full | Partial | Full 776-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. |
## Reading the matrix
</file context>
| | [EC2](@/docs/services/ec2.md) | 791 | ec2Query | Full | Partial | Full 776-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. | | |
| | [EC2](@/docs/services/ec2.md) | 791 | ec2Query | Full | Partial | Full 791-op control plane: VPCs, subnets, security groups, route tables, gateways, ENIs, instances, EBS volumes/snapshots, AMIs (+ watermarks), network ACLs, VPC peering/endpoints, flow logs, launch templates, spot/fleet, capacity/reserved/dedicated hosts, transit gateways (+ multicast/peering/metering/policy-table entries), VPN + Client VPN, IPAM, Verified Access, Network Insights, Outpost/local-gateway/CoIP, and Instance Connect. Instances run as real containers — Docker/Podman by default or native Kubernetes Pods (`FAKECLOUD_EC2_BACKEND=k8s`) — running user-data at boot, with the instance lifecycle mapped to the container lifecycle and `GetConsoleOutput` returning the container log; the control plane degrades to metadata-only when no container runtime is present. A few model ops absent from the vendored SDK are validated via raw ec2Query. | |
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
8bcc034 to
3e44637
Compare
…policy registrations Implements the 15 remaining unimplemented EC2 operations. An association ties an IPAM to one Regional Internet Registry; routing policy registrations (RPKI route origin authorizations) hang off it, keyed by CIDR, and every change produces a delta. The deltas are the audit trail, so they outlive the registrations they describe, and the delta query supports id, time-window, and chronological-order filters. Enabling an association produces the RPKI child request document the registry needs. The derived views all read from the registrations rather than inventing data: route origin authorizations are one per CIDR and ASN pair, the ASN and CIDR views are what those registrations cover, and discovered routes are what the account advertises in the queried region, since fakecloud runs no BGP collector. Route protection findings mark a registration carrying an ASN as valid and one with none as unknown, which is how an unsigned announcement looks to RPKI. Also bounds the container-CLI calls in the test harness. sweep_instance_containers shelled out to docker with no timeout, so a wedged daemon hung the whole test run rather than the one sweep: locally that turned a 20-second test into a multi-minute hang. probe_cli's existing bound is now shared with it. EC2 conformance: 776 -> 791 implemented operations, all passing, 25,716 variants.
reap_stale_containers runs synchronously before the server starts serving, and its docker ps / rm calls had no deadline. A liveness probe answering does not promise the next call will, so a daemon that wedges in between blocked startup outright rather than just the sweep. The bounded wait now lives in container_net alongside the existing probe, and both the reaper and the probe go through it.
A route-protection finding's roaSet carries IpamRouteOriginAuthorization, whose prefix member is `prefix`. The handler emitted `cidr`, which is the spelling of IpamRouteOriginAuthorizationInfo -- the shape GetIpamRouteOriginAuthorizations returns. The two were conflated, so an SDK read every ROA's prefix as absent and discarded the element. The existing test only asserted that `<roaSet>` appeared at all, so it passed. rpkiStrength emitted "strong" and "none". IpamRpkiStrength is `strict | permissive`, so both values deserialized as an unknown variant and any client matching the enum fell through. A registration naming its origin ASNs authorizes exactly those, which is the strict posture. DryRun returned success before resolving anything, so a dry run against an association that does not exist reported 200 while the same call without DryRun returned InvalidIpamInternetRegistryAssociationId.NotFound. Each of the five ops that address an existing association now resolves it first and skips only the mutation, which is what the rest of EC2 does. MaxLength was parsed and then unbounded, though the shape carries @range 0..48 and the member documents that it must cover at least the CIDR's own prefix length. Both are enforced now. The delta time bounds compared RFC 3339 strings byte-wise. Stored timestamps carry milliseconds and an SDK omits them when they are zero, so StartTime=...:00Z dropped every delta recorded in that same second, and a malformed bound filtered everything out with a 200 rather than erroring. The bounds are parsed and compared as instants. EC2 conformance: 791/801 operations, all 18 IPAM registry ops fully passing.
bounded_output piped the child's stdout and then waited for it to exit without reading. A child whose output outgrows the pipe buffer (64 KiB on Linux) blocks on write until someone drains it, so the wait could never finish: the call burned the full 10-second deadline, killed the child and reported failure. `docker ps -a` across a host with a few hundred containers is exactly that much output, which turned the startup reaper and the test harness's container sweep into a silent 10-second stall that swept nothing. Both copies now drain on a helper thread while the bounded wait runs. The regression test asks for 200 KB through the bounded call; against the previous version it fails at the deadline.
3e44637 to
c0ffbda
Compare
A review of the 15 operations that shipped in faiscadev#2511 found them accepting requests they then failed to honour. Each one is fixed here with the test that proves it. - The child request document interpolated `ServiceUri`, the handles, the RPKI version and the parent BPKI TA straight into XML, so an ordinary URI carrying `&` produced a document the RIR cannot parse, and a handle carrying a quote closed an attribute early. All five are escaped. - BatchModifyIpamRoutingPolicyRegistrations read ASNs only as JSON strings, so a document writing them as numbers registered a CIDR that authorized nobody and reported itself unknown/permissive. Numbers are accepted. - A batch entry that could not be applied was skipped after the whole document had already been recorded as published, so nine of ten entries applying still reported success. The document is validated before anything is recorded, and a bad entry fails the request. - Batch entries bypassed the validation the single-op path runs, so a `maxLength` of 200 was stored and emitted for a member the model bounds to 0..48. Both paths share one validation now, and a batch `add` for a CIDR that is already registered is an upsert, matching the operation's own docs. - ModifyIpamRoutingPolicyRegistration rebuilt the record from the request, so `MaxLength`, `Description` and `PermitMoreSpecificAnnouncements` vanished whenever the request omitted them. Modify is a partial update. - DryRun returned success before the checks it exists to surface: a dry-run create against an existing CIDR or a nonexistent IPAM, and a dry-run modify or delete of a CIDR that is not registered, all reported a success the real call then refused. Every dry run now reaches the same verdict as the real call. - The create path parked an association in `pending-enable` and documented that it cannot publish until enabled, but nothing enforced it, leaving EnableIpamInternetRegistryAssociation decorative. Registration writes require an enabled association. - ClientToken was modeled on all five mutating operations and ignored by all of them, so an SDK retrying a timed-out create got a conflict instead of a replay. Tokens are recorded per action and replay their original result. - The eight paginated reads validated MaxResults and then returned everything, never emitting nextToken, and discarded the modeled Filters. They paginate and filter. - DeleteIpamInternetRegistryAssociation deleted an association out from under its registrations; it now refuses with DependencyViolation until they are gone. Also: a conformance ordering assertion compared `Option<usize>`, so a dropped delta passed vacuously (`None < Some`), and the bounded container-CLI helper left its reader thread blocked on a pipe a wrapper script's grandchild still held, leaking a thread per timed-out call on exactly the wedged-daemon path the bound exists for. The helper now runs the CLI in its own process group and kills the group, so the read end closes and the reader exits; collection is bounded by a drain grace. fakecloud-testkit carried a second copy of those helpers with the same leak and now shares core's, and `detect_bridge_gateway`, which still called the CLI unbounded, goes through them too.
Implements the 15 EC2 operations that were still unimplemented, taking EC2 to
791 implemented operations with every one passing conformance.
What these are
An IPAM internet-registry association ties an IPAM to one Regional Internet
Registry (
ripe,apnic,arin,lacnic). Routing policy registrations —RPKI route origin authorizations — hang off an association, keyed by CIDR.
Every change to a registration produces a delta. Deltas are the audit trail, so
they outlive the registrations they describe, and
GetIpamRoutingPolicyRegistrationDeltasfilters by delta id, time window, and chronological order.
BatchModifyIpamRoutingPolicyRegistrationsapplies a whole JSON document ofadditions and removals as a single delta.
Enabling an association produces the RPKI child request document the registry
needs to finish provisioning.
Derived views read from real state
The read operations report what the registrations actually say rather than
fabricating data:
GetIpamRouteOriginAuthorizationsemits one authorization per CIDR and ASN pair.GetIpamInternetRegistryAssociationAsns/Cidrsreport what thoseregistrations cover.
GetIpamDiscoveredRoutesreports what the account advertises in the queriedregion. fakecloud runs no BGP collector, so an invented view of the wider
internet would be fiction.
GetIpamRouteProtectionFindingsmarks a registration carrying an ASNvalidand one with none
unknown, which is how an unsigned announcement looks to RPKI.Test harness hang
sweep_instance_containersshelled out to the container CLI with no timeout, soa wedged Docker daemon blocked the whole test run instead of just that sweep.
Locally this turned a 20-second test into a multi-minute hang. It now shares the
bounded wait that
probe_clialready had, with a regression test.Verification
cargo test -p fakecloud-conformance --test ec2 ipam_: 64 passedcargo build --workspaceandcargo clippy --workspace --all-targets: cleanQuery protocol directly
Summary by cubic
Implements 15 previously unimplemented EC2 IPAM operations for internet-registry associations and routing policy registrations, taking EC2 from 786 to 801 implemented operations (7,491 total). Also fixes the new operations' wire shapes and validation, and bounds every container-CLI call so a wedged Docker daemon can no longer hang a test run or block server startup.
IPAM registry operations
BatchModifyIpamRoutingPolicyRegistrationsapplies a JSON document of additions and removals as one delta, and enabling an association returns the RPKI child request document the registry needs.valid, those without asunknown.strict/permissiveinstead ofstrong/none, and findings name the ROA prefixprefix.MaxLengthis enforced.Container CLI bounds
container_net, shared by the test harness, server reaper, and liveness probe, with a regression test.Written for commit c0ffbda. Summary will update on new commits.