Repository navigation
fix(aws/savingsplans): validate plan type, term and payment before trusting a Cost Explorer offering ID - #510
Conversation
|
@coderabbitai review |
|
Independent adversarial review: CLEAN at
|
| Field | Values | Where the values come from | Accepted by |
|---|---|---|---|
| PlanType | EC2Instance |
:136-148 |
convertPlanType (client.go:564-577) and the EC2Instance-scoped resolveSPPlanType (:313-330) |
| Term | 1yr, 1, 3yr, 3 |
rec.Term, already validated by convertSavingsPlansTermInYears (converters.go:63-72) before CE is queried |
convertTermToSeconds (client.go:582-591), same set |
| PaymentOption | all-upfront, partial-upfront, no-upfront |
rec.PaymentOption, validated by convertPaymentOptionE (converters.go:47-58) |
convertPaymentOption (client.go:597-608), which also accepts the title-case spellings |
The PR's claim that offering IDs exist only for EC2 Instance plans holds in the code. extractEC2SPFields returns an empty struct for every other plan type (parser_sp.go:123). The SDK's SavingsPlansDetails.OfferingId (costexplorer types.go:2295) is generic, but this repo gates it.
Routing. The ec2instance slug goes to an EC2Instance-scoped client (provider.go:480-485). The legacy "" service goes to the unscoped client (:496). A valid EC2Instance rec has no path to a Compute-scoped client.
Ordering. findOfferingID (client.go:466-480) runs resolveSPPlanType, then the term check, then the payment check, then the OfferingID fast path. PurchaseCommitment calls it before CreateSavingsPlan (:229), and ValidateOffering and GetOfferingDetails do the same. No AWS call happens before validation.
Mutation probes (scratch copy, reverted):
- Moving the fast path above the term check fails the invalid-term and invalid-payment subtests.
- Moving it back to the top (main's behaviour) fails all 4 validation subtests.
Non-blocking:
- The new tests use a Compute-scoped client and a Compute rec, while the real producer is EC2Instance. The validators are shared, so this is a coverage gap only.
- Recs persisted outside this repo could carry other spellings. Such recs would already fail on the non-CE path.
Local verification (macOS, exact SHA 6d2dd22)
Mock evidence; no AWS call, no purchase.
- Fail-before: with
origin/main'sclient.goand the PR's tests, all 4 subtests ofTestFindOfferingID_CEOfferingIDStillValidatesInputsFAIL. The fast-path test passes on both versions. - Pass-after:
(cd providers/aws && GOWORK=off go test -race -short ./...)passes, andmake buildandmake vetexit 0.
Labels mirror #53. CodeRabbit is quota-limited. If that still holds at merge: CR waived: quota, adversarial review + local verification + green CI.
…usting a Cost Explorer offering ID findOfferingID returned a Cost Explorer offering ID before running resolveSPPlanType, convertTermToSeconds and convertPaymentOption, so an invalid plan type, term or payment option reached CreateSavingsPlan. The validations now run first; valid inputs keep the fast path. Refs #53 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6d2dd22 to
a050628
Compare
Summary
One slice of the #53 findings tracker. In
providers/aws/services/savingsplans/client.go,findOfferingIDreturned a Cost Explorer offering ID before runningresolveSPPlanType(including the client-scope check),convertTermToSecondsandconvertPaymentOption. A purchase carrying a CE offering ID therefore skipped plan-type, scope, term and payment validation. The three validations now run first; valid inputs keep the fast path, which still skipsDescribeSavingsPlansOfferings.No valid CE-ID purchase is newly rejected: CE offering IDs exist only for EC2 Instance SPs, whose plan type, term and payment values (from the CE recommendation converters) are all accepted by the validators. The only new rejections are hand-built or persisted recs with non-canonical spellings, or a rec routed to a client of the wrong scope (an EC2 ID bought through a Compute client).
Not done: cross-checking the validated values against the offering the ID refers to, which needs an extra
DescribeSavingsPlansOfferingscall.Refs #53
Tests
TestFindOfferingID_CEOfferingIDStillValidatesInputs: invalid term, invalid payment, unsupported plan type, plan type outside the client scope. Each asserts that bothfindOfferingIDandPurchaseCommitmenterror and thatCreateSavingsPlanandDescribeSavingsPlansOfferingsare never called. All four fail with origin/main'sclient.go.TestFindOfferingID_CEOfferingIDFastPath: valid input with an offering ID still skips the offerings lookup.Verification
make build,make vet,(cd providers/aws && GOWORK=off go test -race -short ./services/savingsplans/...)(140 tests), pinned golangci-lint v2.10.1 (0 issues), gofmt, and the commit/pre-push hooks pass. Unit-level evidence only.Local review: an adversarial pass by a non-author reviewer, no actionable findings.
🤖 Generated with Claude Code
Summary by CodeRabbit