-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add build_schema function * feat: add function to build policy definiton * chore: add namespace to roles * chore: add subtype to roles * chore: add actions table * chore: add namespaces table * chore: add support for multiple role types * feat: add build_schema function * feat: add function to build policy definiton * chore: add namespace to roles * chore: add subtype to roles * chore: add actions table * chore: add namespaces table * chore: add support for multiple role types * fix: googleapis/go-genproto#700 * refactor: move schema models to model package * chore: add policies table * refactor: change schema generator Policy to model.Policy * refactor: change struct keys to lowercase * chore: add namespace_id to roles and actions remove slug from actions and namepaces * refactor: remove slug from namespace and actions add namespaceId to roles and actions * chore: add check for action namespace in schema generation * chore: namespace_id to actions and roles struct * fix: create roles api db error * chore: add list policies api * chore: register policy service * chore: add create policy api * chore: add get policy api * chore: add update policy api * chore: add schema generator to create and update policy * chore: add spicedb config and setup in docker-compose * chore: add authz package to connect to spicedb * chore: add authz AddPolicy Method * refactor: fix lint issues * chore: add hook to push schema to spicedb on Create and Update Policy * chore: add namespace field to roles response * feat: add namespace apis * feat: add actions crud apis * feat: add polices crud apis * fix: go import lint issues * chore: update proto path for shield apis * chore: add shield apis proto generated files * fix: lint issues * fix: policy tests issue * fix: schema generator tests issue * fix: sort definitions to fix Schema generator tests issue * fix: sort roles and actions to fix tests * chore: update shield proto path * chore: cleanup unused code and logs * chore: pass context to AddPolicy * chore: fix typo and update polices query to take argument * chore(policy): Add Update method for action and namespace
- Loading branch information
Showing
37 changed files
with
7,390 additions
and
294 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package v1 | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
grpczap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" | ||
"github.com/odpf/shield/internal/schema" | ||
"github.com/odpf/shield/model" | ||
shieldv1 "github.com/odpf/shield/proto/v1" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"google.golang.org/protobuf/types/known/timestamppb" | ||
) | ||
|
||
type ActionService interface { | ||
GetAction(ctx context.Context, id string) (model.Action, error) | ||
ListActions(ctx context.Context) ([]model.Action, error) | ||
CreateAction(ctx context.Context, action model.Action) (model.Action, error) | ||
UpdateAction(ctx context.Context, id string, action model.Action) (model.Action, error) | ||
} | ||
|
||
var grpcActionNotFoundErr = status.Errorf(codes.NotFound, "action doesn't exist") | ||
|
||
func (v Dep) ListActions(ctx context.Context, request *shieldv1.ListActionsRequest) (*shieldv1.ListActionsResponse, error) { | ||
logger := grpczap.Extract(ctx) | ||
var actions []*shieldv1.Action | ||
|
||
actionsList, err := v.ActionService.ListActions(ctx) | ||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
for _, act := range actionsList { | ||
actPB, err := transformActionToPB(act) | ||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
actions = append(actions, &actPB) | ||
} | ||
|
||
return &shieldv1.ListActionsResponse{Actions: actions}, nil | ||
} | ||
|
||
func (v Dep) CreateAction(ctx context.Context, request *shieldv1.CreateActionRequest) (*shieldv1.CreateActionResponse, error) { | ||
logger := grpczap.Extract(ctx) | ||
|
||
newAction, err := v.ActionService.CreateAction(ctx, model.Action{ | ||
Id: request.GetBody().Id, | ||
Name: request.GetBody().Name, | ||
NamespaceId: request.GetBody().NamespaceId, | ||
}) | ||
|
||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
actionPB, err := transformActionToPB(newAction) | ||
|
||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
return &shieldv1.CreateActionResponse{Action: &actionPB}, nil | ||
} | ||
|
||
func (v Dep) GetAction(ctx context.Context, request *shieldv1.GetActionRequest) (*shieldv1.GetActionResponse, error) { | ||
logger := grpczap.Extract(ctx) | ||
|
||
fetchedAction, err := v.ActionService.GetAction(ctx, request.GetId()) | ||
if err != nil { | ||
logger.Error(err.Error()) | ||
switch { | ||
case errors.Is(err, schema.ActionDoesntExist): | ||
return nil, grpcActionNotFoundErr | ||
case errors.Is(err, schema.InvalidUUID): | ||
return nil, grpcBadBodyError | ||
default: | ||
return nil, grpcInternalServerError | ||
} | ||
} | ||
|
||
actionPB, err := transformActionToPB(fetchedAction) | ||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
return &shieldv1.GetActionResponse{Action: &actionPB}, nil | ||
} | ||
|
||
func (v Dep) UpdateAction(ctx context.Context, request *shieldv1.UpdateActionRequest) (*shieldv1.UpdateActionResponse, error) { | ||
logger := grpczap.Extract(ctx) | ||
|
||
updatedAction, err := v.ActionService.UpdateAction(ctx, request.GetId(), model.Action{ | ||
Id: request.GetId(), | ||
Name: request.GetBody().Name, | ||
NamespaceId: request.GetBody().NamespaceId, | ||
}) | ||
|
||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
actionPB, err := transformActionToPB(updatedAction) | ||
if err != nil { | ||
logger.Error(err.Error()) | ||
return nil, grpcInternalServerError | ||
} | ||
|
||
return &shieldv1.UpdateActionResponse{Action: &actionPB}, nil | ||
} | ||
|
||
func transformActionToPB(act model.Action) (shieldv1.Action, error) { | ||
namespace, err := transformNamespaceToPB(act.Namespace) | ||
if err != nil { | ||
return shieldv1.Action{}, err | ||
} | ||
return shieldv1.Action{ | ||
Id: act.Id, | ||
Name: act.Name, | ||
Namespace: &namespace, | ||
CreatedAt: timestamppb.New(act.CreatedAt), | ||
UpdatedAt: timestamppb.New(act.UpdatedAt), | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
package v1 | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"sort" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"github.com/odpf/shield/model" | ||
shieldv1 "github.com/odpf/shield/proto/v1" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
"google.golang.org/protobuf/types/known/timestamppb" | ||
) | ||
|
||
var testActionMap = map[string]model.Action{ | ||
"read": { | ||
Id: "read", | ||
Name: "Read", | ||
Namespace: model.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
"write": { | ||
Id: "write", | ||
Name: "Write", | ||
Namespace: model.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
"manage": { | ||
Id: "manage", | ||
Name: "Manage", | ||
Namespace: model.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
CreatedAt: time.Time{}, | ||
UpdatedAt: time.Time{}, | ||
}, | ||
} | ||
|
||
func TestListActions(t *testing.T) { | ||
t.Parallel() | ||
table := []struct { | ||
title string | ||
mockActionSrc mockActionSrv | ||
req *shieldv1.ListActionsRequest | ||
want *shieldv1.ListActionsResponse | ||
err error | ||
}{ | ||
{ | ||
title: "error in Action Service", | ||
mockActionSrc: mockActionSrv{ListActionsFunc: func(ctx context.Context) (actions []model.Action, err error) { | ||
return []model.Action{}, errors.New("some error") | ||
}}, | ||
want: nil, | ||
err: status.Errorf(codes.Internal, internalServerError.Error()), | ||
}, | ||
{ | ||
title: "success", | ||
mockActionSrc: mockActionSrv{ListActionsFunc: func(ctx context.Context) (actions []model.Action, err error) { | ||
var testActionList []model.Action | ||
for _, act := range testActionMap { | ||
testActionList = append(testActionList, act) | ||
} | ||
|
||
sort.Slice(testActionList[:], func(i, j int) bool { | ||
return strings.Compare(testActionList[i].Id, testActionList[j].Id) < 1 | ||
}) | ||
return testActionList, nil | ||
}}, | ||
want: &shieldv1.ListActionsResponse{Actions: []*shieldv1.Action{ | ||
{ | ||
Id: "manage", | ||
Name: "Manage", | ||
Namespace: &shieldv1.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
{ | ||
Id: "read", | ||
Name: "Read", | ||
Namespace: &shieldv1.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
{ | ||
Id: "write", | ||
Name: "Write", | ||
Namespace: &shieldv1.Namespace{ | ||
Id: "resource-1", | ||
Name: "Resource 1", | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
}}, | ||
err: nil, | ||
}, | ||
} | ||
|
||
for _, tt := range table { | ||
t.Run(tt.title, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
mockDep := Dep{ActionService: tt.mockActionSrc} | ||
resp, err := mockDep.ListActions(context.Background(), tt.req) | ||
|
||
assert.EqualValues(t, tt.want, resp) | ||
assert.EqualValues(t, tt.err, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestCreateAction(t *testing.T) { | ||
t.Parallel() | ||
|
||
table := []struct { | ||
title string | ||
mockActionSrv mockActionSrv | ||
req *shieldv1.CreateActionRequest | ||
want *shieldv1.CreateActionResponse | ||
err error | ||
}{ | ||
{ | ||
title: "error in creating action", | ||
mockActionSrv: mockActionSrv{CreateActionFunc: func(ctx context.Context, act model.Action) (model.Action, error) { | ||
return model.Action{}, errors.New("some error") | ||
}}, | ||
req: &shieldv1.CreateActionRequest{Body: &shieldv1.ActionRequestBody{ | ||
Id: "read", | ||
Name: "Read", | ||
NamespaceId: "team", | ||
}}, | ||
want: nil, | ||
err: grpcInternalServerError, | ||
}, | ||
{ | ||
title: "success", | ||
mockActionSrv: mockActionSrv{CreateActionFunc: func(ctx context.Context, act model.Action) (model.Action, error) { | ||
return model.Action{ | ||
Id: "read", | ||
Name: "Read", | ||
Namespace: model.Namespace{ | ||
Id: "team", | ||
Name: "Team", | ||
}, | ||
}, nil | ||
}}, | ||
req: &shieldv1.CreateActionRequest{Body: &shieldv1.ActionRequestBody{ | ||
Id: "read", | ||
Name: "Read", | ||
NamespaceId: "team", | ||
}}, | ||
want: &shieldv1.CreateActionResponse{Action: &shieldv1.Action{ | ||
Id: "read", | ||
Name: "Read", | ||
Namespace: &shieldv1.Namespace{ | ||
Id: "team", | ||
Name: "Team", | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}, | ||
CreatedAt: timestamppb.New(time.Time{}), | ||
UpdatedAt: timestamppb.New(time.Time{}), | ||
}}, | ||
err: nil, | ||
}, | ||
} | ||
|
||
for _, tt := range table { | ||
t.Run(tt.title, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
mockDep := Dep{ActionService: tt.mockActionSrv} | ||
resp, err := mockDep.CreateAction(context.Background(), tt.req) | ||
assert.EqualValues(t, tt.want, resp) | ||
assert.EqualValues(t, tt.err, err) | ||
}) | ||
} | ||
} | ||
|
||
type mockActionSrv struct { | ||
GetActionFunc func(ctx context.Context, id string) (model.Action, error) | ||
CreateActionFunc func(ctx context.Context, act model.Action) (model.Action, error) | ||
ListActionsFunc func(ctx context.Context) ([]model.Action, error) | ||
UpdateActionFunc func(ctx context.Context, id string, act model.Action) (model.Action, error) | ||
} | ||
|
||
func (m mockActionSrv) GetAction(ctx context.Context, id string) (model.Action, error) { | ||
return m.GetActionFunc(ctx, id) | ||
} | ||
|
||
func (m mockActionSrv) ListActions(ctx context.Context) ([]model.Action, error) { | ||
return m.ListActionsFunc(ctx) | ||
} | ||
|
||
func (m mockActionSrv) CreateAction(ctx context.Context, act model.Action) (model.Action, error) { | ||
return m.CreateActionFunc(ctx, act) | ||
} | ||
|
||
func (m mockActionSrv) UpdateAction(ctx context.Context, id string, act model.Action) (model.Action, error) { | ||
return m.UpdateActionFunc(ctx, id, act) | ||
} |
Oops, something went wrong.