Skip to content

Commit 00afe19

Browse files
authored
feat: Inspect policies in the store (#47)
To prevent name conflicts between function names of the `type InspectPoliciesOption func(*requestv1.InspectPoliciesRequest)` and `type ListPoliciesOption func(*requestv1.ListPoliciesRequest)`, I prefixed the formers' function names with `InspectPoliciesWith`. I am not sure if this is a good idea or not. --------- Signed-off-by: Oğuzhan Durgun <[email protected]>
1 parent 17291e4 commit 00afe19

File tree

6 files changed

+147
-25
lines changed

6 files changed

+147
-25
lines changed

cerbos/client.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88

99
policyv1 "github.com/cerbos/cerbos/api/genpb/cerbos/policy/v1"
10+
responsev1 "github.com/cerbos/cerbos/api/genpb/cerbos/response/v1"
1011
schemav1 "github.com/cerbos/cerbos/api/genpb/cerbos/schema/v1"
1112
)
1213

@@ -43,7 +44,8 @@ type PrincipalContext interface {
4344
type AdminClient interface {
4445
AddOrUpdatePolicy(ctx context.Context, policies *PolicySet) error
4546
AuditLogs(ctx context.Context, opts AuditLogOptions) (<-chan *AuditLogEntry, error)
46-
ListPolicies(ctx context.Context, opts ...ListPoliciesOption) ([]string, error)
47+
ListPolicies(ctx context.Context, opts ...FilterOption) ([]string, error)
48+
InspectPolicies(ctx context.Context, opts ...FilterOption) (*responsev1.InspectPoliciesResponse, error)
4749
GetPolicy(ctx context.Context, ids ...string) ([]*policyv1.Policy, error)
4850
DisablePolicy(ctx context.Context, ids ...string) (uint32, error)
4951
EnablePolicy(ctx context.Context, ids ...string) (uint32, error)

cerbos/grpc_admin.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,16 @@ func (c *GRPCAdminClient) auditLogs(ctx context.Context, opts AuditLogOptions) (
170170
return resp, nil
171171
}
172172

173-
func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...ListPoliciesOption) ([]string, error) {
174-
req := &requestv1.ListPoliciesRequest{}
173+
func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...FilterOption) ([]string, error) {
174+
options := &FilterOptions{}
175175
for _, opt := range opts {
176-
opt(req)
176+
opt(options)
177+
}
178+
req := &requestv1.ListPoliciesRequest{
179+
IncludeDisabled: options.IncludeDisabled,
180+
NameRegexp: options.NameRegexp,
181+
ScopeRegexp: options.ScopeRegexp,
182+
VersionRegexp: options.VersionRegexp,
177183
}
178184
if err := internal.Validate(req); err != nil {
179185
return nil, fmt.Errorf("could not validate list policies request: %w", err)
@@ -187,6 +193,29 @@ func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...ListPolicies
187193
return p.PolicyIds, nil
188194
}
189195

196+
func (c *GRPCAdminClient) InspectPolicies(ctx context.Context, opts ...FilterOption) (*responsev1.InspectPoliciesResponse, error) {
197+
options := &FilterOptions{}
198+
for _, opt := range opts {
199+
opt(options)
200+
}
201+
req := &requestv1.InspectPoliciesRequest{
202+
IncludeDisabled: options.IncludeDisabled,
203+
NameRegexp: options.NameRegexp,
204+
ScopeRegexp: options.ScopeRegexp,
205+
VersionRegexp: options.VersionRegexp,
206+
}
207+
if err := internal.Validate(req); err != nil {
208+
return nil, fmt.Errorf("could not validate get inspect policies request: %w", err)
209+
}
210+
211+
resp, err := c.client.InspectPolicies(metadata.AppendToOutgoingContext(ctx, c.headers...), req, grpc.PerRPCCredentials(c.creds))
212+
if err != nil {
213+
return nil, fmt.Errorf("could not inspect policies: %w", err)
214+
}
215+
216+
return resp, nil
217+
}
218+
190219
func (c *GRPCAdminClient) GetPolicy(ctx context.Context, ids ...string) ([]*policyv1.Policy, error) {
191220
req := &requestv1.GetPolicyRequest{
192221
Id: ids,

cerbos/grpc_admin_test.go

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func TestAdminClient(t *testing.T) {
161161
t.Run("ListPolicies", func(t *testing.T) {
162162
testCases := []struct {
163163
name string
164-
options []ListPoliciesOption
164+
options []FilterOption
165165
want map[string]string
166166
}{
167167
{
@@ -170,7 +170,7 @@ func TestAdminClient(t *testing.T) {
170170
},
171171
{
172172
name: "NameRegexp",
173-
options: []ListPoliciesOption{WithNameRegexp("leave_req")},
173+
options: []FilterOption{WithNameRegexp("leave_req")},
174174
want: map[string]string{
175175
"resource.leave_request.v20210210": "",
176176
"resource.leave_request.vdefault": "",
@@ -181,7 +181,7 @@ func TestAdminClient(t *testing.T) {
181181
},
182182
{
183183
name: "ScopeRegexp",
184-
options: []ListPoliciesOption{WithScopeRegexp("acme")},
184+
options: []FilterOption{WithScopeRegexp("acme")},
185185
want: map[string]string{
186186
"principal.donald_duck.vdefault/acme": "",
187187
"principal.donald_duck.vdefault/acme.hr": "",
@@ -192,14 +192,14 @@ func TestAdminClient(t *testing.T) {
192192
},
193193
{
194194
name: "VersionRegexp",
195-
options: []ListPoliciesOption{WithVersionRegexp(`\d+`)},
195+
options: []FilterOption{WithVersionRegexp(`\d+`)},
196196
want: map[string]string{
197197
"resource.leave_request.v20210210": "",
198198
},
199199
},
200200
{
201201
name: "AllRegexp",
202-
options: []ListPoliciesOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
202+
options: []FilterOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
203203
want: map[string]string{
204204
"principal.donald_duck.vdefault": "",
205205
"principal.donald_duck.vdefault/acme": "",
@@ -225,6 +225,87 @@ func TestAdminClient(t *testing.T) {
225225
}
226226
})
227227

228+
t.Run("InspectPolicies", func(t *testing.T) {
229+
testCases := []struct {
230+
name string
231+
options []FilterOption
232+
want map[string][]string
233+
}{
234+
{
235+
name: "NoFilter",
236+
want: map[string][]string{
237+
"principal.donald_duck.vdefault": {"*"},
238+
"principal.donald_duck.vdefault/acme": {"*"},
239+
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
240+
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
241+
"resource.leave_request.vdefault": {"*"},
242+
"resource.leave_request.vdefault/acme": {"create", "view:public"},
243+
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
244+
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
245+
},
246+
},
247+
{
248+
name: "NameRegexp",
249+
options: []FilterOption{WithNameRegexp("leave_req")},
250+
want: map[string][]string{
251+
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
252+
"resource.leave_request.vdefault": {"*"},
253+
"resource.leave_request.vdefault/acme": {"create", "view:public"},
254+
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
255+
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
256+
},
257+
},
258+
{
259+
name: "ScopeRegexp",
260+
options: []FilterOption{WithScopeRegexp("acme")},
261+
want: map[string][]string{
262+
"principal.donald_duck.vdefault/acme": {"*"},
263+
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
264+
"resource.leave_request.vdefault/acme": {"create", "view:public"},
265+
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
266+
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
267+
},
268+
},
269+
{
270+
name: "VersionRegexp",
271+
options: []FilterOption{WithVersionRegexp(`\d+`)},
272+
want: map[string][]string{
273+
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
274+
},
275+
},
276+
{
277+
name: "AllRegexp",
278+
options: []FilterOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
279+
want: map[string][]string{
280+
"principal.donald_duck.vdefault": {"*"},
281+
"principal.donald_duck.vdefault/acme": {"*"},
282+
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
283+
"resource.leave_request.vdefault": {"*"},
284+
"resource.leave_request.vdefault/acme": {"create", "view:public"},
285+
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
286+
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
287+
},
288+
},
289+
}
290+
291+
for _, tc := range testCases {
292+
tc := tc
293+
t.Run(tc.name, func(t *testing.T) {
294+
have, err := ac.InspectPolicies(context.Background(), tc.options...)
295+
require.NoError(t, err)
296+
require.NotNil(t, have)
297+
require.NotNil(t, have.Results)
298+
for fqn, actions := range tc.want {
299+
t.Run(fqn, func(t *testing.T) {
300+
require.NotNil(t, have.Results[fqn])
301+
require.Len(t, have.Results[fqn].Actions, len(actions))
302+
require.ElementsMatch(t, have.Results[fqn].Actions, actions)
303+
})
304+
}
305+
})
306+
}
307+
})
308+
228309
t.Run("AddOrUpdateSchema", func(t *testing.T) {
229310
ss := NewSchemaSet()
230311
for k, s := range schemas {

cerbos/model.go

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,29 +1212,39 @@ type PlanResourcesResponse struct {
12121212
}
12131213

12141214
type (
1215-
ListPoliciesOption func(*requestv1.ListPoliciesRequest)
1215+
FilterOptions struct {
1216+
NameRegexp string
1217+
ScopeRegexp string
1218+
VersionRegexp string
1219+
IncludeDisabled bool
1220+
}
1221+
// FilterOption allows filtering policies while calling InspectPolicies and ListPolicies.
1222+
FilterOption func(*FilterOptions)
1223+
// ListPoliciesOption allows filtering policies while calling ListPolicies
1224+
// Deprecated: ListPoliciesOption is deprecated, use FilterOption instead.
1225+
ListPoliciesOption = FilterOption
12161226
)
12171227

1218-
func WithIncludeDisabled() ListPoliciesOption {
1219-
return func(request *requestv1.ListPoliciesRequest) {
1220-
request.IncludeDisabled = true
1228+
func WithIncludeDisabled() FilterOption {
1229+
return func(fo *FilterOptions) {
1230+
fo.IncludeDisabled = true
12211231
}
12221232
}
12231233

1224-
func WithNameRegexp(re string) ListPoliciesOption {
1225-
return func(request *requestv1.ListPoliciesRequest) {
1226-
request.NameRegexp = re
1234+
func WithNameRegexp(re string) FilterOption {
1235+
return func(fo *FilterOptions) {
1236+
fo.NameRegexp = re
12271237
}
12281238
}
12291239

1230-
func WithScopeRegexp(re string) ListPoliciesOption {
1231-
return func(request *requestv1.ListPoliciesRequest) {
1232-
request.ScopeRegexp = re
1240+
func WithScopeRegexp(re string) FilterOption {
1241+
return func(fo *FilterOptions) {
1242+
fo.ScopeRegexp = re
12331243
}
12341244
}
12351245

1236-
func WithVersionRegexp(v string) ListPoliciesOption {
1237-
return func(request *requestv1.ListPoliciesRequest) {
1238-
request.VersionRegexp = v
1246+
func WithVersionRegexp(v string) FilterOption {
1247+
return func(fo *FilterOptions) {
1248+
fo.VersionRegexp = v
12391249
}
12401250
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.20
55
require (
66
github.com/bufbuild/protovalidate-go v0.6.1
77
github.com/cenkalti/backoff/v4 v4.3.0
8-
github.com/cerbos/cerbos/api/genpb v0.34.0
8+
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f
99
github.com/ghodss/yaml v1.0.0
1010
github.com/google/go-cmp v0.6.0
1111
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ github.com/bufbuild/protovalidate-go v0.6.1 h1:uzW8r0CDvqApUChNj87VzZVoQSKhcVdw5
1212
github.com/bufbuild/protovalidate-go v0.6.1/go.mod h1:4BR3rKEJiUiTy+sqsusFn2ladOf0kYmA2Reo6BHSBgQ=
1313
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
1414
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
15-
github.com/cerbos/cerbos/api/genpb v0.34.0 h1:HY8k9HVHv000EKU61KrhAia5TmjW4sX2AXNee4I+DZg=
16-
github.com/cerbos/cerbos/api/genpb v0.34.0/go.mod h1:KEUMaRkMsCvEcOI8aptMFscKh6H2bfWgjjjSmRWKg8g=
15+
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f h1:2QY32KPwny2zJCE7fWBdarci+r6hwYeVeHp7xK/BYq8=
16+
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f/go.mod h1:DcozdAIUztxXwtVs88gGgdyCITru7WCTF9vGA6j+H8k=
1717
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
1818
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
1919
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=

0 commit comments

Comments
 (0)