Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Inspect policies in the store #47

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cerbos/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"

policyv1 "github.com/cerbos/cerbos/api/genpb/cerbos/policy/v1"
responsev1 "github.com/cerbos/cerbos/api/genpb/cerbos/response/v1"
schemav1 "github.com/cerbos/cerbos/api/genpb/cerbos/schema/v1"
)

Expand Down Expand Up @@ -43,7 +44,8 @@ type PrincipalContext interface {
type AdminClient interface {
AddOrUpdatePolicy(ctx context.Context, policies *PolicySet) error
AuditLogs(ctx context.Context, opts AuditLogOptions) (<-chan *AuditLogEntry, error)
ListPolicies(ctx context.Context, opts ...ListPoliciesOption) ([]string, error)
ListPolicies(ctx context.Context, opts ...FilterOption) ([]string, error)
InspectPolicies(ctx context.Context, opts ...FilterOption) (*responsev1.InspectPoliciesResponse, error)
GetPolicy(ctx context.Context, ids ...string) ([]*policyv1.Policy, error)
DisablePolicy(ctx context.Context, ids ...string) (uint32, error)
EnablePolicy(ctx context.Context, ids ...string) (uint32, error)
Expand Down
35 changes: 32 additions & 3 deletions cerbos/grpc_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,16 @@ func (c *GRPCAdminClient) auditLogs(ctx context.Context, opts AuditLogOptions) (
return resp, nil
}

func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...ListPoliciesOption) ([]string, error) {
req := &requestv1.ListPoliciesRequest{}
func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...FilterOption) ([]string, error) {
options := &FilterOptions{}
for _, opt := range opts {
opt(req)
opt(options)
}
req := &requestv1.ListPoliciesRequest{
IncludeDisabled: options.IncludeDisabled,
NameRegexp: options.NameRegexp,
ScopeRegexp: options.ScopeRegexp,
VersionRegexp: options.VersionRegexp,
}
if err := internal.Validate(req); err != nil {
return nil, fmt.Errorf("could not validate list policies request: %w", err)
Expand All @@ -187,6 +193,29 @@ func (c *GRPCAdminClient) ListPolicies(ctx context.Context, opts ...ListPolicies
return p.PolicyIds, nil
}

func (c *GRPCAdminClient) InspectPolicies(ctx context.Context, opts ...FilterOption) (*responsev1.InspectPoliciesResponse, error) {
options := &FilterOptions{}
for _, opt := range opts {
opt(options)
}
req := &requestv1.InspectPoliciesRequest{
IncludeDisabled: options.IncludeDisabled,
NameRegexp: options.NameRegexp,
ScopeRegexp: options.ScopeRegexp,
VersionRegexp: options.VersionRegexp,
}
if err := internal.Validate(req); err != nil {
return nil, fmt.Errorf("could not validate get inspect policies request: %w", err)
}

resp, err := c.client.InspectPolicies(metadata.AppendToOutgoingContext(ctx, c.headers...), req, grpc.PerRPCCredentials(c.creds))
if err != nil {
return nil, fmt.Errorf("could not inspect policies: %w", err)
}

return resp, nil
}

func (c *GRPCAdminClient) GetPolicy(ctx context.Context, ids ...string) ([]*policyv1.Policy, error) {
req := &requestv1.GetPolicyRequest{
Id: ids,
Expand Down
91 changes: 86 additions & 5 deletions cerbos/grpc_admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func TestAdminClient(t *testing.T) {
t.Run("ListPolicies", func(t *testing.T) {
testCases := []struct {
name string
options []ListPoliciesOption
options []FilterOption
want map[string]string
}{
{
Expand All @@ -170,7 +170,7 @@ func TestAdminClient(t *testing.T) {
},
{
name: "NameRegexp",
options: []ListPoliciesOption{WithNameRegexp("leave_req")},
options: []FilterOption{WithNameRegexp("leave_req")},
want: map[string]string{
"resource.leave_request.v20210210": "",
"resource.leave_request.vdefault": "",
Expand All @@ -181,7 +181,7 @@ func TestAdminClient(t *testing.T) {
},
{
name: "ScopeRegexp",
options: []ListPoliciesOption{WithScopeRegexp("acme")},
options: []FilterOption{WithScopeRegexp("acme")},
want: map[string]string{
"principal.donald_duck.vdefault/acme": "",
"principal.donald_duck.vdefault/acme.hr": "",
Expand All @@ -192,14 +192,14 @@ func TestAdminClient(t *testing.T) {
},
{
name: "VersionRegexp",
options: []ListPoliciesOption{WithVersionRegexp(`\d+`)},
options: []FilterOption{WithVersionRegexp(`\d+`)},
want: map[string]string{
"resource.leave_request.v20210210": "",
},
},
{
name: "AllRegexp",
options: []ListPoliciesOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
options: []FilterOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
want: map[string]string{
"principal.donald_duck.vdefault": "",
"principal.donald_duck.vdefault/acme": "",
Expand All @@ -225,6 +225,87 @@ func TestAdminClient(t *testing.T) {
}
})

t.Run("InspectPolicies", func(t *testing.T) {
testCases := []struct {
name string
options []FilterOption
want map[string][]string
}{
{
name: "NoFilter",
want: map[string][]string{
"principal.donald_duck.vdefault": {"*"},
"principal.donald_duck.vdefault/acme": {"*"},
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
"resource.leave_request.vdefault": {"*"},
"resource.leave_request.vdefault/acme": {"create", "view:public"},
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
},
},
{
name: "NameRegexp",
options: []FilterOption{WithNameRegexp("leave_req")},
want: map[string][]string{
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
"resource.leave_request.vdefault": {"*"},
"resource.leave_request.vdefault/acme": {"create", "view:public"},
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
},
},
{
name: "ScopeRegexp",
options: []FilterOption{WithScopeRegexp("acme")},
want: map[string][]string{
"principal.donald_duck.vdefault/acme": {"*"},
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
"resource.leave_request.vdefault/acme": {"create", "view:public"},
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
},
},
{
name: "VersionRegexp",
options: []FilterOption{WithVersionRegexp(`\d+`)},
want: map[string][]string{
"resource.leave_request.v20210210": {"*", "approve", "create", "defer", "delete", "remind", "view", "view:*", "view:public"},
},
},
{
name: "AllRegexp",
options: []FilterOption{WithNameRegexp(`.*`), WithScopeRegexp(`.*`), WithVersionRegexp("def")},
want: map[string][]string{
"principal.donald_duck.vdefault": {"*"},
"principal.donald_duck.vdefault/acme": {"*"},
"principal.donald_duck.vdefault/acme.hr": {"view:*"},
"resource.leave_request.vdefault": {"*"},
"resource.leave_request.vdefault/acme": {"create", "view:public"},
"resource.leave_request.vdefault/acme.hr": {"approve", "defer", "delete", "view:*"},
"resource.leave_request.vdefault/acme.hr.uk": {"defer", "delete"},
},
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
have, err := ac.InspectPolicies(context.Background(), tc.options...)
require.NoError(t, err)
require.NotNil(t, have)
require.NotNil(t, have.Results)
for fqn, actions := range tc.want {
t.Run(fqn, func(t *testing.T) {
require.NotNil(t, have.Results[fqn])
require.Len(t, have.Results[fqn].Actions, len(actions))
require.ElementsMatch(t, have.Results[fqn].Actions, actions)
})
}
})
}
})

t.Run("AddOrUpdateSchema", func(t *testing.T) {
ss := NewSchemaSet()
for k, s := range schemas {
Expand Down
36 changes: 23 additions & 13 deletions cerbos/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -1212,29 +1212,39 @@ type PlanResourcesResponse struct {
}

type (
ListPoliciesOption func(*requestv1.ListPoliciesRequest)
FilterOptions struct {
NameRegexp string
ScopeRegexp string
VersionRegexp string
IncludeDisabled bool
}
// FilterOption allows filtering policies while calling InspectPolicies and ListPolicies.
FilterOption func(*FilterOptions)
// ListPoliciesOption allows filtering policies while calling ListPolicies
// Deprecated: ListPoliciesOption is deprecated, use FilterOption instead.
ListPoliciesOption = FilterOption
)

func WithIncludeDisabled() ListPoliciesOption {
return func(request *requestv1.ListPoliciesRequest) {
request.IncludeDisabled = true
func WithIncludeDisabled() FilterOption {
return func(fo *FilterOptions) {
fo.IncludeDisabled = true
}
}

func WithNameRegexp(re string) ListPoliciesOption {
return func(request *requestv1.ListPoliciesRequest) {
request.NameRegexp = re
func WithNameRegexp(re string) FilterOption {
return func(fo *FilterOptions) {
fo.NameRegexp = re
}
}

func WithScopeRegexp(re string) ListPoliciesOption {
return func(request *requestv1.ListPoliciesRequest) {
request.ScopeRegexp = re
func WithScopeRegexp(re string) FilterOption {
return func(fo *FilterOptions) {
fo.ScopeRegexp = re
}
}

func WithVersionRegexp(v string) ListPoliciesOption {
return func(request *requestv1.ListPoliciesRequest) {
request.VersionRegexp = v
func WithVersionRegexp(v string) FilterOption {
return func(fo *FilterOptions) {
fo.VersionRegexp = v
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.20
require (
github.com/bufbuild/protovalidate-go v0.6.1
github.com/cenkalti/backoff/v4 v4.3.0
github.com/cerbos/cerbos/api/genpb v0.34.0
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f
github.com/ghodss/yaml v1.0.0
github.com/google/go-cmp v0.6.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ github.com/bufbuild/protovalidate-go v0.6.1 h1:uzW8r0CDvqApUChNj87VzZVoQSKhcVdw5
github.com/bufbuild/protovalidate-go v0.6.1/go.mod h1:4BR3rKEJiUiTy+sqsusFn2ladOf0kYmA2Reo6BHSBgQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cerbos/cerbos/api/genpb v0.34.0 h1:HY8k9HVHv000EKU61KrhAia5TmjW4sX2AXNee4I+DZg=
github.com/cerbos/cerbos/api/genpb v0.34.0/go.mod h1:KEUMaRkMsCvEcOI8aptMFscKh6H2bfWgjjjSmRWKg8g=
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f h1:2QY32KPwny2zJCE7fWBdarci+r6hwYeVeHp7xK/BYq8=
github.com/cerbos/cerbos/api/genpb v0.34.1-0.20240404120519-19d38a48998f/go.mod h1:DcozdAIUztxXwtVs88gGgdyCITru7WCTF9vGA6j+H8k=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
Expand Down