Skip to content

Commit

Permalink
Merge pull request #70 from garethjevans/better-match-tests
Browse files Browse the repository at this point in the history
chore: improve role matching when namespace is not specified
  • Loading branch information
garethjevans authored Dec 16, 2022
2 parents fe11c38 + 643db32 commit eedba9c
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 104 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ test:

.PHONY: integration
integration:
go test -run Integration ./integration/...
go test -v -run Integration ./integration/...
6 changes: 6 additions & 0 deletions example-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ metadata:
namespace: test-namespace
name: invalid-sa
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: test-namespace
name: sa-with-no-bindings
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/onsi/gomega v1.24.1
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
k8s.io/api v0.26.0
k8s.io/apimachinery v0.26.0
k8s.io/cli-runtime v0.26.0
Expand All @@ -17,7 +18,7 @@ require (
require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/stretchr/objx v0.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)

require (
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
141 changes: 87 additions & 54 deletions integration/expect_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package integration

import (
"github.com/stretchr/testify/assert"
"os"
"os/exec"
"strings"
Expand All @@ -12,40 +13,101 @@ import (
. "github.com/onsi/gomega/gexec"
)

func TestPluginIntegration(t *testing.T) {
func TestIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

RegisterTestingT(t)
type test struct {
name string
sa string
flags []string

command := exec.Command("kubectl", "permissions", "sa-under-test", "-n", "test-namespace")
session, err := Start(command, GinkgoWriter, GinkgoWriter)
if err != nil {
t.Errorf("unable to exec command %s", err)
expectedOut string
expectedErr string
}

response := string(session.Wait(10 * time.Second).Out.Contents())
tests := []test{
{
name: "sa-under-test",
sa: "sa-under-test",
flags: []string{"-n", "test-namespace"},

expectedOut: "ServiceAccount/sa-under-test (test-namespace)\n" +
"\x1b[0;94;40m├\x1b[0m ClusterRoleBinding/cluster-roles\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m ClusterRole/cluster-level-role\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m apps\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m deployments verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m replicasets verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m core.k8s.io\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m configmaps verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m pods verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m pods/log verbs=[get] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m services verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m networking.k8s.io\n\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m ingresses verbs=[get] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m└\x1b[0m RoleBinding/namespaced-roles (test-namespace)\n" +
" \x1b[0;94;40m└\x1b[0m Role/namespaced-role (test-namespace)\n" +
" \x1b[0;94;40m└\x1b[0m core.k8s.io\n" +
" \x1b[0;94;40m└\x1b[0m secrets verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n",
},

{
name: "monitoring",
sa: "monitoring",
flags: []string{"-n", "test-namespace"},

expectedOut: "ServiceAccount/monitoring (test-namespace)\n" +
"\x1b[0;94;40m└\x1b[0m ClusterRoleBinding/monitoring\n" +
" \x1b[0;94;40m└\x1b[0m ClusterRole/monitoring\n" +
" \x1b[0;94;40m└\x1b[0m core.k8s.io\n" +
" \x1b[0;94;40m├\x1b[0m endpoints verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m endpoints verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m pods verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m pods verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m services verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m└\x1b[0m services verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n",
},

{
name: "sa-that-doesnt-exist",
sa: "sa-that-doesnt-exist",
flags: []string{"-n", "test-namespace"},

expectedOut: "",
expectedErr: "Error: serviceaccounts \"sa-that-doesnt-exist\" not found",
},

{
name: "sa-with-no-bindings",
sa: "sa-with-no-bindings",
flags: []string{"-n", "test-namespace"},

expectedOut: "ServiceAccount/sa-with-no-bindings (test-namespace)\n",
},
}

expected :=
"ServiceAccount/sa-under-test (test-namespace)\n" +
"\x1b[0;94;40m├\x1b[0m ClusterRoleBinding/cluster-roles\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m ClusterRole/cluster-level-role\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m apps\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m deployments verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m replicasets verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m core.k8s.io\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m configmaps verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m pods verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m├\x1b[0m pods/log verbs=[get] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m services verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m networking.k8s.io\n\x1b[0;94;40m│\x1b[0m \x1b[0;94;40m└\x1b[0m ingresses verbs=[get] \x1b[0;32m✔ \x1b[0m\n" +
"\x1b[0;94;40m└\x1b[0m RoleBinding/namespaced-roles (test-namespace)\n" +
" \x1b[0;94;40m└\x1b[0m Role/namespaced-role (test-namespace)\n" +
" \x1b[0;94;40m└\x1b[0m core.k8s.io\n" +
" \x1b[0;94;40m└\x1b[0m secrets verbs=[get watch list] \x1b[0;32m✔ \x1b[0m\n"
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
RegisterTestingT(t)

Expect(strings.TrimSpace(response)).To(Equal(strings.TrimSpace(expected)))
var args []string
args = append(args, "permissions", tt.sa)
args = append(args, tt.flags...)

command := exec.Command("kubectl", args...)
session, err := Start(command, GinkgoWriter, GinkgoWriter)
if err != nil {
t.Errorf("unable to exec command %s", err)
}

session = session.Wait(10 * time.Second)
stdOut := string(session.Out.Contents())
stdErr := string(session.Err.Contents())

assert.Equal(t, strings.TrimSpace(tt.expectedOut), strings.TrimSpace(stdOut))
assert.Equal(t, strings.TrimSpace(tt.expectedErr), strings.TrimSpace(stdErr))
})
}
}

func TestPluginIntegrationNoColor(t *testing.T) {
Expand Down Expand Up @@ -84,32 +146,3 @@ func TestPluginIntegrationNoColor(t *testing.T) {
`
Expect(strings.TrimSpace(response)).To(Equal(strings.TrimSpace(expected)))
}

func TestAggregatedRolesIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}

RegisterTestingT(t)

command := exec.Command("kubectl", "permissions", "monitoring", "-n", "test-namespace")
session, err := Start(command, GinkgoWriter, GinkgoWriter)
if err != nil {
t.Errorf("unable to exec command %s", err)
}

response := string(session.Wait(10 * time.Second).Out.Contents())

expected := "ServiceAccount/monitoring (test-namespace)\n" +
"\x1b[0;94;40m└\x1b[0m ClusterRoleBinding/monitoring\n" +
" \x1b[0;94;40m└\x1b[0m ClusterRole/monitoring\n" +
" \x1b[0;94;40m└\x1b[0m core.k8s.io\n" +
" \x1b[0;94;40m├\x1b[0m endpoints verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m endpoints verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m pods verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m pods verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m├\x1b[0m services verbs=[create] \x1b[0;32m✔ \x1b[0m\n" +
" \x1b[0;94;40m└\x1b[0m services verbs=[get list watch] \x1b[0;32m✔ \x1b[0m\n"

Expect(strings.TrimSpace(response)).To(Equal(strings.TrimSpace(expected)))
}
Loading

0 comments on commit eedba9c

Please sign in to comment.