Repository navigation
fix(commitmentopts/azure): probe Savings Plans in the caller's billing currency - #1091
Conversation
…g currency The Azure Savings Plan ValidatePurchase probe hardcoded CurrencyCode "USD", so on a non-USD billing account its verdict described a commitment the account could never buy. ProbeAzure now takes the billing account's currency code from the caller, validates it as a 3-letter code (upper-cased, matching the cloud-commitments-go Azure provider) and fails closed before building a client or sending any request when it is missing or malformed. There is no USD default. Closes LeanerCloud#814 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 2
✨ Finishing Touches
Comment |
|
Independent review (claude-cc-platform reviewer, cold brief): APPROVE No blocking findings. The fix matches #814: the hardcoded Callers: nothing outside Money model: the probe sends a 0.001 hourly placeholder and keeps only the term/plan validity, so a non-USD probe does not conflict with the USD-only money model. Mutation probes (all caught):
Base drift: 19 commits behind main, but none touch these files, and the merge is clean (tree Nits:
Not verified: live Azure currency-mismatch behaviour (needs an account). |
|
Independent review (claude-fleet): APPROVE f0a1492 Findings (none blocking):
Attacked:
Verified locally, on a
Reviewed by an independent agent with no author context. Review only: nothing was pushed, and the GitHub review state is unchanged. |
|
Local verification (macOS, exact head Gate status: two independent reviews approve this SHA (posted above), local verification passes, and CI is green. Merge waits on @IAmJSD marking the PR ready (see #974). |
|
Marked ready and merged by the owner's agent after 2 independent reviews and local verification (see the review and verification comments above, all at |
Root cause
AzureSPProber.probeCombo(internal/commitmentopts/probe_azure.go) built every Savings PlanValidatePurchaseprobe request with a hardcodedCurrencyCode: "USD". Azure checks a commitment against the billing account's currency, so on a non-USD account (EUR, GBP, ...) the probe asked about a purchase that account could never make, and the verdict it got back was about a made-up currency, not the account's.Fix
ProbeAzure(ctx, cred, currencyCode string)now takes the billing account's currency from the caller as an explicit parameter next to the credential. Currency belongs to the account, like the credential, so it is a per-call argument rather than a field on the prober. A prober shared between accounts can't leak one account's currency into another, and there's no mutable state to race on.azureProbeCurrencychecks the code with^[A-Za-z]{3}$and upper-cases it. This matchescommitmentCurrencyin the cloud-commitments-go Azure Savings Plans provider (go#46), so the probe and the real purchase path accept the same inputs.ValidatePurchasecall is sent. There is no USD default.probeComboreceives the validated code and puts it inCommitment.CurrencyCode.No production code calls
ProbeAzuretoday:DefaultAzureProbersis only used in tests, and nothing emits Azure SP recommendations yet, as the issue notes. So the signature change only touches tests. Whoever wires the probe in later will have to supply a resolved currency.Closes #814
Verification
All evidence below is unit/mock: the Azure
ValidatePurchaseclient is a fakeAzureSPValidateAPI. No real Azure API was called. Gap: I have not checked against a live non-USD Azure billing account howValidatePurchasetreats a currency mismatch.New tests in
internal/commitmentopts/probe_azure_test.go:TestAzureSPProber_RequestUsesCallerCurrency:EUR,gbpandUSDeach reach every one of the 6 candidate requests asEUR,GBPandUSD.TestAzureSPProber_UnknownCurrency_FailsClosed:"",US,EURO,U$D,12Aand" usd"each return an error, build no client and make zeroValidatePurchasecalls.ProbeAzuretests now pass"USD"explicitly.Fail before / pass after:
probe_azure.gofrommain: the build fails (want ("context".Context, azcore.TokenCredential)), because the old API has no way to pass a currency."USD"hardcoded, no validation):RequestUsesCallerCurrency/{EUR,gbp}and all 6UnknownCurrency_FailsClosedsubtests FAIL.strings.ToUpper:RequestUsesCallerCurrency/gbpFAILS.[A-Za-z]{3}):UnknownCurrency_FailsClosedFAILS."USD"only in the request body:RequestUsesCallerCurrencyFAILS.AzureSP*/DefaultAzureProberstests pass.Commands (run with
AWS_CONFIG_FILE=/dev/null AWS_SHARED_CREDENTIALS_FILE=/dev/null, because the local~/.aws/configdefault profile is invalid on the dev machine; this package doesn't touch AWS config):No DB, migration or shared-state changes, so there is no concurrency surface to race-test.
Out of scope (noted, not changed)
ProbeAzuredoc comment says "Service.probeAndPersistAzurewires it up", but that function doesn't exist; nothing in production calls the Azure prober. I left the comment and the wiring alone. Whoever addsprobeAndPersistAzurewill need to resolve the account's billing currency (for example from the billing account / Cost Management currency) and pass it in.azureProbeSubscriptionID). That's a separate question from currency.Labels
@cristim, could a maintainer please mirror the issue's triage labels onto this PR:
priority/p2,severity/medium,triaged,urgency/this-quarter,impact/few,effort/s,type/bug.🤖 Generated with Claude Code
Summary by CodeRabbit