From e5b34d59fd0343fd66b37098ea1a0eb0ca84fc3f Mon Sep 17 00:00:00 2001 From: bbernays Date: Wed, 19 Jan 2022 17:00:48 -0500 Subject: [PATCH 1/7] add new policy Filter --- pkg/policy/policy.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index f9cd1c13d7fd26..78b8a90492aa1c 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -1,6 +1,9 @@ package policy -import "fmt" +import ( + "fmt" + "strings" +) type Policies []*Policy @@ -63,6 +66,26 @@ func (p Policy) TotalQueries() int { return count + len(p.Checks) } +func (p Policy) Filter(path string) Policy { + selectorPath := strings.SplitN(path, "/", 3) + if len(selectorPath) == 0 { + return p + } + var emptyPolicy Policy + if selectorPath[0] != p.Name { + return emptyPolicy + } + if len(selectorPath) == 1 { + return p + } + for _, policy := range p.Policies { + if policy.Name == selectorPath[1] { + return policy.Filter(strings.SplitN(path, "/", 2)[1]) + } + } + return emptyPolicy +} + type Meta struct { Type string Version string From 3d592d7f941c72a69fc5337a4062f5c82a8e5a11 Mon Sep 17 00:00:00 2001 From: bbernays Date: Wed, 19 Jan 2022 17:00:59 -0500 Subject: [PATCH 2/7] Add tests for p.Filter --- pkg/policy/policy_test.go | 111 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 pkg/policy/policy_test.go diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go new file mode 100644 index 00000000000000..0a158960e2fb80 --- /dev/null +++ b/pkg/policy/policy_test.go @@ -0,0 +1,111 @@ +package policy + +import ( + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" +) + +func TestFilterPolicies(t *testing.T) { + filterTests := []struct { + p Policy + path string + expectError bool + expectedPolicy Policy + }{ + { + expectError: false, + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "test2", + Policies: Policies{ + &Policy{ + Name: "test", + }, + }, + }, + }, + }, + path: "aws/test1", + expectedPolicy: Policy{}, + }, { + expectError: true, + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "test", + }, + }, + }, + path: "aws/test1", + expectedPolicy: Policy{ + Name: "test", + }, + }, + { + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "level-1", + Policies: Policies{ + &Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + }, + }, + }, + }, + }, + }, + }, + path: "aws/level-1/level-2/level-3", + expectedPolicy: Policy{ + Name: "level-3", + }, + }, { + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "level-1", + Policies: Policies{ + &Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + }, + }, + }, + }, + }, + }, + }, + path: "aws/level-1/level-2", + expectedPolicy: Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + }, + }, + }, + }, + } + for i, tt := range filterTests { + t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) { + diff := cmp.Diff(tt.expectedPolicy, tt.p.Filter(tt.path), cmpopts.IgnoreUnexported(Policy{})) + if diff != "" && !tt.expectError { + t.Fatalf("values are not the same %s", diff) + } + }) + } +} From 85cb429714ada50d7a575eb36c2bc94013c514c7 Mon Sep 17 00:00:00 2001 From: bbernays Date: Wed, 19 Jan 2022 17:01:18 -0500 Subject: [PATCH 3/7] Support Filtering on describe --- pkg/ui/console/client.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/ui/console/client.go b/pkg/ui/console/client.go index da12f271f884e3..737abb7a300397 100644 --- a/pkg/ui/console/client.go +++ b/pkg/ui/console/client.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "strconv" + "strings" "time" "github.com/cloudquery/cloudquery/internal/telemetry" @@ -236,7 +237,7 @@ func (c Client) DescribePolicies(ctx context.Context, policySource string) error } c.c.Logger.Debug("policies to describe", "policies", policiesToDescribe.All()) for _, p := range policiesToDescribe { - if err := c.describePolicy(ctx, p); err != nil { + if err := c.describePolicy(ctx, p, policySource); err != nil { return err } } @@ -536,7 +537,8 @@ func (c Client) describePolicy(ctx context.Context, p *policy.Policy) error { ui.ColorizedOutput(ui.ColorHeader, "Describe Policy %s output:\n\n", p.String()) t := &Table{writer: tablewriter.NewWriter(os.Stdout)} t.SetHeaders("Path", "Description") - buildDescribePolicyTable(t, policy.Policies{p}, "") + pol := p.Filter(strings.ReplaceAll(selector, "//", "/")) + buildDescribePolicyTable(t, policy.Policies{&pol}, "") t.Render() ui.ColorizedOutput(ui.ColorInfo, "To execute any policy use the path defined in the table above.\nFor example `cloudquery policy run %s`", buildPolicyPath(p.Name, getNestedPolicyExample(p.Policies[0], ""))) return nil From 5f796f22ecdadbbf8ba9eefe03af8893237feecd Mon Sep 17 00:00:00 2001 From: bbernays Date: Wed, 19 Jan 2022 17:11:37 -0500 Subject: [PATCH 4/7] Update client.go --- pkg/ui/console/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/ui/console/client.go b/pkg/ui/console/client.go index 737abb7a300397..0f0df3f29e5bc2 100644 --- a/pkg/ui/console/client.go +++ b/pkg/ui/console/client.go @@ -528,7 +528,7 @@ func (c Client) setTelemetryAttributes(span trace.Span) { }) } -func (c Client) describePolicy(ctx context.Context, p *policy.Policy) error { +func (c Client) describePolicy(ctx context.Context, p *policy.Policy, selector string) error { p, err := c.c.LoadPolicy(ctx, p.Name, p.Source) if err != nil { ui.ColorizedOutput(ui.ColorError, err.Error()) @@ -538,7 +538,7 @@ func (c Client) describePolicy(ctx context.Context, p *policy.Policy) error { t := &Table{writer: tablewriter.NewWriter(os.Stdout)} t.SetHeaders("Path", "Description") pol := p.Filter(strings.ReplaceAll(selector, "//", "/")) - buildDescribePolicyTable(t, policy.Policies{&pol}, "") + buildDescribePolicyTable(t, policy.Policies{&pol}, selector[:strings.LastIndexAny(selector, "/")]) t.Render() ui.ColorizedOutput(ui.ColorInfo, "To execute any policy use the path defined in the table above.\nFor example `cloudquery policy run %s`", buildPolicyPath(p.Name, getNestedPolicyExample(p.Policies[0], ""))) return nil From fb55171e9c03a605bd7503c3f95e68b174bf3183 Mon Sep 17 00:00:00 2001 From: bbernays Date: Wed, 19 Jan 2022 17:23:49 -0500 Subject: [PATCH 5/7] Update client.go --- pkg/ui/console/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/ui/console/client.go b/pkg/ui/console/client.go index 0f0df3f29e5bc2..5051f042f399e7 100644 --- a/pkg/ui/console/client.go +++ b/pkg/ui/console/client.go @@ -540,7 +540,7 @@ func (c Client) describePolicy(ctx context.Context, p *policy.Policy, selector s pol := p.Filter(strings.ReplaceAll(selector, "//", "/")) buildDescribePolicyTable(t, policy.Policies{&pol}, selector[:strings.LastIndexAny(selector, "/")]) t.Render() - ui.ColorizedOutput(ui.ColorInfo, "To execute any policy use the path defined in the table above.\nFor example `cloudquery policy run %s`", buildPolicyPath(p.Name, getNestedPolicyExample(p.Policies[0], ""))) + ui.ColorizedOutput(ui.ColorInfo, "To execute any policy use the path defined in the table above.\nFor example `cloudquery policy run %s`\n", buildPolicyPath(p.Name, getNestedPolicyExample(p.Policies[0], ""))) return nil } From a668055b374a60a0a5f43cad85909eb5bddb7eaf Mon Sep 17 00:00:00 2001 From: bbernays Date: Thu, 20 Jan 2022 08:27:42 -0500 Subject: [PATCH 6/7] Add Support for Check level filter --- pkg/policy/policy.go | 19 ++++- pkg/policy/policy_test.go | 155 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 4 deletions(-) diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 78b8a90492aa1c..4ac3a8b63c55dd 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -75,14 +75,25 @@ func (p Policy) Filter(path string) Policy { if selectorPath[0] != p.Name { return emptyPolicy } - if len(selectorPath) == 1 { + + if strings.Count(path, "/") > 0 { + for _, policy := range p.Policies { + if policy.Name == selectorPath[1] { + return policy.Filter(strings.SplitN(path, "/", 2)[1]) + } + } + } + if selectorPath[0] == p.Name && strings.Count(path, "/") == 0 { return p } - for _, policy := range p.Policies { - if policy.Name == selectorPath[1] { - return policy.Filter(strings.SplitN(path, "/", 2)[1]) + for _, check := range p.Checks { + if check.Name == selectorPath[1] { + p.Checks = make([]*Check, 0) + p.Checks = append(p.Checks, check) + return p } } + return emptyPolicy } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index 0a158960e2fb80..fce18f5cf0f81a 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -99,6 +99,161 @@ func TestFilterPolicies(t *testing.T) { }, }, }, + { + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "level-1", + Policies: Policies{ + &Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + }, + }, + }, + }, + }, + }, + }, + }, + path: "aws/level-1/level-2/level-3/Control-1", + expectedPolicy: Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + }, + }, + }, + { + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "level-1", + Policies: Policies{ + &Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + { + Name: "Control-2", + }, + { + Name: "Control-3", + }, + { + Name: "Control-4", + }, + { + Name: "Control-5", + }, + }, + }, + }, + }, + }, + }, + }, + }, + path: "aws/level-1/level-2/level-3", + expectedPolicy: Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + { + Name: "Control-2", + }, + { + Name: "Control-3", + }, + { + Name: "Control-4", + }, + { + Name: "Control-5", + }, + }, + }, + }, + { + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "level-1", + Policies: Policies{ + &Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + { + Name: "Control-2", + }, + { + Name: "Control-3", + }, + { + Name: "Control-4", + }, + { + Name: "Control-5", + }, + }, + }, + }, + }, + }, + }, + }, + }, + path: "aws/level-1/level-2", + expectedPolicy: Policy{ + Name: "level-2", + Policies: Policies{ + &Policy{ + Name: "level-3", + Checks: []*Check{ + { + Name: "Control-1", + }, + { + Name: "Control-2", + }, + { + Name: "Control-3", + }, + { + Name: "Control-4", + }, + { + Name: "Control-5", + }, + }, + }, + }, + }, + }, } for i, tt := range filterTests { t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) { From 194b4b6c70840106b1c0242804611075b3be718e Mon Sep 17 00:00:00 2001 From: bbernays Date: Thu, 20 Jan 2022 09:31:20 -0500 Subject: [PATCH 7/7] Add support and tests for empty selector --- pkg/policy/policy.go | 3 +++ pkg/policy/policy_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 4ac3a8b63c55dd..98085712e4683b 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -67,6 +67,9 @@ func (p Policy) TotalQueries() int { } func (p Policy) Filter(path string) Policy { + if path == "" { + return p + } selectorPath := strings.SplitN(path, "/", 3) if len(selectorPath) == 0 { return p diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index fce18f5cf0f81a..a1ef3e21c22268 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -15,6 +15,36 @@ func TestFilterPolicies(t *testing.T) { expectError bool expectedPolicy Policy }{ + { + expectError: false, + p: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "test2", + Policies: Policies{ + &Policy{ + Name: "test", + }, + }, + }, + }, + }, + path: "", + expectedPolicy: Policy{ + Name: "aws", + Policies: Policies{ + &Policy{ + Name: "test2", + Policies: Policies{ + &Policy{ + Name: "test", + }, + }, + }, + }, + }, + }, { expectError: false, p: Policy{