Compare commits

..
29 Commits
Author SHA1 Message Date
Robert Brennan 59945a4860 Update .goreleaser.yml.envsubst 2024-03-08 16:22:53 -05:00
Robert Brennan c6befdb3fc Update config.yml 2024-03-08 15:08:41 -05:00
Robert Brennan 0bcc48ee2c Merge branch 'master' into rb/updates 2024-03-08 14:54:25 -05:00
Vitor Rodrigo Vezani 4a0713c754 FWI-5804 - expose issue fixer and mutations in the library (#1032)
* Add local path replacement for Polaris module

* expose fix.Execute

* Remove local module replacement in go.mod

* Fix error handling and return error instead of exiting the program
2024-03-08 13:23:33 -03:00
Robert Brennan 9da23c19c8 back up goreleaser version 2024-03-05 16:19:35 -05:00
Robert Brennan 53cbc832e0 fix output-sig flag 2024-03-05 13:47:40 -05:00
Robert Brennan cdf4cb26a2 update go 2024-03-05 11:03:36 -05:00
Robert Brennan 5a404c7106 update deps 2024-03-05 10:32:14 -05:00
Takumi Sue 48fc87a663 Fix trying to list cluster-level resources (#1004)
when namespace specified

close #984
2024-03-05 10:19:02 -05:00
dependabot[bot]andlnx01 1ee4df0c81 Bump github.com/spf13/cobra from 1.7.0 to 1.8.0 (#1024)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.7.0...v1.8.0)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-05 10:17:09 -05:00
b73aabc42e Bump k8s.io/client-go from 0.27.3 to 0.29.0 (#1021)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.3 to 0.29.0.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.27.3...v0.29.0)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Robert Brennan <accounts@rbren.io>
2024-03-05 10:16:47 -05:00
Robert Brennan e60793a022 fix missing PDB check (#1027) 2024-02-13 13:13:11 -05:00
John Slivka c8394bf9d7 fix: conditional expressions should be at very top of additionalSchemaStrings (#1025) 2024-01-03 14:17:04 -06:00
Robert Brennan 0b765df04d Update alpine to 3.19 (#1022) 2023-12-18 11:16:47 -05:00
John Slivka 3e96c582f0 FWI-5385 Add quiet flag to polaris audit CLI command to suppress 'upload to Insights' prompt (#1017)
* add quiet flag to polaris audit CLI command to suppress 'upload to Insights' prompt
* add docs for polaris audit --quiet option
* add additional detail about polaris audit --quiet flag
2023-12-06 15:44:53 -06:00
Terraform User 391b802d4d Managed by Terraform 2023-11-02 15:47:51 -04:00
jdesouza f295dd0fb5 Using controller-utils to get workloads (#1012)
* Using controller-utils to get workloads

* Code cleanup
2023-11-01 15:59:46 -03:00
Robert Brennan 97687761a7 Fix numerical resource ranges (#991)
* fix numerical resource numbers

* add resource range tests
2023-09-05 11:15:45 -06:00
Robert BrennanandAndrew Suderman c856874564 Update topologySpreadConstraint.yaml (#971)
* Update topologySpreadConstraint.yaml

* Update topologySpreadConstraint.yaml

* fix test

* add passing test

---------

Co-authored-by: Andrew Suderman <andy@fairwinds.com>
2023-08-28 08:49:08 -06:00
Takumi Sue 09525d01a1 Add helm-skip-tests flag (#986)
* Add helm-skip-tests flag

close #985

* Update cli doc
2023-08-25 08:39:27 -06:00
Vitor Rodrigo Vezani 10e82cf0ae update CLI documentation (#967) 2023-08-03 10:21:49 -04:00
dependabot[bot]andlnx01 a5144c45b2 Bump k8s.io/apimachinery from 0.27.3 to 0.27.4 (#977)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.27.3 to 0.27.4.
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.27.3...v0.27.4)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 15:47:59 -04:00
Takumi Sue 9be34236cb feat: handle multiple values files (#974) 2023-07-24 14:26:58 -04:00
Andrew Suderman e7eb079921 change kubernetes.io/ label from name to instance (#973)
* Fix #972 change label from name to instance

* Fix tests

* more references

* fix check

* Fix example config
2023-07-13 11:33:15 -06:00
Robert Brennan d55cd4bdf8 Add insights prompt (#968)
* add insights prompt

* switch to stderr

* adjust message

* adjust message
2023-06-29 12:07:26 -04:00
75997f0e93 Bump github.com/AlecAivazis/survey/v2 from 2.3.6 to 2.3.7 (#961)
Bumps [github.com/AlecAivazis/survey/v2](https://github.com/AlecAivazis/survey) from 2.3.6 to 2.3.7.
- [Release notes](https://github.com/AlecAivazis/survey/releases)
- [Commits](https://github.com/AlecAivazis/survey/compare/v2.3.6...v2.3.7)

---
updated-dependencies:
- dependency-name: github.com/AlecAivazis/survey/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grace Gude <44000341+mggude@users.noreply.github.com>
2023-06-29 09:22:11 -06:00
John Slivka b0d86cdcd2 Add option to filter audit results by severity level (#969) 2023-06-28 08:38:47 -05:00
5595de4ef9 Bump k8s.io/client-go from 0.27.2 to 0.27.3 (#960)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.27.2 to 0.27.3.
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.27.2...v0.27.3)

---
updated-dependencies:
- dependency-name: k8s.io/client-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grace Gude <44000341+mggude@users.noreply.github.com>
2023-06-27 11:46:13 -04:00
Robert Brennan 4ca4c8f0f5 Fix nil pointer issue with webhook (#966)
* update

* update go mod

* tidy

* revert go mod

* fix port

* move pod test case

* downgrade controller-runtime

* revert updates

* fix nil pointer

* add logs

* fix var

* remove test requirement

* fix decoder

* fix mutate

* fix test case

* fix logs

* fmt

* fix owned pods in mutate

* fix test

* add logs

* add mutations to tests

* convert to json for patch

* fix up tests

* remove nil check

* fix logs

* add logs

* add env vars to webhook tests
2023-06-22 13:22:19 -04:00
52 changed files with 850 additions and 463 deletions
+5 -4
View File
@@ -114,12 +114,13 @@ jobs:
executor: vm
steps:
- checkout
- *set_environment_variables
- *install_k8s
- *test_k8s
test:
docker:
- image: cimg/go:1.19
- image: cimg/go:1.22
steps:
- checkout
- *set_environment_variables
@@ -135,7 +136,9 @@ jobs:
# The goreleaser image tag determins the version of Go.
# Manually check goreleaser images for their version of Go.
# Ref: https://hub.docker.com/r/goreleaser/goreleaser/tags
- image: goreleaser/goreleaser:v1.18.2
- image: goreleaser/goreleaser:v1.25.0-nightly # Go 1.22.0
environment:
GOLANG_VERSION: "1.22.0"
steps:
- checkout
- setup_remote_docker:
@@ -161,8 +164,6 @@ workflows:
only: /.*/
- build_and_push:
context: org-global
requires:
- test
filters:
branches:
ignore: /pull\/[0-9]+/
+1 -1
View File
@@ -36,7 +36,7 @@ archives:
name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}{{ if .Mips }}_{{ .Mips }}{{ end }}"
signs:
- cmd: cosign
args: ["sign-blob", "--key=hashivault://cosign", "-output-signature=${signature}", "${artifact}"]
args: ["sign-blob", "--yes", "--key=hashivault://cosign", "--output-signature=${signature}", "${artifact}"]
artifacts: checksum
release:
# This is replaced using `envsubst`, depending on the git branch.
+1 -1
View File
@@ -1,2 +1,2 @@
## DO NOT EDIT - Managed by Terraform
* @rbren @mggude
* @rbren @sudermanjr
+1 -1
View File
@@ -1,4 +1,4 @@
FROM alpine:3.18
FROM alpine:3.19
LABEL org.opencontainers.image.authors="FairwindsOps, Inc." \
org.opencontainers.image.vendor="FairwindsOps, Inc." \
+2 -2
View File
@@ -37,10 +37,10 @@ schemaString: |
const: "cluster-admin"
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
type: object
# Do not alert on default ClusterRoleBindings.
{{ if (ne .roleRef.name "view") }}
{{ if and (ne .metadata.name "cluster-admin") (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# Do not alert on default ClusterRoleBindings.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
@@ -1,5 +1,5 @@
successMessage: Label app.kubernetes.io/name matches metadata.name
failureMessage: Label app.kubernetes.io/name must match metadata.name
successMessage: Label app.kubernetes.io/instance matches metadata.name
failureMessage: Label app.kubernetes.io/instance must match metadata.name
category: Reliability
target: Controller
schema:
@@ -12,7 +12,7 @@ schema:
properties:
labels:
type: object
required: ["app.kubernetes.io/name"]
required: ["app.kubernetes.io/instance"]
properties:
app.kubernetes.io/name:
app.kubernetes.io/instance:
const: "{{ .metadata.name }}"
+10 -4
View File
@@ -9,12 +9,18 @@ schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
properties:
metadata:
spec:
type: object
properties:
labels:
template:
type: object
minProperties: 1
properites:
metadata:
type: object
properties:
labels:
type: object
minProperties: 1
additionalSchemaStrings:
policy/PodDisruptionBudget: |
type: object
@@ -30,7 +36,7 @@ additionalSchemaStrings:
matchLabels:
type: object
anyOf:
{{ range $key, $value := .metadata.labels }}
{{ range $key, $value := .spec.template.metadata.labels }}
- properties:
"{{ $key }}":
type: string
@@ -45,10 +45,10 @@ schemaString: |
const: "cluster-admin"
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
type: object
# This schema is validated for all roleBindings, regardless of their roleRef.
{{ if eq .roleRef.kind "ClusterRole" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
@@ -43,10 +43,10 @@ schemaString: |
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/ClusterRole: |
type: object
# This schema is validated for all roleBindings, regardless of their roleRef.
{{ if eq .roleRef.kind "ClusterRole" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
+2 -2
View File
@@ -46,10 +46,10 @@ schemaString: |
minLength: 1
additionalSchemaStrings:
rbac.authorization.k8s.io/Role: |
type: object
# This schema is validated for all roleBindings, regardless of their roleRef.
{{ if eq .roleRef.kind "Role" }}
{{ if and (not (hasPrefix .metadata.name "system:")) (ne .metadata.name "gce:podsecuritypolicy:calico-sa") }}
# This schema is validated for all roleBindings, regardless of their roleRef.
type: object
required: ["metadata", "rules"]
allOf:
- properties:
+5 -9
View File
@@ -2,6 +2,10 @@ successMessage: Pod has a valid topology spread constraint
failureMessage: Pod should be configured with a valid topology spread constraint
category: Reliability
target: PodSpec
controllers:
exclude:
- Job
- CronJob
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
@@ -10,12 +14,4 @@ schema:
properties:
topologySpreadConstraints:
type: array
items:
type: object
properties:
topologyKey:
anyOf:
- type: string
const: "kubernetes.io/hostname"
- type: string
const: "topology.kubernetes.io/zone"
minItems: 1
+35 -10
View File
@@ -24,6 +24,7 @@ import (
"net/http"
"os"
"os/exec"
"strings"
workloads "github.com/fairwindsops/insights-plugins/plugins/workloads"
workloadsPkg "github.com/fairwindsops/insights-plugins/plugins/workloads/pkg"
@@ -48,12 +49,15 @@ var (
resourceToAudit string
useColor bool
helmChart string
helmValues string
helmValues []string
helmSkipTests bool
checks []string
auditNamespace string
severityLevel string
skipSslValidation bool
uploadInsights bool
clusterName string
quiet bool
)
func init() {
@@ -69,12 +73,15 @@ func init() {
auditCmd.PersistentFlags().StringVar(&displayName, "display-name", "", "An optional identifier for the audit.")
auditCmd.PersistentFlags().StringVar(&resourceToAudit, "resource", "", "Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.")
auditCmd.PersistentFlags().StringVar(&helmChart, "helm-chart", "", "Will fill out Helm template")
auditCmd.PersistentFlags().StringVar(&helmValues, "helm-values", "", "Optional flag to add helm values")
auditCmd.PersistentFlags().StringSliceVar(&helmValues, "helm-values", []string{}, "Optional flag to add helm values")
auditCmd.PersistentFlags().BoolVar(&helmSkipTests, "helm-skip-tests", false, "Corresponds to --skip-tests of helm template")
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().StringVar(&severityLevel, "severity", "", "Severity level used to filter results. Behaves like log levels. 'danger' is the least verbose (warning, danger)")
auditCmd.PersistentFlags().BoolVar(&skipSslValidation, "skip-ssl-validation", false, "Skip https certificate verification")
auditCmd.PersistentFlags().BoolVar(&uploadInsights, "upload-insights", false, "Upload scan results to Fairwinds Insights")
auditCmd.PersistentFlags().StringVar(&clusterName, "cluster-name", "", "Set --cluster-name to a descriptive name for the cluster you're auditing")
auditCmd.PersistentFlags().BoolVar(&quiet, "quiet", false, "Suppress the 'upload to Insights' prompt.")
}
var auditCmd = &cobra.Command{
@@ -107,7 +114,7 @@ var auditCmd = &cobra.Command{
}
if helmChart != "" {
var err error
auditPath, err = ProcessHelmTemplates(helmChart, helmValues)
auditPath, err = ProcessHelmTemplates(helmChart, helmValues, helmSkipTests)
if err != nil {
logrus.Errorf("Couldn't process helm chart: %v", err)
os.Exit(1)
@@ -172,10 +179,14 @@ var auditCmd = &cobra.Command{
logrus.Errorf("reporting audit file to insights: %v", err)
os.Exit(1)
}
logrus.Println("Success! You can see your results at:")
logrus.Printf("%s/orgs/%s/clusters/%s/action-items\n", insightsHost, auth.Organization, clusterName)
os.Stderr.WriteString("\n\nSuccess! You can see your results at:")
os.Stderr.WriteString(fmt.Sprintf("\n\n%s/orgs/%s/clusters/%s/action-items\n\n", insightsHost, auth.Organization, clusterName))
} else {
outputAudit(auditData, auditOutputFile, auditOutputURL, auditOutputFormat, useColor, onlyShowFailedTests)
outputAudit(auditData, auditOutputFile, auditOutputURL, auditOutputFormat, useColor, onlyShowFailedTests, severityLevel)
if !quiet {
os.Stderr.WriteString("\n\n🚀 Upload your Polaris findings to Fairwinds Insights to see remediation advice, add teammates, integrate with Slack or Jira, and more:")
os.Stderr.WriteString("\n\n polaris " + strings.Join(os.Args[1:], " ") + " --upload-insights --cluster-name=my-cluster\n\n")
}
}
summary := auditData.GetSummary()
@@ -191,7 +202,7 @@ var auditCmd = &cobra.Command{
}
// ProcessHelmTemplates turns helm into yaml to be processed by Polaris or the other tools.
func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
func ProcessHelmTemplates(helmChart string, helmValues []string, helmSkipTests bool) (string, error) {
cmd := exec.Command("helm", "dependency", "update", helmChart)
output, err := cmd.CombinedOutput()
if err != nil {
@@ -209,8 +220,12 @@ func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
"--output-dir",
dir,
}
if helmValues != "" {
params = append(params, "--values", helmValues)
for _, v := range helmValues {
params = append(params, "--values", v)
}
if helmSkipTests {
params = append(params, "--skip-tests")
}
cmd = exec.Command("helm", params...)
@@ -223,10 +238,20 @@ func ProcessHelmTemplates(helmChart, helmValues string) (string, error) {
return dir, nil
}
func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFormat string, useColor bool, onlyShowFailedTests bool) {
func outputAudit(auditData validator.AuditData, outputFile, outputURL, outputFormat string, useColor bool, onlyShowFailedTests bool, severityLevel string) {
if onlyShowFailedTests {
auditData = auditData.RemoveSuccessfulResults()
}
if severityLevel != "" {
switch severityLevel {
case "danger":
auditData = auditData.FilterResultsBySeverityLevel(cfg.SeverityDanger)
case "warning":
auditData = auditData.FilterResultsBySeverityLevel(cfg.SeverityWarning)
}
}
var outputBytes []byte
var err error
if outputFormat == "score" {
+7 -147
View File
@@ -15,26 +15,17 @@
package cmd
import (
"fmt"
"errors"
"os"
"path/filepath"
"strings"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/mutation"
"github.com/fairwindsops/polaris/pkg/validator"
"github.com/fairwindsops/polaris/pkg/fix"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
const templateLineMarker = "# POLARIS_FIX_TMPL"
const templateOpenMarker = "POLARIS_OPEN_TMPL"
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
var (
filesPath string
checksToFix []string
fixAll bool
isTemplate bool
)
@@ -52,145 +43,14 @@ var fixCommand = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
logrus.Debug("Setting up controller manager")
if filesPath == "" {
logrus.Error("Please specify a files-path flag")
cmd.Help()
os.Exit(1)
}
var yamlFiles []string
fileInfo, err := os.Stat(filesPath)
err := fix.Execute(config, filesPath, isTemplate, checksToFix...)
if err != nil {
logrus.Error(err)
os.Exit(1)
}
if fileInfo.IsDir() {
baseDir := filesPath
if !strings.HasSuffix(filesPath, "/") {
baseDir = baseDir + "/"
}
yamlFiles, err = getYamlFiles(baseDir)
if err != nil {
logrus.Error(err)
if errors.Is(err, fix.ErrFilesPathRequired) {
logrus.Error("Please specify a files-path flag")
cmd.Help()
os.Exit(1)
}
} else {
yamlFiles = append(yamlFiles, filesPath)
logrus.Fatal(err)
}
if len(checksToFix) > 0 {
if len(checksToFix) == 1 && checksToFix[0] == "all" {
allchecks := []string{}
for key := range config.Checks {
allchecks = append(allchecks, key)
}
config.Mutations = allchecks
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
config.Mutations = nil
} else {
config.Mutations = checksToFix
}
}
for _, fullFilePath := range yamlFiles {
yamlContent, err := os.ReadFile(fullFilePath)
if err != nil {
logrus.Fatalf("Error reading file with file path %s: %v", fullFilePath, err)
}
if err != nil {
logrus.Fatalf("Error marshalling %s: %v", fullFilePath, err)
}
if isTemplate {
yamlContent = []byte(detemplate(string(yamlContent)))
}
kubeResources := kube.CreateResourceProviderFromYaml(string(yamlContent))
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
if err != nil {
logrus.Fatalf("Error applying schema check to the resources %s: %v", fullFilePath, err)
}
allMutations := mutation.GetMutationsFromResults(results)
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
}
}
}
if isTemplate {
updatedYamlContent = retemplate(updatedYamlContent)
}
if updatedYamlContent != "" {
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
if err != nil {
logrus.Fatalf("Error writing output to file: %v", err)
}
}
}
},
}
func detemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = detemplateLine(line)
}
return strings.Join(lines, "\n")
}
func retemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = retemplateLine(line)
}
return strings.Join(lines, "\n")
}
func detemplateLine(line string) string {
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
line = strings.ReplaceAll(line, "{", templateOpenMarker)
line = strings.ReplaceAll(line, "}", templateCloseMarker)
return line
}
tmplStart := strings.Index(line, "{{")
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
return newLine
}
func retemplateLine(line string) string {
if !strings.Contains(line, templateLineMarker) {
line = strings.ReplaceAll(line, templateOpenMarker, "{")
line = strings.ReplaceAll(line, templateCloseMarker, "}")
return line
}
return strings.Replace(line, templateLineMarker, "", 1)
}
func getYamlFiles(rootpath string) ([]string, error) {
var list []string
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
list = append(list, path)
}
return nil
})
return list, err
}
+4 -1
View File
@@ -16,6 +16,7 @@ package cmd
import (
"os"
"strings"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/sirupsen/logrus"
@@ -84,7 +85,9 @@ var rootCmd = &cobra.Command{
os.Exit(1)
},
PersistentPostRun: func(cmd *cobra.Command, args []string) {
os.Stderr.WriteString("\n\nWant more? Automate Polaris for free with Fairwinds Insights!\n🚀 https://fairwinds.com/insights-signup/polaris 🚀 \n")
if !strings.HasPrefix(cmd.Use, "audit") {
os.Stderr.WriteString("\n\nWant more? Automate Polaris for free with Fairwinds Insights!\n🚀 https://fairwinds.com/insights-signup/polaris 🚀 \n")
}
},
}
+4 -3
View File
@@ -53,7 +53,8 @@ var webhookCmd = &cobra.Command{
CertDir: certDir,
Port: webhookPort,
WebhookServer: webhook.NewServer(webhook.Options{
CertDir: certDir,
CertDir: certDir,
Port: webhookPort,
CertName: "tls.crt",
KeyName: "tls.key",
}),
@@ -74,10 +75,10 @@ var webhookCmd = &cobra.Command{
}
if enableValidations {
fwebhook.NewValidateWebhook(mgr, fwebhook.Validator{Config: config, Client: mgr.GetClient()})
fwebhook.NewValidateWebhook(mgr, config)
}
if enableMutations {
fwebhook.NewMutateWebhook(mgr, fwebhook.Mutator{Config: config, Client: mgr.GetClient()})
fwebhook.NewMutateWebhook(mgr, config)
}
logrus.Infof("Polaris webhook server listening on port %d", webhookPort)
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
+3
View File
@@ -6,6 +6,9 @@ meta:
---
## Unreleased
* Change `metadataAndNameMismatched` to `metadataAndInstanceMismatched`
## 8.1.1
* Add category for `metadataAndNameMismatched`.
* Fix category for `priorityClassNotSet`.
+2 -2
View File
@@ -17,7 +17,7 @@ key | default | description
`priorityClassNotSet` | `warning` | Fails when a priorityClassName is not set for a pod.
`deploymentMissingReplicas` | `warning` | Fails when there is only one replica for a deployment.
`missingPodDisruptionBudget` | `warning` | Fails when PDB is missing.
`metadataAndNameMismatched` | `warning` | Fails when label `app.kubernetes.io/name` and `metadata.name` mismatch
`metadataAndInstanceMismatched` | `warning` | Fails when label `app.kubernetes.io/instance` and `metadata.name` mismatch
`topologySpreadConstraint` | `warning` | Fails when there is no topology spread constraint on the pod
## Background
@@ -70,4 +70,4 @@ spec:
- [Kubernetes Docs: Configure Liveness and Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)
- [Utilizing Kubernetes Liveness and Readiness Probes to Automatically Recover From Failure](https://medium.com/spire-labs/utilizing-kubernetes-liveness-and-readiness-probes-to-automatically-recover-from-failure-2fe0314f2b2e)
- [Kubernetes Liveness and Readiness Probes: How to Avoid Shooting Yourself in the Foot](https://blog.colinbreck.com/kubernetes-liveness-and-readiness-probes-how-to-avoid-shooting-yourself-in-the-foot/)
- [Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)
- [Topology Spread Constraints](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)
+31 -2
View File
@@ -9,14 +9,18 @@ meta:
# top-level commands
audit
Runs a one-time audit.
auth
Authenticate polaris with Fairwinds Insights
dashboard
Runs the webserver for Polaris dashboard.
fix
Fix Infrastructure as code files.
help
Prints help, if you give it a command then it will print help for that command. Same as -h
version
Prints the version of Polaris
webhook
Runs the webhook webserver
Runs the webhook webserver.
# global flags
-c, --config string Location of Polaris configuration file.
@@ -25,6 +29,7 @@ webhook
--disallow-config-exemptions Disallow exemptions set within the configuration file.
--disallow-annotation-exemptions Disallow any exemption defined as a controller annotation.
--kubeconfig string Paths to a kubeconfig. Only required if out-of-cluster.
--insights-host string Fairwinds Insights host URL. (default "https://insights.fairwinds.com")
--log-level string Logrus log level. (default "info")
# dashboard flags
@@ -38,24 +43,48 @@ webhook
# audit flags
--audit-path string If specified, audits one or more YAML files instead of a cluster.
--checks stringArray Optional flag to specify specific checks to check
--checks strings Optional flag to specify specific checks to check
--cluster-name string Set --cluster-name to a descriptive name for the cluster you're auditing
--color Whether to use color in pretty format. (default true)
--display-name string An optional identifier for the audit.
-f, --format string Output format for results - json, yaml, pretty, or score. (default "json")
--helm-chart string Will fill out Helm template
--helm-values string Optional flag to add helm values
--helm-skip-tests bool Corresponds to --skip-tests of helm template
-h, --help help for audit
--namespace string Namespace to audit. Only applies to in-cluster audits
--only-show-failed-tests If specified, audit output will only show failed tests.
--output-file string Destination file for audit results.
--output-url string Destination URL to send audit results.
--quiet Suppress the 'upload to Insights' prompt.
--resource string Audit a specific resource, in the format namespace/kind/version/name, e.g. nginx-ingress/Deployment.apps/v1/default-backend.
--set-exit-code-below-score int Set an exit code of 4 when the score is below this threshold (1-100).
--set-exit-code-on-danger Set an exit code of 3 when the audit contains danger-level issues.
--severity string Severity level used to filter results. Behaves like log levels. 'danger' is the least verbose (warning, danger)
--skip-ssl-validation Skip https certificate verification
--upload-insights Upload scan results to Fairwinds Insights
# fix flags
--checks strings Optional flag to specify specific checks to fix eg. checks=hostIPCSet,hostPIDSet and checks=all applies fix to all defined checks mutations
--files-path string mutate and fix one or more YAML files in a specified folder
-h, --help help for fix
--template set to true when modifyng a YAML template, like a Helm chart (experimental)
# webhook flags
--disable-webhook-config-installer disable the installer in the webhook server, so it won't install webhook configuration resources during bootstrapping.
-h, --help help for webhook
-p, --port int Port for the dashboard webserver. (default 9876)
# auth sub-commands
login Authenticate polaris with Fairwinds Insights.
logout Log out of a Fairwinds Insights.
status View authentication status.
token Print the auth token gh is configured to use.
```
#### Suppressing 'upload to Insights' output
When running the `polaris audit` subcommand, you can suppress the following output using the `--quiet flag`:
> 🚀 Upload your Polaris findings to Fairwinds Insights to see remediation advice, add teammates, integrate with Slack or Jira, and more:
+1 -1
View File
@@ -9,7 +9,7 @@ checks:
topologySpreadConstraint: warning
pdbDisruptionsIsZero: warning
missingPodDisruptionBudget: warning
metadataAndNameMismatched: warning
metadataAndInstanceMismatched: warning
# efficiency
cpuRequestsMissing: warning
+1 -1
View File
@@ -6,7 +6,7 @@ checks:
pullPolicyNotAlways: warning
readinessProbeMissing: warning
livenessProbeMissing: warning
metadataAndNameMismatched: warning
metadataAndInstanceMismatched: warning
pdbDisruptionsIsZero: warning
missingPodDisruptionBudget: warning
topologySpreadConstraint: warning
+21 -21
View File
@@ -1,9 +1,10 @@
module github.com/fairwindsops/polaris
go 1.20
go 1.22
require (
github.com/AlecAivazis/survey/v2 v2.3.6
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/fairwindsops/controller-utils v0.3.0
github.com/fairwindsops/insights-plugins/plugins/workloads v0.0.0-20230601204422-5c789e15990c
github.com/fatih/color v1.15.0
github.com/gobuffalo/packr/v2 v2.8.3
@@ -11,14 +12,14 @@ require (
github.com/pkg/errors v0.9.1
github.com/qri-io/jsonschema v0.1.2
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
github.com/thoas/go-funk v0.9.3
gomodules.xyz/jsonpatch/v2 v2.3.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.27.2
k8s.io/apimachinery v0.27.2
k8s.io/client-go v0.27.2
k8s.io/api v0.29.0
k8s.io/apimachinery v0.29.0
k8s.io/client-go v0.29.0
sigs.k8s.io/controller-runtime v0.15.0
sigs.k8s.io/yaml v1.3.0
)
@@ -27,12 +28,11 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fairwindsops/controller-utils v0.3.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
@@ -41,8 +41,8 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
@@ -69,20 +69,20 @@ require (
github.com/prometheus/procfs v0.9.0 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.5.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/component-base v0.27.2 // indirect
k8s.io/klog/v2 v2.90.1 // indirect
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)
+64 -63
View File
@@ -37,13 +37,12 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw=
github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI=
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -52,9 +51,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -64,27 +61,24 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ=
github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -97,7 +91,6 @@ github.com/fairwindsops/insights-plugins/plugins/workloads v0.0.0-20230601204422
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
@@ -105,10 +98,10 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
@@ -116,6 +109,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
@@ -160,8 +154,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -173,8 +167,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -193,6 +188,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -249,9 +245,9 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -296,8 +292,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4=
github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -326,6 +324,7 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@@ -338,17 +337,15 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -366,15 +363,13 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
@@ -385,14 +380,15 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -400,6 +396,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -435,6 +432,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -472,8 +470,9 @@ 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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
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=
@@ -486,8 +485,8 @@ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -499,7 +498,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -546,17 +547,17 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -565,8 +566,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -624,7 +627,9 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -702,7 +707,6 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -723,7 +727,6 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -736,12 +739,10 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -754,7 +755,6 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
@@ -766,21 +766,22 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo=
k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4=
k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A=
k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA=
k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo=
k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg=
k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE=
k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ=
k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ=
k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8=
k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38=
k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo=
k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo=
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
@@ -788,7 +789,7 @@ sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0
sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
+1 -1
View File
@@ -55,7 +55,7 @@ var (
// Other checks
"tlsSettingsMissing",
"pdbDisruptionsIsZero",
"metadataAndNameMismatched",
"metadataAndInstanceMismatched",
"missingPodDisruptionBudget",
"missingNetworkPolicy",
"sensitiveConfigmapContent",
+3
View File
@@ -143,6 +143,9 @@ func (max resourceMaximum) Validate(path string, data interface{}, errs *[]jsons
}
func parseQuantity(i interface{}) (resource.Quantity, *[]jsonschema.ValError) {
if resNum, ok := i.(float64); ok {
i = fmt.Sprintf("%f", resNum)
}
resStr, ok := i.(string)
if !ok {
return resource.Quantity{}, &[]jsonschema.ValError{
+159
View File
@@ -0,0 +1,159 @@
package fix
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
"github.com/fairwindsops/polaris/pkg/mutation"
"github.com/fairwindsops/polaris/pkg/validator"
)
const templateLineMarker = "# POLARIS_FIX_TMPL"
const templateOpenMarker = "POLARIS_OPEN_TMPL"
const templateCloseMarker = "POLARIS_CLOSE_TMPL"
var ErrFilesPathRequired = errors.New("files-path flag is required")
func Execute(config config.Configuration, filesPath string, isTemplate bool, checksToFix ...string) error {
if filesPath == "" {
return ErrFilesPathRequired
}
var yamlFiles []string
fileInfo, err := os.Stat(filesPath)
if err != nil {
return fmt.Errorf("error getting file info: %v", err)
}
if fileInfo.IsDir() {
baseDir := filesPath
if !strings.HasSuffix(filesPath, "/") {
baseDir = baseDir + "/"
}
yamlFiles, err = getYamlFiles(baseDir)
if err != nil {
return fmt.Errorf("error getting yaml files from directory: %v", err)
}
} else {
yamlFiles = append(yamlFiles, filesPath)
}
if len(checksToFix) > 0 {
if len(checksToFix) == 1 && checksToFix[0] == "all" {
allchecks := []string{}
for key := range config.Checks {
allchecks = append(allchecks, key)
}
config.Mutations = allchecks
} else if len(checksToFix) == 0 && checksToFix[0] == "none" {
config.Mutations = nil
} else {
config.Mutations = checksToFix
}
}
for _, fullFilePath := range yamlFiles {
yamlContent, err := os.ReadFile(fullFilePath)
if err != nil {
return fmt.Errorf("error reading file with file path %s: %v", fullFilePath, err)
}
if isTemplate {
yamlContent = []byte(detemplate(string(yamlContent)))
}
kubeResources, err := kube.CreateResourceProviderFromYaml(string(yamlContent))
if err != nil {
return fmt.Errorf("error creating resource provider from yaml: %v", err)
}
results, err := validator.ApplyAllSchemaChecksToResourceProvider(&config, kubeResources)
if err != nil {
return fmt.Errorf("error applying schema check to the resources %s: %v", fullFilePath, err)
}
allMutations := mutation.GetMutationsFromResults(results)
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 {
return fmt.Errorf("error applying schema mutations to the resource %s: %v", key, err)
}
if updatedYamlContent != "" {
updatedYamlContent += "\n---\n"
}
updatedYamlContent += mutatedYamlContent
}
}
}
if isTemplate {
updatedYamlContent = retemplate(updatedYamlContent)
}
if updatedYamlContent != "" {
err = os.WriteFile(fullFilePath, []byte(updatedYamlContent), 0644)
if err != nil {
return fmt.Errorf("error writing output to file: %v", err)
}
}
}
return nil
}
func detemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = detemplateLine(line)
}
return strings.Join(lines, "\n")
}
func retemplate(content string) string {
lines := strings.Split(content, "\n")
for idx, line := range lines {
lines[idx] = retemplateLine(line)
}
return strings.Join(lines, "\n")
}
func detemplateLine(line string) string {
if !strings.HasPrefix(strings.TrimSpace(line), "{{") {
line = strings.ReplaceAll(line, "{", templateOpenMarker)
line = strings.ReplaceAll(line, "}", templateCloseMarker)
return line
}
tmplStart := strings.Index(line, "{{")
newLine := line[:tmplStart] + templateLineMarker + line[tmplStart:]
return newLine
}
func retemplateLine(line string) string {
if !strings.Contains(line, templateLineMarker) {
line = strings.ReplaceAll(line, templateOpenMarker, "{")
line = strings.ReplaceAll(line, templateCloseMarker, "}")
return line
}
return strings.Replace(line, templateLineMarker, "", 1)
}
func getYamlFiles(rootpath string) ([]string, error) {
var list []string
err := filepath.Walk(rootpath, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
if filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
list = append(list, path)
}
return nil
})
return list, err
}
+26 -62
View File
@@ -26,6 +26,7 @@ import (
"strings"
"time"
"github.com/fairwindsops/controller-utils/pkg/controller"
conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/sirupsen/logrus"
@@ -33,7 +34,6 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
k8sYaml "k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/client-go/dynamic"
@@ -215,10 +215,13 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
}
// CreateResourceProviderFromYaml returns a new ResourceProvider using the yaml
func CreateResourceProviderFromYaml(yamlContent string) *ResourceProvider {
func CreateResourceProviderFromYaml(yamlContent string) (*ResourceProvider, error) {
resources := newResourceProvider("unknown", "Content", "unknown")
resources.addResourcesFromYaml(string(yamlContent))
return &resources
err := resources.addResourcesFromYaml(string(yamlContent))
if err != nil {
return nil, err
}
return &resources, nil
}
// CreateResourceProviderFromCluster creates a new ResourceProvider using live data from a cluster
@@ -297,13 +300,6 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
}
namespaces = nsList
}
logrus.Info("Loading pods")
pods, err := kube.CoreV1().Pods(c.Namespace).List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Pods: %v", err)
return nil, err
}
logrus.Info("Setting up restmapper")
resources, err := restmapper.GetAPIGroupResources(kube.Discovery())
if err != nil {
@@ -343,6 +339,10 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
logrus.Warnf("Error retrieving mapping of Kind %s because of error: %v", kind, err)
return nil, err
}
if c.Namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameNamespace {
logrus.Infof("Skipping %s because of auditing specific namespace", mapping.GroupVersionKind)
continue
}
logrus.Info("Loading " + kind)
objects, err := dynamic.Resource(mapping.Resource).Namespace(c.Namespace).List(ctx, metav1.ListOptions{})
@@ -358,17 +358,24 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
kubernetesResources = append(kubernetesResources, res)
}
}
objectCache := map[string]unstructured.Unstructured{}
logrus.Info("Loading controllers")
controllers, err := LoadControllers(ctx, pods.Items, dynamic, restMapper, objectCache)
client := controller.Client{
Context: ctx,
Dynamic: dynamic,
RESTMapper: restMapper,
}
topControllers, err := client.GetAllTopControllersSummary("")
if err != nil {
logrus.Errorf("Error loading controllers from pods: %v", err)
return nil, err
return nil, fmt.Errorf("error while getting all TopControllers: %v", err)
}
for _, workload := range topControllers {
topController := workload.TopController
workloadObj, err := NewGenericResourceFromUnstructured(topController, nil)
if err != nil {
return nil, fmt.Errorf("could not parse workload %v: %w", workload, err)
}
kubernetesResources = append(kubernetesResources, workloadObj)
}
// resources loaded from custom checks can also contain controllers and thus would be added twice to the provider
kubernetesResources = deduplicateControllers(append(kubernetesResources, controllers...))
provider.Nodes = nodes.Items
provider.Namespaces = namespaces.Items
@@ -377,49 +384,6 @@ func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interfac
return &provider, nil
}
// LoadControllers loads a list of controllers from the kubeResources Pods
func LoadControllers(ctx context.Context, pods []corev1.Pod, dynamicClient dynamic.Interface, restMapperPointer meta.RESTMapper, objectCache map[string]unstructured.Unstructured) ([]GenericResource, error) {
interfaces := []GenericResource{}
deduped := map[string]*corev1.Pod{}
for idx, pod := range pods {
owners := pod.ObjectMeta.OwnerReferences
if len(owners) == 0 {
deduped[pod.ObjectMeta.Namespace+"/Pod/"+pod.ObjectMeta.Name] = &pods[idx]
continue
}
deduped[pod.ObjectMeta.Namespace+"/"+owners[0].Kind+"/"+owners[0].Name] = &pods[idx]
}
for key, pod := range deduped {
logrus.Debugf("Resolving controller from pod %s", key)
workload, err := ResolveControllerFromPod(ctx, *pod, dynamicClient, restMapperPointer, objectCache)
if err != nil {
return nil, err
}
interfaces = append(interfaces, workload)
}
return interfaces, nil
}
// Because the controllers with an Owner take on the name of the Owner, this eliminates any duplicates.
// In cases like CronJobs older children can hang around, so this takes the most recent.
func deduplicateControllers(inputResources []GenericResource) []GenericResource {
controllerMap := make(map[string]GenericResource)
for _, controller := range inputResources {
key := controller.ObjectMeta.GetNamespace() + "/" + controller.Kind + "/" + controller.ObjectMeta.GetName()
oldController, ok := controllerMap[key]
if !ok || controller.ObjectMeta.GetCreationTimestamp().Time.After(oldController.ObjectMeta.GetCreationTimestamp().Time) {
controllerMap[key] = controller
}
}
results := make([]GenericResource, len(controllerMap))
idx := 0
for _, controller := range controllerMap {
results[idx] = controller
idx++
}
return results
}
func (resources *ResourceProvider) addResourcesFromReader(reader io.Reader) error {
contents, err := io.ReadAll(reader)
if err != nil {
+1 -1
View File
@@ -16,8 +16,8 @@ package kube
import (
"bytes"
"fmt"
"context"
"fmt"
"os"
"testing"
"time"
+84 -62
View File
@@ -25,14 +25,15 @@ var testCases = []struct {
mutated string
patch config.Mutation
message string
}{{
original: oldYaml,
patch: config.Mutation{
Op: "add",
Value: "Denver",
Path: "/pets/0/owners/*/location",
},
mutated: `pets:
}{
{
original: oldYaml,
patch: config.Mutation{
Op: "add",
Value: "Denver",
Path: "/pets/0/owners/*/location",
},
mutated: `pets:
- name: fido
owners:
- name: Alice
@@ -43,27 +44,27 @@ var testCases = []struct {
location: Denver
- name: scooby
`,
}, {
original: oldYaml,
patch: config.Mutation{
Op: "remove",
Path: "/pets/0/owners/*/aliases",
},
mutated: `pets:
}, {
original: oldYaml,
patch: config.Mutation{
Op: "remove",
Path: "/pets/0/owners/*/aliases",
},
mutated: `pets:
- name: fido
owners:
- name: Alice
- name: Bob
- name: scooby
`,
}, {
original: oldYaml,
patch: config.Mutation{
Op: "add",
Value: "rob",
Path: "/pets/0/owners/*/aliases/-",
},
mutated: `pets:
}, {
original: oldYaml,
patch: config.Mutation{
Op: "add",
Value: "rob",
Path: "/pets/0/owners/*/aliases/-",
},
mutated: `pets:
- name: fido
owners:
- name: Alice
@@ -75,23 +76,23 @@ var testCases = []struct {
- rob
- name: scooby
`,
}, {
original: `
}, {
original: `
pets:
- name: fido
`,
patch: config.Mutation{
Op: "add",
Value: "Alice",
Path: "/pets/0/owners/0/name",
},
mutated: `pets:
patch: config.Mutation{
Op: "add",
Value: "Alice",
Path: "/pets/0/owners/0/name",
},
mutated: `pets:
- name: fido
owners:
- name: Alice
`,
}, {
original: `
}, {
original: `
obj:
foo:
bar:
@@ -99,54 +100,75 @@ obj:
- b
baz: quux
`,
patch: config.Mutation{
Op: "replace",
Value: map[string]interface{}{
"bar": []string{"c", "d"},
patch: config.Mutation{
Op: "replace",
Value: map[string]interface{}{
"bar": []string{"c", "d"},
},
Path: "/obj/foo",
},
Path: "/obj/foo",
},
mutated: `obj:
mutated: `obj:
foo:
bar:
- c
- d
baz: quux
`,
}, {
original: `
}, {
original: `
foo: bar
`,
patch: config.Mutation{
Op: "replace",
Value: "baz",
Path: "/foo",
Comment: "# We set this to baz",
},
mutated: `
patch: config.Mutation{
Op: "replace",
Value: "baz",
Path: "/foo",
Comment: "# We set this to baz",
},
mutated: `
foo: baz # We set this to baz
`,
message: "Expected a comment to appear",
}, {
original: `
message: "Expected a comment to appear",
}, {
original: `
foo: bar
`,
patch: config.Mutation{
Op: "add",
Value: map[string]interface{}{
"baz": "quux",
patch: config.Mutation{
Op: "add",
Value: map[string]interface{}{
"baz": "quux",
},
Path: "/extra",
Comment: "# These are extra things",
},
Path: "/extra",
Comment: "# These are extra things",
},
mutated: `
mutated: `
foo: bar
extra:
# These are extra things
baz: quux
`,
message: "Expected a comment to appear next to an object",
}}
message: "Expected a comment to appear next to an object",
},
{
original: `
foo: bar
`,
patch: config.Mutation{
Op: "replace",
Value: map[string]interface{}{
"baz": "quux",
},
Path: "/extra",
Comment: "# These are extra things",
},
mutated: `
foo: bar
extra:
# These are extra things
baz: quux
`,
message: "Expected a comment to appear next to an object",
},
}
func TestApplyAllMutations(t *testing.T) {
for _, tc := range testCases {
+64
View File
@@ -53,6 +53,26 @@ type AuditData struct {
Score uint
}
// FilterResultsBySeverityLevel includes results according to the provided severity level:
// 'danger' is the least verbose, 'warning' is medium verbosity, default behavior will
// include all results, which currently also includes 'ignore'
func (res AuditData) FilterResultsBySeverityLevel(severityLevel config.Severity) AuditData {
resCopy := res
resCopy.Results = []Result{}
filteredResults := funk.Map(res.Results, func(auditDataResult Result) Result {
return auditDataResult.filterResultsBySeverityLevel(severityLevel)
}).([]Result)
for _, result := range filteredResults {
if result.isNotEmpty() {
resCopy.Results = append(resCopy.Results, result)
}
}
return resCopy
}
// RemoveSuccessfulResults removes all tests that have passed
func (res AuditData) RemoveSuccessfulResults() AuditData {
resCopy := res
@@ -108,6 +128,25 @@ func (res ResultSet) removeSuccessfulResults() ResultSet {
return newResults
}
func (res ResultSet) filterResultsBySeverityLevel(severityLevel config.Severity) ResultSet {
newResults := ResultSet{}
for k, resultMessage := range res {
switch severityLevel {
case config.SeverityDanger:
if resultMessage.Severity == config.SeverityDanger {
newResults[k] = resultMessage
}
case config.SeverityWarning:
if resultMessage.Severity == config.SeverityDanger || resultMessage.Severity == config.SeverityWarning {
newResults[k] = resultMessage
}
default:
return res
}
}
return newResults
}
// Result provides results for a Kubernetes object
type Result struct {
Name string
@@ -128,6 +167,16 @@ func (res Result) removeSuccessfulResults() Result {
return resCopy
}
func (res Result) filterResultsBySeverityLevel(severityLevel config.Severity) Result {
resCopy := res
resCopy.Results = res.Results.filterResultsBySeverityLevel(severityLevel)
if res.PodResult != nil {
podCopy := res.PodResult.filterResultsBySeverityLevel(severityLevel)
resCopy.PodResult = &podCopy
}
return resCopy
}
func (res Result) isNotEmpty() bool {
if res.PodResult != nil {
return res.PodResult.isNotEmpty()
@@ -151,6 +200,15 @@ func (res PodResult) removeSuccessfulResults() PodResult {
return resCopy
}
func (res PodResult) filterResultsBySeverityLevel(severityLevel config.Severity) PodResult {
resCopy := PodResult{}
resCopy.Results = res.Results.filterResultsBySeverityLevel(severityLevel)
resCopy.ContainerResults = funk.Map(res.ContainerResults, func(containerResult ContainerResult) ContainerResult {
return containerResult.filterResultsBySeverityLevel(severityLevel)
}).([]ContainerResult)
return resCopy
}
func (res PodResult) isNotEmpty() bool {
for _, cr := range res.ContainerResults {
if cr.isNotEmpty() {
@@ -172,6 +230,12 @@ func (res ContainerResult) removeSuccessfulResults() ContainerResult {
return resCopy
}
func (res ContainerResult) filterResultsBySeverityLevel(severityLevel config.Severity) ContainerResult {
resCopy := res
resCopy.Results = res.Results.filterResultsBySeverityLevel(severityLevel)
return resCopy
}
func (res ContainerResult) isNotEmpty() bool {
return res.Results.isNotEmpty()
}
+10 -12
View File
@@ -35,7 +35,7 @@ import (
type schemaTestCase struct {
Target config.TargetKind
Resource kube.GenericResource
IsInitContianer bool
IsInitContainer bool
Container *corev1.Container
ResourceProvider *kube.ResourceProvider
}
@@ -80,7 +80,7 @@ func resolveCheck(conf *config.Configuration, checkID string, test schemaTestCas
if !conf.IsActionable(check.ID, test.Resource.ObjectMeta, containerName) {
return nil, nil
}
if !check.IsActionable(test.Target, test.Resource.Kind, test.IsInitContianer) {
if !check.IsActionable(test.Target, test.Resource.Kind, test.IsInitContainer) {
return nil, nil
}
templateInput, err := getTemplateInput(test)
@@ -306,7 +306,7 @@ func applyContainerSchemaChecks(conf *config.Configuration, resources *kube.Reso
ResourceProvider: resources,
Resource: controller,
Container: container,
IsInitContianer: isInit,
IsInitContainer: isInit,
}
return applySchemaChecks(conf, test)
}
@@ -408,15 +408,13 @@ func applySchemaCheck(conf *config.Configuration, checkID string, test schemaTes
}
result := makeResult(conf, check, passes, issues)
if !passes {
if funk.Contains(conf.Mutations, checkID) && len(check.Mutations) > 0 {
mutations := funk.Map(check.Mutations, func(mutation config.Mutation) config.Mutation {
mutationCopy := deepCopyMutation(mutation)
mutationCopy.Path = prefix + mutationCopy.Path
return mutationCopy
}).([]config.Mutation)
result.Mutations = mutations
}
if funk.Contains(conf.Mutations, checkID) && len(check.Mutations) > 0 {
mutations := funk.Map(check.Mutations, func(mutation config.Mutation) config.Mutation {
mutationCopy := deepCopyMutation(mutation)
mutationCopy.Path = prefix + mutationCopy.Path
return mutationCopy
}).([]config.Mutation)
result.Mutations = mutations
}
return &result, nil
}
+31 -5
View File
@@ -21,6 +21,7 @@ import (
"github.com/fairwindsops/polaris/pkg/mutation"
"github.com/sirupsen/logrus"
"gomodules.xyz/jsonpatch/v2"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -35,41 +36,66 @@ type Mutator struct {
decoder *admission.Decoder
}
var _ admission.Handler = &Mutator{}
// NewMutateWebhook creates a mutating admission webhook for the apiType.
func NewMutateWebhook(mgr manager.Manager, mutator Mutator) {
func NewMutateWebhook(mgr manager.Manager, c config.Configuration) {
path := "/mutate"
mutator := Mutator{
Client: mgr.GetClient(),
decoder: admission.NewDecoder(runtime.NewScheme()),
Config: c,
}
mgr.GetWebhookServer().Register(path, &webhook.Admission{Handler: &mutator})
}
func (m *Mutator) mutate(req admission.Request) ([]jsonpatch.Operation, error) {
results, kubeResources, err := GetValidatedResults(req.AdmissionRequest.Kind.Kind, m.decoder, req, m.Config)
if err != nil {
logrus.Errorf("Error while validating resource: %v", err)
return nil, err
}
if results == nil {
logrus.Infof("Not mutating owned pod")
return nil, nil
}
patches := mutation.GetMutationsFromResult(results)
originalYaml, err := yaml.JSONToYAML(kubeResources.OriginalObjectJSON)
if err != nil {
logrus.Errorf("Failed to convert JSON to YAML: %v", err)
return nil, err
}
mutatedYamlStr, err := mutation.ApplyAllMutations(string(originalYaml), patches)
if err != nil {
logrus.Errorf("Failed to apply mutations: %v", err)
return nil, err
}
return jsonpatch.CreatePatch(originalYaml, []byte(mutatedYamlStr))
mutatedJson, err := yaml.YAMLToJSON([]byte(mutatedYamlStr))
if err != nil {
logrus.Errorf("Failed to convert YAML to JSON: %v", err)
return nil, err
}
ops, err := jsonpatch.CreatePatch(kubeResources.OriginalObjectJSON, mutatedJson)
if err != nil {
logrus.Errorf("Failed to create patch from mutation: %v", err)
return nil, err
}
return ops, nil
}
// Handle for Validator to run validation checks.
func (m *Mutator) Handle(ctx context.Context, req admission.Request) admission.Response {
logrus.Info("Starting request")
logrus.Info("Starting mutation request")
patches, err := m.mutate(req)
if err != nil {
logrus.Errorf("Error while getting mutations: %v", err)
return admission.Errored(403, err)
}
if patches == nil {
logrus.Infof("No patches generated")
return admission.Allowed("Allowed")
}
logrus.Infof("Generated %d patches", len(patches))
return admission.Patched("", patches...)
}
+22 -21
View File
@@ -25,6 +25,7 @@ import (
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/webhook"
@@ -38,19 +39,14 @@ type Validator struct {
Config config.Configuration
}
// InjectDecoder injects the decoder.
func (v *Validator) InjectDecoder(d *admission.Decoder) error {
logrus.Info("Injecting decoder")
v.decoder = d
return nil
}
var _ admission.Handler = &Validator{}
// NewValidateWebhook creates a validating admission webhook for the apiType.
func NewValidateWebhook(mgr manager.Manager, validator Validator) {
func NewValidateWebhook(mgr manager.Manager, c config.Configuration) {
path := "/validate"
validator := Validator{
Client: mgr.GetClient(),
decoder: admission.NewDecoder(runtime.NewScheme()),
Config: c,
}
mgr.GetWebhookServer().Register(path, &webhook.Admission{Handler: &validator})
}
@@ -60,35 +56,40 @@ func (v *Validator) handleInternal(req admission.Request) (*validator.Result, ku
// GetValidatedResults returns the validated results.
func GetValidatedResults(kind string, decoder *admission.Decoder, req admission.Request, config config.Configuration) (*validator.Result, kube.GenericResource, error) {
var controller kube.GenericResource
var resource kube.GenericResource
var err error
if kind == "Pod" {
if decoder == nil {
panic("Decoder is nil!")
}
pod := corev1.Pod{}
err := decoder.Decode(req, &pod)
if err != nil {
return nil, controller, err
logrus.Errorf("Failed to decode pod: %v", err)
return nil, resource, err
}
if len(pod.ObjectMeta.OwnerReferences) > 0 {
logrus.Infof("Allowing owned pod %s/%s to pass through webhook", pod.ObjectMeta.Namespace, pod.ObjectMeta.Name)
return nil, controller, nil
return nil, resource, nil
}
controller, err = kube.NewGenericResourceFromPod(pod, pod)
resource, err = kube.NewGenericResourceFromPod(pod, pod)
} else {
controller, err = kube.NewGenericResourceFromBytes(req.Object.Raw)
resource, err = kube.NewGenericResourceFromBytes(req.Object.Raw)
}
if err != nil {
return nil, controller, err
logrus.Errorf("Failed to create resource: %v", err)
return nil, resource, err
}
controllerResult, err := validator.ApplyAllSchemaChecks(&config, nil, controller)
resourceResult, err := validator.ApplyAllSchemaChecks(&config, nil, resource)
if err != nil {
return nil, controller, err
return nil, resource, err
}
return &controllerResult, controller, nil
return &resourceResult, resource, nil
}
// Handle for Validator to run validation checks.
func (v *Validator) Handle(ctx context.Context, req admission.Request) admission.Response {
logrus.Info("Starting request")
logrus.Info("Starting admission request")
result, _, err := v.handleInternal(req)
if err != nil {
logrus.Errorf("Error validating request: %v", err)
@@ -3,7 +3,7 @@ kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: not-nginx
app.kubernetes.io/instance: not-nginx
spec:
containers:
- name: nginx
@@ -3,7 +3,7 @@ kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: nginx
spec:
containers:
- name: nginx
@@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
labels:
app.kubernetes.io/name: zookeeper
foo: bar
spec:
template:
spec:
containers:
- name: zookeeper
image: zookeeper
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zookeeper-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app.kubernetes.io/name: zookeeper
@@ -2,10 +2,11 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
labels:
app.kubernetes.io/name: zookeeper
spec:
template:
metadata:
labels:
app.kubernetes.io/name: zookeeper
spec:
containers:
- name: zookeeper
@@ -2,10 +2,12 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
labels:
app.kubernetes.io/name: zookeeper
spec:
template:
metadata:
labels:
app.kubernetes.io/name: zookeeper
foo: bar
spec:
containers:
- name: zookeeper
+32
View File
@@ -0,0 +1,32 @@
containers:
exclude:
- initContainer
successMessage: Resource limits are within the required range
failureMessage: Resource limits should be within the required range
category: Resources
target: Container
schema:
'$schema': http://json-schema.org/draft-07/schema
type: object
required:
- resources
properties:
resources:
type: object
required:
- limits
properties:
limits:
type: object
required:
- memory
- cpu
properties:
memory:
type: string
resourceMinimum: 100Mi # 104857600 bytes
resourceMaximum: 6G
cpu:
type: string
resourceMinimum: 100m
resourceMaximum: "2"
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 250Mi
cpu: 0.05
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 104857599
cpu: 1
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 250Mi
cpu: 1.5
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 104857600
cpu: 1
@@ -0,0 +1,30 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
labels:
role: service
tier: backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test
rules:
- apiGroups: [""]
resources: [services]
verbs: [get, list]
---
# check when there are no cluster roles present
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test
roleRef:
kind: Role
name: test
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: test
@@ -0,0 +1,30 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
labels:
role: service
tier: backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test
rules:
- apiGroups: [""]
resources: [services]
verbs: [get, list]
---
# check when there are no cluster roles present
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test
roleRef:
kind: Role
name: test
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: test
@@ -0,0 +1,30 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: test
labels:
role: service
tier: backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: test
rules:
- apiGroups: [""]
resources: [services]
verbs: [get, list]
---
# check when there are no cluster roles present
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: test
roleRef:
kind: Role
name: test
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: test
@@ -19,10 +19,7 @@ spec:
app.kubernetes.io/name: basic-demo
app.kubernetes.io/instance: demo
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: farglebargle
whenUnsatisfiable: ScheduleAnyway
topologySpreadConstraints: []
containers:
- name: basic-demo
image: "quay.io/fairwinds/docker-demo:latest"
@@ -21,8 +21,13 @@ spec:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: "topology.kubernetes.io/zone"
whenUnsatisfiable: ScheduleAnyway
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: foo
matchLabelKeys:
- pod-template-hash
containers:
- name: basic-demo
image: "quay.io/fairwinds/docker-demo:latest"
@@ -17,6 +17,7 @@ spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
securityContext:
@@ -26,4 +27,4 @@ spec:
runAsNonRoot: true
capabilities:
drop:
- ALL
- ALL
+16
View File
@@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-2
spec:
containers:
- name: nginx
image: nginx:1.7.9
securityContext:
allowPrivilegeEscalation: false
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
+5 -3
View File
@@ -60,7 +60,7 @@ function clean_up() {
echo "Uninstalling webhook and webhook config"
kubectl delete validatingwebhookconfigurations polaris-webhook --wait=false || true
kubectl delete validatingwebhookconfigurations polaris-validate-webhook --wait=false || true
kubectl delete validatingwebhookconfigurations polaris-mutate-webhook --wait=false || true
kubectl delete mutatingwebhookconfigurations polaris-mutate-webhook --wait=false || true
kubectl -n polaris delete deploy -l app=polaris --wait=false || true
echo -e "\n\nDone cleaning up\n\n"
}
@@ -82,11 +82,12 @@ kubectl create ns tests
echo "Installing a bad deployment"
kubectl apply -n scale-test -f ./test/webhook_cases/failing_test.deployment.yaml
echo "Installing the webhook"
echo "Installing the webhook at version $CI_SHA1"
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install polaris fairwinds-stable/polaris --namespace polaris --create-namespace \
--set dashboard.enable=false \
--set webhook.enable=true \
--set webhook.mutate=true \
--set image.tag=$CI_SHA1
echo "Waiting for the webhook to come online"
@@ -105,6 +106,7 @@ for filename in test/webhook_cases/passing_test.*.yaml; do
if ! kubectl apply -n tests -f $filename; then
ALL_TESTS_PASSED=0
echo -e "${RED}****Test Failed: Polaris prevented a resource with no configuration issues****${NC}"
kubectl logs -n polaris deploy/polaris-webhook
else
echo -e "${GREEN}****Test Passed: Polaris correctly allowed this resource****${NC}"
fi
@@ -118,7 +120,7 @@ for filename in test/webhook_cases/failing_test.*.yaml; do
if kubectl apply -n tests -f $filename; then
ALL_TESTS_PASSED=0
echo -e "${RED}****Test Failed: Polaris should have prevented this resource due to configuration issues.****${NC}"
kubectl logs -n polaris $(kubectl get po -oname -n polaris | grep webhook)
kubectl logs -n polaris deploy/polaris-webhook
else
echo -e "${GREEN}****Test Passed: Polaris correctly prevented this resource****${NC}"
fi