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) } }) } }