Repository navigation
fix(iac/aws): RI Marketplace listing actions are granted in no IaC flavor #1968
Description
Summary
POST /api/purchases/{id}/marketplace-list calls ec2:CreateReservedInstancesListing with the deployment's ambient runtime credentials, and the cancel and status paths call ec2:CancelReservedInstancesListing and ec2:DescribeReservedInstancesListings. None of the three actions appears in any Terraform module, the CloudFormation template or a federation bundle, so on a stock deployment every listing attempt is refused by AWS. reserveAndCreateListing claims the listing slot in the database before the AWS call, so the row passes through pending and depends on releaseMarketplaceClaim to recover; the cancel path is equally unauthorized, so the operator cannot unwind through CUDly either.
Location
terraform/modules/compute/aws/lambda/main.tf:349-390(runtimeri_exchangeEC2 statement) at 3c0f8acterraform/modules/compute/aws/fargate/main.tf(same statement) andcloudformation/stacks/CUDly/template.yaml- callers:
providers/aws/services/ec2/client.go:1048,:1070,:1111(SDK calls declared at:31-33);internal/api/handler_marketplace.go:248; routes registered unconditionally atinternal/api/router.go:194-195; credentials frominternal/api/handler_ri_exchange.go:1259-1275(LoadDefaultConfig)
Failure scenario
A user with sell permission lists a convertible RI on the Marketplace from a Lambda or Fargate deployment provisioned from any template. The DB claim is written, AWS returns UnauthorizedOperation, and the row is left to the claim-release path. LeanerCloud/cloud-commitments-platform#100 separately notes the handler maps that error to HTTP 400, so the operator is pointed at a phantom client bug rather than the IAM gap.
Evidence
"ec2:DescribeReservedInstances",
"ec2:DescribeReservedInstancesOfferings",
"ec2:GetReservedInstancesExchangeQuote",
"ec2:AcceptReservedInstancesExchangeQuote",
"ec2:PurchaseReservedInstancesOffering",
"ec2:DescribeInstanceTypeOfferings",
"ec2:DescribeRegions",Suggested fix
Add ec2:CreateReservedInstancesListing, ec2:DescribeReservedInstancesListings and ec2:CancelReservedInstancesListing to the runtime EC2 statement in the Lambda module, the Fargate module and the CloudFormation template, and cover them with the same SDK-call-versus-template guard proposed for ce:GetCostAndUsage.
Found by the 2026-09-02 codebase audit, finding A13-002, reported by one reviewer and independently confirmed by a second. Full report: docs/audits/codebase-audit-2026-09-02.md.
Activity
fix(iac/aws): grant the runtime role nine actions the code calls
cristim commentedon Sep 14, 2026
Merged PR #2077 as efd6e95 after native macOS verification, fresh-context independent Astra review, substantive clean full CodeRabbit review and all28 exact-HEAD check/status entries passing. Reviewed HEAD899ab790d and merge commit have the identical tree39f40be04a616331f686ec61250d0398fbd99c4a; parent is the reviewed base81f2fc3.
Verified: six missing CE/EC2 grants across allthree runtime IaC flavors; native stdlib Go/race/parity tests; exact-main failure, corrected candidate pass and seven omission/comment mutations; source, Allow/role attachment and RI-only tag scope inspected. Final evidence is linked in the PR body. No checks were bypassed.
Post-merge workflows are being watched. No manual apply, purchase, listing, cancellation or tagging was performed. Deployed IAM acceptance, seller eligibility and cross-account runtime behavior are not claimed verified. AWS Sanity credentialed steps were skipped due to absent read-only role configuration.
Follow-ups remain LeanerCloud/cloud-commitments-platform#42 and LeanerCloud/cloud-commitments-go#107 for unsupported/unproved tagging contracts; LeanerCloud/cloud-commitments-platform#261 for Marketplace credentials, LeanerCloud/cloud-commitments-platform#27 for polling/seller checks and LeanerCloud/cloud-commitments-platform#335 for failed compensating cancellation. This merge addresses the missing-grant scope only; auto-closure of #1967/#1968 does not close those separate issues.
cristim commentedon Sep 14, 2026
Post-merge verification for #2077 is complete: all eight workflows at efd6e95 passed, including the three cloud deployment workflows and their health/smoke checks. Detailed proof and limits: #2077 (comment) . This does not claim live purchase, Marketplace or tagging acceptance; the previously linked follow-up issues remain open.