verify / verify (push) Successful in 4m17s
Signed-off-by: Cole Speelman <crspeelman@gmail.com>
102 lines
4.1 KiB
Go
102 lines
4.1 KiB
Go
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package organizations
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"errors"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type roleInvitationRepositoryStub struct {
|
|
repositoryStub
|
|
audit AuditEvent
|
|
ownerRole string
|
|
created int
|
|
}
|
|
|
|
func (r *roleInvitationRepositoryStub) CreateInvitationWithRoles(_ context.Context, invitation Invitation, ownerRole string, audit AuditEvent) error {
|
|
r.created++
|
|
r.invitation, r.audit, r.ownerRole = invitation, audit, ownerRole
|
|
return nil
|
|
}
|
|
|
|
func (r *roleInvitationRepositoryStub) AcceptInvitationWithRoles(_ context.Context, _ [32]byte, userID, ownerRole string, _ time.Time, audit AuditEvent) error {
|
|
r.acceptedUser, r.ownerRole, r.audit = userID, ownerRole, audit
|
|
return nil
|
|
}
|
|
|
|
func TestInvitationRoleNamesAreBoundedAndUnambiguous(t *testing.T) {
|
|
input := []string{"buyer", "billing"}
|
|
roles, err := (Invitation{DirectRoles: input}).RoleNames()
|
|
if err != nil || !slices.Equal(roles, []string{"billing", "buyer"}) || !slices.Equal(input, []string{"buyer", "billing"}) {
|
|
t.Fatalf("roles=%v input=%v err=%v", roles, input, err)
|
|
}
|
|
for _, invitation := range []Invitation{
|
|
{DirectRole: "owner", DirectRoles: []string{"buyer"}},
|
|
{DirectRoles: []string{"buyer", "buyer"}},
|
|
{DirectRoles: []string{"not a role"}},
|
|
{DirectRoles: make([]string, 17)},
|
|
} {
|
|
if _, err := invitation.RoleNames(); err == nil {
|
|
t.Fatalf("invalid roles accepted=%+v", invitation)
|
|
}
|
|
}
|
|
if roles, err = (Invitation{DirectRole: "buyer"}).RoleNames(); err != nil || !slices.Equal(roles, []string{"buyer"}) {
|
|
t.Fatalf("legacy=%v err=%v", roles, err)
|
|
}
|
|
}
|
|
|
|
func TestRoleInvitationServicePreservesOwnerRequirementAndRequest(t *testing.T) {
|
|
r := &roleInvitationRepositoryStub{}
|
|
service, err := New(r, Options{OwnerRole: "owner", OwnerManagedInvitations: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
input := InviteWithAccess{OrganizationID: "organization-123", InvitedByUserID: "owner-12345678", Email: " Member@example.test ", DirectRoles: []string{"buyer", "billing"}, Lifetime: time.Hour, RequestID: "request-invite"}
|
|
raw, invitation, err := service.InviteWithAccess(t.Context(), input)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if invitation.Digest != sha256.Sum256([]byte(raw)) || invitation.RequiredOwnerRole != "owner" || r.ownerRole != "owner" || r.audit.RequestID != input.RequestID || !slices.Equal(invitation.DirectRoles, []string{"billing", "buyer"}) || invitation.Email != "member@example.test" {
|
|
t.Fatalf("invitation or audit mismatch: %+v %+v", invitation, r.audit)
|
|
}
|
|
if !slices.Equal(input.DirectRoles, []string{"buyer", "billing"}) {
|
|
t.Fatal("caller roles mutated")
|
|
}
|
|
if err = service.AcceptInvitation(t.Context(), raw, "member-12345678"); err != nil || r.ownerRole != "owner" || r.acceptedUser != "member-12345678" {
|
|
t.Fatalf("accept=%v owner=%q user=%q", err, r.ownerRole, r.acceptedUser)
|
|
}
|
|
input.RequestID = strings.Repeat("x", 129)
|
|
if _, _, err = service.InviteWithAccess(t.Context(), input); err == nil || r.created != 1 {
|
|
t.Fatal("oversized request accepted")
|
|
}
|
|
if _, err = New(r, Options{OwnerManagedInvitations: true}); err == nil {
|
|
t.Fatal("owner-managed service without owner accepted")
|
|
}
|
|
}
|
|
|
|
func TestRoleInvitationHasNoPartialLegacyFallback(t *testing.T) {
|
|
for _, input := range []InviteWithAccess{
|
|
{DirectRoles: []string{"buyer", "billing"}}, {DirectRole: "owner"}, {},
|
|
} {
|
|
r := &repositoryStub{}
|
|
service, err := New(r, Options{OwnerRole: "owner", OwnerManagedInvitations: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
input.OrganizationID, input.InvitedByUserID, input.Email, input.Lifetime = "organization-123", "owner-12345678", "member@example.test", time.Hour
|
|
if _, _, err = service.InviteWithAccess(t.Context(), input); !errors.Is(err, ErrRoleInvitationUnsupported) || r.invitation.ID != "" {
|
|
t.Fatalf("legacy fallback=%v", err)
|
|
}
|
|
r.invitation = Invitation{OrganizationID: input.OrganizationID, ID: "invitation-1234", RequiredOwnerRole: "owner"}
|
|
if err = service.AcceptInvitation(t.Context(), strings.Repeat("a", 43), "member-12345678"); !errors.Is(err, ErrRoleInvitationUnsupported) || r.acceptedUser != "" {
|
|
t.Fatalf("legacy acceptance fallback=%v", err)
|
|
}
|
|
}
|
|
}
|