| index 424f92416..ae714ffe9 100644 |
| --- a/internal/mail/aws_test.go |
| +++ b/internal/mail/aws_test.go |
| @@ -170,14 +170,109 @@ func TestEnsureIdentityRefusesNoTokens(t *testing.T) { |
| } |
| } |
| |
| -// TestEnsureIdentityRefusesAMismatchedRegion pins the region guard: an |
| -// awsProvisioner is bound to one client at construction, and a caller naming |
| -// a different region must be refused loudly rather than silently routed |
| -// through the wrong client. |
| -func TestEnsureIdentityRefusesAMismatchedRegion(t *testing.T) { |
| - p := &awsProvisioner{ses: &stubSES{}, account: "123456789012", region: "eu-west-1"} |
| - if _, err := p.EnsureIdentity(context.Background(), "us-east-1", "example.com", "mail.example.com"); err == nil { |
| - t.Fatal("EnsureIdentity accepted a region other than the one the provisioner is bound to") |
| +// wellFormedIdentityStub returns a stubSES whose CreateEmailIdentity and |
| +// PutEmailIdentityMailFromAttributes both succeed, with three non-empty |
| +// DKIM tokens. Used by the region-guard tests below so that success or |
| +// failure turns ENTIRELY on checkRegion and never on fix #3's zero-token |
| +// guard — round 1's TestEnsureIdentityRefusesAMismatchedRegion used a bare |
| +// &stubSES{}, whose zero-value CreateEmailIdentity success carries no |
| +// DkimAttributes; the zero-token guard fired and satisfied "an error came |
| +// back" even with checkRegion's call site deleted entirely, so the test |
| +// passed for the wrong reason. Confirmed empirically below (see the |
| +// round-2 fix report) by removing the checkRegion call and rerunning. |
| +func wellFormedIdentityStub() *stubSES { |
| + return &stubSES{ |
| + createEmailIdentity: func(*sesv2.CreateEmailIdentityInput) (*sesv2.CreateEmailIdentityOutput, error) { |
| + return &sesv2.CreateEmailIdentityOutput{ |
| + DkimAttributes: &sesv2types.DkimAttributes{Tokens: []string{"t1", "t2", "t3"}}, |
| + }, nil |
| + }, |
| + } |
| +} |
| + |
| +// TestRegionGuardRefusesAMismatch covers all four SES-facing methods that |
| +// take a region parameter (EnsureConfigSet, EnsureIdentity, IdentityStatus, |
| +// DeleteIdentity): a caller naming a region other than the one the |
| +// provisioner is bound to must be refused, and the refusal must be |
| +// checkRegion's — not an error that happens to fire for an unrelated |
| +// reason. Every stub here answers with an unconditional success for |
| +// whatever SES call the guard is supposed to prevent from ever being |
| +// reached, so if the guard is silently removed the call SUCCEEDS instead of |
| +// merely "erroring somehow" — which is what makes the errors.Is assertion |
| +// meaningful rather than vacuous. |
| +func TestRegionGuardRefusesAMismatch(t *testing.T) { |
| + const boundRegion = "eu-west-1" |
| + const otherRegion = "us-east-1" |
| + |
| + cases := []struct { |
| + name string |
| + call func(p *awsProvisioner) error |
| + }{ |
| + {"EnsureConfigSet", func(p *awsProvisioner) error { |
| + return p.EnsureConfigSet(context.Background(), otherRegion, "cfg", "arn:aws:sns:eu-west-1:123456789012:topic") |
| + }}, |
| + {"EnsureIdentity", func(p *awsProvisioner) error { |
| + _, err := p.EnsureIdentity(context.Background(), otherRegion, "example.com", "mail.example.com") |
| + return err |
| + }}, |
| + {"IdentityStatus", func(p *awsProvisioner) error { |
| + _, err := p.IdentityStatus(context.Background(), otherRegion, "example.com") |
| + return err |
| + }}, |
| + {"DeleteIdentity", func(p *awsProvisioner) error { |
| + return p.DeleteIdentity(context.Background(), otherRegion, "example.com") |
| + }}, |
| + } |
| + |
| + for _, tc := range cases { |
| + t.Run(tc.name, func(t *testing.T) { |
| + p := &awsProvisioner{ses: wellFormedIdentityStub(), account: "123456789012", region: boundRegion} |
| + err := tc.call(p) |
| + if err == nil { |
| + t.Fatalf("%s accepted region %q against a provisioner bound to %q", tc.name, otherRegion, boundRegion) |
| + } |
| + if !errors.Is(err, errRegionMismatch) { |
| + t.Fatalf("%s error = %v, want it to wrap errRegionMismatch", tc.name, err) |
| + } |
| + }) |
| + } |
| +} |
| + |
| +// TestRegionGuardPassesAnEmptyRegionThrough pins the deliberate escape: |
| +// checkRegion treats "" as "caller doesn't care" rather than a mismatch. |
| +// Each case uses a stub that succeeds unconditionally, so a passing test |
| +// here means the guard did not fire — not that some other stub default |
| +// happened to swallow an error. |
| +func TestRegionGuardPassesAnEmptyRegionThrough(t *testing.T) { |
| + const boundRegion = "eu-west-1" |
| + |
| + cases := []struct { |
| + name string |
| + call func(p *awsProvisioner) error |
| + }{ |
| + {"EnsureConfigSet", func(p *awsProvisioner) error { |
| + return p.EnsureConfigSet(context.Background(), "", "cfg", "arn:aws:sns:eu-west-1:123456789012:topic") |
| + }}, |
| + {"EnsureIdentity", func(p *awsProvisioner) error { |
| + _, err := p.EnsureIdentity(context.Background(), "", "example.com", "mail.example.com") |
| + return err |
| + }}, |
| + {"IdentityStatus", func(p *awsProvisioner) error { |
| + _, err := p.IdentityStatus(context.Background(), "", "example.com") |
| + return err |
| + }}, |
| + {"DeleteIdentity", func(p *awsProvisioner) error { |
| + return p.DeleteIdentity(context.Background(), "", "example.com") |
| + }}, |
| + } |
| + |
| + for _, tc := range cases { |
| + t.Run(tc.name, func(t *testing.T) { |
| + p := &awsProvisioner{ses: wellFormedIdentityStub(), account: "123456789012", region: boundRegion} |
| + if err := tc.call(p); err != nil { |
| + t.Fatalf("%s with an empty region was refused: %v", tc.name, err) |
| + } |
| + }) |
| } |
| } |
| |