Skip to content

Commit da4faf5

Browse files
authored
feat(policy): actions service RPCs should actually hit storage layer CRUD (#2063)
### Proposed Changes * roundtrip to db storage in actions service RPCs ### Checklist - [ ] I have added or updated unit tests - [ ] I have added or updated integration tests (if appropriate) - [ ] I have added or updated documentation ### Testing Instructions
1 parent 30d2a7e commit da4faf5

File tree

9 files changed

+127
-29
lines changed

9 files changed

+127
-29
lines changed

sdk/sdk.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/opentdf/platform/protocol/go/authorization"
1919
"github.com/opentdf/platform/protocol/go/entityresolution"
2020
"github.com/opentdf/platform/protocol/go/policy"
21+
"github.com/opentdf/platform/protocol/go/policy/actions"
2122
"github.com/opentdf/platform/protocol/go/policy/attributes"
2223
"github.com/opentdf/platform/protocol/go/policy/kasregistry"
2324
"github.com/opentdf/platform/protocol/go/policy/namespaces"
@@ -63,14 +64,15 @@ type SDK struct {
6364
conn *grpc.ClientConn
6465
dialOptions []grpc.DialOption
6566
tokenSource auth.AccessTokenSource
66-
Namespaces namespaces.NamespaceServiceClient
67+
Actions actions.ActionServiceClient
6768
Attributes attributes.AttributesServiceClient
69+
Authorization authorization.AuthorizationServiceClient
70+
EntityResoution entityresolution.EntityResolutionServiceClient
71+
KeyAccessServerRegistry kasregistry.KeyAccessServerRegistryServiceClient
72+
Namespaces namespaces.NamespaceServiceClient
6873
ResourceMapping resourcemapping.ResourceMappingServiceClient
6974
SubjectMapping subjectmapping.SubjectMappingServiceClient
70-
KeyAccessServerRegistry kasregistry.KeyAccessServerRegistryServiceClient
7175
Unsafe unsafe.UnsafeServiceClient
72-
Authorization authorization.AuthorizationServiceClient
73-
EntityResoution entityresolution.EntityResolutionServiceClient
7476
wellknownConfiguration wellknownconfiguration.WellKnownServiceClient
7577
}
7678

@@ -193,6 +195,7 @@ func New(platformEndpoint string, opts ...Option) (*SDK, error) {
193195
conn: platformConn,
194196
dialOptions: dialOptions,
195197
tokenSource: accessTokenSource,
198+
Actions: actions.NewActionServiceClient(platformConn),
196199
Attributes: attributes.NewAttributesServiceClient(platformConn),
197200
Namespaces: namespaces.NewNamespaceServiceClient(platformConn),
198201
ResourceMapping: resourcemapping.NewResourceMappingServiceClient(platformConn),

service/logger/audit/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const (
2121
ObjectTypeEntityObject
2222
ObjectTypeResourceMappingGroup
2323
ObjectTypePublicKey
24+
ObjectTypeAction
2425
)
2526

2627
func (ot ObjectType) String() string {
@@ -38,6 +39,8 @@ func (ot ObjectType) String() string {
3839
"key_object",
3940
"entity_object",
4041
"resource_mapping_group",
42+
"public_key",
43+
"action",
4144
}[ot]
4245
}
4346

service/pkg/server/services_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ type mockTestServiceOptions struct {
2626
dbRegister serviceregistry.DBRegister
2727
}
2828

29+
const numExpectedPolicyServices = 7
30+
2931
func mockTestServiceRegistry(opts mockTestServiceOptions) (serviceregistry.IService, *spyTestService) {
3032
spy := &spyTestService{}
3133
mockTestServiceDefaults := mockTestServiceOptions{
@@ -112,7 +114,7 @@ func (suite *ServiceTestSuite) Test_RegisterCoreServices_In_Mode_ALL_Expect_All_
112114

113115
policy, err := registry.GetNamespace(servicePolicy)
114116
suite.Require().NoError(err)
115-
suite.Len(policy.Services, 6)
117+
suite.Len(policy.Services, numExpectedPolicyServices)
116118
suite.Equal(modeCore, policy.Mode)
117119

118120
wellKnown, err := registry.GetNamespace(serviceWellKnown)
@@ -143,7 +145,7 @@ func (suite *ServiceTestSuite) Test_RegisterCoreServices_In_Mode_Core_Expect_Cor
143145

144146
policy, err := registry.GetNamespace(servicePolicy)
145147
suite.Require().NoError(err)
146-
suite.Len(policy.Services, 6)
148+
suite.Len(policy.Services, numExpectedPolicyServices)
147149
suite.Equal(modeCore, policy.Mode)
148150

149151
wellKnown, err := registry.GetNamespace(serviceWellKnown)
@@ -170,7 +172,7 @@ func (suite *ServiceTestSuite) Test_RegisterServices_In_Mode_Core_Plus_Kas_Expec
170172

171173
policy, err := registry.GetNamespace(servicePolicy)
172174
suite.Require().NoError(err)
173-
suite.Len(policy.Services, 6)
175+
suite.Len(policy.Services, numExpectedPolicyServices)
174176
suite.Equal(modeCore, policy.Mode)
175177

176178
wellKnown, err := registry.GetNamespace(serviceWellKnown)
@@ -197,7 +199,7 @@ func (suite *ServiceTestSuite) Test_RegisterServices_In_Mode_Core_Plus_Kas_Expec
197199

198200
policy, err := registry.GetNamespace(servicePolicy)
199201
suite.Require().NoError(err)
200-
suite.Len(policy.Services, 6)
202+
suite.Len(policy.Services, numExpectedPolicyServices)
201203
suite.Equal(modeCore, policy.Mode)
202204

203205
wellKnown, err := registry.GetNamespace(serviceWellKnown)

service/policy/actions/actions.go

Lines changed: 108 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ package actions
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"log/slog"
87

98
"connectrpc.com/connect"
109
"github.com/opentdf/platform/protocol/go/policy/actions"
1110
"github.com/opentdf/platform/protocol/go/policy/actions/actionsconnect"
1211
"github.com/opentdf/platform/service/logger"
12+
"github.com/opentdf/platform/service/logger/audit"
1313
"github.com/opentdf/platform/service/pkg/config"
14+
"github.com/opentdf/platform/service/pkg/db"
1415
"github.com/opentdf/platform/service/pkg/serviceregistry"
1516

1617
policyconfig "github.com/opentdf/platform/service/policy/config"
@@ -78,22 +79,118 @@ func NewRegistration(ns string, dbRegister serviceregistry.DBRegister) *servicer
7879
}
7980
}
8081

81-
func (a *ActionService) GetAction(context.Context, *connect.Request[actions.GetActionRequest]) (*connect.Response[actions.GetActionResponse], error) {
82-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("GetAction is not implemented"))
82+
func (a *ActionService) GetAction(ctx context.Context, req *connect.Request[actions.GetActionRequest]) (*connect.Response[actions.GetActionResponse], error) {
83+
rsp := &actions.GetActionResponse{}
84+
85+
a.logger.DebugContext(ctx, "getting action", slog.Any("identifier", req.Msg.GetIdentifier()))
86+
87+
action, err := a.dbClient.GetAction(ctx, req.Msg)
88+
if err != nil {
89+
return nil, db.StatusifyError(err, db.ErrTextGetRetrievalFailed, slog.Any("identifier", req.Msg.GetIdentifier()))
90+
}
91+
rsp.Action = action
92+
93+
return connect.NewResponse(rsp), nil
8394
}
8495

85-
func (a *ActionService) ListActions(context.Context, *connect.Request[actions.ListActionsRequest]) (*connect.Response[actions.ListActionsResponse], error) {
86-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("ListActions is not implemented"))
96+
func (a *ActionService) ListActions(ctx context.Context, req *connect.Request[actions.ListActionsRequest]) (*connect.Response[actions.ListActionsResponse], error) {
97+
a.logger.DebugContext(ctx, "listing actions")
98+
rsp, err := a.dbClient.ListActions(ctx, req.Msg)
99+
if err != nil {
100+
return nil, db.StatusifyError(err, db.ErrTextListRetrievalFailed)
101+
}
102+
a.logger.DebugContext(ctx, "listed actions")
103+
return connect.NewResponse(rsp), nil
87104
}
88105

89-
func (a *ActionService) CreateAction(context.Context, *connect.Request[actions.CreateActionRequest]) (*connect.Response[actions.CreateActionResponse], error) {
90-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("CreateAction is not implemented"))
106+
func (a *ActionService) CreateAction(ctx context.Context, req *connect.Request[actions.CreateActionRequest]) (*connect.Response[actions.CreateActionResponse], error) {
107+
a.logger.DebugContext(ctx, "creating action", slog.String("name", req.Msg.GetName()))
108+
auditParams := audit.PolicyEventParams{
109+
ActionType: audit.ActionTypeCreate,
110+
ObjectType: audit.ObjectTypeAction,
111+
}
112+
rsp := &actions.CreateActionResponse{}
113+
114+
err := a.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error {
115+
action, err := txClient.CreateAction(ctx, req.Msg)
116+
if err != nil {
117+
return err
118+
}
119+
120+
auditParams.ObjectID = action.GetId()
121+
auditParams.Original = action
122+
a.logger.Audit.PolicyCRUDSuccess(ctx, auditParams)
123+
124+
rsp.Action = action
125+
return nil
126+
})
127+
if err != nil {
128+
a.logger.Audit.PolicyCRUDFailure(ctx, auditParams)
129+
return nil, db.StatusifyError(err, db.ErrTextCreationFailed, slog.String("action", req.Msg.String()))
130+
}
131+
return connect.NewResponse(rsp), nil
91132
}
92133

93-
func (a *ActionService) UpdateAction(context.Context, *connect.Request[actions.UpdateActionRequest]) (*connect.Response[actions.UpdateActionResponse], error) {
94-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("UpdateAction is not implemented"))
134+
func (a *ActionService) UpdateAction(ctx context.Context, req *connect.Request[actions.UpdateActionRequest]) (*connect.Response[actions.UpdateActionResponse], error) {
135+
actionID := req.Msg.GetId()
136+
a.logger.DebugContext(ctx, "updating action", slog.String("id", actionID))
137+
rsp := &actions.UpdateActionResponse{}
138+
139+
auditParams := audit.PolicyEventParams{
140+
ActionType: audit.ActionTypeUpdate,
141+
ObjectType: audit.ObjectTypeAction,
142+
ObjectID: actionID,
143+
}
144+
145+
err := a.dbClient.RunInTx(ctx, func(txClient *policydb.PolicyDBClient) error {
146+
original, err := txClient.GetAction(ctx, &actions.GetActionRequest{
147+
Identifier: &actions.GetActionRequest_Id{
148+
Id: actionID,
149+
},
150+
})
151+
if err != nil {
152+
return err
153+
}
154+
155+
updated, err := txClient.UpdateAction(ctx, req.Msg)
156+
if err != nil {
157+
return err
158+
}
159+
160+
auditParams.Original = original
161+
auditParams.Updated = updated
162+
a.logger.Audit.PolicyCRUDSuccess(ctx, auditParams)
163+
164+
rsp.Action = updated
165+
return nil
166+
})
167+
if err != nil {
168+
a.logger.Audit.PolicyCRUDFailure(ctx, auditParams)
169+
return nil, db.StatusifyError(err, db.ErrTextUpdateFailed, slog.String("action", req.Msg.String()))
170+
}
171+
172+
return connect.NewResponse(rsp), nil
95173
}
96174

97-
func (a *ActionService) DeleteAction(context.Context, *connect.Request[actions.DeleteActionRequest]) (*connect.Response[actions.DeleteActionResponse], error) {
98-
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("DeleteAction is not implemented"))
175+
func (a *ActionService) DeleteAction(ctx context.Context, req *connect.Request[actions.DeleteActionRequest]) (*connect.Response[actions.DeleteActionResponse], error) {
176+
rsp := &actions.DeleteActionResponse{}
177+
actionID := req.Msg.GetId()
178+
179+
auditParams := audit.PolicyEventParams{
180+
ActionType: audit.ActionTypeDelete,
181+
ObjectType: audit.ObjectTypeAction,
182+
ObjectID: actionID,
183+
}
184+
a.logger.DebugContext(ctx, "deleting action", slog.String("id", actionID))
185+
186+
deleted, err := a.dbClient.DeleteAction(ctx, req.Msg)
187+
if err != nil {
188+
a.logger.Audit.PolicyCRUDFailure(ctx, auditParams)
189+
return nil, db.StatusifyError(err, db.ErrTextDeletionFailed, slog.String("action", req.Msg.String()))
190+
}
191+
192+
a.logger.Audit.PolicyCRUDSuccess(ctx, auditParams)
193+
rsp.Action = deleted
194+
195+
return connect.NewResponse(rsp), nil
99196
}

service/policy/db/actions.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ func (c PolicyDBClient) DeleteAction(ctx context.Context, req *actions.DeleteAct
199199
}
200200
// standard action
201201
name := strings.ToLower(got.GetName())
202-
isStandard := ActionStandard(name).IsValid()
203-
if isStandard {
202+
if ActionStandard(name).IsValid() {
204203
return nil, fmt.Errorf("cannot delete standard action %s: %w", name, db.ErrRestrictViolation)
205204
}
206205
return nil, db.ErrNotFound

service/policy/db/query.sql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,6 @@ INSERT INTO attribute_value_public_key_map (value_id, key_id) VALUES ($1, $2);
12281228
-- name: removePublicKeyFromAttributeValue :execrows
12291229
DELETE FROM attribute_value_public_key_map WHERE value_id = $1 AND key_id = $2;
12301230

1231-
12321231
----------------------------------------------------------------
12331232
-- ACTIONS
12341233
----------------------------------------------------------------

service/policy/db/subject_mappings.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"fmt"
88
"strings"
99

10-
"github.com/jackc/pgerrcode"
11-
"github.com/jackc/pgx/v5"
1210
"github.com/opentdf/platform/protocol/go/common"
1311
"github.com/opentdf/platform/protocol/go/policy"
1412
"github.com/opentdf/platform/protocol/go/policy/subjectmapping"
@@ -508,10 +506,6 @@ func (c PolicyDBClient) UpdateSubjectMapping(ctx context.Context, r *subjectmapp
508506

509507
_, err = c.Queries.updateSubjectMapping(ctx, updateParams)
510508
if err != nil {
511-
// CTE behavior requires custom handling with divide by zero to detect 0 count
512-
if strings.Contains(err.Error(), pgerrcode.DivisionByZero) {
513-
err = pgx.ErrNoRows
514-
}
515509
return nil, db.WrapIfKnownInvalidQueryErr(err)
516510
}
517511

service/policy/namespaces/namespaces.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ func (ns NamespacesService) GetNamespace(ctx context.Context, req *connect.Reque
117117

118118
func (ns NamespacesService) CreateNamespace(ctx context.Context, req *connect.Request[namespaces.CreateNamespaceRequest]) (*connect.Response[namespaces.CreateNamespaceResponse], error) {
119119
ns.logger.Debug("creating new namespace", slog.String("name", req.Msg.GetName()))
120-
121120
auditParams := audit.PolicyEventParams{
122121
ActionType: audit.ActionTypeCreate,
123122
ObjectType: audit.ObjectTypeNamespace,

service/policy/policy.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"embed"
55

66
"github.com/opentdf/platform/service/pkg/serviceregistry"
7+
"github.com/opentdf/platform/service/policy/actions"
78
"github.com/opentdf/platform/service/policy/attributes"
89
"github.com/opentdf/platform/service/policy/db/migrations"
910
"github.com/opentdf/platform/service/policy/kasregistry"
@@ -34,6 +35,7 @@ func NewRegistrations() []serviceregistry.IService {
3435
subjectmapping.NewRegistration(namespace, dbRegister),
3536
kasregistry.NewRegistration(namespace, dbRegister),
3637
unsafe.NewRegistration(namespace, dbRegister),
38+
actions.NewRegistration(namespace, dbRegister),
3739
}...)
3840
return registrations
3941
}

0 commit comments

Comments
 (0)