From 9ddac76d80e747e743f411e6c0810b5d4470c88d Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Thu, 15 Oct 2026 12:15:36 +0200 Subject: [PATCH 1/2] feat(archera): associate ec2 savings plan identities Match current line items by source, provider offering and native basis. Keep amount provenance and economic compatibility explicit. --- internal/archera/recommendation_match.go | 195 ++++++++++++++++++ internal/archera/recommendation_match_test.go | 190 +++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 internal/archera/recommendation_match.go create mode 100644 internal/archera/recommendation_match_test.go diff --git a/internal/archera/recommendation_match.go b/internal/archera/recommendation_match.go new file mode 100644 index 000000000..d94b554e0 --- /dev/null +++ b/internal/archera/recommendation_match.go @@ -0,0 +1,195 @@ +package archera + +import ( + "errors" + "math/big" + "strings" + "unicode" + + "github.com/google/uuid" +) + +const ( + awsSPYearSeconds int64 = 31536000 + awsSPThreeYearSeconds int64 = 94608000 +) + +type RecommendationIdentity struct { + Provider, SourceAccountID, Service, PlanType, OfferingID string + Region, TopLevelRegion, InstanceFamily, Payment string + NativeDurationSeconds int64 + HourlyCommitment *big.Rat +} + +type LineItemIdentity struct { + ID, PlanID, OfferID, Provider, SourceAccountID, ProviderOfferingID string + Type, PlanType, Region, InstanceFamily, Payment string + DurationSeconds, SelectedCommitment *big.Rat +} + +type ComparisonIdentity struct { + Region *string + IsCurrent bool + LineItemID, CurrentOfferID, Provider, CurrentType, CurrentPayment string + CurrentSelectedAmount *big.Rat +} + +type MatchStatus string + +const ( + MatchUnavailable MatchStatus = "unavailable" + ResourceAssociated MatchStatus = "resource_associated" +) + +type RecommendationMatch struct { + Status MatchStatus + LineItemID, Reason, AmountProvenance, EconomicStatus string +} + +func MatchRecommendation(planID string, rec *RecommendationIdentity, rows []ComparisonIdentity, items []LineItemIdentity) (RecommendationMatch, error) { + unavailable := RecommendationMatch{Status: MatchUnavailable, Reason: "identity_unproven"} + if !validRecommendation(rec) { + return unavailable, nil + } + index, err := comparisonIndex(planID, rows, items) + if err != nil { + return unavailable, err + } + if index == nil { + return unavailable, nil + } + var selected *LineItemIdentity + for i := range items { + if !sameResource(rec, &items[i]) { + continue + } + if selected != nil { + unavailable.Reason = "ambiguous_line_items" + return unavailable, nil + } + selected = &items[i] + } + if selected == nil { + return unavailable, nil + } + row := index[strings.ToLower(selected.ID)] + if !sameCurrentBasis(rec, row) { + unavailable.Reason = "comparison_basis_unproven" + return unavailable, nil + } + result := RecommendationMatch{ + Status: ResourceAssociated, LineItemID: row.LineItemID, + AmountProvenance: "stored_decimal_only", EconomicStatus: "unavailable_source_precision", + } + return result, nil +} + +func validRecommendation(r *RecommendationIdentity) bool { + if r == nil { + return false + } + if r.Provider != "aws" || r.Service != "savings-plans-ec2instance" || r.PlanType != "EC2Instance" { + return false + } + if r.NativeDurationSeconds != awsSPYearSeconds && r.NativeDurationSeconds != awsSPThreeYearSeconds { + return false + } + return validDimensions(r) && validPayment(r.Payment) && sameAmount(r.HourlyCommitment, r.HourlyCommitment) +} + +func validDimensions(r *RecommendationIdentity) bool { + for _, value := range []string{r.SourceAccountID, r.OfferingID, r.Region, r.InstanceFamily} { + if value == "" { + return false + } + } + return usableSource(r.SourceAccountID) && (r.TopLevelRegion == "" || r.TopLevelRegion == r.Region) +} + +func validPayment(payment string) bool { + switch payment { + case "no_upfront", "partial_upfront", "all_upfront": + return true + default: + return false + } +} + +func sameAmount(a, b *big.Rat) bool { + return a != nil && b != nil && a.Sign() > 0 && b.Sign() > 0 && a.Cmp(b) == 0 +} + +type resourceIdentity struct { + provider, source, offering, plan, region, family, payment string +} + +func sameResource(r *RecommendationIdentity, item *LineItemIdentity) bool { + want := resourceIdentity{r.Provider, r.SourceAccountID, r.OfferingID, r.PlanType, r.Region, r.InstanceFamily, r.Payment} + got := resourceIdentity{item.Provider, item.SourceAccountID, item.ProviderOfferingID, item.PlanType, item.Region, item.InstanceFamily, item.Payment} + return want == got && item.Type == "savings_plan" && item.DurationSeconds != nil && + item.DurationSeconds.Cmp(new(big.Rat).SetInt64(r.NativeDurationSeconds)) == 0 && + sameAmount(r.HourlyCommitment, item.SelectedCommitment) +} + +func sameCurrentBasis(r *RecommendationIdentity, row *ComparisonIdentity) bool { + return row != nil && row.IsCurrent && row.Region != nil && *row.Region == r.Region && row.Provider == r.Provider && row.CurrentType == "savings_plan" && + row.CurrentPayment == r.Payment && sameAmount(r.HourlyCommitment, row.CurrentSelectedAmount) +} + +func comparisonIndex(planID string, rows []ComparisonIdentity, items []LineItemIdentity) (map[string]*ComparisonIdentity, error) { + if !validMatchUUID(planID) { + return nil, nil + } + lineItems := make(map[string]*LineItemIdentity, len(items)) + for i := range items { + if !validLineReference(planID, &items[i]) { + return nil, nil + } + id := strings.ToLower(items[i].ID) + if lineItems[id] != nil { + return nil, errors.New("duplicate Archera line-item reference") + } + lineItems[id] = &items[i] + } + index := make(map[string]*ComparisonIdentity, len(rows)) + for i := range rows { + if !validComparisonReference(&rows[i], lineItems) { + return nil, nil + } + id := strings.ToLower(rows[i].LineItemID) + if index[id] != nil { + return nil, errors.New("duplicate Archera comparison reference") + } + index[id] = &rows[i] + } + return index, nil +} + +func usableSource(source string) bool { + for _, r := range source { + if unicode.IsSpace(r) || unicode.IsControl(r) || unicode.In(r, unicode.Cf) { + return false + } + } + return true +} + +func validMatchUUID(id string) bool { + if len(id) != 36 { + return false + } + _, err := uuid.Parse(id) + return err == nil +} + +func validLineReference(planID string, item *LineItemIdentity) bool { + return validMatchUUID(item.ID) && validMatchUUID(item.OfferID) && validMatchUUID(item.PlanID) && strings.EqualFold(planID, item.PlanID) +} + +func validComparisonReference(row *ComparisonIdentity, items map[string]*LineItemIdentity) bool { + if !validMatchUUID(row.LineItemID) || !validMatchUUID(row.CurrentOfferID) { + return false + } + item := items[strings.ToLower(row.LineItemID)] + return item != nil && strings.EqualFold(row.CurrentOfferID, item.OfferID) +} diff --git a/internal/archera/recommendation_match_test.go b/internal/archera/recommendation_match_test.go new file mode 100644 index 000000000..adbed56c3 --- /dev/null +++ b/internal/archera/recommendation_match_test.go @@ -0,0 +1,190 @@ +package archera + +import ( + "encoding/json" + "math/big" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +const ( + matchPlan = "baadf00d-ffff-4aba-8ada-abcdefabcdef" + matchItem = "caadf00d-ffff-4aba-8ada-abcdefabcdef" + matchOffer = "daadf00d-ffff-4aba-8ada-abcdefabcdef" +) + +func matchFixture() (*RecommendationIdentity, []ComparisonIdentity, []LineItemIdentity) { + r := &RecommendationIdentity{ + Provider: "aws", SourceAccountID: "source-account-a", Service: "savings-plans-ec2instance", + PlanType: "EC2Instance", OfferingID: "provider-offer-a", Region: "us-east-1", + InstanceFamily: "m5", Payment: "no_upfront", NativeDurationSeconds: 31536000, + HourlyCommitment: big.NewRat(1, 2), + } + region := r.Region + row := ComparisonIdentity{Region: ®ion, IsCurrent: true, + LineItemID: matchItem, CurrentOfferID: matchOffer, Provider: "aws", + CurrentType: "savings_plan", CurrentPayment: "no_upfront", CurrentSelectedAmount: big.NewRat(1, 2), + } + item := LineItemIdentity{ + ID: matchItem, PlanID: matchPlan, OfferID: matchOffer, Provider: "aws", + SourceAccountID: r.SourceAccountID, ProviderOfferingID: r.OfferingID, Type: "savings_plan", + PlanType: r.PlanType, Region: r.Region, InstanceFamily: r.InstanceFamily, Payment: r.Payment, + DurationSeconds: big.NewRat(31536000, 1), SelectedCommitment: big.NewRat(1, 2), + } + return r, []ComparisonIdentity{row}, []LineItemIdentity{item} +} + +func TestMatchRecommendationAssociatesOnlyProvenResourceIdentity(t *testing.T) { + rec, rows, items := matchFixture() + items[0].ID = strings.ToUpper(matchItem) + items[0].PlanID = strings.ToUpper(matchPlan) + items[0].OfferID = strings.ToUpper(matchOffer) + before, marshalErr := json.Marshal([]any{rec, rows, items}) + require.NoError(t, marshalErr) + result, err := MatchRecommendation(matchPlan, rec, rows, items) + require.NoError(t, err) + require.Equal(t, ResourceAssociated, result.Status) + require.Equal(t, matchItem, result.LineItemID) + require.Equal(t, "stored_decimal_only", result.AmountProvenance) + require.Equal(t, "unavailable_source_precision", result.EconomicStatus) + require.Equal(t, "1/2", rec.HourlyCommitment.RatString()) + require.Equal(t, "1/2", items[0].SelectedCommitment.RatString()) + after, marshalErr := json.Marshal([]any{rec, rows, items}) + require.NoError(t, marshalErr) + require.Equal(t, before, after) + rec.NativeDurationSeconds = 94608000 + items[0].DurationSeconds = big.NewRat(94608000, 1) + result, err = MatchRecommendation(matchPlan, rec, rows, items) + require.NoError(t, err) + require.Equal(t, ResourceAssociated, result.Status) +} + +func TestMatchRecommendationRefusesUnprovenAssociation(t *testing.T) { + tests := []struct { + name string + change func(*RecommendationIdentity, *ComparisonIdentity, *LineItemIdentity) + }{ + {"unusable_source", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.SourceAccountID = "source\naccount" + i.SourceAccountID = r.SourceAccountID + }}, + {"unknown_source", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.SourceAccountID = "" + i.SourceAccountID = "" + }}, + {"collector_is_not_source", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.SourceAccountID = "collector-account" + }}, + {"source_case", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.SourceAccountID = "SOURCE-account-a" + }}, + {"provider", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { i.Provider = "gcp" }}, + {"offering", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.ProviderOfferingID = "other-offer" + }}, + {"missing_offering", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.OfferingID = "" + i.ProviderOfferingID = "" + }}, + {"unsupported_service", func(r *RecommendationIdentity, _ *ComparisonIdentity, _ *LineItemIdentity) { + r.Service = "savings-plans-compute" + }}, + {"invented_type", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.Type = "aws/savingsplan/EC2Instance" + }}, + {"plan_type", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { i.PlanType = "Compute" }}, + {"family", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { i.InstanceFamily = "m6" }}, + {"missing_details_region", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.Region = "" + i.Region = "" + }}, + {"contradictory_top_region", func(r *RecommendationIdentity, _ *ComparisonIdentity, _ *LineItemIdentity) { + r.TopLevelRegion = "us-west-2" + }}, + {"native_duration", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.DurationSeconds = big.NewRat(94608000, 1) + }}, + {"payment", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { i.Payment = "all_upfront" }}, + {"amount_mismatch", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.SelectedCommitment = big.NewRat(1, 1) + }}, + {"missing_hourly", func(r *RecommendationIdentity, _ *ComparisonIdentity, _ *LineItemIdentity) { r.HourlyCommitment = nil }}, + {"zero_hourly", func(r *RecommendationIdentity, _ *ComparisonIdentity, _ *LineItemIdentity) { + r.HourlyCommitment = new(big.Rat) + }}, + {"current_amount", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { + c.CurrentSelectedAmount = big.NewRat(2, 1) + }}, + {"offering_case", func(_ *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + i.ProviderOfferingID = "PROVIDER-offer-a" + }}, + {"missing_family", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.InstanceFamily = "" + i.InstanceFamily = "" + }}, + {"unsupported_native_term", func(r *RecommendationIdentity, _ *ComparisonIdentity, i *LineItemIdentity) { + r.NativeDurationSeconds = 123 + i.DurationSeconds = big.NewRat(123, 1) + }}, + {"current_provider", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { c.Provider = "gcp" }}, + {"current_unit_type", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { c.CurrentType = "ri" }}, + {"current_flag", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { c.IsCurrent = false }}, + {"current_region", func(_ *RecommendationIdentity, c *ComparisonIdentity, i *LineItemIdentity) { + c.Region = &i.InstanceFamily + }}, + {"missing_current_region", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { c.Region = nil }}, + {"current_offer", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { + c.CurrentOfferID = "different" + }}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r, rows, items := matchFixture() + tt.change(r, &rows[0], &items[0]) + got, err := MatchRecommendation(matchPlan, r, rows, items) + require.NoError(t, err) + require.Equal(t, MatchUnavailable, got.Status) + require.Empty(t, got.LineItemID) + }) + } +} + +func TestMatchRecommendationRejectsAmbiguousVendorRows(t *testing.T) { + r, rows, items := matchFixture() + rows = append(rows, rows[0]) + _, err := MatchRecommendation(matchPlan, r, rows, items) + require.Error(t, err) + r, rows, items = matchFixture() + items = append(items, items[0]) + items[1].ID = "eaadf00d-ffff-4aba-8ada-abcdefabcdef" + rows = append(rows, rows[0]) + rows[1].LineItemID = items[1].ID + got, err := MatchRecommendation(matchPlan, r, rows, items) + require.NoError(t, err) + require.Equal(t, MatchUnavailable, got.Status) + require.Empty(t, got.LineItemID) +} + +func TestMatchRecommendationRejectsEqualMalformedUUIDReferences(t *testing.T) { + for _, bad := range []string{"", "not-a-uuid", strings.ReplaceAll(matchItem, "-", "")} { + for _, field := range []string{"plan", "item", "offer"} { + t.Run(field+"_"+bad, func(t *testing.T) { + r, rows, items := matchFixture() + plan := matchPlan + switch field { + case "plan": + plan, items[0].PlanID = bad, bad + case "item": + rows[0].LineItemID, items[0].ID = bad, bad + case "offer": + rows[0].CurrentOfferID, items[0].OfferID = bad, bad + } + got, err := MatchRecommendation(plan, r, rows, items) + require.NoError(t, err) + require.Equal(t, MatchUnavailable, got.Status) + }) + } + } +} From 902586f2430e561900b91265abf877ee9e589034 Mon Sep 17 00:00:00 2001 From: Cristian Magherusan-Stanciu Date: Thu, 15 Oct 2026 12:32:15 +0200 Subject: [PATCH 2/2] test(archera): exercise uuid comparison guards Use valid unequal offers and invalid UUIDs of the required length. Prove both checks have independent regression coverage. --- internal/archera/recommendation_match_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/archera/recommendation_match_test.go b/internal/archera/recommendation_match_test.go index adbed56c3..310a295e0 100644 --- a/internal/archera/recommendation_match_test.go +++ b/internal/archera/recommendation_match_test.go @@ -136,7 +136,7 @@ func TestMatchRecommendationRefusesUnprovenAssociation(t *testing.T) { }}, {"missing_current_region", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { c.Region = nil }}, {"current_offer", func(_ *RecommendationIdentity, c *ComparisonIdentity, _ *LineItemIdentity) { - c.CurrentOfferID = "different" + c.CurrentOfferID = "faadf00d-ffff-4aba-8ada-abcdefabcdef" }}, } for _, tt := range tests { @@ -168,7 +168,7 @@ func TestMatchRecommendationRejectsAmbiguousVendorRows(t *testing.T) { } func TestMatchRecommendationRejectsEqualMalformedUUIDReferences(t *testing.T) { - for _, bad := range []string{"", "not-a-uuid", strings.ReplaceAll(matchItem, "-", "")} { + for _, bad := range []string{"", "not-a-uuid", strings.ReplaceAll(matchItem, "-", ""), "zzzzzzzz-zzzz-4zzz-8zzz-zzzzzzzzzzzz"} { for _, field := range []string{"plan", "item", "offer"} { t.Run(field+"_"+bad, func(t *testing.T) { r, rows, items := matchFixture()