Repository navigation
fix(iac/aws): RI Marketplace listing actions are granted in no IaC flavor #1968
Description
Activity
- addedtriagedItem has been triagedItem has been triagedpriority/p1Next up; this sprintNext up; this sprintseverity/highSignificant harmSignificant harmurgency/this-sprintWithin the current sprintWithin the current sprintimpact/fewLimited audienceLimited audienceeffort/sHoursHourstype/bugDefectDefect
on Sep 7, 2026 - added a commit that references this issue
on 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.
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.
Summary
POST /api/purchases/{id}/marketplace-listcallsec2:CreateReservedInstancesListingwith the deployment's ambient runtime credentials, and the cancel and status paths callec2:CancelReservedInstancesListingandec2: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.reserveAndCreateListingclaims the listing slot in the database before the AWS call, so the row passes throughpendingand depends onreleaseMarketplaceClaimto 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.yamlproviders/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
sellpermission 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
Suggested fix
Add
ec2:CreateReservedInstancesListing,ec2:DescribeReservedInstancesListingsandec2:CancelReservedInstancesListingto 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 force: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.