package core
import "testing"
const (
ownerID = 1
otherID = 2
)
func repoWith(v Visibility) *Repo {
return &Repo{ID: 10, Name: "db", OwnerID: ownerID, OwnerName: "owner", Path: "/x", Visibility: v}
}
func ptr(m AccessMode) *AccessMode { return &m }
// grant bundles the four operation outcomes for one matrix cell.
type grant struct{ browse, clone, push, admin bool }
func (g grant) want(op Op) bool {
switch op {
case OpBrowse:
return g.browse
case OpCloneRead:
return g.clone
case OpPush:
return g.push
case OpAdmin:
return g.admin
}
return false
}
func TestAllowedMatrix(t *testing.T) {
anon := (*Caller)(nil)
user := &Caller{UserID: otherID, Username: "user", UserType: UserTypeUser}
owner := &Caller{UserID: ownerID, Username: "owner", UserType: UserTypeUser}
suspendedOwner := &Caller{UserID: ownerID, Username: "owner", UserType: UserTypeSuspended, Suspended: true}
suspendedUser := &Caller{UserID: otherID, Username: "user", UserType: UserTypeSuspended, Suspended: true}
readOnly := grant{browse: true, clone: true}
readWrite := grant{browse: true, clone: true, push: true}
all := grant{browse: true, clone: true, push: true, admin: true}
none := grant{}
tests := []struct {
name string
caller *Caller
repo *Repo
acl *AccessMode
want grant
}{
// anonymous, no ACL
{"anon/public", anon, repoWith(VisibilityPublic), nil, readOnly},
{"anon/unlisted", anon, repoWith(VisibilityUnlisted), nil, readOnly},
{"anon/private", anon, repoWith(VisibilityPrivate), nil, none},
// authenticated non-owner, no ACL (same as anonymous)
{"user/public", user, repoWith(VisibilityPublic), nil, readOnly},
{"user/unlisted", user, repoWith(VisibilityUnlisted), nil, readOnly},
{"user/private", user, repoWith(VisibilityPrivate), nil, none},
// ACL RO grant: browse+clone on every visibility, incl. PRIVATE
{"acl-ro/public", user, repoWith(VisibilityPublic), ptr(AccessRO), readOnly},
{"acl-ro/unlisted", user, repoWith(VisibilityUnlisted), ptr(AccessRO), readOnly},
{"acl-ro/private", user, repoWith(VisibilityPrivate), ptr(AccessRO), readOnly},
// ACL RW grant: + push, never admin, on every visibility
{"acl-rw/public", user, repoWith(VisibilityPublic), ptr(AccessRW), readWrite},
{"acl-rw/unlisted", user, repoWith(VisibilityUnlisted), ptr(AccessRW), readWrite},
{"acl-rw/private", user, repoWith(VisibilityPrivate), ptr(AccessRW), readWrite},
// owner: everything on every visibility
{"owner/public", owner, repoWith(VisibilityPublic), nil, all},
{"owner/unlisted", owner, repoWith(VisibilityUnlisted), nil, all},
{"owner/private", owner, repoWith(VisibilityPrivate), nil, all},
// suspended: reads only, never push/admin
{"suspended-owner/private", suspendedOwner, repoWith(VisibilityPrivate), nil, readOnly},
{"suspended-owner/public", suspendedOwner, repoWith(VisibilityPublic), nil, readOnly},
{"suspended-user-rw/private", suspendedUser, repoWith(VisibilityPrivate), ptr(AccessRW), readOnly},
{"suspended-user-rw/public", suspendedUser, repoWith(VisibilityPublic), ptr(AccessRW), readOnly},
{"suspended-user-ro/private", suspendedUser, repoWith(VisibilityPrivate), ptr(AccessRO), readOnly},
}
ops := []Op{OpBrowse, OpCloneRead, OpPush, OpAdmin}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
for _, op := range ops {
got := Allowed(tt.caller, tt.repo, tt.acl, op)
want := tt.want.want(op)
if got != want {
t.Errorf("Allowed(%s, %s) = %v, want %v", tt.name, op, got, want)
}
}
})
}
}
func TestAllowedUnknownOpDenied(t *testing.T) {
owner := &Caller{UserID: ownerID}
if Allowed(owner, repoWith(VisibilityPublic), nil, Op(99)) {
t.Fatal("unknown op must be denied even for the owner")
}
}
func TestAllowedNilRepoDenied(t *testing.T) {
owner := &Caller{UserID: ownerID}
for _, op := range []Op{OpBrowse, OpCloneRead, OpPush, OpAdmin} {
if Allowed(owner, nil, nil, op) {
t.Fatalf("nil repo must deny %s", op)
}
}
}
func TestNotFoundForPrivate(t *testing.T) {
anon := (*Caller)(nil)
user := &Caller{UserID: otherID}
owner := &Caller{UserID: ownerID}
tests := []struct {
name string
caller *Caller
repo *Repo
acl *AccessMode
want bool
}{
{"nil-repo", anon, nil, nil, true},
{"public-anon", anon, repoWith(VisibilityPublic), nil, false},
{"unlisted-anon", anon, repoWith(VisibilityUnlisted), nil, false},
{"private-anon-hidden", anon, repoWith(VisibilityPrivate), nil, true},
{"private-unauthorized-user-hidden", user, repoWith(VisibilityPrivate), nil, true},
{"private-owner-visible", owner, repoWith(VisibilityPrivate), nil, false},
{"private-acl-ro-visible", user, repoWith(VisibilityPrivate), ptr(AccessRO), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NotFoundForPrivate(tt.caller, tt.repo, tt.acl); got != tt.want {
t.Fatalf("NotFoundForPrivate(%s) = %v, want %v", tt.name, got, tt.want)
}
})
}
}