Skip to content

Commit

Permalink
Add use-role-filter option on dashboard GetxTemplate API
Browse files Browse the repository at this point in the history
  • Loading branch information
jlandowner committed Aug 2, 2023
1 parent bf76964 commit 365ea3d
Show file tree
Hide file tree
Showing 17 changed files with 732 additions and 131 deletions.
97 changes: 87 additions & 10 deletions internal/dashboard/__snapshots__/template_handler_test.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: admin-user, empty 1']
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: admin-user, empty, 1']
SnapShot = """
{
\"message\": \"No items found\"
}
"""
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: admin-user, not empty 1']
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: admin-user, not empty, 1']
SnapShot = """
{
\"items\": [
Expand Down Expand Up @@ -41,14 +41,14 @@ SnapShot = """
}
"""
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: normal-user, empty 1']
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: normal-user, empty, 1']
SnapShot = """
{
\"message\": \"No items found\"
}
"""
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: normal-user, not empty 1']
['Dashboard server [Template] [GetUserAddonTemplates] ✅ success in normal context: Entry: normal-user, not empty, 1']
SnapShot = """
{
\"items\": [
Expand Down Expand Up @@ -84,17 +84,17 @@ SnapShot = """
}
"""
['Dashboard server [Template] [GetUserAddonTemplates] ❌ fail with an unexpected error at list: Entry: admin-user, not empty 1']
['Dashboard server [Template] [GetUserAddonTemplates] ❌ fail with an unexpected error at list: Entry: admin-user, not empty, 1']
SnapShot = 'internal: failed to list UserAddon Templates'

['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: admin-user, empty 1']
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: admin-user, empty, 1']
SnapShot = """
{
\"message\": \"No items found\"
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: admin-user, not empty 1']
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: admin-user, not empty, 1']
SnapShot = """
{
\"items\": [
Expand Down Expand Up @@ -123,19 +123,93 @@ SnapShot = """
\"default_value\": \"FUGAfuga\"
}
]
},
{
\"name\": \"template3\"
}
]
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: normal-user, empty 1']
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: normal-user, empty, 1']
SnapShot = """
{
\"message\": \"No items found\"
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: normal-user, not empty 1']
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: normal-user, not empty, 1']
SnapShot = """
{
\"items\": [
{
\"name\": \"template1\",
\"required_vars\": [
{
\"var_name\": \"{{HOGE}}\",
\"default_value\": \"HOGEhoge\"
},
{
\"var_name\": \"{{FUGA}}\",
\"default_value\": \"FUGAfuga\"
}
]
},
{
\"name\": \"template2\",
\"required_vars\": [
{
\"var_name\": \"{{HOGE}}\",
\"default_value\": \"HOGEhoge\"
},
{
\"var_name\": \"{{FUGA}}\",
\"default_value\": \"FUGAfuga\"
}
]
},
{
\"name\": \"template3\"
}
]
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: normal-user, not empty, use_role_filter:true 1']
SnapShot = """
{
\"items\": [
{
\"name\": \"template1\",
\"required_vars\": [
{
\"var_name\": \"{{HOGE}}\",
\"default_value\": \"HOGEhoge\"
},
{
\"var_name\": \"{{FUGA}}\",
\"default_value\": \"FUGAfuga\"
}
]
},
{
\"name\": \"template2\",
\"required_vars\": [
{
\"var_name\": \"{{HOGE}}\",
\"default_value\": \"HOGEhoge\"
},
{
\"var_name\": \"{{FUGA}}\",
\"default_value\": \"FUGAfuga\"
}
]
}
]
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ✅ success in normal context: Entry: role-user, not empty, 1']
SnapShot = """
{
\"items\": [
Expand Down Expand Up @@ -164,10 +238,13 @@ SnapShot = """
\"default_value\": \"FUGAfuga\"
}
]
},
{
\"name\": \"template3\"
}
]
}
"""
['Dashboard server [Template] [GetWorkspaceTemplates] ❌ fail with an unexpected error at list: Entry: admin-user, not empty 1']
['Dashboard server [Template] [GetWorkspaceTemplates] ❌ fail with an unexpected error at list: Entry: admin-user, not empty, 1']
SnapShot = 'internal: failed to list WorkspaceTemplates'
15 changes: 15 additions & 0 deletions internal/dashboard/auth_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,21 @@ func validateCallerHasAdminForAllRoles(tryRoleNames []string) func(map[string]st
}
}

func validateCallerHasAdminForAtLeastOneRole(tryRoleNames []cosmov1alpha1.UserRole) func(map[string]string) error {
return func(callerGroupRoleMap map[string]string) error {
for _, r := range tryRoleNames {
tryAccessGroup, _ := r.GetGroupAndRole()
callerRoleForTriedGroup := callerGroupRoleMap[tryAccessGroup]

// Allow if caller has at least one administrative privilege for tried group.
if callerRoleForTriedGroup == cosmov1alpha1.AdminRoleName {
return nil
}
}
return fmt.Errorf("denied to access")
}
}

var passAllAdmin = func(map[string]string) error {
return nil
}
18 changes: 13 additions & 5 deletions internal/dashboard/template_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import (
"strings"

connect_go "github.com/bufbuild/connect-go"
"google.golang.org/protobuf/types/known/emptypb"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/utils/pointer"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/clog"
"github.com/cosmo-workspace/cosmo/pkg/kosmo"
"github.com/cosmo-workspace/cosmo/pkg/kubeutil"
dashv1alpha1 "github.com/cosmo-workspace/cosmo/proto/gen/dashboard/v1alpha1"
"github.com/cosmo-workspace/cosmo/proto/gen/dashboard/v1alpha1/dashboardv1alpha1connect"
Expand All @@ -26,16 +26,20 @@ func (s *Server) TemplateServiceHandler(mux *http.ServeMux) {
mux.Handle(path, s.contextMiddleware(handler))
}

func (s *Server) GetWorkspaceTemplates(ctx context.Context, req *connect_go.Request[emptypb.Empty]) (*connect_go.Response[dashv1alpha1.GetWorkspaceTemplatesResponse], error) {
func (s *Server) GetWorkspaceTemplates(ctx context.Context, req *connect_go.Request[dashv1alpha1.GetWorkspaceTemplatesRequest]) (*connect_go.Response[dashv1alpha1.GetWorkspaceTemplatesResponse], error) {
log := clog.FromContext(ctx).WithCaller()

user := callerFromContext(ctx)

tmpls, err := s.Klient.ListWorkspaceTemplates(ctx, user)
tmpls, err := s.Klient.ListWorkspaceTemplates(ctx)
if err != nil {
return nil, ErrResponse(log, err)
}

if req.Msg.UseRoleFilter != nil && *req.Msg.UseRoleFilter {
tmpls = kosmo.FilterTemplates(ctx, tmpls, user)
}

addonTmpls := make([]*dashv1alpha1.Template, 0, len(tmpls))
for _, v := range tmpls {
addonTmpls = append(addonTmpls, convertTemplateToDashv1alpha1Template(v))
Expand All @@ -52,16 +56,20 @@ func (s *Server) GetWorkspaceTemplates(ctx context.Context, req *connect_go.Requ
return connect_go.NewResponse(res), nil
}

func (s *Server) GetUserAddonTemplates(ctx context.Context, req *connect_go.Request[emptypb.Empty]) (*connect_go.Response[dashv1alpha1.GetUserAddonTemplatesResponse], error) {
func (s *Server) GetUserAddonTemplates(ctx context.Context, req *connect_go.Request[dashv1alpha1.GetUserAddonTemplatesRequest]) (*connect_go.Response[dashv1alpha1.GetUserAddonTemplatesResponse], error) {
log := clog.FromContext(ctx).WithCaller()

user := callerFromContext(ctx)

tmpls, err := s.Klient.ListUserAddonTemplates(ctx, user)
tmpls, err := s.Klient.ListUserAddonTemplates(ctx)
if err != nil {
return nil, ErrResponse(log, err)
}

if req.Msg.UseRoleFilter != nil && *req.Msg.UseRoleFilter {
tmpls = kosmo.FilterTemplates(ctx, tmpls, user)
}

addonTmpls := make([]*dashv1alpha1.Template, len(tmpls))
for i, v := range tmpls {
tmpl := convertTemplateToDashv1alpha1Template(v)
Expand Down
53 changes: 30 additions & 23 deletions internal/dashboard/template_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,25 @@ import (
. "github.com/cosmo-workspace/cosmo/pkg/snap"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"google.golang.org/protobuf/types/known/emptypb"
"k8s.io/utils/pointer"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
dashboardv1alpha1 "github.com/cosmo-workspace/cosmo/proto/gen/dashboard/v1alpha1"
"github.com/cosmo-workspace/cosmo/proto/gen/dashboard/v1alpha1/dashboardv1alpha1connect"
)

var _ = Describe("Dashboard server [Template]", func() {

var (
userSession string
adminSession string
client dashboardv1alpha1connect.TemplateServiceClient
userSession string
roleUserSession string
adminSession string
client dashboardv1alpha1connect.TemplateServiceClient
)

BeforeEach(func() {
userSession = test_CreateLoginUserSession("normal-user", "お名前", nil, "password")
roleUserSession = test_CreateLoginUserSession("role-user", "お名前", []cosmov1alpha1.UserRole{{Name: "my-role"}}, "password")
adminSession = test_CreateLoginUserSession("admin-user", "アドミン", []cosmov1alpha1.UserRole{cosmov1alpha1.PrivilegedRole}, "password")
client = dashboardv1alpha1connect.NewTemplateServiceClient(http.DefaultClient, "http://localhost:8888")
})
Expand All @@ -37,18 +39,21 @@ var _ = Describe("Dashboard server [Template]", func() {

Describe("[GetWorkspaceTemplates]", func() {

run_test := func(loginUser string, testCase string) {
run_test := func(loginUser string, testCase string, req *dashboardv1alpha1.GetWorkspaceTemplatesRequest) {
if testCase == "not empty" {
testUtil.CreateTemplate(cosmov1alpha1.TemplateLabelEnumTypeWorkspace, "template1")
testUtil.CreateTemplate(cosmov1alpha1.TemplateLabelEnumTypeWorkspace, "template2")
testUtil.CreateTemplateForUserRole(cosmov1alpha1.TemplateLabelEnumTypeWorkspace, "template3", "my-role")
}
session := userSession
if loginUser == "admin-user" {
session = adminSession
} else if loginUser == "role-user" {
session = roleUserSession
}
By("---------------test start----------------")
ctx := context.Background()
res, err := client.GetWorkspaceTemplates(ctx, NewRequestWithSession(&emptypb.Empty{}, session))
res, err := client.GetWorkspaceTemplates(ctx, NewRequestWithSession(req, session))
if err == nil {
Ω(res.Msg).To(MatchSnapShot())
} else {
Expand All @@ -60,24 +65,26 @@ var _ = Describe("Dashboard server [Template]", func() {

DescribeTable("✅ success in normal context:",
run_test,
Entry(nil, "admin-user", "empty"),
Entry(nil, "admin-user", "not empty"),
Entry(nil, "normal-user", "empty"),
Entry(nil, "normal-user", "not empty"),
Entry(nil, "admin-user", "empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
Entry(nil, "admin-user", "not empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
Entry(nil, "normal-user", "empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
Entry(nil, "normal-user", "not empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
Entry(nil, "normal-user", "not empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{UseRoleFilter: pointer.Bool(true)}),
Entry(nil, "role-user", "not empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
)

DescribeTable("❌ fail with an unexpected error at list:",
func(user string, testCase string) {
func(user string, testCase string, req *dashboardv1alpha1.GetWorkspaceTemplatesRequest) {
clientMock.SetListError((*Server).GetWorkspaceTemplates, errors.New("template list error"))
run_test(user, testCase)
run_test(user, testCase, req)
},
Entry(nil, "admin-user", "not empty"),
Entry(nil, "admin-user", "not empty", &dashboardv1alpha1.GetWorkspaceTemplatesRequest{}),
)
})

Describe("[GetUserAddonTemplates]", func() {

run_test := func(loginUser string, testCase string) {
run_test := func(loginUser string, testCase string, req *dashboardv1alpha1.GetUserAddonTemplatesRequest) {
if testCase == "not empty" {
testUtil.CreateTemplate(cosmov1alpha1.TemplateLabelEnumTypeUserAddon, "useraddon1")
testUtil.CreateTemplate(cosmov1alpha1.TemplateLabelEnumTypeUserAddon, "useraddon2")
Expand All @@ -88,7 +95,7 @@ var _ = Describe("Dashboard server [Template]", func() {
}
By("---------------test start----------------")
ctx := context.Background()
res, err := client.GetUserAddonTemplates(ctx, NewRequestWithSession(&emptypb.Empty{}, session))
res, err := client.GetUserAddonTemplates(ctx, NewRequestWithSession(req, session))
if err == nil {
Ω(res.Msg).To(MatchSnapShot())
} else {
Expand All @@ -100,18 +107,18 @@ var _ = Describe("Dashboard server [Template]", func() {

DescribeTable("✅ success in normal context:",
run_test,
Entry(nil, "admin-user", "empty"),
Entry(nil, "admin-user", "not empty"),
Entry(nil, "normal-user", "empty"),
Entry(nil, "normal-user", "not empty"),
Entry(nil, "admin-user", "empty", &dashboardv1alpha1.GetUserAddonTemplatesRequest{}),
Entry(nil, "admin-user", "not empty", &dashboardv1alpha1.GetUserAddonTemplatesRequest{}),
Entry(nil, "normal-user", "empty", &dashboardv1alpha1.GetUserAddonTemplatesRequest{}),
Entry(nil, "normal-user", "not empty", &dashboardv1alpha1.GetUserAddonTemplatesRequest{}),
)

DescribeTable("❌ fail with an unexpected error at list:",
func(user string, testCase string) {
func(user string, testCase string, req *dashboardv1alpha1.GetUserAddonTemplatesRequest) {
clientMock.SetListError((*Server).GetUserAddonTemplates, errors.New("template list error"))
run_test(user, testCase)
run_test(user, testCase, req)
},
Entry(nil, "admin-user", "not empty"),
Entry(nil, "admin-user", "not empty", &dashboardv1alpha1.GetUserAddonTemplatesRequest{}),
)
})
})
Loading

0 comments on commit 365ea3d

Please sign in to comment.