Compare commits

...
5 Commits
Author SHA1 Message Date
Robert BrennanandVitor Rodrigo Vezani 5ff5a2cf94 Update pkg/kube/resources_test.go
Co-authored-by: Vitor Rodrigo Vezani <vitor.vezani@fairwinds.com>
2023-03-02 15:34:25 -05:00
Robert Brennan d46a8c86be preserve ordering of resources 2023-03-02 11:07:53 -05:00
fsl 6abfbb3570 Update package-lock.json (#923)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-21 09:24:09 -05:00
fsl b75db7fc5b Bump golang.org/x/net from 0.6.0 to 0.7.0 (#922)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-21 08:50:39 -05:00
fsl 501744a65f Skip https certificate verification (#920)
Signed-off-by: fengshunli <1171313930@qq.com>
2023-02-17 15:10:28 -05:00
10 changed files with 95 additions and 105 deletions
+10 -3
View File
@@ -17,6 +17,7 @@ package cmd
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
@@ -45,6 +46,7 @@ var (
helmValues string
checks []string
auditNamespace string
skipSslValidation bool
)
func init() {
@@ -63,6 +65,7 @@ func init() {
auditCmd.PersistentFlags().StringVar(&helmValues, "helm-values", "", "Optional flag to add helm values")
auditCmd.PersistentFlags().StringSliceVar(&checks, "checks", []string{}, "Optional flag to specify specific checks to check")
auditCmd.PersistentFlags().StringVar(&auditNamespace, "namespace", "", "Namespace to audit. Only applies to in-cluster audits")
auditCmd.PersistentFlags().BoolVar(&skipSslValidation, "skip-ssl-validation", false, "Skip https certificate verification")
}
var auditCmd = &cobra.Command{
@@ -202,9 +205,13 @@ func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFor
} else {
req.Header.Set("Content-Type", "text/plain")
}
client := &http.Client{}
resp, err := client.Do(req)
client := &http.Client{}
if skipSslValidation {
transport := &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
client = &http.Client{Transport: transport}
}
resp, err := client.Do(req)
if err != nil {
logrus.Errorf("Error making request for output: %v", err)
os.Exit(1)
@@ -223,7 +230,7 @@ func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFor
}
if outputFile != "" {
err := os.WriteFile(outputFile, []byte(outputBytes), 0644)
err := os.WriteFile(outputFile, outputBytes, 0644)
if err != nil {
logrus.Errorf("Error writing output to file: %v", err)
os.Exit(1)
+12 -13
View File
@@ -113,20 +113,19 @@ var fixCommand = &cobra.Command{
updatedYamlContent := ""
if len(allMutations) > 0 {
for _, resources := range kubeResources.Resources {
for _, resource := range resources {
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
mutations := allMutations[key]
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
if err != nil {
logrus.Errorf("Error applying schema mutations to the resource %s: %v", key, err)
os.Exit(1)
}
if updatedYamlContent != "" {
updatedYamlContent += "\n---\n"
}
updatedYamlContent += mutatedYamlContent
for _, resource := range kubeResources.Resources {
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
fmt.Println("resource", key)
mutations := allMutations[key]
mutatedYamlContent, err := mutation.ApplyAllMutations(string(resource.OriginalObjectYAML), mutations)
if err != nil {
logrus.Errorf("Error applying schema mutations to the resource %s: %v", key, err)
os.Exit(1)
}
if updatedYamlContent != "" {
updatedYamlContent += "\n---\n"
}
updatedYamlContent += mutatedYamlContent
}
}
+18 -18
View File
@@ -4144,7 +4144,7 @@
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
@@ -4706,7 +4706,7 @@
"dependencies": {
"cacache": "^12.0.3",
"find-cache-dir": "^2.1.0",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"globby": "^7.1.1",
"is-glob": "^4.0.1",
"loader-utils": "^1.2.3",
@@ -5393,8 +5393,8 @@
}
},
"node_modules/decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.1.tgz",
"integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og==",
"engines": {
"node": ">=0.10"
@@ -6694,7 +6694,7 @@
"dependencies": {
"@mrmlnc/readdir-enhanced": "^2.2.1",
"@nodelib/fs.stat": "^1.1.2",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"is-glob": "^4.0.0",
"merge2": "^1.2.3",
"micromatch": "^3.1.10"
@@ -7148,8 +7148,8 @@
}
},
"node_modules/glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
"dependencies": {
"is-glob": "^3.1.0",
@@ -11134,7 +11134,7 @@
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
"dev": true,
"dependencies": {
"decode-uri-component": "^0.2.0",
"decode-uri-component": "^0.2.1",
"object-assign": "^4.1.0",
"strict-uri-encode": "^1.0.0"
},
@@ -12370,7 +12370,7 @@
"deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
"dependencies": {
"atob": "^2.1.2",
"decode-uri-component": "^0.2.0",
"decode-uri-component": "^0.2.1",
"resolve-url": "^0.2.1",
"source-map-url": "^0.4.0",
"urix": "^0.1.0"
@@ -18303,7 +18303,7 @@
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
@@ -18773,7 +18773,7 @@
"requires": {
"cacache": "^12.0.3",
"find-cache-dir": "^2.1.0",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"globby": "^7.1.1",
"is-glob": "^4.0.1",
"loader-utils": "^1.2.3",
@@ -19325,8 +19325,8 @@
"dev": true
},
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.1.tgz",
"integrity": "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og=="
},
"decompress-response": {
@@ -20329,7 +20329,7 @@
"requires": {
"@mrmlnc/readdir-enhanced": "^2.2.1",
"@nodelib/fs.stat": "^1.1.2",
"glob-parent": "^3.1.0",
"glob-parent": "^5.1.2",
"is-glob": "^4.0.0",
"merge2": "^1.2.3",
"micromatch": "^3.1.10"
@@ -20672,8 +20672,8 @@
}
},
"glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==",
"requires": {
"is-glob": "^3.1.0",
@@ -23869,7 +23869,7 @@
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
"dev": true,
"requires": {
"decode-uri-component": "^0.2.0",
"decode-uri-component": "^0.2.1",
"object-assign": "^4.1.0",
"strict-uri-encode": "^1.0.0"
}
@@ -24894,7 +24894,7 @@
"integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
"requires": {
"atob": "^2.1.2",
"decode-uri-component": "^0.2.0",
"decode-uri-component": "^0.2.1",
"resolve-url": "^0.2.1",
"source-map-url": "^0.4.0",
"urix": "^0.1.0"
+1 -1
View File
@@ -69,7 +69,7 @@ require (
github.com/prometheus/common v0.39.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
golang.org/x/net v0.6.0 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/term v0.5.0 // indirect
+2 -2
View File
@@ -455,8 +455,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+24 -38
View File
@@ -51,48 +51,34 @@ type ResourceProvider struct {
SourceType string
Nodes []corev1.Node
Namespaces []corev1.Namespace
Resources resourceKindMap
Resources resourceSet
}
type resourceKindMap map[string][]GenericResource
type resourceSet []GenericResource
func (rkm resourceKindMap) addResource(r GenericResource) {
gvk := r.Resource.GroupVersionKind()
var key string
if gvk.Group != "" {
key = gvk.Group + "/" + gvk.Kind
} else {
key = gvk.Kind
}
rkm[key] = append(rkm[key], r)
}
func (rkm resourceKindMap) addResources(rs []GenericResource) {
func (rs resourceSet) GetNumberOfControllers() int {
total := 0
for _, r := range rs {
rkm.addResource(r)
}
}
func (rkm resourceKindMap) GetLength() int {
total := 0
for _, rs := range rkm {
total += len(rs)
}
return total
}
func (rkm resourceKindMap) GetNumberOfControllers() int {
total := 0
for _, rs := range rkm {
for _, r := range rs {
if r.PodSpec != nil {
total++
}
if r.PodSpec != nil {
total++
}
}
return total
}
func (rs resourceSet) GetAllOfGroupKind(gk string) []GenericResource {
return funk.Filter(rs, func(res GenericResource) bool {
gvk := res.Resource.GroupVersionKind()
var key string
if gvk.Group != "" {
key = gvk.Group + "/" + gvk.Kind
} else {
key = gvk.Kind
}
return key == gk
}).([]GenericResource)
}
// This is here for backward compatibility reasons
func maybeTransformKindIntoGroupKind(k string) string {
if k == "Ingress" {
@@ -122,7 +108,7 @@ func newResourceProvider(version, sourceType, sourceName string) ResourceProvide
CreationTime: time.Now(),
Nodes: make([]corev1.Node, 0),
Namespaces: make([]corev1.Namespace, 0),
Resources: make(map[string][]GenericResource),
Resources: make([]GenericResource, 0),
}
}
@@ -193,7 +179,7 @@ func CreateResourceProviderFromResource(ctx context.Context, workload string) (*
return nil, err
}
resources.Resources.addResource(workloadObj)
resources.Resources = append(resources.Resources, workloadObj)
return &resources, nil
}
@@ -377,7 +363,7 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
provider.Nodes = nodes.Items
provider.Namespaces = namespaces.Items
provider.Resources.addResources(kubernetesResources)
provider.Resources = append(provider.Resources, kubernetesResources...)
logrus.Info("Done loading Kubernetes resources")
return &provider, nil
}
@@ -479,13 +465,13 @@ func (resources *ResourceProvider) addResourceFromString(contents string) error
return err
}
workload.OriginalObjectYAML = contentBytes
resources.Resources.addResource(workload)
resources.Resources = append(resources.Resources, workload)
} else {
newResource, err := NewGenericResourceFromBytes(contentBytes)
if err != nil {
return err
}
resources.Resources.addResource(newResource)
resources.Resources = append(resources.Resources, newResource)
}
return err
}
+18 -14
View File
@@ -21,9 +21,11 @@ import (
"testing"
"time"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/thoas/go-funk"
"github.com/fairwindsops/polaris/test"
"github.com/stretchr/testify/assert"
conf "github.com/fairwindsops/polaris/pkg/config"
)
func TestGetResourcesFromPath(t *testing.T) {
@@ -42,12 +44,10 @@ func TestGetResourcesFromPath(t *testing.T) {
assert.Equal(t, "two", provider.Namespaces[0].ObjectMeta.Name)
namespaceCount := map[string]int{}
for _, resources := range provider.Resources {
for _, controller := range resources {
namespaceCount[controller.ObjectMeta.GetNamespace()]++
}
for _, controller := range provider.Resources {
namespaceCount[controller.ObjectMeta.GetNamespace()]++
}
assert.Equal(t, 11, provider.Resources.GetLength())
assert.Equal(t, 11, len(provider.Resources))
assert.Equal(t, 10, namespaceCount[""])
assert.Equal(t, 1, namespaceCount["two"])
}
@@ -64,8 +64,11 @@ func TestGetMultipleResourceFromSingleFile(t *testing.T) {
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 6, len(resources.Resources), "Should have 6 resources")
deployment := funk.Find(resources.Resources, func(res GenericResource) bool {
return res.Resource.GroupVersionKind().Kind == "Deployment"
}).(GenericResource)
assert.Equal(t, "dashboard", deployment.PodSpec.Containers[0].Name)
assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace")
assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name)
@@ -87,8 +90,11 @@ func TestAddResourcesFromReader(t *testing.T) {
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 1, len(resources.Resources["extensions/Deployment"]), "Should have one controller")
assert.Equal(t, "dashboard", resources.Resources["extensions/Deployment"][0].PodSpec.Containers[0].Name)
assert.Equal(t, 6, len(resources.Resources), "Should have 6 resources")
deployment := funk.Find(resources.Resources, func(res GenericResource) bool {
return res.Resource.GroupVersionKind().Kind == "Deployment"
}).(GenericResource)
assert.Equal(t, "dashboard", deployment.PodSpec.Containers[0].Name)
assert.Equal(t, 2, len(resources.Namespaces), "Should have a namespace")
assert.Equal(t, "polaris", resources.Namespaces[0].ObjectMeta.Name)
@@ -158,10 +164,8 @@ func TestGetResourceFromAPI(t *testing.T) {
assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
assert.Equal(t, 5, len(resources.Resources), "Should have 5 controllers")
for _, controllers := range resources.Resources {
for _, ctrl := range controllers {
expectedNames[ctrl.ObjectMeta.GetName()] = true
}
for _, ctrl := range resources.Resources {
expectedNames[ctrl.ObjectMeta.GetName()] = true
}
for name, val := range expectedNames {
assert.Equal(t, true, val, name)
+6 -3
View File
@@ -72,7 +72,10 @@ func TestControllerLevelChecks(t *testing.T) {
Severity: "danger",
Category: "Reliability",
}
for _, controller := range res.Resources["Deployment"] {
for _, controller := range res.Resources {
if controller.Resource.GroupVersionKind().Kind != "Deployment" {
continue
}
actualResult, err := applyControllerSchemaChecks(&c, nil, controller)
if err != nil {
panic(err)
@@ -96,7 +99,7 @@ func TestControllerLevelChecks(t *testing.T) {
res, err := kube.CreateResourceProviderFromPath("../kube/test_files/test_1")
assert.Equal(t, nil, err, "Error should be nil")
assert.Equal(t, 11, res.Resources.GetLength())
assert.Equal(t, 11, len(res.Resources))
testResources(res)
replicaSpec := map[string]interface{}{"replicas": 2}
@@ -111,7 +114,7 @@ func TestControllerLevelChecks(t *testing.T) {
k8s, dynamicClient := test.SetupTestAPI(&d1, &p1, &d2, &p2)
res, err = kube.CreateResourceProviderFromAPI(context.Background(), k8s, "test", dynamicClient, conf.Configuration{})
assert.Equal(t, err, nil, "error should be nil")
assert.Equal(t, 2, res.Resources.GetLength(), "Should have two controllers")
assert.Equal(t, 2, len(res.Resources), "Should have two controllers")
testResources(res)
}
+2 -10
View File
@@ -173,18 +173,10 @@ func hasExemptionAnnotation(objMeta metaV1.Object, checkID string) bool {
// ApplyAllSchemaChecksToResourceProvider applies all available checks to a ResourceProvider
func ApplyAllSchemaChecksToResourceProvider(conf *config.Configuration, resourceProvider *kube.ResourceProvider) ([]Result, error) {
results := []Result{}
if resourceProvider == nil {
return nil, errors.New("No resource provider set, cannot apply schema checks")
}
for _, resources := range resourceProvider.Resources {
kindResults, err := ApplyAllSchemaChecksToAllResources(conf, resourceProvider, resources)
if err != nil {
return results, err
}
results = append(results, kindResults...)
}
return results, nil
return ApplyAllSchemaChecksToAllResources(conf, resourceProvider, resourceProvider.Resources)
}
// ApplyAllSchemaChecksToAllResources applies available checks to a list of resources
@@ -381,7 +373,7 @@ func applySchemaCheck(conf *config.Configuration, checkID string, test schemaTes
logrus.Warnf("No ResourceProvider available, check %s will not work in this context (e.g. admission control)", checkID)
break
}
resources := test.ResourceProvider.Resources[groupkind]
resources := test.ResourceProvider.Resources.GetAllOfGroupKind(groupkind)
namespace := test.Resource.ObjectMeta.GetNamespace()
if test.Resource.Kind == "Namespace" {
namespace = test.Resource.ObjectMeta.GetName()
+2 -3
View File
@@ -51,9 +51,8 @@ func TestMutations(t *testing.T) {
assert.Len(t, results, 1)
allMutations := mutation.GetMutationsFromResults(results)
assert.Len(t, allMutations, 1)
for _, resources := range tc.resources.Resources {
assert.Len(t, resources, 1)
key := fmt.Sprintf("%s/%s/%s", resources[0].Kind, resources[0].Resource.GetName(), resources[0].Resource.GetNamespace())
for _, resource := range tc.resources.Resources {
key := fmt.Sprintf("%s/%s/%s", resource.Kind, resource.Resource.GetName(), resource.Resource.GetNamespace())
mutations := allMutations[key]
yamlContent, err := mutation.ApplyAllMutations(tc.manifest, mutations)
assert.NoError(t, err)