Skip to content
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
39 changes: 38 additions & 1 deletion pkg/policy/policy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package policy

import "fmt"
import (
"fmt"
"strings"
)

type Policies []*Policy

Expand Down Expand Up @@ -63,6 +66,40 @@ func (p Policy) TotalQueries() int {
return count + len(p.Checks)
}

func (p Policy) Filter(path string) Policy {
Comment thread
bbernays marked this conversation as resolved.
if path == "" {
return p
}
selectorPath := strings.SplitN(path, "/", 3)
if len(selectorPath) == 0 {
return p
}
var emptyPolicy Policy
if selectorPath[0] != p.Name {
return emptyPolicy
}

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 _, check := range p.Checks {
if check.Name == selectorPath[1] {
p.Checks = make([]*Check, 0)
p.Checks = append(p.Checks, check)
return p
}
}

return emptyPolicy
}

type Meta struct {
Type string
Version string
Expand Down
296 changes: 296 additions & 0 deletions pkg/policy/policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
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: "",
expectedPolicy: Policy{
Name: "aws",
Policies: Policies{
&Policy{
Name: "test2",
Policies: Policies{
&Policy{
Name: "test",
},
},
},
},
},
},
{
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",
},
},
},
},
{
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) {
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)
}
})
}
}
10 changes: 6 additions & 4 deletions pkg/ui/console/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"os"
"strconv"
"strings"
"time"

"github.com/cloudquery/cloudquery/internal/telemetry"
Expand Down Expand Up @@ -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
}
}
Expand Down Expand Up @@ -527,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())
Expand All @@ -536,9 +537,10 @@ 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}, 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
}

Expand Down