package main import "testing" // A bucket name is checked here so the refusal names the module that asked. // // The store would refuse most of these itself, as a REST error arriving inside a provisioner log, // with nothing saying which consumer's manifest caused it. func TestABucketNameThatWouldNotWorkIsRefusedHere(t *testing.T) { for _, name := range []string{ "", // nothing asked for "ab", // too short "-lead", "trail-", "Photos", // upper case: arrives lower-cased, and works until somebody looks "my_bucket", // underscore "a.b", // dots are legal in S3 and break TLS host matching; not worth the surprise } { if err := usableBucketName(name); err == nil { t.Errorf("%q was accepted", name) } } } func TestAnOrdinaryBucketNameIsAccepted(t *testing.T) { for _, name := range []string{"photos", "a-b-c", "backups2026", "abc"} { if err := usableBucketName(name); err != nil { t.Errorf("%q was refused: %v", name, err) } } } // The policy a consumer gets names its own bucket and nothing else. // // **The half that matters is what it does not say.** A policy granting `arn:aws:s3:::*` would // pass every test that checks a consumer can reach its own bucket, and would give every consumer // the whole store. func TestThePolicyGrantsOneBucketAndNoOther(t *testing.T) { policy := onlyThatBucket("photos") for _, want := range []string{`"arn:aws:s3:::photos"`, `"arn:aws:s3:::photos/*"`} { if !contains(policy, want) { t.Errorf("the policy does not carry %s:\n%s", want, policy) } } for _, unwanted := range []string{`:::*`, `"*"`, `:::photos-other`} { if contains(policy, unwanted) { t.Errorf("the policy carries %s, which reaches beyond the bucket asked for:\n%s", unwanted, policy) } } } // A policy is per consumer, so one asking for a second bucket cannot widen another's. func TestTwoConsumersGetPoliciesThatDoNotOverlap(t *testing.T) { if contains(onlyThatBucket("photos"), "invoices") || contains(onlyThatBucket("invoices"), "photos") { t.Error("a consumer's policy names another consumer's bucket") } } func contains(haystack, needle string) bool { for i := 0; i+len(needle) <= len(haystack); i++ { if haystack[i:i+len(needle)] == needle { return true } } return false }