carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package mail
2
3import (
4 "context"
5 "errors"
6 "testing"
7)
8
9// Idempotence is the contract, not a nicety: every walk re-runs after a
10// half-failure, so a second EnsureIdentity must be a success that returns
11// the SAME tokens — fresh tokens would orphan the DNS already published.
12func TestMemEnsureIdentityIsIdempotentAndTokenStable(t *testing.T) {
13 ctx, p := context.Background(), NewMemProvisioner("1")
14 first, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "mail-eu-west-1.x.com", true)
15 if err != nil {
16 t.Fatalf("EnsureIdentity: %v", err)
17 }
18 if len(first.DKIMTokens) != 3 {
19 t.Fatalf("want 3 DKIM tokens, got %d", len(first.DKIMTokens))
20 }
21 second, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "mail-eu-west-1.x.com", true)
22 if err != nil {
23 t.Fatalf("re-EnsureIdentity: %v", err)
24 }
25 if first.ARN != second.ARN || first.DKIMTokens[0] != second.DKIMTokens[0] {
26 t.Fatal("re-ensuring changed the identity — the published DNS would be orphaned")
27 }
28}
29
30// Without adopt, the fake refuses an existing identity untouched, as SES
31// does through awsProvisioner (#216).
32func TestMemEnsureIdentityWithoutAdoptRefusesUntouched(t *testing.T) {
33 ctx, p := context.Background(), NewMemProvisioner("1")
34 first, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "m1.x.com", false)
35 if err != nil || !first.Created {
36 t.Fatalf("create = %+v, %v", first, err)
37 }
38 if _, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "m2.x.com", false); !errors.Is(err, ErrIdentityExists) {
39 t.Fatalf("re-ensure without adopt = %v, want ErrIdentityExists", err)
40 }
41 if got := p.Identities[identityKey("eu-west-1", "x.com")].MailFrom; got != "m1.x.com" {
42 t.Fatalf("MAIL FROM rewritten to %q without adopt", got)
43 }
44 again, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "m1.x.com", true)
45 if err != nil || again.Created {
46 t.Fatalf("adopt = %+v, %v; want the existing identity, not Created", again, err)
47 }
48}
49
50func TestMemIdentitiesAreRegionScoped(t *testing.T) {
51 ctx, p := context.Background(), NewMemProvisioner("1")
52 eu, _ := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "mail-eu-west-1.x.com", true)
53 us, _ := p.EnsureIdentity(ctx, "us-east-1", "x.com", "mail-us-east-1.x.com", true)
54 if eu.ARN == us.ARN {
55 t.Fatal("one ARN served two regions")
56 }
57 if eu.DKIMTokens[0] == us.DKIMTokens[0] {
58 t.Fatal("two regions shared a DKIM token — they are independent identities")
59 }
60}
61
62func TestMemDeleteIsIdempotent(t *testing.T) {
63 ctx, p := context.Background(), NewMemProvisioner("1")
64 if err := p.DeleteIdentity(ctx, "eu-west-1", "absent.com"); err != nil {
65 t.Fatalf("deleting an absent identity = %v, want nil", err)
66 }
67 if err := p.DeleteUser(ctx, "absent-user"); err != nil {
68 t.Fatalf("deleting an absent user = %v, want nil", err)
69 }
70}
71
72// The pause is SetKeyActive, and the fake must model it so a walk test can
73// assert a paused credential really is inactive.
74func TestMemSetKeyActiveTogglesTheKey(t *testing.T) {
75 ctx, p := context.Background(), NewMemProvisioner("1")
76 if _, err := p.EnsureUser(ctx, "u", UserPath, []string{"arn:aws:ses:eu-west-1:1:identity/x.com"}, nil, []string{"x.com"}); err != nil {
77 t.Fatalf("EnsureUser: %v", err)
78 }
79 id, _, err := p.MintKey(ctx, "u")
80 if err != nil {
81 t.Fatalf("MintKey: %v", err)
82 }
83 if !p.Users["u"].Keys[id].Active {
84 t.Fatal("a freshly minted key must be active")
85 }
86 if err := p.SetKeyActive(ctx, "u", id, false); err != nil {
87 t.Fatalf("SetKeyActive: %v", err)
88 }
89 if p.Users["u"].Keys[id].Active {
90 t.Fatal("SetKeyActive(false) did not deactivate the key")
91 }
92}
93
94// ReapKeys is what finds a key stranded by a crash between mint and record —
95// no record names it, so only list-and-delete can.
96func TestMemReapKeysKeepsOnlyTheNamedOnes(t *testing.T) {
97 ctx, p := context.Background(), NewMemProvisioner("1")
98 p.EnsureUser(ctx, "u", UserPath, []string{"arn:aws:ses:eu-west-1:1:identity/x.com"}, nil, []string{"x.com"})
99 keep, _, _ := p.MintKey(ctx, "u")
100 stranded, _, _ := p.MintKey(ctx, "u")
101 if err := p.ReapKeys(ctx, "u", []string{keep}); err != nil {
102 t.Fatalf("ReapKeys: %v", err)
103 }
104 if _, ok := p.Users["u"].Keys[stranded]; ok {
105 t.Fatal("ReapKeys left a key the record does not name")
106 }
107 if _, ok := p.Users["u"].Keys[keep]; !ok {
108 t.Fatal("ReapKeys deleted a key it was told to keep")
109 }
110}
111
112// IAM hard-caps every user at two access keys. MintKey must enforce that
113// cap in the fake too, since a rotation walk (Task 13) mints a second key
114// while the first is still live, and a fake that let a third key through
115// would pass a test that fails the first time it runs against real IAM.
116// Both halves matter: the first two must succeed (a cap misapplied at two
117// would break ordinary rotation), and only the third must fail.
118func TestMemMintKeyEnforcesTheTwoKeyCap(t *testing.T) {
119 ctx, p := context.Background(), NewMemProvisioner("1")
120 if _, err := p.EnsureUser(ctx, "u", UserPath, []string{"arn:aws:ses:eu-west-1:1:identity/x.com"}, nil, []string{"x.com"}); err != nil {
121 t.Fatalf("EnsureUser: %v", err)
122 }
123 if _, _, err := p.MintKey(ctx, "u"); err != nil {
124 t.Fatalf("first MintKey: %v, want success", err)
125 }
126 if _, _, err := p.MintKey(ctx, "u"); err != nil {
127 t.Fatalf("second MintKey: %v, want success — the cap must not fire before the third key", err)
128 }
129 if _, _, err := p.MintKey(ctx, "u"); err == nil {
130 t.Fatal("third MintKey succeeded, want IAM's two-key-per-user limit enforced")
131 }
132}
133
134// EnsureUser must refuse an ungranted principal rather than create one with
135// no policy — an unscoped sending user is the failure this package exists to
136// prevent.
137func TestMemEnsureUserRefusesAnEmptyGrant(t *testing.T) {
138 if _, err := NewMemProvisioner("1").EnsureUser(context.Background(), "u", UserPath, nil, nil, nil); err == nil {
139 t.Fatal("EnsureUser with no ARNs returned success")
140 }
141}
142
143func TestMemFailNextIsOneShot(t *testing.T) {
144 ctx, p := context.Background(), NewMemProvisioner("1")
145 boom := errors.New("boom")
146 p.FailNext["EnsureIdentity"] = boom
147 if _, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "m.x.com", true); !errors.Is(err, boom) {
148 t.Fatalf("first call = %v, want boom", err)
149 }
150 if _, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "m.x.com", true); err != nil {
151 t.Fatalf("second call = %v, want nil", err)
152 }
153}
154
155// The fake refuses to delete an identity that is still associated with a
156// tenant, because SES does. A walk that got the order wrong would pass
157// against a permissive fake and fail on the first real teardown.
158func TestMemProvisionerRefusesToDeleteAnAssociatedIdentity(t *testing.T) {
159 ctx := context.Background()
160 p := NewMemProvisioner("1")
161 id, err := p.EnsureIdentity(ctx, "eu-west-1", "x.com", "mail-eu-west-1.x.com", true)
162 if err != nil {
163 t.Fatal(err)
164 }
165 if err := p.AssociateTenantResource(ctx, "carlos-bag", id.ARN); err != nil {
166 t.Fatal(err)
167 }
168 if err := p.DeleteIdentity(ctx, "eu-west-1", "x.com"); err == nil {
169 t.Fatal("an associated identity was deleted")
170 }
171 if err := p.DisassociateTenantResource(ctx, "carlos-bag", id.ARN); err != nil {
172 t.Fatal(err)
173 }
174 // Disassociating twice is a success, like every other verb on this seam.
175 if err := p.DisassociateTenantResource(ctx, "carlos-bag", id.ARN); err != nil {
176 t.Fatal(err)
177 }
178 if err := p.DeleteIdentity(ctx, "eu-west-1", "x.com"); err != nil {
179 t.Fatal(err)
180 }
181}
182