mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-14 18:09:55 +00:00
Compare commits
83 Commits
v3.0.35-rc
...
v3.0.43
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b33f1c8cc7 | ||
|
|
4929af510e | ||
|
|
f28bb11c55 | ||
|
|
8bff4a02e1 | ||
|
|
33d1e018ec | ||
|
|
0c74599314 | ||
|
|
c23b85cc84 | ||
|
|
aab10d14a2 | ||
|
|
2fcbe54e4e | ||
|
|
078d154ab8 | ||
|
|
cc9dcf827e | ||
|
|
76943d05fb | ||
|
|
621ac111cb | ||
|
|
3f80bce811 | ||
|
|
cc6895fc50 | ||
|
|
7d9d8e4b59 | ||
|
|
f8d4bf515d | ||
|
|
774ebe4a5f | ||
|
|
45a07a8046 | ||
|
|
ff96edae4d | ||
|
|
34b82cad27 | ||
|
|
1a4c979ab8 | ||
|
|
3481af4a5b | ||
|
|
71dc7a702c | ||
|
|
6d92389285 | ||
|
|
bd0be45c0b | ||
|
|
7ebf078d0c | ||
|
|
1bd729cf83 | ||
|
|
88b9b22bca | ||
|
|
182162d521 | ||
|
|
1c02191bb1 | ||
|
|
ca66ccb33d | ||
|
|
07eda20b88 | ||
|
|
108c84d97d | ||
|
|
35e7fa2b94 | ||
|
|
abb7917b29 | ||
|
|
31ba56a0cf | ||
|
|
b3efe4d003 | ||
|
|
5faade2b66 | ||
|
|
79207f66be | ||
|
|
af39f9a7ef | ||
|
|
482b7c1f67 | ||
|
|
82e2fd0be2 | ||
|
|
6eec751027 | ||
|
|
4a6480c8b4 | ||
|
|
a51bfa4c3e | ||
|
|
2a48af3c17 | ||
|
|
ffeb4577e3 | ||
|
|
b5c7422355 | ||
|
|
e41b5d77a0 | ||
|
|
5afaae8847 | ||
|
|
011fc0689d | ||
|
|
db30020c95 | ||
|
|
c5341a356b | ||
|
|
85a7f57373 | ||
|
|
cd9ebdf08f | ||
|
|
bc602a78ab | ||
|
|
a2361fd155 | ||
|
|
aa8d41fc2e | ||
|
|
5bd4beb41f | ||
|
|
dbf21dee37 | ||
|
|
be49d9b7be | ||
|
|
7a5699fba3 | ||
|
|
1f8afecea8 | ||
|
|
3ebb1d749e | ||
|
|
f80c9d947d | ||
|
|
03b76ff4aa | ||
|
|
01531b6276 | ||
|
|
aedfe1c4c0 | ||
|
|
d2bedc1d2b | ||
|
|
35288e7b85 | ||
|
|
cd046fa695 | ||
|
|
407b8be08f | ||
|
|
b211fe9148 | ||
|
|
525e51d68e | ||
|
|
daabd6c81a | ||
|
|
5b351d5eec | ||
|
|
a5b607ae2e | ||
|
|
fec51b00ba | ||
|
|
4f9809eec1 | ||
|
|
c0c25c3430 | ||
|
|
6ed3e408be | ||
|
|
6042818a71 |
4
.github/workflows/00-pr-scanner.yaml
vendored
4
.github/workflows/00-pr-scanner.yaml
vendored
@@ -27,6 +27,7 @@ jobs:
|
||||
deployments: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
discussions: read
|
||||
packages: read
|
||||
pages: read
|
||||
@@ -54,6 +55,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: write
|
||||
pages: read
|
||||
pull-requests: read
|
||||
@@ -66,7 +68,7 @@ jobs:
|
||||
COMPONENT_NAME: kubescape
|
||||
CGO_ENABLED: 0
|
||||
GO111MODULE: ""
|
||||
GO_VERSION: "1.23"
|
||||
GO_VERSION: "1.24"
|
||||
RELEASE: "latest"
|
||||
CLIENT: test
|
||||
secrets: inherit
|
||||
|
||||
6
.github/workflows/02-release.yaml
vendored
6
.github/workflows/02-release.yaml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
retag:
|
||||
outputs:
|
||||
NEW_TAG: ${{ steps.tag-calculator.outputs.NEW_TAG }}
|
||||
runs-on: ubuntu22-core4-mem16-ssd150
|
||||
runs-on: ubuntu-large
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- id: tag-calculator
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
COMPONENT_NAME: kubescape
|
||||
CGO_ENABLED: 0
|
||||
GO111MODULE: ""
|
||||
GO_VERSION: "1.23"
|
||||
GO_VERSION: "1.24"
|
||||
RELEASE: ${{ needs.retag.outputs.NEW_TAG }}
|
||||
CLIENT: release
|
||||
secrets: inherit
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
attestations: read
|
||||
contents: write
|
||||
uses: ./.github/workflows/e-post-release.yaml
|
||||
needs: [publish-image]
|
||||
needs: [retag, publish-image]
|
||||
with:
|
||||
TAG: ${{ needs.retag.outputs.NEW_TAG }}
|
||||
secrets: inherit
|
||||
|
||||
14
.github/workflows/a-pr-scanner.yaml
vendored
14
.github/workflows/a-pr-scanner.yaml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
name: Create cross-platform build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
runs-on: ubuntu22-core4-mem16-ssd150
|
||||
runs-on: ubuntu-large
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
run: ${{ env.DOCKER_CMD }} sh -c 'cd httphandler && go test -v ./...'
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
|
||||
- uses: anchore/sbom-action/download-syft@v0.15.2
|
||||
- uses: anchore/sbom-action/download-syft@v0
|
||||
name: Setup Syft
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v6
|
||||
@@ -70,20 +70,18 @@ jobs:
|
||||
|
||||
- name: golangci-lint
|
||||
continue-on-error: false
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
version: latest
|
||||
version: v2.1
|
||||
args: --timeout 10m
|
||||
only-new-issues: true
|
||||
skip-pkg-cache: true
|
||||
skip-build-cache: true
|
||||
|
||||
scanners:
|
||||
env:
|
||||
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
name: PR Scanner
|
||||
runs-on: ubuntu22-core4-mem16-ssd150
|
||||
runs-on: ubuntu-large
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -92,7 +90,7 @@ jobs:
|
||||
- uses: actions/setup-go@v4
|
||||
name: Installing go
|
||||
with:
|
||||
go-version: "1.23"
|
||||
go-version: "1.24"
|
||||
- name: Scanning - Forbidden Licenses (go-licenses)
|
||||
id: licenses-scan
|
||||
continue-on-error: true
|
||||
|
||||
@@ -18,7 +18,7 @@ on:
|
||||
GO_VERSION:
|
||||
required: false
|
||||
type: string
|
||||
default: "1.23"
|
||||
default: "1.24"
|
||||
GO111MODULE:
|
||||
required: false
|
||||
type: string
|
||||
@@ -70,7 +70,7 @@ on:
|
||||
type: string
|
||||
GO_VERSION:
|
||||
type: string
|
||||
default: "1.23"
|
||||
default: "1.24"
|
||||
GO111MODULE:
|
||||
required: true
|
||||
type: string
|
||||
@@ -248,7 +248,7 @@ jobs:
|
||||
CGO_ENABLED: 0
|
||||
GO111MODULE: "on"
|
||||
BUILD_PLATFORM: linux/amd64,linux/arm64
|
||||
GO_VERSION: "1.23"
|
||||
GO_VERSION: "1.24"
|
||||
REQUIRED_TESTS: '[
|
||||
"ks_microservice_create_2_cronjob_mitre_and_nsa_proxy",
|
||||
"ks_microservice_triggering_with_cron_job",
|
||||
@@ -308,7 +308,7 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.8.13'
|
||||
python-version: '3.9'
|
||||
cache: 'pip'
|
||||
|
||||
- name: create env
|
||||
|
||||
2
.github/workflows/build-image.yaml
vendored
2
.github/workflows/build-image.yaml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
CGO_ENABLED: 0
|
||||
GO111MODULE: "on"
|
||||
BUILD_PLATFORM: ${{ inputs.PLATFORMS && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
|
||||
GO_VERSION: "1.23"
|
||||
GO_VERSION: "1.24"
|
||||
REQUIRED_TESTS: '[]'
|
||||
COSIGN: ${{ inputs.CO_SIGN }}
|
||||
HELM_E2E_TEST: false
|
||||
|
||||
1
.github/workflows/d-publish-image.yaml
vendored
1
.github/workflows/d-publish-image.yaml
vendored
@@ -7,6 +7,7 @@ permissions:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: read
|
||||
pages: read
|
||||
pull-requests: read
|
||||
|
||||
2
.github/workflows/e-post-release.yaml
vendored
2
.github/workflows/e-post-release.yaml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
uses: rajatjindal/krew-release-bot@v0.0.47
|
||||
if: github.repository_owner == 'kubescape'
|
||||
env:
|
||||
GITHUB_REF: ${{ inputs.TAG }}
|
||||
GITHUB_REF: refs/tags/${{ inputs.TAG }}
|
||||
- name: Invoke workflow to update packaging
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
if: github.repository_owner == 'kubescape'
|
||||
|
||||
@@ -1,51 +1,57 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
shadow: true
|
||||
dupl:
|
||||
threshold: 200
|
||||
goconst:
|
||||
min-len: 3
|
||||
min-occurrences: 2
|
||||
gocognit:
|
||||
min-complexity: 65
|
||||
|
||||
version: "2"
|
||||
linters:
|
||||
enable:
|
||||
- gosec
|
||||
- staticcheck
|
||||
- nolintlint
|
||||
- gofmt
|
||||
- unused
|
||||
- govet
|
||||
- bodyclose
|
||||
- typecheck
|
||||
- goimports
|
||||
- ineffassign
|
||||
- gosimple
|
||||
- gosec
|
||||
- nolintlint
|
||||
disable:
|
||||
# temporarily disabled
|
||||
- errcheck
|
||||
- dupl
|
||||
- gocritic
|
||||
- errcheck
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- gocritic
|
||||
- lll
|
||||
- nakedret
|
||||
- revive
|
||||
- stylecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
#- forbidigo # <- see later
|
||||
# should remain disabled
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
issues:
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- revive
|
||||
text: "var-naming"
|
||||
- linters:
|
||||
- revive
|
||||
text: "type name will be used as (.+?) by other packages, and that stutters"
|
||||
- linters:
|
||||
- stylecheck
|
||||
text: "ST1003"
|
||||
settings:
|
||||
dupl:
|
||||
threshold: 200
|
||||
gocognit:
|
||||
min-complexity: 65
|
||||
goconst:
|
||||
min-len: 3
|
||||
min-occurrences: 2
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- revive
|
||||
text: var-naming
|
||||
- linters:
|
||||
- revive
|
||||
text: type name will be used as (.+?) by other packages, and that stutters
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: ST1003
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM --platform=$BUILDPLATFORM golang:1.23-bookworm AS builder
|
||||
FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS builder
|
||||
|
||||
ENV GO111MODULE=on CGO_ENABLED=0
|
||||
WORKDIR /work
|
||||
|
||||
@@ -26,7 +26,7 @@ var (
|
||||
%[1]s list controls
|
||||
|
||||
Control documentation:
|
||||
https://hub.armosec.io/docs/controls
|
||||
https://kubescape.io/docs/controls/
|
||||
`, cautils.ExecName())
|
||||
)
|
||||
|
||||
|
||||
@@ -6,13 +6,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/distribution/reference"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/kubescape/v3/cmd/shared"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/kubescape/kubescape/v3/pkg/imagescan"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -28,6 +27,7 @@ var patchCmdExamples = fmt.Sprintf(`
|
||||
func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
|
||||
var patchInfo metav1.PatchInfo
|
||||
var scanInfo cautils.ScanInfo
|
||||
var useDefaultMatchers bool
|
||||
|
||||
patchCmd := &cobra.Command{
|
||||
Use: "patch --image <image>:<tag> [flags]",
|
||||
@@ -49,12 +49,15 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
results, err := ks.Patch(&patchInfo, &scanInfo)
|
||||
// Set the UseDefaultMatchers field in scanInfo
|
||||
scanInfo.UseDefaultMatchers = useDefaultMatchers
|
||||
|
||||
exceedsSeverityThreshold, err := ks.Patch(&patchInfo, &scanInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imagescan.ExceedsSeverityThreshold(results, imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)) {
|
||||
if exceedsSeverityThreshold {
|
||||
shared.TerminateOnExceedingSeverity(&scanInfo, logger.L())
|
||||
}
|
||||
|
||||
@@ -76,6 +79,7 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
|
||||
patchCmd.PersistentFlags().BoolVarP(&scanInfo.VerboseMode, "verbose", "v", false, "Display full report. Default to false")
|
||||
|
||||
patchCmd.PersistentFlags().StringVarP(&scanInfo.FailThresholdSeverity, "severity-threshold", "s", "", "Severity threshold is the severity of a vulnerability at which the command fails and returns exit code 1")
|
||||
patchCmd.PersistentFlags().BoolVarP(&useDefaultMatchers, "use-default-matchers", "", true, "Use default matchers (true) or CPE matchers (false) for image scanning")
|
||||
|
||||
return patchCmd
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "kubescape",
|
||||
Short: "Kubescape is a tool for testing Kubernetes security posture. Docs: https://hub.armosec.io/docs",
|
||||
Short: "Kubescape is a tool for testing Kubernetes security posture. Docs: https://kubescape.io/docs/",
|
||||
Example: ksExamples,
|
||||
PersistentPreRun: func(cmd *cobra.Command, args []string) {
|
||||
k8sinterface.SetClusterContextName(rootInfo.KubeContext)
|
||||
|
||||
@@ -29,7 +29,7 @@ var (
|
||||
Run '%[1]s list controls' for the list of supported controls
|
||||
|
||||
Control documentation:
|
||||
https://hub.armosec.io/docs/controls
|
||||
https://kubescape.io/docs/controls/
|
||||
`, cautils.ExecName())
|
||||
)
|
||||
|
||||
@@ -99,7 +99,7 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if err := results.HandleResults(ks.Context()); err != nil {
|
||||
if err := results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if !scanInfo.VerboseMode {
|
||||
|
||||
@@ -117,7 +117,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ks.Context()); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/kubescape/kubescape/v3/pkg/imagescan"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -33,6 +32,7 @@ var (
|
||||
func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
|
||||
var imgCredentials shared.ImageCredentials
|
||||
var exceptions string
|
||||
var useDefaultMatchers bool
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "image <image>:<tag> [flags]",
|
||||
@@ -54,18 +54,19 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
|
||||
}
|
||||
|
||||
imgScanInfo := &metav1.ImageScanInfo{
|
||||
Image: args[0],
|
||||
Username: imgCredentials.Username,
|
||||
Password: imgCredentials.Password,
|
||||
Exceptions: exceptions,
|
||||
Image: args[0],
|
||||
Username: imgCredentials.Username,
|
||||
Password: imgCredentials.Password,
|
||||
Exceptions: exceptions,
|
||||
UseDefaultMatchers: useDefaultMatchers,
|
||||
}
|
||||
|
||||
results, err := ks.ScanImage(imgScanInfo, scanInfo)
|
||||
exceedsSeverityThreshold, err := ks.ScanImage(imgScanInfo, scanInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imagescan.ExceedsSeverityThreshold(results, imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)) {
|
||||
if exceedsSeverityThreshold {
|
||||
shared.TerminateOnExceedingSeverity(scanInfo, logger.L())
|
||||
}
|
||||
|
||||
@@ -77,6 +78,7 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
|
||||
cmd.PersistentFlags().StringVarP(&exceptions, "exceptions", "", "", "Path to the exceptions file")
|
||||
cmd.PersistentFlags().StringVarP(&imgCredentials.Username, "username", "u", "", "Username for registry login")
|
||||
cmd.PersistentFlags().StringVarP(&imgCredentials.Password, "password", "p", "", "Password for registry login")
|
||||
cmd.PersistentFlags().BoolVarP(&useDefaultMatchers, "use-default-matchers", "", true, "Use default matchers (true) or CPE matchers (false)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -92,6 +92,7 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.PrintAttackTree, "print-attack-tree", "", false, "Print attack tree")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.EnableRegoPrint, "enable-rego-prints", "", false, "Enable sending to rego prints to the logs (use with debug log level: -l debug)")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.ScanImages, "scan-images", "", false, "Scan resources images")
|
||||
scanCmd.PersistentFlags().BoolVarP(&scanInfo.UseDefaultMatchers, "use-default-matchers", "", true, "Use default matchers (true) or CPE matchers (false) for image scanning")
|
||||
|
||||
scanCmd.PersistentFlags().MarkDeprecated("fail-threshold", "use '--compliance-threshold' flag instead. Flag will be removed at 1.Dec.2023")
|
||||
scanCmd.PersistentFlags().MarkDeprecated("create-account", "Create account is no longer supported. In case of a missing Account ID and a configured backend server, a new account id will be generated automatically by Kubescape. Feel free to contact the Kubescape maintainers for more information.")
|
||||
@@ -139,7 +140,7 @@ func securityScan(scanInfo cautils.ScanInfo, ks meta.IKubescape) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ks.Context()); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), &scanInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/cmd/shared"
|
||||
@@ -186,20 +187,23 @@ type spyLogger struct {
|
||||
setItems []spyLogMessage
|
||||
}
|
||||
|
||||
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) SetLevel(level string) error { return nil }
|
||||
func (l *spyLogger) GetLevel() string { return "" }
|
||||
func (l *spyLogger) SetWriter(w *os.File) {}
|
||||
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
|
||||
func (l *spyLogger) LoggerName() string { return "" }
|
||||
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
|
||||
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
|
||||
var _ helpers.ILogger = &spyLogger{}
|
||||
|
||||
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) SetLevel(level string) error { return nil }
|
||||
func (l *spyLogger) GetLevel() string { return "" }
|
||||
func (l *spyLogger) SetWriter(w *os.File) {}
|
||||
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
|
||||
func (l *spyLogger) LoggerName() string { return "" }
|
||||
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
|
||||
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) TimedWrapper(funcName string, timeout time.Duration, task func()) {}
|
||||
|
||||
func (l *spyLogger) Fatal(msg string, details ...helpers.IDetails) {
|
||||
firstDetail := details[0]
|
||||
|
||||
@@ -70,7 +70,7 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ks.Context()); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
@@ -20,20 +21,23 @@ type spyLogger struct {
|
||||
setItems []spyLogMessage
|
||||
}
|
||||
|
||||
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) SetLevel(level string) error { return nil }
|
||||
func (l *spyLogger) GetLevel() string { return "" }
|
||||
func (l *spyLogger) SetWriter(w *os.File) {}
|
||||
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
|
||||
func (l *spyLogger) LoggerName() string { return "" }
|
||||
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
|
||||
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
|
||||
var _ helpers.ILogger = &spyLogger{}
|
||||
|
||||
func (l *spyLogger) Error(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Success(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Warning(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Info(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) Debug(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) SetLevel(level string) error { return nil }
|
||||
func (l *spyLogger) GetLevel() string { return "" }
|
||||
func (l *spyLogger) SetWriter(w *os.File) {}
|
||||
func (l *spyLogger) GetWriter() *os.File { return &os.File{} }
|
||||
func (l *spyLogger) LoggerName() string { return "" }
|
||||
func (l *spyLogger) Ctx(_ context.Context) helpers.ILogger { return l }
|
||||
func (l *spyLogger) Start(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopSuccess(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) StopError(msg string, details ...helpers.IDetails) {}
|
||||
func (l *spyLogger) TimedWrapper(funcName string, timeout time.Duration, task func()) {}
|
||||
|
||||
func (l *spyLogger) Fatal(msg string, details ...helpers.IDetails) {
|
||||
firstDetail := details[0]
|
||||
|
||||
@@ -220,9 +220,11 @@ func createPolicyBinding(bindingName string, policyName string, action string, p
|
||||
}
|
||||
|
||||
policyBinding.Spec.ValidationActions = []admissionv1.ValidationAction{admissionv1.ValidationAction(action)}
|
||||
paramAction := admissionv1.DenyAction
|
||||
if paramRefName != "" {
|
||||
policyBinding.Spec.ParamRef = &admissionv1.ParamRef{
|
||||
Name: paramRefName,
|
||||
Name: paramRefName,
|
||||
ParameterNotFoundAction: ¶mAction,
|
||||
}
|
||||
}
|
||||
// Marshal the policy binding to YAML
|
||||
|
||||
@@ -16,14 +16,11 @@ func GetVersionCmd(ks meta.IKubescape) *cobra.Command {
|
||||
Long: ``,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
v := versioncheck.NewIVersionCheckHandler(ks.Context())
|
||||
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil)
|
||||
if err := v.CheckLatestVersion(ks.Context(), versionCheckRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = v.CheckLatestVersion(ks.Context(), versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil))
|
||||
|
||||
fmt.Fprintf(cmd.OutOrStdout(),
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(),
|
||||
"Your current version is: %s\n",
|
||||
versionCheckRequest.ClientVersion,
|
||||
versioncheck.BuildNumber,
|
||||
)
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestGetVersionCmd(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Undefined Build Number",
|
||||
buildNumber: "",
|
||||
buildNumber: "unknown",
|
||||
want: "Your current version is: unknown\n",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -24,8 +24,7 @@ const (
|
||||
configFileName string = "config"
|
||||
kubescapeNamespace string = "kubescape"
|
||||
|
||||
kubescapeConfigMapName string = "kubescape-config" // deprecated - for backward compatibility
|
||||
kubescapeCloudConfigMapName string = "ks-cloud-config" // deprecated - for backward compatibility
|
||||
kubescapeConfigMapName string = "kubescape-config" // deprecated - for backward compatibility
|
||||
|
||||
cloudConfigMapLabelSelector string = "kubescape.io/infra=config"
|
||||
credsLabelSelectors string = "kubescape.io/infra=credentials" //nolint:gosec
|
||||
@@ -207,6 +206,8 @@ func NewClusterConfig(k8s *k8sinterface.KubernetesApi, accountID, accessKey, clu
|
||||
loadConfigFromFile(c.configObj)
|
||||
}
|
||||
|
||||
loadUrlsFromFile(c.configObj)
|
||||
|
||||
// second, load urls from config map
|
||||
c.updateConfigEmptyFieldsFromKubescapeConfigMap()
|
||||
|
||||
@@ -270,15 +271,12 @@ func (c *ClusterConfig) updateConfigEmptyFieldsFromKubescapeConfigMap() error {
|
||||
return err
|
||||
}
|
||||
var ksConfigMap *corev1.ConfigMap
|
||||
var urlsConfigMap *corev1.ConfigMap
|
||||
if len(configMaps.Items) == 0 {
|
||||
// try to find configmaps by name (for backward compatibility)
|
||||
ksConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeConfigMapName, metav1.GetOptions{})
|
||||
urlsConfigMap, _ = c.k8s.KubernetesClient.CoreV1().ConfigMaps(c.configMapNamespace).Get(context.Background(), kubescapeCloudConfigMapName, metav1.GetOptions{})
|
||||
} else {
|
||||
// use the first configmap with the label
|
||||
ksConfigMap = &configMaps.Items[0]
|
||||
urlsConfigMap = &configMaps.Items[0]
|
||||
}
|
||||
|
||||
if ksConfigMap != nil {
|
||||
@@ -291,30 +289,6 @@ func (c *ClusterConfig) updateConfigEmptyFieldsFromKubescapeConfigMap() error {
|
||||
}
|
||||
}
|
||||
|
||||
if urlsConfigMap != nil {
|
||||
if jsonConf, ok := urlsConfigMap.Data["services"]; ok {
|
||||
services, err := servicediscovery.GetServices(
|
||||
servicediscoveryv2.NewServiceDiscoveryStreamV2([]byte(jsonConf)),
|
||||
)
|
||||
if err != nil {
|
||||
// try to parse as v1
|
||||
services, err = servicediscovery.GetServices(
|
||||
servicediscoveryv1.NewServiceDiscoveryStreamV1([]byte(jsonConf)),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if services.GetApiServerUrl() != "" {
|
||||
c.configObj.CloudAPIURL = services.GetApiServerUrl()
|
||||
}
|
||||
if services.GetReportReceiverHttpUrl() != "" {
|
||||
c.configObj.CloudReportURL = services.GetReportReceiverHttpUrl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -397,7 +371,7 @@ func (c *ClusterConfig) updateConfigData(configMap *corev1.ConfigMap) {
|
||||
func loadConfigFromFile(configObj *ConfigObj) error {
|
||||
dat, err := os.ReadFile(ConfigFileFullPath())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil // no config file
|
||||
}
|
||||
return readConfig(dat, configObj)
|
||||
}
|
||||
@@ -413,6 +387,32 @@ func readConfig(dat []byte, configObj *ConfigObj) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadUrlsFromFile(obj *ConfigObj) error {
|
||||
dat, err := os.ReadFile("/etc/config/services.json")
|
||||
if err != nil {
|
||||
return nil // no config file
|
||||
}
|
||||
services, err := servicediscovery.GetServices(
|
||||
servicediscoveryv2.NewServiceDiscoveryStreamV2(dat),
|
||||
)
|
||||
if err != nil {
|
||||
// try to parse as v1
|
||||
services, err = servicediscovery.GetServices(
|
||||
servicediscoveryv1.NewServiceDiscoveryStreamV1(dat),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if services.GetApiServerUrl() != "" {
|
||||
obj.CloudAPIURL = services.GetApiServerUrl()
|
||||
}
|
||||
if services.GetReportReceiverHttpUrl() != "" {
|
||||
obj.CloudReportURL = services.GetReportReceiverHttpUrl()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteConfigFile() error {
|
||||
return os.Remove(ConfigFileFullPath())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/kubescape/k8s-interface/workloadinterface"
|
||||
"github.com/kubescape/opa-utils/reporthandling"
|
||||
@@ -20,8 +23,14 @@ type K8SResources map[string][]string
|
||||
type ExternalResources map[string][]string
|
||||
|
||||
type ImageScanData struct {
|
||||
PresenterConfig *models.PresenterConfig
|
||||
Image string
|
||||
Context pkg.Context
|
||||
IgnoredMatches []match.IgnoredMatch
|
||||
Image string
|
||||
Matches match.Matches
|
||||
Packages []pkg.Package
|
||||
RemainingMatches *match.Matches
|
||||
SBOM *sbom.SBOM
|
||||
VulnerabilityProvider vulnerability.Provider
|
||||
}
|
||||
|
||||
type ScanTypes string
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package cautils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -12,7 +15,12 @@ import (
|
||||
helmchart "helm.sh/helm/v3/pkg/chart"
|
||||
helmloader "helm.sh/helm/v3/pkg/chart/loader"
|
||||
helmchartutil "helm.sh/helm/v3/pkg/chartutil"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
helmdownloader "helm.sh/helm/v3/pkg/downloader"
|
||||
helmengine "helm.sh/helm/v3/pkg/engine"
|
||||
helmgetter "helm.sh/helm/v3/pkg/getter"
|
||||
helmregistry "helm.sh/helm/v3/pkg/registry"
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
type HelmChart struct {
|
||||
@@ -24,7 +32,51 @@ func IsHelmDirectory(path string) (bool, error) {
|
||||
return helmchartutil.IsChartDir(path)
|
||||
}
|
||||
|
||||
// newRegistryClient creates a Helm registry client for chart authentication
|
||||
func newRegistryClient(certFile, keyFile, caFile string, insecureSkipTLS, plainHTTP bool, username, password string) (*helmregistry.Client, error) {
|
||||
// Basic client options with debug disabled
|
||||
opts := []helmregistry.ClientOption{
|
||||
helmregistry.ClientOptDebug(false),
|
||||
helmregistry.ClientOptWriter(io.Discard),
|
||||
}
|
||||
|
||||
// Add TLS certificates if provided
|
||||
if certFile != "" && keyFile != "" {
|
||||
opts = append(opts, helmregistry.ClientOptCredentialsFile(certFile))
|
||||
}
|
||||
|
||||
// Add CA certificate if provided
|
||||
if caFile != "" {
|
||||
opts = append(opts, helmregistry.ClientOptCredentialsFile(caFile))
|
||||
}
|
||||
|
||||
// Enable plain HTTP if needed
|
||||
if insecureSkipTLS {
|
||||
opts = append(opts, helmregistry.ClientOptPlainHTTP())
|
||||
}
|
||||
|
||||
registryClient, err := helmregistry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return registryClient, nil
|
||||
}
|
||||
|
||||
// defaultKeyring returns the default GPG keyring path for chart verification
|
||||
func defaultKeyring() string {
|
||||
if v, ok := os.LookupEnv("GNUPGHOME"); ok {
|
||||
return filepath.Join(v, "pubring.gpg")
|
||||
}
|
||||
return filepath.Join(homedir.HomeDir(), ".gnupg", "pubring.gpg")
|
||||
}
|
||||
|
||||
func NewHelmChart(path string) (*HelmChart, error) {
|
||||
// Build chart dependencies before loading if Chart.lock exists
|
||||
if err := buildDependencies(path); err != nil {
|
||||
logger.L().Warning("Failed to build chart dependencies", helpers.String("path", path), helpers.Error(err))
|
||||
}
|
||||
|
||||
chart, err := helmloader.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -36,6 +88,35 @@ func NewHelmChart(path string) (*HelmChart, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// buildDependencies builds chart dependencies using the downloader manager
|
||||
func buildDependencies(chartPath string) error {
|
||||
// Create registry client for authentication
|
||||
registryClient, err := newRegistryClient("", "", "", false, false, "", "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create registry client: %w", err)
|
||||
}
|
||||
|
||||
// Create downloader manager with required configuration
|
||||
settings := cli.New()
|
||||
manager := &helmdownloader.Manager{
|
||||
Out: io.Discard, // Suppress output during scanning
|
||||
ChartPath: chartPath,
|
||||
Keyring: defaultKeyring(),
|
||||
SkipUpdate: false, // Allow updates to get latest dependencies
|
||||
Getters: helmgetter.All(settings),
|
||||
RegistryClient: registryClient,
|
||||
Debug: false,
|
||||
}
|
||||
|
||||
// Build dependencies from Chart.lock file
|
||||
err = manager.Build()
|
||||
if e, ok := err.(helmdownloader.ErrRepoNotFound); ok {
|
||||
return fmt.Errorf("%s. Please add missing repos via 'helm repo add'", e.Error())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (hc *HelmChart) GetName() string {
|
||||
return hc.chart.Name()
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ type ScanInfo struct {
|
||||
TriggeredByCLI bool // indicates whether the scan was triggered by the CLI
|
||||
ScanType ScanTypes
|
||||
ScanImages bool
|
||||
UseDefaultMatchers bool
|
||||
ChartPath string
|
||||
FilePath string
|
||||
scanningContext *ScanningContext
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
ksmetav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
@@ -111,7 +110,9 @@ func regexStringMatch(pattern, target string) bool {
|
||||
// exception policy.
|
||||
func isTargetImage(targets []Target, attributes Attributes) bool {
|
||||
for _, target := range targets {
|
||||
return regexStringMatch(target.Attributes.Registry, attributes.Registry) && regexStringMatch(target.Attributes.Organization, attributes.Organization) && regexStringMatch(target.Attributes.ImageName, attributes.ImageName) && regexStringMatch(target.Attributes.ImageTag, attributes.ImageTag)
|
||||
if regexStringMatch(target.Attributes.Registry, attributes.Registry) && regexStringMatch(target.Attributes.Organization, attributes.Organization) && regexStringMatch(target.Attributes.ImageName, attributes.ImageName) && regexStringMatch(target.Attributes.ImageTag, attributes.ImageTag) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -161,11 +162,16 @@ func getUniqueVulnerabilitiesAndSeverities(policies []VulnerabilitiesIgnorePolic
|
||||
return uniqueVulnsList, uniqueSeversList
|
||||
}
|
||||
|
||||
func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (bool, error) {
|
||||
logger.L().Start(fmt.Sprintf("Scanning image %s...", imgScanInfo.Image))
|
||||
|
||||
dbCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc := imagescan.NewScanService(dbCfg)
|
||||
distCfg, installCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, imgScanInfo.UseDefaultMatchers)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err))
|
||||
return false, err
|
||||
}
|
||||
defer svc.Close()
|
||||
|
||||
creds := imagescan.RegistryCredentials{
|
||||
Username: imgScanInfo.Username,
|
||||
@@ -178,16 +184,16 @@ func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *ca
|
||||
exceptionPolicies, err := GetImageExceptionsFromFile(imgScanInfo.Exceptions)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to load exceptions from file: %s", imgScanInfo.Exceptions))
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
vulnerabilityExceptions, severityExceptions = getUniqueVulnerabilitiesAndSeverities(exceptionPolicies, imgScanInfo.Image)
|
||||
}
|
||||
|
||||
scanResults, err := svc.Scan(ks.Context(), imgScanInfo.Image, creds, vulnerabilityExceptions, severityExceptions)
|
||||
imageScanData, err := svc.Scan(ks.Context(), imgScanInfo.Image, creds, vulnerabilityExceptions, severityExceptions)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to scan image: %s", imgScanInfo.Image))
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
logger.L().StopSuccess(fmt.Sprintf("Successfully scanned image: %s", imgScanInfo.Image))
|
||||
@@ -200,12 +206,7 @@ func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *ca
|
||||
|
||||
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
|
||||
|
||||
resultsHandler.ImageScanData = []cautils.ImageScanData{
|
||||
{
|
||||
PresenterConfig: scanResults,
|
||||
Image: imgScanInfo.Image,
|
||||
},
|
||||
}
|
||||
resultsHandler.ImageScanData = []cautils.ImageScanData{*imageScanData}
|
||||
|
||||
return scanResults, resultsHandler.HandleResults(ks.Context())
|
||||
return svc.ExceedsSeverityThreshold(imagescan.ParseSeverity(scanInfo.FailThresholdSeverity), imageScanData.Matches), resultsHandler.HandleResults(ks.Context(), scanInfo)
|
||||
}
|
||||
|
||||
@@ -241,6 +241,33 @@ func TestIsTargetImage(t *testing.T) {
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
targets: []Target{
|
||||
{
|
||||
Attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kubescape",
|
||||
ImageName: "kubescape*",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: "library",
|
||||
ImageName: "alpine",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: "library",
|
||||
ImageName: "alpine",
|
||||
ImageTag: "latest",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -7,14 +7,13 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
|
||||
v2 "github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/maruel/natural"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
var listFunc = map[string]func(context.Context, *metav1.ListPolicies) ([]string, error){
|
||||
@@ -100,30 +99,19 @@ func prettyPrintListFormat(ctx context.Context, targetPolicy string, policies []
|
||||
return
|
||||
}
|
||||
|
||||
policyTable := tablewriter.NewWriter(printer.GetWriter(ctx, ""))
|
||||
policyTable := table.NewWriter()
|
||||
policyTable.SetOutputMirror(printer.GetWriter(ctx, ""))
|
||||
|
||||
policyTable.SetAutoWrapText(true)
|
||||
header := fmt.Sprintf("Supported %s", targetPolicy)
|
||||
policyTable.SetHeader([]string{header})
|
||||
policyTable.SetHeaderLine(true)
|
||||
policyTable.SetRowLine(true)
|
||||
policyTable.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
policyTable.SetAutoFormatHeaders(false)
|
||||
policyTable.SetAlignment(tablewriter.ALIGN_CENTER)
|
||||
policyTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
data := v2.Matrix{}
|
||||
policyTable.AppendHeader(table.Row{header})
|
||||
policyTable.Style().Options.SeparateHeader = true
|
||||
policyTable.Style().Options.SeparateRows = true
|
||||
policyTable.Style().Format.HeaderAlign = text.AlignLeft
|
||||
policyTable.Style().Format.Header = text.FormatDefault
|
||||
policyTable.Style().Format.RowAlign = text.AlignCenter
|
||||
policyTable.Style().Box = table.StyleBoxRounded
|
||||
|
||||
controlRows := generatePolicyRows(policies)
|
||||
|
||||
var headerColors []tablewriter.Colors
|
||||
for range controlRows[0] {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor})
|
||||
}
|
||||
policyTable.SetHeaderColor(headerColors...)
|
||||
|
||||
data = append(data, controlRows...)
|
||||
|
||||
policyTable.AppendBulk(data)
|
||||
policyTable.AppendRows(generatePolicyRows(policies))
|
||||
policyTable.Render()
|
||||
}
|
||||
|
||||
@@ -134,40 +122,32 @@ func jsonListFormat(_ context.Context, _ string, policies []string) {
|
||||
}
|
||||
|
||||
func prettyPrintControls(ctx context.Context, policies []string) {
|
||||
controlsTable := tablewriter.NewWriter(printer.GetWriter(ctx, ""))
|
||||
controlsTable := table.NewWriter()
|
||||
controlsTable.SetOutputMirror(printer.GetWriter(ctx, ""))
|
||||
|
||||
controlsTable.SetAutoWrapText(false)
|
||||
controlsTable.SetHeaderLine(true)
|
||||
controlsTable.SetRowLine(true)
|
||||
controlsTable.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
controlsTable.SetAutoFormatHeaders(false)
|
||||
controlsTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
controlsTable.Style().Options.SeparateHeader = true
|
||||
controlsTable.Style().Options.SeparateRows = true
|
||||
controlsTable.Style().Format.HeaderAlign = text.AlignLeft
|
||||
controlsTable.Style().Format.Header = text.FormatDefault
|
||||
controlsTable.Style().Box = table.StyleBoxRounded
|
||||
controlsTable.SetColumnConfigs([]table.ColumnConfig{{Number: 1, Align: text.AlignRight}})
|
||||
|
||||
controlRows := generateControlRows(policies)
|
||||
|
||||
short := utils.CheckShortTerminalWidth(controlRows, []string{"Control ID", "Control name", "Docs", "Frameworks"})
|
||||
short := utils.CheckShortTerminalWidth(controlRows, table.Row{"Control ID", "Control name", "Docs", "Frameworks"})
|
||||
if short {
|
||||
controlsTable.SetAutoWrapText(false)
|
||||
controlsTable.SetHeader([]string{"Controls"})
|
||||
controlsTable.AppendHeader(table.Row{"Controls"})
|
||||
controlRows = shortFormatControlRows(controlRows)
|
||||
} else {
|
||||
controlsTable.SetHeader([]string{"Control ID", "Control name", "Docs", "Frameworks"})
|
||||
controlsTable.AppendHeader(table.Row{"Control ID", "Control name", "Docs", "Frameworks"})
|
||||
}
|
||||
var headerColors []tablewriter.Colors
|
||||
for range controlRows[0] {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor})
|
||||
}
|
||||
controlsTable.SetHeaderColor(headerColors...)
|
||||
|
||||
data := v2.Matrix{}
|
||||
data = append(data, controlRows...)
|
||||
|
||||
controlsTable.AppendBulk(data)
|
||||
controlsTable.AppendRows(controlRows)
|
||||
controlsTable.Render()
|
||||
}
|
||||
|
||||
func generateControlRows(policies []string) [][]string {
|
||||
rows := [][]string{}
|
||||
func generateControlRows(policies []string) []table.Row {
|
||||
rows := make([]table.Row, 0, len(policies))
|
||||
|
||||
for _, control := range policies {
|
||||
|
||||
@@ -188,7 +168,7 @@ func generateControlRows(policies []string) [][]string {
|
||||
|
||||
docs := cautils.GetControlLink(id)
|
||||
|
||||
currentRow := []string{id, control, docs, strings.Replace(framework, " ", "\n", -1)}
|
||||
currentRow := table.Row{id, control, docs, strings.Replace(framework, " ", "\n", -1)}
|
||||
|
||||
rows = append(rows, currentRow)
|
||||
}
|
||||
@@ -196,20 +176,19 @@ func generateControlRows(policies []string) [][]string {
|
||||
return rows
|
||||
}
|
||||
|
||||
func generatePolicyRows(policies []string) [][]string {
|
||||
rows := [][]string{}
|
||||
func generatePolicyRows(policies []string) []table.Row {
|
||||
rows := make([]table.Row, 0, len(policies))
|
||||
|
||||
for _, policy := range policies {
|
||||
currentRow := []string{policy}
|
||||
rows = append(rows, currentRow)
|
||||
rows = append(rows, table.Row{policy})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func shortFormatControlRows(controlRows [][]string) [][]string {
|
||||
rows := [][]string{}
|
||||
func shortFormatControlRows(controlRows []table.Row) []table.Row {
|
||||
rows := make([]table.Row, 0, len(controlRows))
|
||||
for _, controlRow := range controlRows {
|
||||
rows = append(rows, []string{fmt.Sprintf("Control ID"+strings.Repeat(" ", 3)+": %+v\nControl Name"+strings.Repeat(" ", 1)+": %+v\nDocs"+strings.Repeat(" ", 9)+": %+v\nFrameworks"+strings.Repeat(" ", 3)+": %+v", controlRow[0], controlRow[1], controlRow[2], strings.Replace(controlRow[3], "\n", " ", -1))})
|
||||
rows = append(rows, table.Row{fmt.Sprintf("Control ID"+strings.Repeat(" ", 3)+": %+v\nControl Name"+strings.Repeat(" ", 1)+": %+v\nDocs"+strings.Repeat(" ", 9)+": %+v\nFrameworks"+strings.Repeat(" ", 3)+": %+v", controlRow[0], controlRow[1], controlRow[2], strings.Replace(controlRow[3].(string), "\n", " ", -1))})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -105,7 +106,7 @@ func TestGeneratePolicyRows_NonEmptyPolicyList(t *testing.T) {
|
||||
result := generatePolicyRows(policies)
|
||||
|
||||
// Assert
|
||||
assert.Equal(t, [][]string{{"policy1"}, {"policy2"}, {"policy3"}}, result)
|
||||
assert.Equal(t, []table.Row{{"policy1"}, {"policy2"}, {"policy3"}}, result)
|
||||
}
|
||||
|
||||
// Returns an empty 2D slice for an empty list of policies.
|
||||
@@ -122,12 +123,12 @@ func TestGeneratePolicyRows_EmptyPolicyList(t *testing.T) {
|
||||
|
||||
// The function returns a list of rows, each containing a formatted string with control ID, control name, docs, and frameworks.
|
||||
func TestShortFormatControlRows_ReturnsListOfRowsWithFormattedString(t *testing.T) {
|
||||
controlRows := [][]string{
|
||||
controlRows := []table.Row{
|
||||
{"ID1", "Control 1", "Docs 1", "Framework 1"},
|
||||
{"ID2", "Control 2", "Docs 2", "Framework 2"},
|
||||
}
|
||||
|
||||
want := [][]string{
|
||||
want := []table.Row{
|
||||
{"Control ID : ID1\nControl Name : Control 1\nDocs : Docs 1\nFrameworks : Framework 1"},
|
||||
{"Control ID : ID2\nControl Name : Control 2\nDocs : Docs 2\nFrameworks : Framework 2"},
|
||||
}
|
||||
@@ -139,12 +140,12 @@ func TestShortFormatControlRows_ReturnsListOfRowsWithFormattedString(t *testing.
|
||||
|
||||
// The function formats the control rows correctly, replacing newlines in the frameworks column with line breaks.
|
||||
func TestShortFormatControlRows_FormatsControlRowsCorrectly(t *testing.T) {
|
||||
controlRows := [][]string{
|
||||
controlRows := []table.Row{
|
||||
{"ID1", "Control 1", "Docs 1", "Framework\n1"},
|
||||
{"ID2", "Control 2", "Docs 2", "Framework\n2"},
|
||||
}
|
||||
|
||||
want := [][]string{
|
||||
want := []table.Row{
|
||||
{"Control ID : ID1\nControl Name : Control 1\nDocs : Docs 1\nFrameworks : Framework 1"},
|
||||
{"Control ID : ID2\nControl Name : Control 2\nDocs : Docs 2\nFrameworks : Framework 2"},
|
||||
}
|
||||
@@ -156,11 +157,11 @@ func TestShortFormatControlRows_FormatsControlRowsCorrectly(t *testing.T) {
|
||||
|
||||
// The function handles a control row with an empty control ID.
|
||||
func TestShortFormatControlRows_HandlesControlRowWithEmptyControlID(t *testing.T) {
|
||||
controlRows := [][]string{
|
||||
controlRows := []table.Row{
|
||||
{"", "Control 1", "Docs 1", "Framework 1"},
|
||||
}
|
||||
|
||||
want := [][]string{
|
||||
want := []table.Row{
|
||||
{"Control ID : \nControl Name : Control 1\nDocs : Docs 1\nFrameworks : Framework 1"},
|
||||
}
|
||||
|
||||
@@ -171,11 +172,11 @@ func TestShortFormatControlRows_HandlesControlRowWithEmptyControlID(t *testing.T
|
||||
|
||||
// The function handles a control row with an empty control name.
|
||||
func TestShortFormatControlRows_HandlesControlRowWithEmptyControlName(t *testing.T) {
|
||||
controlRows := [][]string{
|
||||
controlRows := []table.Row{
|
||||
{"ID1", "", "Docs 1", "Framework 1"},
|
||||
}
|
||||
|
||||
want := [][]string{
|
||||
want := []table.Row{
|
||||
{"Control ID : ID1\nControl Name : \nDocs : Docs 1\nFrameworks : Framework 1"},
|
||||
}
|
||||
|
||||
@@ -192,7 +193,7 @@ func TestGenerateControlRowsWithAllFields(t *testing.T) {
|
||||
"3|Control 3|Framework 3",
|
||||
}
|
||||
|
||||
want := [][]string{
|
||||
want := []table.Row{
|
||||
{"1", "Control 1", "https://hub.armosec.io/docs/1", "Framework\n1"},
|
||||
{"2", "Control 2", "https://hub.armosec.io/docs/2", "Framework\n2"},
|
||||
{"3", "Control 3", "https://hub.armosec.io/docs/3", "Framework\n3"},
|
||||
@@ -215,7 +216,7 @@ func TestGenerateControlRowsHandlesPoliciesWithEmptyStringOrNoPipesOrOnePipeMiss
|
||||
"5|Control 5||Extra 5",
|
||||
}
|
||||
|
||||
expectedRows := [][]string{
|
||||
expectedRows := []table.Row{
|
||||
{"", "", "https://hub.armosec.io/docs/", ""},
|
||||
{"1", "", "https://hub.armosec.io/docs/1", ""},
|
||||
{"2", "Control 2", "https://hub.armosec.io/docs/2", "Framework\n2"},
|
||||
@@ -252,18 +253,18 @@ func TestGenerateTableWithCorrectHeadersAndRows(t *testing.T) {
|
||||
os.Stdout = rescueStdout
|
||||
|
||||
// got := buf.String()
|
||||
want := `┌────────────┬──────────────┬───────────────────────────────┬────────────┐
|
||||
want := `╭────────────┬──────────────┬───────────────────────────────┬────────────╮
|
||||
│ Control ID │ Control name │ Docs │ Frameworks │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 1 │ Control 1 │ https://hub.armosec.io/docs/1 │ Framework │
|
||||
│ │ │ │ 1 │
|
||||
│ │ │ │ 1 │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 2 │ Control 2 │ https://hub.armosec.io/docs/2 │ Framework │
|
||||
│ │ │ │ 2 │
|
||||
│ │ │ │ 2 │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 3 │ Control 3 │ https://hub.armosec.io/docs/3 │ Framework │
|
||||
│ │ │ │ 3 │
|
||||
└────────────┴──────────────┴───────────────────────────────┴────────────┘
|
||||
│ │ │ │ 3 │
|
||||
╰────────────┴──────────────┴───────────────────────────────┴────────────╯
|
||||
`
|
||||
|
||||
assert.Equal(t, want, string(got))
|
||||
@@ -294,7 +295,7 @@ func TestGenerateTableWithMalformedPoliciesAndPrettyPrintHeadersAndRows(t *testi
|
||||
|
||||
os.Stdout = rescueStdout
|
||||
|
||||
want := `┌────────────┬──────────────┬───────────────────────────────┬────────────┐
|
||||
want := `╭────────────┬──────────────┬───────────────────────────────┬────────────╮
|
||||
│ Control ID │ Control name │ Docs │ Frameworks │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ │ │ https://hub.armosec.io/docs/ │ │
|
||||
@@ -302,18 +303,18 @@ func TestGenerateTableWithMalformedPoliciesAndPrettyPrintHeadersAndRows(t *testi
|
||||
│ 1 │ │ https://hub.armosec.io/docs/1 │ │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 2 │ Control 2 │ https://hub.armosec.io/docs/2 │ Framework │
|
||||
│ │ │ │ 2 │
|
||||
│ │ │ │ 2 │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 3 │ Control 3 │ https://hub.armosec.io/docs/3 │ Framework │
|
||||
│ │ │ │ 3 │
|
||||
│ │ │ │ 3 │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 4 │ │ https://hub.armosec.io/docs/4 │ Framework │
|
||||
│ │ │ │ 4 │
|
||||
│ │ │ │ 4 │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ │ │ https://hub.armosec.io/docs/ │ │
|
||||
├────────────┼──────────────┼───────────────────────────────┼────────────┤
|
||||
│ 5 │ Control 5 │ https://hub.armosec.io/docs/5 │ │
|
||||
└────────────┴──────────────┴───────────────────────────────┴────────────┘
|
||||
╰────────────┴──────────────┴───────────────────────────────┴────────────╯
|
||||
`
|
||||
|
||||
assert.Equal(t, want, string(got))
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter"
|
||||
"github.com/anchore/clio"
|
||||
grypejson "github.com/anchore/grype/grype/presenter/json"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
copaGrype "github.com/anubhav06/copa-grype/grype"
|
||||
"github.com/containerd/platforms"
|
||||
"github.com/docker/buildx/build"
|
||||
"github.com/docker/cli/cli/config"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
@@ -17,21 +24,37 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
|
||||
"github.com/kubescape/kubescape/v3/pkg/imagescan"
|
||||
"github.com/moby/buildkit/client"
|
||||
"github.com/moby/buildkit/client/llb"
|
||||
"github.com/moby/buildkit/exporter/containerimage/exptypes"
|
||||
gwclient "github.com/moby/buildkit/frontend/gateway/client"
|
||||
"github.com/moby/buildkit/session"
|
||||
"github.com/moby/buildkit/session/auth/authprovider"
|
||||
"github.com/project-copacetic/copacetic/pkg/buildkit"
|
||||
"github.com/project-copacetic/copacetic/pkg/pkgmgr"
|
||||
"github.com/project-copacetic/copacetic/pkg/types/unversioned"
|
||||
"github.com/project-copacetic/copacetic/pkg/utils"
|
||||
"github.com/quay/claircore/osrelease"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
const (
|
||||
copaProduct = "copa"
|
||||
)
|
||||
|
||||
func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (bool, error) {
|
||||
|
||||
// ===================== Scan the image =====================
|
||||
logger.L().Start(fmt.Sprintf("Scanning image: %s", patchInfo.Image))
|
||||
|
||||
// Setup the scan service
|
||||
dbCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc := imagescan.NewScanService(dbCfg)
|
||||
distCfg, installCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, scanInfo.UseDefaultMatchers)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err))
|
||||
return false, err
|
||||
}
|
||||
defer svc.Close()
|
||||
creds := imagescan.RegistryCredentials{
|
||||
Username: patchInfo.Username,
|
||||
Password: patchInfo.Password,
|
||||
@@ -39,15 +62,21 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan
|
||||
// Scan the image
|
||||
scanResults, err := svc.Scan(ks.Context(), patchInfo.Image, creds, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
model, err := models.NewDocument(clio.Identification{}, scanResults.Packages, scanResults.Context,
|
||||
*scanResults.RemainingMatches, scanResults.IgnoredMatches, scanResults.VulnerabilityProvider, nil, nil, models.DefaultSortStrategy, false)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to create document: %w", err)
|
||||
}
|
||||
|
||||
// If the scan results ID is empty, set it to "grype"
|
||||
if scanResults.ID.Name == "" {
|
||||
scanResults.ID.Name = "grype"
|
||||
if model.Descriptor.Name == "" {
|
||||
model.Descriptor.Name = "grype"
|
||||
}
|
||||
// Save the scan results to a file in json format
|
||||
pres := presenter.GetPresenter("json", "", false, *scanResults)
|
||||
pres := grypejson.NewPresenter(models.PresenterConfig{Document: model, SBOM: scanResults.SBOM})
|
||||
|
||||
fileName := fmt.Sprintf("%s:%s.json", patchInfo.ImageName, patchInfo.ImageTag)
|
||||
fileName = strings.ReplaceAll(fileName, "/", "-")
|
||||
@@ -55,7 +84,7 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan
|
||||
writer := printer.GetWriter(ks.Context(), fileName)
|
||||
|
||||
if err = pres.Present(writer); err != nil {
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
logger.L().StopSuccess(fmt.Sprintf("Successfully scanned image: %s", patchInfo.Image))
|
||||
|
||||
@@ -69,7 +98,7 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan
|
||||
}
|
||||
|
||||
if err = copaPatch(ks.Context(), patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Restore the output streams
|
||||
@@ -83,7 +112,7 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan
|
||||
|
||||
scanResultsPatched, err := svc.Scan(ks.Context(), patchedImageName, creds, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return false, err
|
||||
}
|
||||
logger.L().StopSuccess(fmt.Sprintf("Successfully re-scanned image: %s", patchedImageName))
|
||||
|
||||
@@ -99,14 +128,9 @@ func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.Scan
|
||||
outputPrinters := GetOutputPrinters(scanInfo, ks.Context(), "")
|
||||
uiPrinter := GetUIPrinter(ks.Context(), scanInfo, "")
|
||||
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
|
||||
resultsHandler.ImageScanData = []cautils.ImageScanData{
|
||||
{
|
||||
PresenterConfig: scanResultsPatched,
|
||||
Image: patchedImageName,
|
||||
},
|
||||
}
|
||||
resultsHandler.ImageScanData = []cautils.ImageScanData{*scanResultsPatched}
|
||||
|
||||
return scanResultsPatched, resultsHandler.HandleResults(ks.Context())
|
||||
return svc.ExceedsSeverityThreshold(imagescan.ParseSeverity(scanInfo.FailThresholdSeverity), scanResultsPatched.Matches), resultsHandler.HandleResults(ks.Context(), scanInfo)
|
||||
}
|
||||
|
||||
func disableCopaLogger() {
|
||||
@@ -160,43 +184,185 @@ func patchWithContext(ctx context.Context, buildkitAddr, image, reportFile, patc
|
||||
}
|
||||
}
|
||||
|
||||
var updates *unversioned.UpdateManifest
|
||||
// Parse report for update packages
|
||||
updates, err := tryParseScanReport(reportFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := buildkit.NewClient(ctx, bkOpts)
|
||||
bkClient, err := buildkit.NewClient(ctx, bkOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("copa: error creating buildkit client :: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
defer bkClient.Close()
|
||||
|
||||
// Configure buildctl/client for use by package manager
|
||||
config, err := buildkit.InitializeBuildkitConfig(ctx, client, image, updates)
|
||||
dockerConfig := config.LoadDefaultConfigFile(os.Stderr)
|
||||
cfg := authprovider.DockerAuthProviderConfig{ConfigFile: dockerConfig}
|
||||
attachable := []session.Attachable{authprovider.NewDockerAuthProvider(cfg)}
|
||||
solveOpt := client.SolveOpt{
|
||||
Exports: []client.ExportEntry{
|
||||
{
|
||||
Type: client.ExporterImage,
|
||||
Attrs: map[string]string{
|
||||
"name": patchedImageName,
|
||||
"push": "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
Frontend: "", // i.e. we are passing in the llb.Definition directly
|
||||
Session: attachable, // used for authprovider, sshagentprovider and secretprovider
|
||||
}
|
||||
solveOpt.SourcePolicy, err = build.ReadSourcePolicy()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("copa: error reading source policy :: %w", err)
|
||||
}
|
||||
|
||||
// Create package manager helper
|
||||
pkgmgr, err := pkgmgr.GetPackageManager(updates.Metadata.OS.Type, config, workingFolder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildChannel := make(chan *client.SolveStatus)
|
||||
_, err = bkClient.Build(ctx, solveOpt, copaProduct, func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
|
||||
// Configure buildctl/client for use by package manager
|
||||
config, err := buildkit.InitializeBuildkitConfig(ctx, c, image)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copa: error initializing buildkit config for image %s :: %w", image, err)
|
||||
}
|
||||
|
||||
// Export the patched image state to Docker
|
||||
patchedImageState, _, err := pkgmgr.InstallUpdates(ctx, updates, ignoreError)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Create package manager helper
|
||||
var manager pkgmgr.PackageManager
|
||||
if reportFile == "" {
|
||||
// determine OS family
|
||||
fileBytes, err := buildkit.ExtractFileFromState(ctx, c, &config.ImageState, "/etc/os-release")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to extract /etc/os-release file from state %w", err)
|
||||
}
|
||||
|
||||
if err = buildkit.SolveToDocker(ctx, config.Client, patchedImageState, config.ConfigData, patchedImageName); err != nil {
|
||||
return err
|
||||
}
|
||||
osType, err := getOSType(ctx, fileBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copa: error getting os type :: %w", err)
|
||||
}
|
||||
|
||||
osVersion, err := getOSVersion(ctx, fileBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copa: error getting os version :: %w", err)
|
||||
}
|
||||
|
||||
// get package manager based on os family type
|
||||
manager, err = pkgmgr.GetPackageManager(osType, osVersion, config, workingFolder)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copa: error getting package manager for ostype=%s, version=%s :: %w", osType, osVersion, err)
|
||||
}
|
||||
// do not specify updates, will update all
|
||||
updates = nil
|
||||
} else {
|
||||
// get package manager based on os family type
|
||||
manager, err = pkgmgr.GetPackageManager(updates.Metadata.OS.Type, updates.Metadata.OS.Version, config, workingFolder)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("copa: error getting package manager by family type: ostype=%s, osversion=%s :: %w", updates.Metadata.OS.Type, updates.Metadata.OS.Version, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Export the patched image state to Docker
|
||||
// TODO: Add support for other output modes as buildctl does.
|
||||
log.Infof("Patching %d vulnerabilities", len(updates.Updates))
|
||||
patchedImageState, errPkgs, err := manager.InstallUpdates(ctx, updates, ignoreError)
|
||||
log.Infof("Error is: %v", err)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
platform := platforms.Normalize(platforms.DefaultSpec())
|
||||
if platform.OS != "linux" {
|
||||
platform.OS = "linux"
|
||||
}
|
||||
|
||||
def, err := patchedImageState.Marshal(ctx, llb.Platform(platform))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := c.Solve(ctx, gwclient.SolveRequest{
|
||||
Definition: def.ToPB(),
|
||||
Evaluate: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.AddMeta(exptypes.ExporterImageConfigKey, config.ConfigData)
|
||||
|
||||
// Currently can only validate updates if updating via scanner
|
||||
if reportFile != "" {
|
||||
// create a new manifest with the successfully patched packages
|
||||
validatedManifest := &unversioned.UpdateManifest{
|
||||
Metadata: unversioned.Metadata{
|
||||
OS: unversioned.OS{
|
||||
Type: updates.Metadata.OS.Type,
|
||||
Version: updates.Metadata.OS.Version,
|
||||
},
|
||||
Config: unversioned.Config{
|
||||
Arch: updates.Metadata.Config.Arch,
|
||||
},
|
||||
},
|
||||
Updates: []unversioned.UpdatePackage{},
|
||||
}
|
||||
for _, update := range updates.Updates {
|
||||
if !slices.Contains(errPkgs, update.Name) {
|
||||
validatedManifest.Updates = append(validatedManifest.Updates, update)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}, buildChannel)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getOSType(ctx context.Context, osreleaseBytes []byte) (string, error) {
|
||||
r := bytes.NewReader(osreleaseBytes)
|
||||
osData, err := osrelease.Parse(ctx, r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to parse os-release data %w", err)
|
||||
}
|
||||
|
||||
osType := strings.ToLower(osData["NAME"])
|
||||
switch {
|
||||
case strings.Contains(osType, "alpine"):
|
||||
return "alpine", nil
|
||||
case strings.Contains(osType, "debian"):
|
||||
return "debian", nil
|
||||
case strings.Contains(osType, "ubuntu"):
|
||||
return "ubuntu", nil
|
||||
case strings.Contains(osType, "amazon"):
|
||||
return "amazon", nil
|
||||
case strings.Contains(osType, "centos"):
|
||||
return "centos", nil
|
||||
case strings.Contains(osType, "mariner"):
|
||||
return "cbl-mariner", nil
|
||||
case strings.Contains(osType, "azure linux"):
|
||||
return "azurelinux", nil
|
||||
case strings.Contains(osType, "red hat"):
|
||||
return "redhat", nil
|
||||
case strings.Contains(osType, "rocky"):
|
||||
return "rocky", nil
|
||||
case strings.Contains(osType, "oracle"):
|
||||
return "oracle", nil
|
||||
case strings.Contains(osType, "alma"):
|
||||
return "alma", nil
|
||||
default:
|
||||
log.Error("unsupported osType ", osType)
|
||||
return "", errors.ErrUnsupported
|
||||
}
|
||||
}
|
||||
|
||||
func getOSVersion(ctx context.Context, osreleaseBytes []byte) (string, error) {
|
||||
r := bytes.NewReader(osreleaseBytes)
|
||||
osData, err := osrelease.Parse(ctx, r)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to parse os-release data %w", err)
|
||||
}
|
||||
|
||||
return osData["VERSION_ID"], nil
|
||||
}
|
||||
|
||||
// This function adds support to copa for patching Kubescape produced results
|
||||
func tryParseScanReport(file string) (*unversioned.UpdateManifest, error) {
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
|
||||
}
|
||||
|
||||
if scanInfo.ScanImages {
|
||||
scanImages(scanInfo.ScanType, scanData, ks.Context(), resultsHandling)
|
||||
scanImages(scanInfo.ScanType, scanData, ks.Context(), resultsHandling, scanInfo)
|
||||
}
|
||||
// ========================= results handling =====================
|
||||
resultsHandling.SetData(scanData)
|
||||
@@ -214,7 +214,7 @@ func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsH
|
||||
return resultsHandling, nil
|
||||
}
|
||||
|
||||
func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx context.Context, resultsHandling *resultshandling.ResultsHandler) {
|
||||
func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx context.Context, resultsHandling *resultshandling.ResultsHandler, scanInfo *cautils.ScanInfo) {
|
||||
var imagesToScan []string
|
||||
|
||||
if scanType == cautils.ScanTypeWorkload {
|
||||
@@ -243,8 +243,13 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx
|
||||
}
|
||||
}
|
||||
|
||||
dbCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc := imagescan.NewScanService(dbCfg)
|
||||
distCfg, installCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc, err := imagescan.NewScanServiceWithMatchers(distCfg, installCfg, scanInfo.UseDefaultMatchers)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err))
|
||||
return
|
||||
}
|
||||
defer svc.Close()
|
||||
|
||||
for _, img := range imagesToScan {
|
||||
logger.L().Start("Scanning", helpers.String("image", img))
|
||||
@@ -255,17 +260,14 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx
|
||||
}
|
||||
}
|
||||
|
||||
func scanSingleImage(ctx context.Context, img string, svc imagescan.Service, resultsHandling *resultshandling.ResultsHandler) error {
|
||||
func scanSingleImage(ctx context.Context, img string, svc *imagescan.Service, resultsHandling *resultshandling.ResultsHandler) error {
|
||||
|
||||
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{}, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resultsHandling.ImageScanData = append(resultsHandling.ImageScanData, cautils.ImageScanData{
|
||||
Image: img,
|
||||
PresenterConfig: scanResults,
|
||||
})
|
||||
resultsHandling.ImageScanData = append(resultsHandling.ImageScanData, *scanResults)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package v1
|
||||
|
||||
type ImageScanInfo struct {
|
||||
Username string
|
||||
Password string
|
||||
Image string
|
||||
Exceptions string
|
||||
Username string
|
||||
Password string
|
||||
Image string
|
||||
Exceptions string
|
||||
UseDefaultMatchers bool
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package meta
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling"
|
||||
@@ -27,8 +26,8 @@ type IKubescape interface {
|
||||
Fix(fixInfo *metav1.FixInfo) error
|
||||
|
||||
// patch
|
||||
Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
|
||||
Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (bool, error)
|
||||
|
||||
// scan image
|
||||
ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
|
||||
ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (bool, error)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package mocks
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling"
|
||||
@@ -15,38 +14,38 @@ func (m *MockIKubescape) Context() context.Context {
|
||||
return context.TODO()
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
func (m *MockIKubescape) Scan(_ *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) List(listPolicies *metav1.ListPolicies) error {
|
||||
func (m *MockIKubescape) List(_ *metav1.ListPolicies) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Download(downloadInfo *metav1.DownloadInfo) error {
|
||||
func (m *MockIKubescape) Download(_ *metav1.DownloadInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) SetCachedConfig(setConfig *metav1.SetConfig) error {
|
||||
func (m *MockIKubescape) SetCachedConfig(_ *metav1.SetConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error {
|
||||
func (m *MockIKubescape) ViewCachedConfig(_ *metav1.ViewConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error {
|
||||
func (m *MockIKubescape) DeleteCachedConfig(_ *metav1.DeleteConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Fix(fixInfo *metav1.FixInfo) error {
|
||||
func (m *MockIKubescape) Fix(_ *metav1.FixInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
return nil, nil
|
||||
func (m *MockIKubescape) Patch(_ *metav1.PatchInfo, _ *cautils.ScanInfo) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
return nil, nil
|
||||
func (m *MockIKubescape) ScanImage(_ *metav1.ImageScanInfo, _ *cautils.ScanInfo) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ spec:
|
||||
allowPrivilegeEscalation: true
|
||||
privileged: true
|
||||
readOnlyRootFilesystem: true
|
||||
procMount: Unmasked
|
||||
ports:
|
||||
- name: scanner # Do not change port name
|
||||
containerPort: 7888
|
||||
|
||||
@@ -96,7 +96,7 @@ func (hsh *HostSensorHandler) Init(ctx context.Context) error {
|
||||
|
||||
hsh.populatePodNamesToNodeNames(ctx, log)
|
||||
if err := hsh.checkPodForEachNode(); err != nil {
|
||||
logger.L().Ctx(ctx).Warning(failedToValidateHostSensorPodStatus, helpers.Error(err))
|
||||
return fmt.Errorf("%s: %v", failedToValidateHostSensorPodStatus, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -37,7 +37,6 @@ spec:
|
||||
allowPrivilegeEscalation: true
|
||||
privileged: true
|
||||
readOnlyRootFilesystem: true
|
||||
procMount: Unmasked
|
||||
ports:
|
||||
- name: scanner # Do not change port name
|
||||
containerPort: 7888
|
||||
|
||||
@@ -232,7 +232,7 @@ func (k8sHandler *K8sResourceHandler) collectCloudResources(ctx context.Context,
|
||||
if !strings.Contains(err.Error(), cloudv1.NotSupportedMsg) {
|
||||
// Return error with useful info on how to configure credentials for getting cloud provider info
|
||||
logger.L().Debug("failed to get cloud data", helpers.String("resourceKind", resourceKind), helpers.Error(err))
|
||||
err = fmt.Errorf("failed to get %s descriptive information. Read more: https://hub.armosec.io/docs/kubescape-integration-with-cloud-providers", strings.ToUpper(k8sHandler.cloudProvider))
|
||||
err = fmt.Errorf("failed to get %s descriptive information. Read more: https://kubescape.io/docs/integrations/kubescape-integration-with-cloud-providers/", strings.ToUpper(k8sHandler.cloudProvider))
|
||||
cautils.SetInfoMapForResources(err.Error(), cloudResources, sessionObj.InfoMap)
|
||||
}
|
||||
|
||||
@@ -478,8 +478,15 @@ func (k8sHandler *K8sResourceHandler) setCloudProvider() error {
|
||||
// NoSchedule taint with empty value is usually applied to controlplane
|
||||
func isMasterNodeTaints(taints []v1.Taint) bool {
|
||||
for _, taint := range taints {
|
||||
if taint.Effect == v1.TaintEffectNoSchedule && taint.Value == "" {
|
||||
return true
|
||||
if taint.Effect == v1.TaintEffectNoSchedule {
|
||||
// NoSchedule taint with empty value is usually applied to controlplane
|
||||
if taint.Value == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if taint.Key == "node-role.kubernetes.io/control-plane" && taint.Value == "true" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -14,264 +14,264 @@ import (
|
||||
)
|
||||
|
||||
func TestIsMasterNodeTaints(t *testing.T) {
|
||||
noTaintNode := `
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Node",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock",
|
||||
"node.alpha.kubernetes.io/ttl": "0",
|
||||
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
|
||||
},
|
||||
"creationTimestamp": "2022-05-16T10:52:32Z",
|
||||
"labels": {
|
||||
"beta.kubernetes.io/arch": "amd64",
|
||||
"beta.kubernetes.io/os": "linux",
|
||||
"kubernetes.io/arch": "amd64",
|
||||
"kubernetes.io/hostname": "danielg-minikube",
|
||||
"kubernetes.io/os": "linux",
|
||||
"minikube.k8s.io/commit": "3e64b11ed75e56e4898ea85f96b2e4af0301f43d",
|
||||
"minikube.k8s.io/name": "danielg-minikube",
|
||||
"minikube.k8s.io/updated_at": "2022_05_16T13_52_35_0700",
|
||||
"minikube.k8s.io/version": "v1.25.1",
|
||||
"node-role.kubernetes.io/control-plane": "",
|
||||
"node-role.kubernetes.io/master": "",
|
||||
"node.kubernetes.io/exclude-from-external-load-balancers": ""
|
||||
},
|
||||
"name": "danielg-minikube",
|
||||
"resourceVersion": "9432",
|
||||
"uid": "fc4afcb6-4ca4-4038-ba54-5e16065a614a"
|
||||
},
|
||||
"spec": {
|
||||
"podCIDR": "10.244.0.0/24",
|
||||
"podCIDRs": [
|
||||
"10.244.0.0/24"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"addresses": [
|
||||
noTaintNodeJson := `
|
||||
{
|
||||
"address": "192.168.49.2",
|
||||
"type": "InternalIP"
|
||||
"apiVersion": "v1",
|
||||
"kind": "Node",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock",
|
||||
"node.alpha.kubernetes.io/ttl": "0",
|
||||
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
|
||||
},
|
||||
"creationTimestamp": "2022-05-16T10:52:32Z",
|
||||
"labels": {
|
||||
"beta.kubernetes.io/arch": "amd64",
|
||||
"beta.kubernetes.io/os": "linux",
|
||||
"kubernetes.io/arch": "amd64",
|
||||
"kubernetes.io/hostname": "danielg-minikube",
|
||||
"kubernetes.io/os": "linux",
|
||||
"minikube.k8s.io/commit": "3e64b11ed75e56e4898ea85f96b2e4af0301f43d",
|
||||
"minikube.k8s.io/name": "danielg-minikube",
|
||||
"minikube.k8s.io/updated_at": "2022_05_16T13_52_35_0700",
|
||||
"minikube.k8s.io/version": "v1.25.1",
|
||||
"node-role.kubernetes.io/control-plane": "",
|
||||
"node-role.kubernetes.io/master": "",
|
||||
"node.kubernetes.io/exclude-from-external-load-balancers": ""
|
||||
},
|
||||
"name": "danielg-minikube",
|
||||
"resourceVersion": "9432",
|
||||
"uid": "fc4afcb6-4ca4-4038-ba54-5e16065a614a"
|
||||
},
|
||||
{
|
||||
"address": "danielg-minikube",
|
||||
"type": "Hostname"
|
||||
"spec": {
|
||||
"podCIDR": "10.244.0.0/24",
|
||||
"podCIDRs": [
|
||||
"10.244.0.0/24"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"addresses": [
|
||||
{
|
||||
"address": "192.168.49.2",
|
||||
"type": "InternalIP"
|
||||
},
|
||||
{
|
||||
"address": "danielg-minikube",
|
||||
"type": "Hostname"
|
||||
}
|
||||
],
|
||||
"allocatable": {
|
||||
"cpu": "4",
|
||||
"ephemeral-storage": "94850516Ki",
|
||||
"hugepages-2Mi": "0",
|
||||
"memory": "10432976Ki",
|
||||
"pods": "110"
|
||||
},
|
||||
"capacity": {
|
||||
"cpu": "4",
|
||||
"ephemeral-storage": "94850516Ki",
|
||||
"hugepages-2Mi": "0",
|
||||
"memory": "10432976Ki",
|
||||
"pods": "110"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has sufficient memory available",
|
||||
"reason": "KubeletHasSufficientMemory",
|
||||
"status": "False",
|
||||
"type": "MemoryPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has no disk pressure",
|
||||
"reason": "KubeletHasNoDiskPressure",
|
||||
"status": "False",
|
||||
"type": "DiskPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has sufficient PID available",
|
||||
"reason": "KubeletHasSufficientPID",
|
||||
"status": "False",
|
||||
"type": "PIDPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:45Z",
|
||||
"message": "kubelet is posting ready status",
|
||||
"reason": "KubeletReady",
|
||||
"status": "True",
|
||||
"type": "Ready"
|
||||
}
|
||||
],
|
||||
"daemonEndpoints": {
|
||||
"kubeletEndpoint": {
|
||||
"Port": 10250
|
||||
}
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"names": [
|
||||
"requarks/wiki@sha256:dd83fff15e77843ff934b25c28c865ac000edf7653e5d11adad1dd51df87439d"
|
||||
],
|
||||
"sizeBytes": 441083858
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"mariadb@sha256:821d0411208eaa88f9e1f0daccd1d534f88d19baf724eb9a2777cbedb10b6c66"
|
||||
],
|
||||
"sizeBytes": 400782682
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/etcd@sha256:64b9ea357325d5db9f8a723dcf503b5a449177b17ac87d69481e126bb724c263",
|
||||
"k8s.gcr.io/etcd:3.5.1-0"
|
||||
],
|
||||
"sizeBytes": 292558922
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kubernetesui/dashboard@sha256:ec27f462cf1946220f5a9ace416a84a57c18f98c777876a8054405d1428cc92e",
|
||||
"kubernetesui/dashboard:v2.3.1"
|
||||
],
|
||||
"sizeBytes": 220033604
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-apiserver@sha256:f54681a71cce62cbc1b13ebb3dbf1d880f849112789811f98b6aebd2caa2f255",
|
||||
"k8s.gcr.io/kube-apiserver:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 135162256
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-controller-manager@sha256:a7ed87380108a2d811f0d392a3fe87546c85bc366e0d1e024dfa74eb14468604",
|
||||
"k8s.gcr.io/kube-controller-manager:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 124971684
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8",
|
||||
"k8s.gcr.io/kube-proxy:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 112327826
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/kubescape/kubescape@sha256:6196f766be50d94b45d903a911f5ee95ac99bc392a1324c3e063bec41efd98ba",
|
||||
"quay.io/kubescape/kubescape:v2.0.153"
|
||||
],
|
||||
"sizeBytes": 110345054
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d"
|
||||
],
|
||||
"sizeBytes": 109129446
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/action-trigger@sha256:b93707d10ff86aac8dfa42ad37192d6bcf9aceeb4321b21756e438389c26e07c",
|
||||
"quay.io/armosec/action-trigger:v0.0.5"
|
||||
],
|
||||
"sizeBytes": 65127067
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/images-vulnerabilities-scan@sha256:a5f9ddc04a7fdce6d52ef85a21f0de567d8e04d418c2bc5bf5d72b151c997625",
|
||||
"quay.io/armosec/images-vulnerabilities-scan:v0.0.7"
|
||||
],
|
||||
"sizeBytes": 61446712
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/images-vulnerabilities-scan@sha256:2f879858da89f6542e3223fb18d6d793810cc2ad6e398b66776475e4218b6af5",
|
||||
"quay.io/armosec/images-vulnerabilities-scan:v0.0.8"
|
||||
],
|
||||
"sizeBytes": 61446528
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/cluster-collector@sha256:2c4f733d09f7f4090ace04585230bdfacbbc29a3ade38a2e1233d2c0f730d9b6",
|
||||
"quay.io/armosec/cluster-collector:v0.0.9"
|
||||
],
|
||||
"sizeBytes": 53699576
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-scheduler@sha256:8be4eb1593cf9ff2d91b44596633b7815a3753696031a1eb4273d1b39427fa8c",
|
||||
"k8s.gcr.io/kube-scheduler:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 53488305
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/coredns/coredns@sha256:5b6ec0d6de9baaf3e92d0f66cd96a25b9edbce8716f5f15dcd1a616b3abd590e",
|
||||
"k8s.gcr.io/coredns/coredns:v1.8.6"
|
||||
],
|
||||
"sizeBytes": 46829283
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kubernetesui/metrics-scraper@sha256:36d5b3f60e1a144cc5ada820910535074bdf5cf73fb70d1ff1681537eef4e172",
|
||||
"kubernetesui/metrics-scraper:v1.0.7"
|
||||
],
|
||||
"sizeBytes": 34446077
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"gcr.io/k8s-minikube/storage-provisioner@sha256:18eb69d1418e854ad5a19e399310e52808a8321e4c441c1dddad8977a0d7a944",
|
||||
"gcr.io/k8s-minikube/storage-provisioner:v5"
|
||||
],
|
||||
"sizeBytes": 31465472
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/notification-server@sha256:b6e9b296cd53bd3b2b42c516d8ab43db998acff1124a57aff8d66b3dd7881979",
|
||||
"quay.io/armosec/notification-server:v0.0.3"
|
||||
],
|
||||
"sizeBytes": 20209940
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
|
||||
"quay.io/kubescape/host-scanner:latest"
|
||||
],
|
||||
"sizeBytes": 11796788
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/pause@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db",
|
||||
"k8s.gcr.io/pause:3.6"
|
||||
],
|
||||
"sizeBytes": 682696
|
||||
}
|
||||
],
|
||||
"nodeInfo": {
|
||||
"architecture": "amd64",
|
||||
"bootID": "828cbe73-120b-43cf-aae0-9e2d15b8c873",
|
||||
"containerRuntimeVersion": "docker://20.10.12",
|
||||
"kernelVersion": "5.13.0-40-generic",
|
||||
"kubeProxyVersion": "v1.23.1",
|
||||
"kubeletVersion": "v1.23.1",
|
||||
"machineID": "8de776e053e140d6a14c2d2def3d6bb8",
|
||||
"operatingSystem": "linux",
|
||||
"osImage": "Ubuntu 20.04.2 LTS",
|
||||
"systemUUID": "da12dc19-10bf-4033-a440-2d9aa33d6fe3"
|
||||
}
|
||||
}
|
||||
],
|
||||
"allocatable": {
|
||||
"cpu": "4",
|
||||
"ephemeral-storage": "94850516Ki",
|
||||
"hugepages-2Mi": "0",
|
||||
"memory": "10432976Ki",
|
||||
"pods": "110"
|
||||
},
|
||||
"capacity": {
|
||||
"cpu": "4",
|
||||
"ephemeral-storage": "94850516Ki",
|
||||
"hugepages-2Mi": "0",
|
||||
"memory": "10432976Ki",
|
||||
"pods": "110"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has sufficient memory available",
|
||||
"reason": "KubeletHasSufficientMemory",
|
||||
"status": "False",
|
||||
"type": "MemoryPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has no disk pressure",
|
||||
"reason": "KubeletHasNoDiskPressure",
|
||||
"status": "False",
|
||||
"type": "DiskPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:29Z",
|
||||
"message": "kubelet has sufficient PID available",
|
||||
"reason": "KubeletHasSufficientPID",
|
||||
"status": "False",
|
||||
"type": "PIDPressure"
|
||||
},
|
||||
{
|
||||
"lastHeartbeatTime": "2022-05-16T14:14:31Z",
|
||||
"lastTransitionTime": "2022-05-16T10:52:45Z",
|
||||
"message": "kubelet is posting ready status",
|
||||
"reason": "KubeletReady",
|
||||
"status": "True",
|
||||
"type": "Ready"
|
||||
}
|
||||
],
|
||||
"daemonEndpoints": {
|
||||
"kubeletEndpoint": {
|
||||
"Port": 10250
|
||||
}
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"names": [
|
||||
"requarks/wiki@sha256:dd83fff15e77843ff934b25c28c865ac000edf7653e5d11adad1dd51df87439d"
|
||||
],
|
||||
"sizeBytes": 441083858
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"mariadb@sha256:821d0411208eaa88f9e1f0daccd1d534f88d19baf724eb9a2777cbedb10b6c66"
|
||||
],
|
||||
"sizeBytes": 400782682
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/etcd@sha256:64b9ea357325d5db9f8a723dcf503b5a449177b17ac87d69481e126bb724c263",
|
||||
"k8s.gcr.io/etcd:3.5.1-0"
|
||||
],
|
||||
"sizeBytes": 292558922
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kubernetesui/dashboard@sha256:ec27f462cf1946220f5a9ace416a84a57c18f98c777876a8054405d1428cc92e",
|
||||
"kubernetesui/dashboard:v2.3.1"
|
||||
],
|
||||
"sizeBytes": 220033604
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-apiserver@sha256:f54681a71cce62cbc1b13ebb3dbf1d880f849112789811f98b6aebd2caa2f255",
|
||||
"k8s.gcr.io/kube-apiserver:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 135162256
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-controller-manager@sha256:a7ed87380108a2d811f0d392a3fe87546c85bc366e0d1e024dfa74eb14468604",
|
||||
"k8s.gcr.io/kube-controller-manager:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 124971684
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-proxy@sha256:e40f3a28721588affcf187f3f246d1e078157dabe274003eaa2957a83f7170c8",
|
||||
"k8s.gcr.io/kube-proxy:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 112327826
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/kubescape/kubescape@sha256:6196f766be50d94b45d903a911f5ee95ac99bc392a1324c3e063bec41efd98ba",
|
||||
"quay.io/kubescape/kubescape:v2.0.153"
|
||||
],
|
||||
"sizeBytes": 110345054
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"nginx@sha256:f7988fb6c02e0ce69257d9bd9cf37ae20a60f1df7563c3a2a6abe24160306b8d"
|
||||
],
|
||||
"sizeBytes": 109129446
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/action-trigger@sha256:b93707d10ff86aac8dfa42ad37192d6bcf9aceeb4321b21756e438389c26e07c",
|
||||
"quay.io/armosec/action-trigger:v0.0.5"
|
||||
],
|
||||
"sizeBytes": 65127067
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/images-vulnerabilities-scan@sha256:a5f9ddc04a7fdce6d52ef85a21f0de567d8e04d418c2bc5bf5d72b151c997625",
|
||||
"quay.io/armosec/images-vulnerabilities-scan:v0.0.7"
|
||||
],
|
||||
"sizeBytes": 61446712
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/images-vulnerabilities-scan@sha256:2f879858da89f6542e3223fb18d6d793810cc2ad6e398b66776475e4218b6af5",
|
||||
"quay.io/armosec/images-vulnerabilities-scan:v0.0.8"
|
||||
],
|
||||
"sizeBytes": 61446528
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/cluster-collector@sha256:2c4f733d09f7f4090ace04585230bdfacbbc29a3ade38a2e1233d2c0f730d9b6",
|
||||
"quay.io/armosec/cluster-collector:v0.0.9"
|
||||
],
|
||||
"sizeBytes": 53699576
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/kube-scheduler@sha256:8be4eb1593cf9ff2d91b44596633b7815a3753696031a1eb4273d1b39427fa8c",
|
||||
"k8s.gcr.io/kube-scheduler:v1.23.1"
|
||||
],
|
||||
"sizeBytes": 53488305
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/coredns/coredns@sha256:5b6ec0d6de9baaf3e92d0f66cd96a25b9edbce8716f5f15dcd1a616b3abd590e",
|
||||
"k8s.gcr.io/coredns/coredns:v1.8.6"
|
||||
],
|
||||
"sizeBytes": 46829283
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"kubernetesui/metrics-scraper@sha256:36d5b3f60e1a144cc5ada820910535074bdf5cf73fb70d1ff1681537eef4e172",
|
||||
"kubernetesui/metrics-scraper:v1.0.7"
|
||||
],
|
||||
"sizeBytes": 34446077
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"gcr.io/k8s-minikube/storage-provisioner@sha256:18eb69d1418e854ad5a19e399310e52808a8321e4c441c1dddad8977a0d7a944",
|
||||
"gcr.io/k8s-minikube/storage-provisioner:v5"
|
||||
],
|
||||
"sizeBytes": 31465472
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/armosec/notification-server@sha256:b6e9b296cd53bd3b2b42c516d8ab43db998acff1124a57aff8d66b3dd7881979",
|
||||
"quay.io/armosec/notification-server:v0.0.3"
|
||||
],
|
||||
"sizeBytes": 20209940
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"quay.io/kubescape/host-scanner@sha256:82139d2561039726be060df2878ef023c59df7c536fbd7f6d766af5a99569fee",
|
||||
"quay.io/kubescape/host-scanner:latest"
|
||||
],
|
||||
"sizeBytes": 11796788
|
||||
},
|
||||
{
|
||||
"names": [
|
||||
"k8s.gcr.io/pause@sha256:3d380ca8864549e74af4b29c10f9cb0956236dfb01c40ca076fb6c37253234db",
|
||||
"k8s.gcr.io/pause:3.6"
|
||||
],
|
||||
"sizeBytes": 682696
|
||||
}
|
||||
],
|
||||
"nodeInfo": {
|
||||
"architecture": "amd64",
|
||||
"bootID": "828cbe73-120b-43cf-aae0-9e2d15b8c873",
|
||||
"containerRuntimeVersion": "docker://20.10.12",
|
||||
"kernelVersion": "5.13.0-40-generic",
|
||||
"kubeProxyVersion": "v1.23.1",
|
||||
"kubeletVersion": "v1.23.1",
|
||||
"machineID": "8de776e053e140d6a14c2d2def3d6bb8",
|
||||
"operatingSystem": "linux",
|
||||
"osImage": "Ubuntu 20.04.2 LTS",
|
||||
"systemUUID": "da12dc19-10bf-4033-a440-2d9aa33d6fe3"
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
var l v1.Node
|
||||
_ = json.Unmarshal([]byte(noTaintNode), &l)
|
||||
assert.False(t, isMasterNodeTaints(l.Spec.Taints))
|
||||
`
|
||||
var noTaintNode v1.Node
|
||||
_ = json.Unmarshal([]byte(noTaintNodeJson), &noTaintNode)
|
||||
assert.False(t, isMasterNodeTaints(noTaintNode.Spec.Taints))
|
||||
|
||||
taintNode :=
|
||||
taintNodeJson :=
|
||||
`
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
@@ -532,8 +532,60 @@ func TestIsMasterNodeTaints(t *testing.T) {
|
||||
}
|
||||
}
|
||||
`
|
||||
_ = json.Unmarshal([]byte(taintNode), &l)
|
||||
assert.True(t, isMasterNodeTaints(l.Spec.Taints))
|
||||
var taintNode v1.Node
|
||||
_ = json.Unmarshal([]byte(taintNodeJson), &taintNode)
|
||||
assert.True(t, isMasterNodeTaints(taintNode.Spec.Taints))
|
||||
|
||||
taintNodeJson1 :=
|
||||
`
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Node",
|
||||
"metadata": {
|
||||
"annotations": {
|
||||
"kubeadm.alpha.kubernetes.io/cri-socket": "/var/run/dockershim.sock",
|
||||
"node.alpha.kubernetes.io/ttl": "0",
|
||||
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
|
||||
},
|
||||
"creationTimestamp": "2022-05-16T10:52:32Z",
|
||||
"labels": {
|
||||
"beta.kubernetes.io/arch": "amd64",
|
||||
"beta.kubernetes.io/os": "linux",
|
||||
"kubernetes.io/arch": "amd64",
|
||||
"kubernetes.io/hostname": "danielg-minikube",
|
||||
"kubernetes.io/os": "linux",
|
||||
"minikube.k8s.io/commit": "3e64b11ed75e56e4898ea85f96b2e4af0301f43d",
|
||||
"minikube.k8s.io/name": "danielg-minikube",
|
||||
"minikube.k8s.io/updated_at": "2022_05_16T13_52_35_0700",
|
||||
"minikube.k8s.io/version": "v1.25.1",
|
||||
"node-role.kubernetes.io/control-plane": "",
|
||||
"node-role.kubernetes.io/master": "",
|
||||
"node.kubernetes.io/exclude-from-external-load-balancers": ""
|
||||
},
|
||||
"name": "danielg-minikube",
|
||||
"resourceVersion": "9871",
|
||||
"uid": "fc4afcb6-4ca4-4038-ba54-5e16065a614a"
|
||||
},
|
||||
"spec": {
|
||||
"podCIDR": "10.244.0.0/24",
|
||||
"podCIDRs": [
|
||||
"10.244.0.0/24"
|
||||
],
|
||||
"taints": [
|
||||
{
|
||||
"effect": "NoSchedule",
|
||||
"key": "node-role.kubernetes.io/control-plane",
|
||||
"value": "true"
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": {}
|
||||
}
|
||||
`
|
||||
|
||||
var taintNode1 v1.Node
|
||||
_ = json.Unmarshal([]byte(taintNodeJson1), &taintNode1)
|
||||
assert.True(t, isMasterNodeTaints(taintNode1.Spec.Taints))
|
||||
}
|
||||
|
||||
func TestSetMapNamespaceToNumOfResources(t *testing.T) {
|
||||
|
||||
@@ -9,7 +9,7 @@ const (
|
||||
emptySpace = " "
|
||||
middleItem = "├── "
|
||||
continueItem = "│ "
|
||||
lastItem = "└── "
|
||||
lastItem = "╰── "
|
||||
)
|
||||
|
||||
type (
|
||||
@@ -66,7 +66,7 @@ func (t *tree) Items() []Tree {
|
||||
return t.items
|
||||
}
|
||||
|
||||
// Print returns an visual representation of the tree
|
||||
// Print returns a visual representation of the tree
|
||||
func (t *tree) Print() string {
|
||||
return newPrinter().Print(t)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestTreePrint(t *testing.T) {
|
||||
tree: SimpleTreeMock(),
|
||||
want: "root\n" +
|
||||
"├── child1\n" +
|
||||
"└── child2\n",
|
||||
"╰── child2\n",
|
||||
},
|
||||
{
|
||||
name: "SimpleTreeWithLinesMock",
|
||||
@@ -42,36 +42,36 @@ func TestTreePrint(t *testing.T) {
|
||||
"├── child3\n" +
|
||||
"│ Line2\n" +
|
||||
"│ Line3\n" +
|
||||
"└── child4\n",
|
||||
"╰── child4\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeMock1",
|
||||
tree: SubTreeMock1(),
|
||||
want: "root\n" +
|
||||
"└── child1\n" +
|
||||
" └── child1.1\n",
|
||||
"╰── child1\n" +
|
||||
" ╰── child1.1\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeMock2",
|
||||
tree: SubTreeMock2(),
|
||||
want: "root\n" +
|
||||
"├── child1\n" +
|
||||
"│ └── child1.1\n" +
|
||||
"│ ╰── child1.1\n" +
|
||||
"├── child2\n" +
|
||||
"└── child3\n" +
|
||||
" └── child3.1\n",
|
||||
"╰── child3\n" +
|
||||
" ╰── child3.1\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeWithLinesMock",
|
||||
tree: SubTreeWithLinesMock(),
|
||||
want: "root\n" +
|
||||
"├── child1\n" +
|
||||
"│ └── child1.1\n" +
|
||||
"│ ╰── child1.1\n" +
|
||||
"│ Line2\n" +
|
||||
"│ Line3\n" +
|
||||
"├── child2\n" +
|
||||
"└── child3\n" +
|
||||
" └── child3.1\n" +
|
||||
"╰── child3\n" +
|
||||
" ╰── child3.1\n" +
|
||||
" Line2\n" +
|
||||
" Line3\n",
|
||||
},
|
||||
@@ -85,8 +85,8 @@ func TestTreePrint(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintText_LastTree(t *testing.T) {
|
||||
inputText := "Root\n├── Child1\n└── Child2"
|
||||
expectedOutput := "└── Root\n ├── Child1\n └── Child2\n"
|
||||
inputText := "Root\n├── Child1\n╰── Child2"
|
||||
expectedOutput := "╰── Root\n ├── Child1\n ╰── Child2\n"
|
||||
|
||||
result := p.printText(inputText, []bool{}, true)
|
||||
|
||||
@@ -94,8 +94,8 @@ func TestPrintText_LastTree(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPrintText_NotLastTree(t *testing.T) {
|
||||
inputText := "Root\n├── Child1\n└── Child2"
|
||||
expectedOutput := "├── Root\n│ ├── Child1\n│ └── Child2\n"
|
||||
inputText := "Root\n├── Child1\n╰── Child2"
|
||||
expectedOutput := "├── Root\n│ ├── Child1\n│ ╰── Child2\n"
|
||||
|
||||
result := p.printText(inputText, []bool{}, false)
|
||||
|
||||
@@ -122,7 +122,7 @@ func Test_printer_printItems(t *testing.T) {
|
||||
name: "SimpleTreeMock",
|
||||
tree: SimpleTreeMock(),
|
||||
want: "├── child1\n" +
|
||||
"└── child2\n",
|
||||
"╰── child2\n",
|
||||
},
|
||||
{
|
||||
name: "SimpleTreeWithLinesMock",
|
||||
@@ -132,33 +132,33 @@ func Test_printer_printItems(t *testing.T) {
|
||||
"├── child3\n" +
|
||||
"│ Line2\n" +
|
||||
"│ Line3\n" +
|
||||
"└── child4\n",
|
||||
"╰── child4\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeMock1",
|
||||
tree: SubTreeMock1(),
|
||||
want: "└── child1\n" +
|
||||
" └── child1.1\n",
|
||||
want: "╰── child1\n" +
|
||||
" ╰── child1.1\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeMock2",
|
||||
tree: SubTreeMock2(),
|
||||
want: "├── child1\n" +
|
||||
"│ └── child1.1\n" +
|
||||
"│ ╰── child1.1\n" +
|
||||
"├── child2\n" +
|
||||
"└── child3\n" +
|
||||
" └── child3.1\n",
|
||||
"╰── child3\n" +
|
||||
" ╰── child3.1\n",
|
||||
},
|
||||
{
|
||||
name: "SubTreeWithLinesMock",
|
||||
tree: SubTreeWithLinesMock(),
|
||||
want: "├── child1\n" +
|
||||
"│ └── child1.1\n" +
|
||||
"│ ╰── child1.1\n" +
|
||||
"│ Line2\n" +
|
||||
"│ Line3\n" +
|
||||
"├── child2\n" +
|
||||
"└── child3\n" +
|
||||
" └── child3.1\n" +
|
||||
"╰── child3\n" +
|
||||
" ╰── child3.1\n" +
|
||||
" Line2\n" +
|
||||
" Line3\n",
|
||||
},
|
||||
|
||||
@@ -95,7 +95,7 @@ func (prettyPrinter *PrettyPrinter) printAttackTracks(opaSessionObj *cautils.OPA
|
||||
})
|
||||
|
||||
for i := 0; i < topResourceCount && i < len(resources); i++ {
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+getSeparator("^")+"\n")
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n%s\n", getSeparator("^"))
|
||||
resource := resources[i]
|
||||
resourceObj := opaSessionObj.AllResources[resource.ResourceID]
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/grype/grype/presenter"
|
||||
grypejson "github.com/anchore/grype/grype/presenter/json"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
@@ -17,7 +18,6 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"k8s.io/utils/strings/slices"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -70,17 +70,10 @@ func (jp *JsonPrinter) convertToImageScanSummary(imageScanData []cautils.ImageSc
|
||||
imageScanSummary.Images = append(imageScanSummary.Images, imageScanData[i].Image)
|
||||
}
|
||||
|
||||
presenterConfig := imageScanData[i].PresenterConfig
|
||||
doc, err := models.NewDocument(clio.Identification{}, presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus)
|
||||
if err != nil {
|
||||
logger.L().Error(fmt.Sprintf("failed to create document for image: %v", imageScanData[i].Image), helpers.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
CVEs := extractCVEs(doc.Matches)
|
||||
CVEs := extractCVEs(imageScanData[i].Matches)
|
||||
imageScanSummary.CVEs = append(imageScanSummary.CVEs, CVEs...)
|
||||
|
||||
setPkgNameToScoreMap(doc.Matches, imageScanSummary.PackageScores)
|
||||
setPkgNameToScoreMap(imageScanData[i].Matches, imageScanSummary.PackageScores)
|
||||
|
||||
setSeverityToSummaryMap(CVEs, imageScanSummary.MapsSeverityToSummary)
|
||||
}
|
||||
@@ -92,9 +85,15 @@ func (jp *JsonPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.O
|
||||
var err error
|
||||
|
||||
if opaSessionObj != nil {
|
||||
err = printConfigurationsScanning(opaSessionObj, ctx, imageScanData, jp)
|
||||
err = printConfigurationsScanning(opaSessionObj, imageScanData, jp)
|
||||
} else if imageScanData != nil {
|
||||
err = jp.PrintImageScan(ctx, imageScanData[0].PresenterConfig)
|
||||
model, err2 := models.NewDocument(clio.Identification{}, imageScanData[0].Packages, imageScanData[0].Context,
|
||||
*imageScanData[0].RemainingMatches, imageScanData[0].IgnoredMatches, imageScanData[0].VulnerabilityProvider, nil, nil, models.DefaultSortStrategy, false)
|
||||
if err2 != nil {
|
||||
logger.L().Ctx(ctx).Error("failed to create document: %w", helpers.Error(err))
|
||||
return
|
||||
}
|
||||
err = grypejson.NewPresenter(models.PresenterConfig{Document: model, SBOM: imageScanData[0].SBOM}).Present(jp.writer)
|
||||
} else {
|
||||
err = fmt.Errorf("no data provided")
|
||||
}
|
||||
@@ -107,7 +106,7 @@ func (jp *JsonPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.O
|
||||
printer.LogOutputFile(jp.writer.Name())
|
||||
}
|
||||
|
||||
func printConfigurationsScanning(opaSessionObj *cautils.OPASessionObj, ctx context.Context, imageScanData []cautils.ImageScanData, jp *JsonPrinter) error {
|
||||
func printConfigurationsScanning(opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData, jp *JsonPrinter) error {
|
||||
|
||||
if imageScanData != nil {
|
||||
imageScanSummary, err := jp.convertToImageScanSummary(imageScanData)
|
||||
@@ -168,14 +167,6 @@ func convertToReportSummary(input map[string]*imageprinter.SeveritySummary) map[
|
||||
return output
|
||||
}
|
||||
|
||||
func (jp *JsonPrinter) PrintImageScan(ctx context.Context, scanResults *models.PresenterConfig) error {
|
||||
if scanResults == nil {
|
||||
return fmt.Errorf("no image vulnerability data provided")
|
||||
}
|
||||
pres := presenter.GetPresenter("json", "", false, *scanResults)
|
||||
return pres.Present(jp.writer)
|
||||
}
|
||||
|
||||
func (jp *JsonPrinter) PrintNextSteps() {
|
||||
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/kubescape/opa-utils/objectsenvelopes"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"k8s.io/utils/strings/slices"
|
||||
)
|
||||
|
||||
@@ -90,17 +89,10 @@ func (pp *PrettyPrinter) convertToImageScanSummary(imageScanData []cautils.Image
|
||||
imageScanSummary.Images = append(imageScanSummary.Images, imageScanData[i].Image)
|
||||
}
|
||||
|
||||
presenterConfig := imageScanData[i].PresenterConfig
|
||||
doc, err := models.NewDocument(clio.Identification{}, presenterConfig.Packages, presenterConfig.Context, presenterConfig.Matches, presenterConfig.IgnoredMatches, presenterConfig.MetadataProvider, nil, presenterConfig.DBStatus)
|
||||
if err != nil {
|
||||
logger.L().Error(fmt.Sprintf("failed to create document for image: %v", imageScanData[i].Image), helpers.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
CVEs := extractCVEs(doc.Matches)
|
||||
CVEs := extractCVEs(imageScanData[i].Matches)
|
||||
imageScanSummary.CVEs = append(imageScanSummary.CVEs, CVEs...)
|
||||
|
||||
setPkgNameToScoreMap(doc.Matches, imageScanSummary.PackageScores)
|
||||
setPkgNameToScoreMap(imageScanData[i].Matches, imageScanSummary.PackageScores)
|
||||
|
||||
setSeverityToSummaryMap(CVEs, imageScanSummary.MapsSeverityToSummary)
|
||||
}
|
||||
@@ -121,9 +113,8 @@ func (pp *PrettyPrinter) ActionPrint(_ context.Context, opaSessionObj *cautils.O
|
||||
if opaSessionObj != nil {
|
||||
// TODO line is currently printed on framework scan only
|
||||
if isPrintSeparatorType(pp.scanType) {
|
||||
fmt.Fprintf(pp.writer, "\n"+
|
||||
gchalk.WithAnsi256(238).Bold(fmt.Sprintf("%s\n", strings.Repeat("─", 50)))+
|
||||
"\n")
|
||||
fmt.Fprintf(pp.writer, "\n%s\n\n",
|
||||
gchalk.WithAnsi256(238).Bold(strings.Repeat("─", 50)))
|
||||
} else {
|
||||
fmt.Fprintf(pp.writer, "\n")
|
||||
}
|
||||
@@ -174,20 +165,20 @@ func (pp *PrettyPrinter) printHeader(opaSessionObj *cautils.OPASessionObj) {
|
||||
} else if pp.scanType == cautils.ScanTypeWorkload {
|
||||
cautils.InfoDisplay(pp.writer, "Workload security posture overview for:\n")
|
||||
ns := opaSessionObj.SingleResourceScan.GetNamespace()
|
||||
rows := [][]string{}
|
||||
var rows []table.Row
|
||||
if ns != "" {
|
||||
rows = append(rows, []string{"Namespace", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetNamespace())})
|
||||
rows = append(rows, table.Row{"Namespace", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetNamespace())})
|
||||
}
|
||||
rows = append(rows, []string{"Kind", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetKind())})
|
||||
rows = append(rows, []string{"Name", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetName())})
|
||||
rows = append(rows, table.Row{"Kind", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetKind())})
|
||||
rows = append(rows, table.Row{"Name", gchalk.WithBrightWhite().Bold(opaSessionObj.SingleResourceScan.GetName())})
|
||||
|
||||
table := tablewriter.NewWriter(pp.writer)
|
||||
tableWriter := table.NewWriter()
|
||||
tableWriter.SetOutputMirror(pp.writer)
|
||||
|
||||
table.SetColumnAlignment([]int{tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_LEFT})
|
||||
table.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
table.AppendBulk(rows)
|
||||
tableWriter.SetColumnConfigs([]table.ColumnConfig{{Number: 1, Align: text.AlignRight}, {Number: 2, Align: text.AlignLeft}})
|
||||
tableWriter.AppendRows(rows)
|
||||
|
||||
table.Render()
|
||||
tableWriter.Render()
|
||||
|
||||
cautils.SimpleDisplay(pp.writer, "\nIn this overview, Kubescape shows you a summary of the security posture of a workload, including key controls that apply to its configuration, and the vulnerability status of the container image.\n\n\n")
|
||||
}
|
||||
@@ -209,7 +200,7 @@ func (pp *PrettyPrinter) SetWriter(ctx context.Context, outputFile string) {
|
||||
pp.SetMainPrinter()
|
||||
}
|
||||
|
||||
func (pp *PrettyPrinter) Score(score float32) {
|
||||
func (pp *PrettyPrinter) Score(_ float32) {
|
||||
}
|
||||
|
||||
func (pp *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries, allResources map[string]workloadinterface.IMetadata, sortedControlIDs [][]string) {
|
||||
@@ -218,12 +209,12 @@ func (pp *PrettyPrinter) printResults(controls *reportsummary.ControlSummaries,
|
||||
controlSummary := controls.GetControl(reportsummary.EControlCriteriaID, c) // summaryDetails.Controls ListControls().All() Controls.GetControl(ca)
|
||||
pp.printTitle(controlSummary)
|
||||
pp.printResources(controlSummary, allResources)
|
||||
pp.printSummary(c, controlSummary)
|
||||
pp.printSummary(controlSummary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (prettyPrinter *PrettyPrinter) printSummary(controlName string, controlSummary reportsummary.IControlSummary) {
|
||||
func (prettyPrinter *PrettyPrinter) printSummary(controlSummary reportsummary.IControlSummary) {
|
||||
cautils.SimpleDisplay(prettyPrinter.writer, "Summary - ")
|
||||
cautils.SuccessDisplay(prettyPrinter.writer, "Passed:%v ", controlSummary.NumberOfResources().Passed())
|
||||
cautils.WarningDisplay(prettyPrinter.writer, "Action Required:%v ", controlSummary.NumberOfResources().Skipped())
|
||||
|
||||
@@ -3,15 +3,15 @@ package configurationprinter
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
docsPrefix = "https://hub.armosec.io/docs"
|
||||
docsPrefix = "https://kubescape.io/docs/controls"
|
||||
scanControlPrefix = "$ kubescape scan control"
|
||||
controlNameHeader = "Control name"
|
||||
statusHeader = ""
|
||||
@@ -21,15 +21,15 @@ const (
|
||||
)
|
||||
|
||||
// initializes the table headers and column alignments based on the category type
|
||||
func initCategoryTableData(categoryType CategoryType) ([]string, []int) {
|
||||
func initCategoryTableData(categoryType CategoryType) (table.Row, []table.ColumnConfig) {
|
||||
if categoryType == TypeCounting {
|
||||
return getCategoryCountingTypeHeaders(), getCountingTypeAlignments()
|
||||
}
|
||||
return getCategoryStatusTypeHeaders(), getStatusTypeAlignments()
|
||||
}
|
||||
|
||||
func getCategoryStatusTypeHeaders() []string {
|
||||
headers := make([]string, 3)
|
||||
func getCategoryStatusTypeHeaders() table.Row {
|
||||
headers := make(table.Row, 3)
|
||||
headers[0] = statusHeader
|
||||
headers[1] = controlNameHeader
|
||||
headers[2] = docsHeader
|
||||
@@ -37,8 +37,8 @@ func getCategoryStatusTypeHeaders() []string {
|
||||
return headers
|
||||
}
|
||||
|
||||
func getCategoryCountingTypeHeaders() []string {
|
||||
headers := make([]string, 3)
|
||||
func getCategoryCountingTypeHeaders() table.Row {
|
||||
headers := make(table.Row, 3)
|
||||
headers[0] = controlNameHeader
|
||||
headers[1] = resourcesHeader
|
||||
headers[2] = runHeader
|
||||
@@ -46,16 +46,16 @@ func getCategoryCountingTypeHeaders() []string {
|
||||
return headers
|
||||
}
|
||||
|
||||
func getStatusTypeAlignments() []int {
|
||||
return []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER}
|
||||
func getStatusTypeAlignments() []table.ColumnConfig {
|
||||
return []table.ColumnConfig{{Number: 1, Align: text.AlignCenter}, {Number: 2, Align: text.AlignLeft}, {Number: 3, Align: text.AlignCenter}}
|
||||
}
|
||||
|
||||
func getCountingTypeAlignments() []int {
|
||||
return []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT}
|
||||
func getCountingTypeAlignments() []table.ColumnConfig {
|
||||
return []table.ColumnConfig{{Number: 1, Align: text.AlignLeft}, {Number: 2, Align: text.AlignCenter}, {Number: 3, Align: text.AlignLeft}}
|
||||
}
|
||||
|
||||
// returns a row for status type table based on the control summary
|
||||
func generateCategoryStatusRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars) []string {
|
||||
func generateCategoryStatusRow(controlSummary reportsummary.IControlSummary) table.Row {
|
||||
|
||||
// show only passed, failed and action required controls
|
||||
status := controlSummary.GetStatus()
|
||||
@@ -63,7 +63,7 @@ func generateCategoryStatusRow(controlSummary reportsummary.IControlSummary, inf
|
||||
return nil
|
||||
}
|
||||
|
||||
rows := make([]string, 3)
|
||||
rows := make(table.Row, 3)
|
||||
|
||||
rows[0] = utils.GetStatusIcon(controlSummary.GetStatus().Status())
|
||||
|
||||
@@ -80,31 +80,26 @@ func generateCategoryStatusRow(controlSummary reportsummary.IControlSummary, inf
|
||||
|
||||
}
|
||||
|
||||
func getCategoryTableWriter(writer io.Writer, headers []string, columnAligments []int) *tablewriter.Table {
|
||||
table := tablewriter.NewWriter(writer)
|
||||
table.SetHeader(headers)
|
||||
table.SetHeaderLine(true)
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetColumnAlignment(columnAligments)
|
||||
table.SetAutoWrapText(false)
|
||||
table.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
var headerColors []tablewriter.Colors
|
||||
for range headers {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.FgHiYellowColor})
|
||||
}
|
||||
table.SetHeaderColor(headerColors...)
|
||||
return table
|
||||
func getCategoryTableWriter(writer io.Writer, headers table.Row, columnAlignments []table.ColumnConfig) table.Writer {
|
||||
tableWriter := table.NewWriter()
|
||||
tableWriter.SetOutputMirror(writer)
|
||||
tableWriter.AppendHeader(headers)
|
||||
tableWriter.Style().Options.SeparateHeader = true
|
||||
tableWriter.Style().Format.HeaderAlign = text.AlignLeft
|
||||
tableWriter.Style().Format.Header = text.FormatDefault
|
||||
tableWriter.SetColumnConfigs(columnAlignments)
|
||||
tableWriter.Style().Box = table.StyleBoxRounded
|
||||
return tableWriter
|
||||
}
|
||||
|
||||
func renderSingleCategory(writer io.Writer, categoryName string, table *tablewriter.Table, rows [][]string, infoToPrintInfo []utils.InfoStars) {
|
||||
func renderSingleCategory(writer io.Writer, categoryName string, tableWriter table.Writer, rows []table.Row, infoToPrintInfo []utils.InfoStars) {
|
||||
|
||||
cautils.InfoDisplay(writer, categoryName+"\n")
|
||||
|
||||
table.ClearRows()
|
||||
table.AppendBulk(rows)
|
||||
tableWriter.ResetRows()
|
||||
tableWriter.AppendRows(rows)
|
||||
|
||||
table.Render()
|
||||
tableWriter.Render()
|
||||
|
||||
if len(infoToPrintInfo) > 0 {
|
||||
printCategoryInfo(writer, infoToPrintInfo)
|
||||
|
||||
@@ -3,13 +3,13 @@ package configurationprinter
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -17,20 +17,20 @@ func TestInitCategoryTableData(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
categoryType CategoryType
|
||||
expectedHeaders []string
|
||||
expectedAlignments []int
|
||||
expectedHeaders table.Row
|
||||
expectedAlignments []table.ColumnConfig
|
||||
}{
|
||||
{
|
||||
name: "Test1",
|
||||
categoryType: TypeCounting,
|
||||
expectedHeaders: []string{"Control name", "Resources", "View details"},
|
||||
expectedAlignments: []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT},
|
||||
expectedHeaders: table.Row{"Control name", "Resources", "View details"},
|
||||
expectedAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignLeft}, {Number: 2, Align: text.AlignCenter}, {Number: 3, Align: text.AlignLeft}},
|
||||
},
|
||||
{
|
||||
name: "Test2",
|
||||
categoryType: TypeStatus,
|
||||
expectedHeaders: []string{"", "Control name", "Docs"},
|
||||
expectedAlignments: []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER},
|
||||
expectedHeaders: table.Row{"", "Control name", "Docs"},
|
||||
expectedAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignCenter}, {Number: 2, Align: text.AlignLeft}, {Number: 3, Align: text.AlignCenter}},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -42,8 +42,8 @@ func TestInitCategoryTableData(t *testing.T) {
|
||||
if len(alignments) != len(tt.expectedAlignments) {
|
||||
t.Errorf("initCategoryTableData() alignments = %v, want %v", alignments, tt.expectedAlignments)
|
||||
}
|
||||
assert.True(t, reflect.DeepEqual(headers, tt.expectedHeaders))
|
||||
assert.True(t, reflect.DeepEqual(alignments, tt.expectedAlignments))
|
||||
assert.Equal(t, headers, tt.expectedHeaders)
|
||||
assert.Equal(t, alignments, tt.expectedAlignments)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -88,52 +88,12 @@ func TestGetCategoryCountingTypeHeaders(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStatusTypeAlignments(t *testing.T) {
|
||||
alignments := getStatusTypeAlignments()
|
||||
|
||||
if len(alignments) != 3 {
|
||||
t.Errorf("Expected 3 alignments, got %d", len(alignments))
|
||||
}
|
||||
|
||||
if alignments[0] != tablewriter.ALIGN_CENTER {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_CENTER, alignments[0])
|
||||
}
|
||||
|
||||
if alignments[1] != tablewriter.ALIGN_LEFT {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_LEFT, alignments[1])
|
||||
}
|
||||
|
||||
if alignments[2] != tablewriter.ALIGN_CENTER {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_CENTER, alignments[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCountingTypeAlignments(t *testing.T) {
|
||||
alignments := getCountingTypeAlignments()
|
||||
|
||||
if len(alignments) != 3 {
|
||||
t.Errorf("Expected 3 alignments, got %d", len(alignments))
|
||||
}
|
||||
|
||||
if alignments[0] != tablewriter.ALIGN_LEFT {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_LEFT, alignments[0])
|
||||
}
|
||||
|
||||
if alignments[1] != tablewriter.ALIGN_CENTER {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_CENTER, alignments[1])
|
||||
}
|
||||
|
||||
if alignments[2] != tablewriter.ALIGN_LEFT {
|
||||
t.Errorf("Expected %d, got %d", tablewriter.ALIGN_LEFT, alignments[2])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
controlSummary reportsummary.IControlSummary
|
||||
infoToPrintInfo []utils.InfoStars
|
||||
expectedRows []string
|
||||
expectedRows table.Row
|
||||
}{
|
||||
{
|
||||
name: "failed control",
|
||||
@@ -142,7 +102,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusFailed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"❌", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: table.Row{"❌", "test", "https://kubescape.io/docs/controls/ctrlid"},
|
||||
},
|
||||
{
|
||||
name: "skipped control",
|
||||
@@ -154,7 +114,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
},
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"⚠️", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: table.Row{"⚠️", "test", "https://kubescape.io/docs/controls/ctrlid"},
|
||||
infoToPrintInfo: []utils.InfoStars{
|
||||
{
|
||||
Info: "testInfo",
|
||||
@@ -169,7 +129,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusPassed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"✅", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: table.Row{"✅", "test", "https://kubescape.io/docs/controls/ctrlid"},
|
||||
},
|
||||
{
|
||||
name: "big name",
|
||||
@@ -178,36 +138,36 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusFailed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"❌", "testtesttesttesttesttesttesttesttesttesttesttestte...", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: table.Row{"❌", "testtesttesttesttesttesttesttesttesttesttesttestte...", "https://kubescape.io/docs/controls/ctrlid"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
row := generateCategoryStatusRow(tt.controlSummary, tt.infoToPrintInfo)
|
||||
assert.True(t, reflect.DeepEqual(row, tt.expectedRows))
|
||||
row := generateCategoryStatusRow(tt.controlSummary)
|
||||
assert.Equal(t, tt.expectedRows, row)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCategoryTableWriter(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
headers []string
|
||||
columnAligments []int
|
||||
want string
|
||||
name string
|
||||
headers table.Row
|
||||
columnAlignments []table.ColumnConfig
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Test1",
|
||||
headers: []string{"Control name", "Resources", "View details"},
|
||||
columnAligments: []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT},
|
||||
want: "┌──────────────┬───────────┬──────────────┐\n│ Control name │ Resources │ View details │\n├──────────────┼───────────┼──────────────┤\n└──────────────┴───────────┴──────────────┘\n",
|
||||
name: "Test1",
|
||||
headers: table.Row{"Control name", "Resources", "View details"},
|
||||
columnAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignLeft}, {Number: 2, Align: text.AlignCenter}, {Number: 3, Align: text.AlignLeft}},
|
||||
want: "╭──────────────┬───────────┬──────────────╮\n│ Control name │ Resources │ View details │\n├──────────────┼───────────┼──────────────┤\n╰──────────────┴───────────┴──────────────╯\n",
|
||||
},
|
||||
{
|
||||
name: "Test2",
|
||||
headers: []string{"", "Control name", "Docs"},
|
||||
columnAligments: []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER},
|
||||
want: "┌──┬──────────────┬──────┐\n│ │ Control name │ Docs │\n├──┼──────────────┼──────┤\n└──┴──────────────┴──────┘\n",
|
||||
name: "Test2",
|
||||
headers: table.Row{"", "Control name", "Docs"},
|
||||
columnAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignCenter}, {Number: 2, Align: text.AlignLeft}, {Number: 3, Align: text.AlignCenter}},
|
||||
want: "╭──┬──────────────┬──────╮\n│ │ Control name │ Docs │\n├──┼──────────────┼──────┤\n╰──┴──────────────┴──────╯\n",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -219,7 +179,7 @@ func TestGetCategoryTableWriter(t *testing.T) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
tableWriter := getCategoryTableWriter(f, tt.headers, tt.columnAligments)
|
||||
tableWriter := getCategoryTableWriter(f, tt.headers, tt.columnAlignments)
|
||||
|
||||
// Redirect stderr to the temporary file
|
||||
oldStderr := os.Stderr
|
||||
@@ -245,61 +205,61 @@ func TestGetCategoryTableWriter(t *testing.T) {
|
||||
|
||||
func TestRenderSingleCategory(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
categoryName string
|
||||
rows [][]string
|
||||
infoToPrintInfo []utils.InfoStars
|
||||
headers []string
|
||||
columnAligments []int
|
||||
want string
|
||||
name string
|
||||
categoryName string
|
||||
rows []table.Row
|
||||
infoToPrintInfo []utils.InfoStars
|
||||
headers table.Row
|
||||
columnAlignments []table.ColumnConfig
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "Test1",
|
||||
categoryName: "Resources",
|
||||
rows: [][]string{
|
||||
rows: []table.Row{
|
||||
{"Regular", "regular line", "1"},
|
||||
{"Thick", "particularly thick line", "2"},
|
||||
{"Double", "double line", "3"},
|
||||
},
|
||||
infoToPrintInfo: []utils.InfoStars{
|
||||
utils.InfoStars{
|
||||
{
|
||||
Stars: "1",
|
||||
Info: "Low severity",
|
||||
},
|
||||
utils.InfoStars{
|
||||
{
|
||||
Stars: "5",
|
||||
Info: "Critical severity",
|
||||
},
|
||||
},
|
||||
headers: []string{"Control name", "Resources", "View details"},
|
||||
columnAligments: []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT},
|
||||
want: "Resources\n┌──────────────┬─────────────────────────┬──────────────┐\n│ Control name │ Resources │ View details │\n├──────────────┼─────────────────────────┼──────────────┤\n│ Regular │ regular line │ 1 │\n│ Thick │ particularly thick line │ 2 │\n│ Double │ double line │ 3 │\n└──────────────┴─────────────────────────┴──────────────┘\n1 Low severity\n5 Critical severity\n\n",
|
||||
headers: table.Row{"Control name", "Resources", "View details"},
|
||||
columnAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignLeft}, {Number: 2, Align: text.AlignCenter}, {Number: 3, Align: text.AlignLeft}},
|
||||
want: "Resources\n╭──────────────┬─────────────────────────┬──────────────╮\n│ Control name │ Resources │ View details │\n├──────────────┼─────────────────────────┼──────────────┤\n│ Regular │ regular line │ 1 │\n│ Thick │ particularly thick line │ 2 │\n│ Double │ double line │ 3 │\n╰──────────────┴─────────────────────────┴──────────────╯\n1 Low severity\n5 Critical severity\n\n",
|
||||
},
|
||||
{
|
||||
name: "Test2",
|
||||
categoryName: "Control name",
|
||||
rows: [][]string{
|
||||
rows: []table.Row{
|
||||
{"Regular", "regular line", "1"},
|
||||
{"Thick", "particularly thick line", "2"},
|
||||
{"Double", "double line", "3"},
|
||||
},
|
||||
infoToPrintInfo: []utils.InfoStars{
|
||||
utils.InfoStars{
|
||||
{
|
||||
Stars: "1",
|
||||
Info: "Low severity",
|
||||
},
|
||||
utils.InfoStars{
|
||||
{
|
||||
Stars: "5",
|
||||
Info: "Critical severity",
|
||||
},
|
||||
utils.InfoStars{
|
||||
{
|
||||
Stars: "4",
|
||||
Info: "High severity",
|
||||
},
|
||||
},
|
||||
headers: []string{"Control name", "Resources", "View details"},
|
||||
columnAligments: []int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT},
|
||||
want: "Control name\n┌──────────────┬─────────────────────────┬──────────────┐\n│ Control name │ Resources │ View details │\n├──────────────┼─────────────────────────┼──────────────┤\n│ Regular │ regular line │ 1 │\n│ Thick │ particularly thick line │ 2 │\n│ Double │ double line │ 3 │\n└──────────────┴─────────────────────────┴──────────────┘\n1 Low severity\n5 Critical severity\n4 High severity\n\n",
|
||||
headers: table.Row{"Control name", "Resources", "View details"},
|
||||
columnAlignments: []table.ColumnConfig{{Number: 1, Align: text.AlignLeft}, {Number: 2, Align: text.AlignCenter}, {Number: 3, Align: text.AlignLeft}},
|
||||
want: "Control name\n╭──────────────┬─────────────────────────┬──────────────╮\n│ Control name │ Resources │ View details │\n├──────────────┼─────────────────────────┼──────────────┤\n│ Regular │ regular line │ 1 │\n│ Thick │ particularly thick line │ 2 │\n│ Double │ double line │ 3 │\n╰──────────────┴─────────────────────────┴──────────────╯\n1 Low severity\n5 Critical severity\n4 High severity\n\n",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -311,7 +271,7 @@ func TestRenderSingleCategory(t *testing.T) {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
tableWriter := getCategoryTableWriter(f, tt.headers, tt.columnAligments)
|
||||
tableWriter := getCategoryTableWriter(f, tt.headers, tt.columnAlignments)
|
||||
|
||||
// Redirect stderr to the temporary file
|
||||
oldStderr := os.Stderr
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
@@ -17,11 +18,11 @@ func NewClusterPrinter() *ClusterPrinter {
|
||||
|
||||
var _ TablePrinter = &ClusterPrinter{}
|
||||
|
||||
func (cp *ClusterPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (cp *ClusterPrinter) PrintSummaryTable(_ io.Writer, _ *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
}
|
||||
|
||||
func (cp *ClusterPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (cp *ClusterPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapClusterControlsToCategories)
|
||||
|
||||
@@ -38,17 +39,17 @@ func (cp *ClusterPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails
|
||||
func (cp *ClusterPrinter) renderSingleCategoryTable(categoryName string, categoryType CategoryType, writer io.Writer, controlSummaries []reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars) {
|
||||
sortControlSummaries(controlSummaries)
|
||||
|
||||
headers, columnAligments := initCategoryTableData(categoryType)
|
||||
headers, columnAlignments := initCategoryTableData(categoryType)
|
||||
|
||||
table := getCategoryTableWriter(writer, headers, columnAligments)
|
||||
tableWriter := getCategoryTableWriter(writer, headers, columnAlignments)
|
||||
|
||||
var rows [][]string
|
||||
var rows []table.Row
|
||||
for _, ctrls := range controlSummaries {
|
||||
var row []string
|
||||
var row table.Row
|
||||
if categoryType == TypeCounting {
|
||||
row = cp.generateCountingCategoryRow(ctrls)
|
||||
} else {
|
||||
row = generateCategoryStatusRow(ctrls, infoToPrintInfo)
|
||||
row = generateCategoryStatusRow(ctrls)
|
||||
}
|
||||
if len(row) > 0 {
|
||||
rows = append(rows, row)
|
||||
@@ -59,19 +60,19 @@ func (cp *ClusterPrinter) renderSingleCategoryTable(categoryName string, categor
|
||||
return
|
||||
}
|
||||
|
||||
renderSingleCategory(writer, categoryName, table, rows, infoToPrintInfo)
|
||||
renderSingleCategory(writer, categoryName, tableWriter, rows, infoToPrintInfo)
|
||||
|
||||
}
|
||||
|
||||
func (cp *ClusterPrinter) generateCountingCategoryRow(controlSummary reportsummary.IControlSummary) []string {
|
||||
func (cp *ClusterPrinter) generateCountingCategoryRow(controlSummary reportsummary.IControlSummary) table.Row {
|
||||
|
||||
row := make([]string, 3)
|
||||
row := make(table.Row, 3)
|
||||
|
||||
row[0] = controlSummary.GetName()
|
||||
|
||||
failedResources := controlSummary.NumberOfResources().Failed()
|
||||
if failedResources > 0 {
|
||||
row[1] = string(gchalk.WithYellow().Bold(fmt.Sprintf("%d", failedResources)))
|
||||
row[1] = gchalk.WithYellow().Bold(fmt.Sprintf("%d", failedResources))
|
||||
} else {
|
||||
row[1] = fmt.Sprintf("%d", failedResources)
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
type FrameworkPrinter struct {
|
||||
@@ -38,19 +38,21 @@ func (fp *FrameworkPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *
|
||||
// When scanning controls the framework list will be empty
|
||||
cautils.SimpleDisplay(writer, utils.FrameworksScoresToString(summaryDetails.ListFrameworks())+"\n")
|
||||
|
||||
controlCountersTable := tablewriter.NewWriter(writer)
|
||||
controlCountersTable := table.NewWriter()
|
||||
controlCountersTable.SetOutputMirror(writer)
|
||||
|
||||
controlCountersTable.SetColumnAlignment([]int{tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_LEFT})
|
||||
controlCountersTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
controlCountersTable.AppendBulk(ControlCountersForSummary(summaryDetails.NumberOfControls()))
|
||||
controlCountersTable.SetColumnConfigs([]table.ColumnConfig{{Number: 1, Align: text.AlignRight}, {Number: 2, Align: text.AlignLeft}})
|
||||
controlCountersTable.Style().Box = table.StyleBoxRounded
|
||||
controlCountersTable.AppendRows(ControlCountersForSummary(summaryDetails.NumberOfControls()))
|
||||
controlCountersTable.Render()
|
||||
|
||||
cautils.SimpleDisplay(writer, "\nFailed resources by severity:\n\n")
|
||||
|
||||
severityCountersTable := tablewriter.NewWriter(writer)
|
||||
severityCountersTable.SetColumnAlignment([]int{tablewriter.ALIGN_RIGHT, tablewriter.ALIGN_LEFT})
|
||||
severityCountersTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
severityCountersTable.AppendBulk(renderSeverityCountersSummary(summaryDetails.GetResourcesSeverityCounters()))
|
||||
severityCountersTable := table.NewWriter()
|
||||
severityCountersTable.SetOutputMirror(writer)
|
||||
severityCountersTable.SetColumnConfigs([]table.ColumnConfig{{Number: 1, Align: text.AlignRight}, {Number: 2, Align: text.AlignLeft}})
|
||||
severityCountersTable.Style().Box = table.StyleBoxRounded
|
||||
severityCountersTable.AppendRows(renderSeverityCountersSummary(summaryDetails.GetResourcesSeverityCounters()))
|
||||
severityCountersTable.Render()
|
||||
|
||||
cautils.SimpleDisplay(writer, "\n")
|
||||
@@ -59,14 +61,15 @@ func (fp *FrameworkPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *
|
||||
cautils.SimpleDisplay(writer, "Run with '--verbose'/'-v' to see control failures for each resource.\n\n")
|
||||
}
|
||||
|
||||
summaryTable := tablewriter.NewWriter(writer)
|
||||
summaryTable := table.NewWriter()
|
||||
summaryTable.SetOutputMirror(writer)
|
||||
|
||||
summaryTable.SetAutoWrapText(false)
|
||||
summaryTable.SetHeaderLine(true)
|
||||
summaryTable.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
summaryTable.SetAutoFormatHeaders(false)
|
||||
summaryTable.SetColumnAlignment(GetColumnsAlignments())
|
||||
summaryTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
summaryTable.Style().Options.SeparateHeader = true
|
||||
summaryTable.Style().Format.HeaderAlign = text.AlignLeft
|
||||
summaryTable.Style().Format.Header = text.FormatDefault
|
||||
summaryTable.Style().Format.Footer = text.FormatDefault
|
||||
summaryTable.SetColumnConfigs(GetColumnsAlignments())
|
||||
summaryTable.Style().Box = table.StyleBoxRounded
|
||||
|
||||
printAll := fp.getVerboseMode()
|
||||
if summaryDetails.NumberOfResources().Failed() == 0 {
|
||||
@@ -74,7 +77,7 @@ func (fp *FrameworkPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *
|
||||
printAll = true
|
||||
}
|
||||
|
||||
dataRows := [][]string{}
|
||||
var dataRows []table.Row
|
||||
|
||||
infoToPrintInfo := utils.MapInfoToPrintInfo(summaryDetails.Controls)
|
||||
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
|
||||
@@ -88,28 +91,23 @@ func (fp *FrameworkPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *
|
||||
|
||||
short := utils.CheckShortTerminalWidth(dataRows, GetControlTableHeaders(false))
|
||||
if short {
|
||||
summaryTable.SetRowLine(true)
|
||||
summaryTable.Style().Options.SeparateRows = true
|
||||
dataRows = shortFormatRow(dataRows)
|
||||
} else {
|
||||
summaryTable.SetColumnAlignment(GetColumnsAlignments())
|
||||
summaryTable.SetColumnConfigs(GetColumnsAlignments())
|
||||
summaryTable.Style().Format.FooterAlign = text.AlignCenter
|
||||
}
|
||||
summaryTable.SetHeader(GetControlTableHeaders(short))
|
||||
summaryTable.SetFooter(GenerateFooter(summaryDetails, short))
|
||||
summaryTable.AppendHeader(GetControlTableHeaders(short))
|
||||
summaryTable.AppendFooter(GenerateFooter(summaryDetails, short))
|
||||
|
||||
var headerColors []tablewriter.Colors
|
||||
for range dataRows[0] {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor})
|
||||
}
|
||||
summaryTable.SetHeaderColor(headerColors...)
|
||||
|
||||
summaryTable.AppendBulk(dataRows)
|
||||
summaryTable.AppendRows(dataRows)
|
||||
summaryTable.Render()
|
||||
|
||||
utils.PrintInfo(writer, infoToPrintInfo)
|
||||
}
|
||||
|
||||
func shortFormatRow(dataRows [][]string) [][]string {
|
||||
rows := [][]string{}
|
||||
func shortFormatRow(dataRows []table.Row) []table.Row {
|
||||
rows := make([]table.Row, 0, len(dataRows))
|
||||
for _, dataRow := range dataRows {
|
||||
// Define the row content using a formatted string
|
||||
rowContent := fmt.Sprintf("Severity%s: %+v\nControl Name%s: %+v\nFailed Resources%s: %+v\nAll Resources%s: %+v\n%% Compliance-Score%s: %+v",
|
||||
@@ -125,22 +123,22 @@ func shortFormatRow(dataRows [][]string) [][]string {
|
||||
dataRow[summaryColumnComplianceScore])
|
||||
|
||||
// Append the formatted row content to the rows slice
|
||||
rows = append(rows, []string{rowContent})
|
||||
rows = append(rows, table.Row{rowContent})
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func (fp *FrameworkPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (fp *FrameworkPrinter) PrintCategoriesTables(_ io.Writer, _ *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
}
|
||||
|
||||
func renderSeverityCountersSummary(counters reportsummary.ISeverityCounters) [][]string {
|
||||
func renderSeverityCountersSummary(counters reportsummary.ISeverityCounters) []table.Row {
|
||||
|
||||
rows := [][]string{}
|
||||
rows = append(rows, []string{"Critical", utils.GetColorForVulnerabilitySeverity("Critical")(strconv.Itoa(counters.NumberOfCriticalSeverity()))})
|
||||
rows = append(rows, []string{"High", utils.GetColorForVulnerabilitySeverity("High")(strconv.Itoa(counters.NumberOfHighSeverity()))})
|
||||
rows = append(rows, []string{"Medium", utils.GetColorForVulnerabilitySeverity("Medium")(strconv.Itoa(counters.NumberOfMediumSeverity()))})
|
||||
rows = append(rows, []string{"Low", utils.GetColorForVulnerabilitySeverity("Low")(strconv.Itoa(counters.NumberOfLowSeverity()))})
|
||||
rows := make([]table.Row, 0, 4)
|
||||
rows = append(rows, table.Row{"Critical", utils.GetColorForVulnerabilitySeverity("Critical")(strconv.Itoa(counters.NumberOfCriticalSeverity()))})
|
||||
rows = append(rows, table.Row{"High", utils.GetColorForVulnerabilitySeverity("High")(strconv.Itoa(counters.NumberOfHighSeverity()))})
|
||||
rows = append(rows, table.Row{"Medium", utils.GetColorForVulnerabilitySeverity("Medium")(strconv.Itoa(counters.NumberOfMediumSeverity()))})
|
||||
rows = append(rows, table.Row{"Low", utils.GetColorForVulnerabilitySeverity("Low")(strconv.Itoa(counters.NumberOfLowSeverity()))})
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -32,7 +33,7 @@ func (m *MockISeverityCounters) NumberOfLowSeverity() int {
|
||||
return m.LowCount
|
||||
}
|
||||
|
||||
func (m *MockISeverityCounters) Increase(severity string, amount int) {
|
||||
func (m *MockISeverityCounters) Increase(_ string, _ int) {
|
||||
}
|
||||
|
||||
func TestNewFrameworkPrinter(t *testing.T) {
|
||||
@@ -60,28 +61,28 @@ func TestGetVerboseMode(t *testing.T) {
|
||||
func TestShortRowFormat(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
rows [][]string
|
||||
expectedRows [][]string
|
||||
rows []table.Row
|
||||
expectedRows []table.Row
|
||||
}{
|
||||
{
|
||||
name: "Test Empty rows",
|
||||
rows: [][]string{},
|
||||
expectedRows: [][]string{},
|
||||
rows: []table.Row{},
|
||||
expectedRows: []table.Row{},
|
||||
},
|
||||
{
|
||||
name: "Test Non empty row",
|
||||
rows: [][]string{
|
||||
rows: []table.Row{
|
||||
{"Medium", "Control 1", "2", "20", "0.8"},
|
||||
},
|
||||
expectedRows: [][]string{[]string{"Severity : Medium\nControl Name : Control 1\nFailed Resources : 2\nAll Resources : 20\n% Compliance-Score : 0.8"}},
|
||||
expectedRows: []table.Row{{"Severity : Medium\nControl Name : Control 1\nFailed Resources : 2\nAll Resources : 20\n% Compliance-Score : 0.8"}},
|
||||
},
|
||||
{
|
||||
name: "Test Non empty rows",
|
||||
rows: [][]string{
|
||||
rows: []table.Row{
|
||||
{"Medium", "Control 1", "2", "20", "0.8"},
|
||||
{"Low", "Control 2", "0", "30", "1.0"},
|
||||
},
|
||||
expectedRows: [][]string{[]string{"Severity : Medium\nControl Name : Control 1\nFailed Resources : 2\nAll Resources : 20\n% Compliance-Score : 0.8"}, []string{"Severity : Low\nControl Name : Control 2\nFailed Resources : 0\nAll Resources : 30\n% Compliance-Score : 1.0"}},
|
||||
expectedRows: []table.Row{{"Severity : Medium\nControl Name : Control 1\nFailed Resources : 2\nAll Resources : 20\n% Compliance-Score : 0.8"}, {"Severity : Low\nControl Name : Control 2\nFailed Resources : 0\nAll Resources : 30\n% Compliance-Score : 1.0"}},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -96,12 +97,12 @@ func TestRenderSeverityCountersSummary(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
counters MockISeverityCounters
|
||||
expected [][]string
|
||||
expected []table.Row
|
||||
}{
|
||||
{
|
||||
name: "All empty",
|
||||
counters: MockISeverityCounters{},
|
||||
expected: [][]string{[]string{"Critical", "0"}, []string{"High", "0"}, []string{"Medium", "0"}, []string{"Low", "0"}},
|
||||
expected: []table.Row{{"Critical", "0"}, {"High", "0"}, {"Medium", "0"}, {"Low", "0"}},
|
||||
},
|
||||
{
|
||||
name: "All different",
|
||||
@@ -111,7 +112,7 @@ func TestRenderSeverityCountersSummary(t *testing.T) {
|
||||
MediumCount: 27,
|
||||
LowCount: 37,
|
||||
},
|
||||
expected: [][]string{[]string{"Critical", "7"}, []string{"High", "17"}, []string{"Medium", "27"}, []string{"Low", "37"}},
|
||||
expected: []table.Row{{"Critical", "7"}, {"High", "17"}, {"Medium", "27"}, {"Low", "37"}},
|
||||
},
|
||||
{
|
||||
name: "All equal",
|
||||
@@ -121,7 +122,7 @@ func TestRenderSeverityCountersSummary(t *testing.T) {
|
||||
MediumCount: 7,
|
||||
LowCount: 7,
|
||||
},
|
||||
expected: [][]string{[]string{"Critical", "7"}, []string{"High", "7"}, []string{"Medium", "7"}, []string{"Low", "7"}},
|
||||
expected: []table.Row{{"Critical", "7"}, {"High", "7"}, {"Medium", "7"}, {"Low", "7"}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling"
|
||||
@@ -24,15 +25,15 @@ func NewRepoPrinter(inputPatterns []string) *RepoPrinter {
|
||||
|
||||
var _ TablePrinter = &RepoPrinter{}
|
||||
|
||||
func (rp *RepoPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (rp *RepoPrinter) PrintSummaryTable(_ io.Writer, _ *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
}
|
||||
|
||||
func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapRepoControlsToCategories)
|
||||
|
||||
tableRended := false
|
||||
tableRendered := false
|
||||
for _, id := range repoCategoriesDisplayOrder {
|
||||
categoryControl, ok := categoriesToCategoryControls[id]
|
||||
if !ok {
|
||||
@@ -43,10 +44,10 @@ func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *r
|
||||
continue
|
||||
}
|
||||
|
||||
tableRended = tableRended || rp.renderSingleCategoryTable(categoryControl.CategoryName, mapCategoryToType[id], writer, categoryControl.controlSummaries, utils.MapInfoToPrintInfoFromIface(categoryControl.controlSummaries))
|
||||
tableRendered = tableRendered || rp.renderSingleCategoryTable(categoryControl.CategoryName, mapCategoryToType[id], writer, categoryControl.controlSummaries, utils.MapInfoToPrintInfoFromIface(categoryControl.controlSummaries))
|
||||
}
|
||||
|
||||
if !tableRended {
|
||||
if !tableRendered {
|
||||
fmt.Fprintln(writer, gchalk.WithGreen().Bold("All controls passed. No issues found"))
|
||||
}
|
||||
|
||||
@@ -55,21 +56,21 @@ func (rp *RepoPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *r
|
||||
func (rp *RepoPrinter) renderSingleCategoryTable(categoryName string, categoryType CategoryType, writer io.Writer, controlSummaries []reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars) bool {
|
||||
sortControlSummaries(controlSummaries)
|
||||
|
||||
headers, columnAligments := initCategoryTableData(categoryType)
|
||||
headers, columnAlignments := initCategoryTableData(categoryType)
|
||||
|
||||
table := getCategoryTableWriter(writer, headers, columnAligments)
|
||||
tableWriter := getCategoryTableWriter(writer, headers, columnAlignments)
|
||||
|
||||
var rows [][]string
|
||||
var rows []table.Row
|
||||
for _, ctrls := range controlSummaries {
|
||||
if ctrls.NumberOfResources().Failed() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var row []string
|
||||
var row table.Row
|
||||
if categoryType == TypeCounting {
|
||||
row = rp.generateCountingCategoryRow(ctrls, rp.inputPatterns)
|
||||
} else {
|
||||
row = generateCategoryStatusRow(ctrls, infoToPrintInfo)
|
||||
row = generateCategoryStatusRow(ctrls)
|
||||
}
|
||||
if len(row) > 0 {
|
||||
rows = append(rows, row)
|
||||
@@ -80,18 +81,18 @@ func (rp *RepoPrinter) renderSingleCategoryTable(categoryName string, categoryTy
|
||||
return false
|
||||
}
|
||||
|
||||
renderSingleCategory(writer, categoryName, table, rows, infoToPrintInfo)
|
||||
renderSingleCategory(writer, categoryName, tableWriter, rows, infoToPrintInfo)
|
||||
return true
|
||||
}
|
||||
|
||||
func (rp *RepoPrinter) generateCountingCategoryRow(controlSummary reportsummary.IControlSummary, inputPatterns []string) []string {
|
||||
rows := make([]string, 3)
|
||||
func (rp *RepoPrinter) generateCountingCategoryRow(controlSummary reportsummary.IControlSummary, inputPatterns []string) table.Row {
|
||||
rows := make(table.Row, 3)
|
||||
|
||||
rows[0] = controlSummary.GetName()
|
||||
|
||||
failedResources := controlSummary.NumberOfResources().Failed()
|
||||
if failedResources > 0 {
|
||||
rows[1] = string(gchalk.WithYellow().Bold(fmt.Sprintf("%d", failedResources)))
|
||||
rows[1] = gchalk.WithYellow().Bold(fmt.Sprintf("%d", failedResources))
|
||||
} else {
|
||||
rows[1] = fmt.Sprintf("%d", failedResources)
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -21,12 +22,12 @@ const (
|
||||
_summaryRowLen = iota
|
||||
)
|
||||
|
||||
func ControlCountersForSummary(counters reportsummary.ICounters) [][]string {
|
||||
rows := [][]string{}
|
||||
rows = append(rows, []string{"Controls", strconv.Itoa(counters.All())})
|
||||
rows = append(rows, []string{"Passed", strconv.Itoa(counters.Passed())})
|
||||
rows = append(rows, []string{"Failed", strconv.Itoa(counters.Failed())})
|
||||
rows = append(rows, []string{"Action Required", strconv.Itoa(counters.Skipped())})
|
||||
func ControlCountersForSummary(counters reportsummary.ICounters) []table.Row {
|
||||
rows := make([]table.Row, 0, 4)
|
||||
rows = append(rows, table.Row{"Controls", strconv.Itoa(counters.All())})
|
||||
rows = append(rows, table.Row{"Passed", strconv.Itoa(counters.Passed())})
|
||||
rows = append(rows, table.Row{"Failed", strconv.Itoa(counters.Failed())})
|
||||
rows = append(rows, table.Row{"Action Required", strconv.Itoa(counters.Skipped())})
|
||||
|
||||
return rows
|
||||
}
|
||||
@@ -35,13 +36,13 @@ func GetSeverityColumn(controlSummary reportsummary.IControlSummary) string {
|
||||
return utils.GetColor(apis.ControlSeverityToInt(controlSummary.GetScoreFactor()))(apis.ControlSeverityToString(controlSummary.GetScoreFactor()))
|
||||
}
|
||||
|
||||
func GetControlTableHeaders(short bool) []string {
|
||||
var headers []string
|
||||
func GetControlTableHeaders(short bool) table.Row {
|
||||
var headers table.Row
|
||||
if short {
|
||||
headers = make([]string, 1)
|
||||
headers = make(table.Row, 1)
|
||||
headers[0] = "Controls"
|
||||
} else {
|
||||
headers = make([]string, _summaryRowLen)
|
||||
headers = make(table.Row, _summaryRowLen)
|
||||
headers[summaryColumnName] = "Control name"
|
||||
headers[summaryColumnCounterFailed] = "Failed resources"
|
||||
headers[summaryColumnCounterAll] = "All Resources"
|
||||
@@ -51,22 +52,22 @@ func GetControlTableHeaders(short bool) []string {
|
||||
return headers
|
||||
}
|
||||
|
||||
func GetColumnsAlignments() []int {
|
||||
alignments := make([]int, _summaryRowLen)
|
||||
alignments[summaryColumnSeverity] = tablewriter.ALIGN_CENTER
|
||||
alignments[summaryColumnName] = tablewriter.ALIGN_LEFT
|
||||
alignments[summaryColumnCounterFailed] = tablewriter.ALIGN_CENTER
|
||||
alignments[summaryColumnCounterAll] = tablewriter.ALIGN_CENTER
|
||||
alignments[summaryColumnComplianceScore] = tablewriter.ALIGN_CENTER
|
||||
return alignments
|
||||
func GetColumnsAlignments() []table.ColumnConfig {
|
||||
return []table.ColumnConfig{
|
||||
{Number: summaryColumnSeverity + 1, Align: text.AlignCenter},
|
||||
{Number: summaryColumnName + 1, Align: text.AlignLeft},
|
||||
{Number: summaryColumnCounterFailed + 1, Align: text.AlignCenter},
|
||||
{Number: summaryColumnCounterAll + 1, Align: text.AlignCenter},
|
||||
{Number: summaryColumnComplianceScore + 1, Align: text.AlignCenter},
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars, verbose bool) []string {
|
||||
row := make([]string, _summaryRowLen)
|
||||
func GenerateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars, verbose bool) table.Row {
|
||||
row := make(table.Row, _summaryRowLen)
|
||||
|
||||
// ignore passed results
|
||||
if !verbose && (controlSummary.GetStatus().IsPassed()) {
|
||||
return []string{}
|
||||
return table.Row{}
|
||||
}
|
||||
|
||||
row[summaryColumnSeverity] = GetSeverityColumn(controlSummary)
|
||||
@@ -98,14 +99,14 @@ func GetInfoColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo
|
||||
return ""
|
||||
}
|
||||
|
||||
func GenerateFooter(summaryDetails *reportsummary.SummaryDetails, short bool) []string {
|
||||
var row []string
|
||||
func GenerateFooter(summaryDetails *reportsummary.SummaryDetails, short bool) table.Row {
|
||||
var row table.Row
|
||||
if short {
|
||||
row = make([]string, 1)
|
||||
row = make(table.Row, 1)
|
||||
row[0] = fmt.Sprintf("Resource Summary"+strings.Repeat(" ", 0)+"\n\nFailed Resources"+strings.Repeat(" ", 1)+": %d\nAll Resources"+strings.Repeat(" ", 4)+": %d\n%% Compliance-Score"+strings.Repeat(" ", 4)+": %.2f%%", summaryDetails.NumberOfResources().Failed(), summaryDetails.NumberOfResources().All(), summaryDetails.ComplianceScore)
|
||||
} else {
|
||||
// Severity | Control name | failed resources | all resources | % success
|
||||
row = make([]string, _summaryRowLen)
|
||||
row = make(table.Row, _summaryRowLen)
|
||||
row[summaryColumnName] = "Resource Summary"
|
||||
row[summaryColumnCounterFailed] = fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed())
|
||||
row[summaryColumnCounterAll] = fmt.Sprintf("%d", summaryDetails.NumberOfResources().All())
|
||||
|
||||
@@ -542,14 +542,14 @@ func TestGetDocsForControl(t *testing.T) {
|
||||
controlSummary: &reportsummary.ControlSummary{
|
||||
ControlID: "ctrlID1",
|
||||
},
|
||||
expectedDocsLink: "https://hub.armosec.io/docs/ctrlid1",
|
||||
expectedDocsLink: "https://kubescape.io/docs/controls/ctrlid1",
|
||||
},
|
||||
{
|
||||
name: "control with lowercase ID",
|
||||
controlSummary: &reportsummary.ControlSummary{
|
||||
ControlID: "ctrlid1",
|
||||
},
|
||||
expectedDocsLink: "https://hub.armosec.io/docs/ctrlid1",
|
||||
expectedDocsLink: "https://kubescape.io/docs/controls/ctrlid1",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package configurationprinter
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
)
|
||||
@@ -16,11 +17,11 @@ func NewWorkloadPrinter() *WorkloadPrinter {
|
||||
return &WorkloadPrinter{}
|
||||
}
|
||||
|
||||
func (wp *WorkloadPrinter) PrintSummaryTable(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (wp *WorkloadPrinter) PrintSummaryTable(_ io.Writer, _ *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
}
|
||||
|
||||
func (wp *WorkloadPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
func (wp *WorkloadPrinter) PrintCategoriesTables(writer io.Writer, summaryDetails *reportsummary.SummaryDetails, _ [][]string) {
|
||||
|
||||
categoriesToCategoryControls := mapCategoryToSummary(summaryDetails.ListControls(), mapWorkloadControlsToCategories)
|
||||
|
||||
@@ -30,21 +31,20 @@ func (wp *WorkloadPrinter) PrintCategoriesTables(writer io.Writer, summaryDetail
|
||||
continue
|
||||
}
|
||||
|
||||
wp.renderSingleCategoryTable(categoryControl.CategoryName, mapCategoryToType[id], writer, categoryControl.controlSummaries, utils.MapInfoToPrintInfoFromIface(categoryControl.controlSummaries))
|
||||
wp.renderSingleCategoryTable(categoryControl.CategoryName, writer, categoryControl.controlSummaries, utils.MapInfoToPrintInfoFromIface(categoryControl.controlSummaries))
|
||||
}
|
||||
}
|
||||
|
||||
func (wp *WorkloadPrinter) renderSingleCategoryTable(categoryName string, categoryType CategoryType, writer io.Writer, controlSummaries []reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars) {
|
||||
func (wp *WorkloadPrinter) renderSingleCategoryTable(categoryName string, writer io.Writer, controlSummaries []reportsummary.IControlSummary, infoToPrintInfo []utils.InfoStars) {
|
||||
sortControlSummaries(controlSummaries)
|
||||
|
||||
headers, columnAligments := wp.initCategoryTableData()
|
||||
headers, columnAlignments := wp.initCategoryTableData()
|
||||
|
||||
table := getCategoryTableWriter(writer, headers, columnAligments)
|
||||
tableWriter := getCategoryTableWriter(writer, headers, columnAlignments)
|
||||
|
||||
var rows [][]string
|
||||
var rows []table.Row
|
||||
for _, ctrls := range controlSummaries {
|
||||
var row []string
|
||||
row = generateCategoryStatusRow(ctrls, infoToPrintInfo)
|
||||
row := generateCategoryStatusRow(ctrls)
|
||||
if len(row) > 0 {
|
||||
rows = append(rows, row)
|
||||
}
|
||||
@@ -54,9 +54,9 @@ func (wp *WorkloadPrinter) renderSingleCategoryTable(categoryName string, catego
|
||||
return
|
||||
}
|
||||
|
||||
renderSingleCategory(writer, categoryName, table, rows, infoToPrintInfo)
|
||||
renderSingleCategory(writer, categoryName, tableWriter, rows, infoToPrintInfo)
|
||||
}
|
||||
|
||||
func (wp *WorkloadPrinter) initCategoryTableData() ([]string, []int) {
|
||||
func (wp *WorkloadPrinter) initCategoryTableData() (table.Row, []table.ColumnConfig) {
|
||||
return getCategoryStatusTypeHeaders(), getStatusTypeAlignments()
|
||||
}
|
||||
|
||||
@@ -3,17 +3,19 @@ package configurationprinter
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWorkloadScan_InitCategoryTableData(t *testing.T) {
|
||||
|
||||
expectedHeader := []string{"", "Control name", "Docs"}
|
||||
expectedAlign := []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER}
|
||||
expectedAlign := []table.ColumnConfig{{Number: 1, Align: text.AlignCenter}, {Number: 2, Align: text.AlignLeft}, {Number: 3, Align: text.AlignCenter}}
|
||||
|
||||
workloadPrinter := NewWorkloadPrinter()
|
||||
|
||||
headers, columnAligments := workloadPrinter.initCategoryTableData()
|
||||
headers, columnAlignments := workloadPrinter.initCategoryTableData()
|
||||
|
||||
for i := range headers {
|
||||
if headers[i] != expectedHeader[i] {
|
||||
@@ -21,10 +23,8 @@ func TestWorkloadScan_InitCategoryTableData(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
for i := range columnAligments {
|
||||
if columnAligments[i] != expectedAlign[i] {
|
||||
t.Errorf("Expected column alignment %d, got %d", expectedAlign[i], columnAligments[i])
|
||||
}
|
||||
for i := range columnAlignments {
|
||||
assert.Equal(t, expectedAlign[i], columnAlignments[i])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestPrintImageScanningTable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "┌──────────┬───────────────┬───────────┬─────────┬──────────┐\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ │\n│ Medium │ CVE-2020-0003 │ package3 │ 1.0.0 │ │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n└──────────┴───────────────┴───────────┴─────────┴──────────┘\n",
|
||||
want: "╭──────────┬───────────────┬───────────┬─────────┬──────────╮\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ │\n│ Medium │ CVE-2020-0003 │ package3 │ 1.0.0 │ │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n╰──────────┴───────────────┴───────────┴─────────┴──────────╯\n",
|
||||
},
|
||||
{
|
||||
name: "check fixed CVEs show versions",
|
||||
@@ -65,7 +65,7 @@ func TestPrintImageScanningTable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "┌──────────┬───────────────┬───────────┬─────────┬──────────┐\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ v1,v2 │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n└──────────┴───────────────┴───────────┴─────────┴──────────┘\n",
|
||||
want: "╭──────────┬───────────────┬───────────┬─────────┬──────────╮\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ v1,v2 │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n╰──────────┴───────────────┴───────────┴─────────┴──────────╯\n",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -6,33 +6,28 @@ import (
|
||||
"strings"
|
||||
|
||||
v5 "github.com/anchore/grype/grype/db/v5"
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
func renderTable(writer io.Writer, headers []string, columnAlignments []int, rows [][]string) {
|
||||
table := tablewriter.NewWriter(writer)
|
||||
table.SetHeader(headers)
|
||||
table.SetHeaderLine(true)
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAutoFormatHeaders(false)
|
||||
table.SetColumnAlignment(columnAlignments)
|
||||
table.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
func renderTable(writer io.Writer, headers table.Row, columnAlignments []table.ColumnConfig, rows []table.Row) {
|
||||
tableWriter := table.NewWriter()
|
||||
tableWriter.SetOutputMirror(writer)
|
||||
tableWriter.AppendHeader(headers)
|
||||
tableWriter.Style().Options.SeparateHeader = true
|
||||
tableWriter.Style().Format.HeaderAlign = text.AlignLeft
|
||||
tableWriter.Style().Format.Header = text.FormatDefault
|
||||
tableWriter.SetColumnConfigs(columnAlignments)
|
||||
tableWriter.Style().Box = table.StyleBoxRounded
|
||||
|
||||
var headerColors []tablewriter.Colors
|
||||
for range rows[0] {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor})
|
||||
}
|
||||
table.SetHeaderColor(headerColors...)
|
||||
tableWriter.AppendRows(rows)
|
||||
|
||||
table.AppendBulk(rows)
|
||||
|
||||
table.Render()
|
||||
tableWriter.Render()
|
||||
}
|
||||
|
||||
func generateRows(summary ImageScanSummary) [][]string {
|
||||
rows := make([][]string, 0, len(summary.CVEs))
|
||||
func generateRows(summary ImageScanSummary) []table.Row {
|
||||
rows := make([]table.Row, 0, len(summary.CVEs))
|
||||
|
||||
// sort CVEs by severity
|
||||
sort.Slice(summary.CVEs, func(i, j int) bool {
|
||||
@@ -46,8 +41,8 @@ func generateRows(summary ImageScanSummary) [][]string {
|
||||
return rows
|
||||
}
|
||||
|
||||
func generateRow(cve CVE) []string {
|
||||
row := make([]string, 5)
|
||||
func generateRow(cve CVE) table.Row {
|
||||
row := make(table.Row, 5)
|
||||
row[imageColumnSeverity] = utils.GetColorForVulnerabilitySeverity(cve.Severity)(cve.Severity)
|
||||
row[imageColumnName] = cve.ID
|
||||
row[imageColumnComponent] = cve.Package
|
||||
@@ -59,13 +54,15 @@ func generateRow(cve CVE) []string {
|
||||
// if the CVE is not fixed, show the state
|
||||
} else if cve.FixedState == string(v5.WontFixState) {
|
||||
row[imageColumnFixedIn] = cve.FixedState
|
||||
} else {
|
||||
row[imageColumnFixedIn] = ""
|
||||
}
|
||||
|
||||
return row
|
||||
}
|
||||
|
||||
func getImageScanningHeaders() []string {
|
||||
headers := make([]string, 5)
|
||||
func getImageScanningHeaders() table.Row {
|
||||
headers := make(table.Row, 5)
|
||||
headers[imageColumnSeverity] = "Severity"
|
||||
headers[imageColumnName] = "Vulnerability"
|
||||
headers[imageColumnComponent] = "Component"
|
||||
@@ -74,6 +71,12 @@ func getImageScanningHeaders() []string {
|
||||
return headers
|
||||
}
|
||||
|
||||
func getImageScanningColumnsAlignments() []int {
|
||||
return []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT}
|
||||
func getImageScanningColumnsAlignments() []table.ColumnConfig {
|
||||
return []table.ColumnConfig{
|
||||
{Number: 1, Align: text.AlignCenter},
|
||||
{Number: 2, Align: text.AlignLeft},
|
||||
{Number: 3, Align: text.AlignLeft},
|
||||
{Number: 4, Align: text.AlignLeft},
|
||||
{Number: 5, Align: text.AlignLeft},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
|
||||
v5 "github.com/anchore/grype/grype/db/v5"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -46,7 +45,7 @@ func TestRenderTable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "┌──────────┬───────────────┬───────────┬─────────┬──────────┐\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ │\n│ Medium │ CVE-2020-0003 │ package3 │ 1.0.0 │ │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n└──────────┴───────────────┴───────────┴─────────┴──────────┘\n",
|
||||
want: "╭──────────┬───────────────┬───────────┬─────────┬──────────╮\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ │\n│ Medium │ CVE-2020-0003 │ package3 │ 1.0.0 │ │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n╰──────────┴───────────────┴───────────┴─────────┴──────────╯\n",
|
||||
},
|
||||
{
|
||||
name: "check fixed CVEs show versions",
|
||||
@@ -69,7 +68,7 @@ func TestRenderTable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
want: "┌──────────┬───────────────┬───────────┬─────────┬──────────┐\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ v1,v2 │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n└──────────┴───────────────┴───────────┴─────────┴──────────┘\n",
|
||||
want: "╭──────────┬───────────────┬───────────┬─────────┬──────────╮\n│ Severity │ Vulnerability │ Component │ Version │ Fixed in │\n├──────────┼───────────────┼───────────┼─────────┼──────────┤\n│ High │ CVE-2020-0002 │ package2 │ 1.0.0 │ v1,v2 │\n│ Low │ CVE-2020-0001 │ package1 │ 1.0.0 │ │\n╰──────────┴───────────────┴───────────┴─────────┴──────────╯\n",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -247,15 +246,3 @@ func TestGetImageScanningHeaders(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetImageScanningColumnsAlignments(t *testing.T) {
|
||||
alignments := getImageScanningColumnsAlignments()
|
||||
|
||||
expectedAlignments := []int{tablewriter.ALIGN_CENTER, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT}
|
||||
|
||||
for i := range alignments {
|
||||
if alignments[i] != expectedAlignments[i] {
|
||||
t.Errorf("expected %d, got %d", expectedAlignments[i], alignments[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/enescakir/emoji"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
@@ -138,19 +139,19 @@ func GetStatusIcon(status apis.ScanningStatus) string {
|
||||
}
|
||||
}
|
||||
|
||||
func CheckShortTerminalWidth(rows [][]string, headers []string) bool {
|
||||
func CheckShortTerminalWidth(rows []table.Row, headers table.Row) bool {
|
||||
maxWidth := 0
|
||||
for _, row := range rows {
|
||||
rowWidth := 0
|
||||
for idx, cell := range row {
|
||||
cellLen := len(cell)
|
||||
cellLen := len(cell.(string))
|
||||
if cellLen > 50 { // Take only 50 characters of each sentence for counting size
|
||||
cellLen = 50
|
||||
}
|
||||
if cellLen > len(headers[idx]) {
|
||||
if cellLen > len(headers[idx].(string)) {
|
||||
rowWidth += cellLen
|
||||
} else {
|
||||
rowWidth += len(headers[idx])
|
||||
rowWidth += len(headers[idx].(string))
|
||||
}
|
||||
rowWidth += 2
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/k8s-interface/workloadinterface"
|
||||
@@ -59,9 +58,6 @@ func (pp *PrometheusPrinter) generatePrometheusFormat(
|
||||
return m
|
||||
}
|
||||
|
||||
func (pp *PrometheusPrinter) PrintImageScan(context.Context, *models.PresenterConfig) {
|
||||
}
|
||||
|
||||
func (pp *PrometheusPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) {
|
||||
if opaSessionObj == nil {
|
||||
logger.L().Ctx(ctx).Error("failed to print results, missing data")
|
||||
|
||||
@@ -2,16 +2,18 @@ package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/kubescape/k8s-interface/workloadinterface"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -43,61 +45,46 @@ func (prettyPrinter *PrettyPrinter) resourceTable(opaSessionObj *cautils.OPASess
|
||||
if resource.GetNamespace() != "" {
|
||||
fmt.Fprintf(prettyPrinter.writer, "Namespace: %s\n", resource.GetNamespace())
|
||||
}
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n"+prettyprinter.ControlCountersForResource(result.ListControlsIDs(nil))+"\n\n")
|
||||
fmt.Fprintf(prettyPrinter.writer, "\n%s\n\n", prettyprinter.ControlCountersForResource(result.ListControlsIDs(nil)))
|
||||
|
||||
summaryTable := tablewriter.NewWriter(prettyPrinter.writer)
|
||||
summaryTable := table.NewWriter()
|
||||
summaryTable.SetOutputMirror(prettyPrinter.writer)
|
||||
|
||||
summaryTable.SetAutoWrapText(true)
|
||||
summaryTable.SetAutoMergeCells(true)
|
||||
summaryTable.SetHeaderLine(true)
|
||||
summaryTable.SetRowLine(true)
|
||||
summaryTable.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
summaryTable.SetAutoFormatHeaders(false)
|
||||
summaryTable.SetUnicodeHVC(tablewriter.Regular, tablewriter.Regular, gchalk.Ansi256(238))
|
||||
summaryTable.Style().Options.SeparateHeader = true
|
||||
summaryTable.Style().Options.SeparateRows = true
|
||||
summaryTable.Style().Format.HeaderAlign = text.AlignLeft
|
||||
summaryTable.Style().Format.Header = text.FormatDefault
|
||||
summaryTable.Style().Box = table.StyleBoxRounded
|
||||
|
||||
resourceRows := [][]string{}
|
||||
if raw := generateResourceRows(result.ListControls(), &opaSessionObj.Report.SummaryDetails); len(raw) > 0 {
|
||||
resourceRows = append(resourceRows, raw...)
|
||||
}
|
||||
resourceRows := generateResourceRows(result.ListControls(), &opaSessionObj.Report.SummaryDetails, resource)
|
||||
|
||||
short := utils.CheckShortTerminalWidth(resourceRows, generateResourceHeader(false))
|
||||
if short {
|
||||
summaryTable.SetAutoWrapText(false)
|
||||
summaryTable.SetAutoMergeCells(false)
|
||||
resourceRows = shortFormatResource(resourceRows)
|
||||
}
|
||||
summaryTable.SetHeader(generateResourceHeader(short))
|
||||
summaryTable.AppendHeader(generateResourceHeader(short))
|
||||
|
||||
var headerColors []tablewriter.Colors
|
||||
for range resourceRows[0] {
|
||||
headerColors = append(headerColors, tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiYellowColor})
|
||||
}
|
||||
summaryTable.SetHeaderColor(headerColors...)
|
||||
|
||||
data := Matrix{}
|
||||
data = append(data, resourceRows...)
|
||||
// For control scan framework will be nil
|
||||
|
||||
sort.Sort(data)
|
||||
summaryTable.AppendBulk(data)
|
||||
summaryTable.AppendRows(resourceRows)
|
||||
|
||||
summaryTable.Render()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl, summaryDetails *reportsummary.SummaryDetails) [][]string {
|
||||
rows := [][]string{}
|
||||
func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl, summaryDetails *reportsummary.SummaryDetails, resource workloadinterface.IMetadata) []table.Row {
|
||||
var rows []table.Row
|
||||
|
||||
for i := range controls {
|
||||
row := make([]string, _resourceRowLen)
|
||||
row := make(table.Row, _resourceRowLen)
|
||||
|
||||
if !controls[i].GetStatus(nil).IsFailed() {
|
||||
continue
|
||||
}
|
||||
|
||||
row[resourceColumnURL] = cautils.GetControlLink(controls[i].GetID())
|
||||
row[resourceColumnPath] = strings.Join(AssistedRemediationPathsToString(&controls[i]), "\n")
|
||||
paths := AssistedRemediationPathsToString(&controls[i])
|
||||
addContainerNameToAssistedRemediation(resource, &paths)
|
||||
row[resourceColumnPath] = strings.Join(paths, "\n")
|
||||
row[resourceColumnName] = controls[i].GetName()
|
||||
|
||||
if c := summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, controls[i].GetID()); c != nil {
|
||||
@@ -110,22 +97,32 @@ func generateResourceRows(controls []resourcesresults.ResourceAssociatedControl,
|
||||
return rows
|
||||
}
|
||||
|
||||
func generateResourceHeader(short bool) []string {
|
||||
headers := make([]string, 0)
|
||||
|
||||
if short {
|
||||
headers = append(headers, "Resources")
|
||||
} else {
|
||||
headers = append(headers, []string{"Severity", "Control name", "Docs", "Assisted remediation"}...)
|
||||
func addContainerNameToAssistedRemediation(resource workloadinterface.IMetadata, paths *[]string) {
|
||||
for i := range *paths {
|
||||
re := regexp.MustCompile(`spec\.containers\[(\d+)]`)
|
||||
match := re.FindStringSubmatch((*paths)[i])
|
||||
if len(match) == 2 {
|
||||
index, _ := strconv.Atoi(match[1])
|
||||
wl := workloadinterface.NewWorkloadObj(resource.GetObject())
|
||||
containers, _ := wl.GetContainers()
|
||||
containerName := containers[index].Name
|
||||
(*paths)[i] = (*paths)[i] + " (" + containerName + ")"
|
||||
}
|
||||
}
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
func shortFormatResource(resourceRows [][]string) [][]string {
|
||||
rows := [][]string{}
|
||||
for _, resourceRow := range resourceRows {
|
||||
rows = append(rows, []string{fmt.Sprintf("Severity"+strings.Repeat(" ", 13)+": %+v\nControl Name"+strings.Repeat(" ", 9)+": %+v\nDocs"+strings.Repeat(" ", 17)+": %+v\nAssisted Remediation"+strings.Repeat(" ", 1)+": %+v", resourceRow[resourceColumnSeverity], resourceRow[resourceColumnName], resourceRow[resourceColumnURL], strings.Replace(resourceRow[resourceColumnPath], "\n", "\n"+strings.Repeat(" ", 23), -1))})
|
||||
func generateResourceHeader(short bool) table.Row {
|
||||
if short {
|
||||
return table.Row{"Resources"}
|
||||
} else {
|
||||
return table.Row{"Severity", "Control name", "Docs", "Assisted remediation"}
|
||||
}
|
||||
}
|
||||
|
||||
func shortFormatResource(resourceRows []table.Row) []table.Row {
|
||||
rows := make([]table.Row, len(resourceRows))
|
||||
for i, resourceRow := range resourceRows {
|
||||
rows[i] = table.Row{fmt.Sprintf("Severity"+strings.Repeat(" ", 13)+": %+v\nControl Name"+strings.Repeat(" ", 9)+": %+v\nDocs"+strings.Repeat(" ", 17)+": %+v\nAssisted Remediation"+strings.Repeat(" ", 1)+": %+v", resourceRow[resourceColumnSeverity], resourceRow[resourceColumnName], resourceRow[resourceColumnURL], strings.Replace(resourceRow[resourceColumnPath].(string), "\n", "\n"+strings.Repeat(" ", 23), -1))}
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/kubescape/k8s-interface/workloadinterface"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
@@ -326,15 +328,15 @@ func TestFailedPathsToString(t *testing.T) {
|
||||
|
||||
func TestShortFormatResource(t *testing.T) {
|
||||
// Create a test case with an empty resourceRows slice
|
||||
emptyResourceRows := [][]string{}
|
||||
emptyResourceRows := []table.Row{}
|
||||
|
||||
// Create a test case with a single resource row
|
||||
singleResourceRow := [][]string{
|
||||
singleResourceRow := []table.Row{
|
||||
{"High", "Control1", "https://example.com/doc1", "Path1"},
|
||||
}
|
||||
|
||||
// Create a test case with multiple resource rows
|
||||
multipleResourceRows := [][]string{
|
||||
multipleResourceRows := []table.Row{
|
||||
{"Medium", "Control2", "https://example.com/doc2", "Path2"},
|
||||
{"Low", "Control3", "https://example.com/doc3", "Path3"},
|
||||
}
|
||||
@@ -343,11 +345,11 @@ func TestShortFormatResource(t *testing.T) {
|
||||
assert.Empty(t, actualRows)
|
||||
|
||||
actualRows = shortFormatResource(singleResourceRow)
|
||||
expectedRows := [][]string{{"Severity : High\nControl Name : Control1\nDocs : https://example.com/doc1\nAssisted Remediation : Path1"}}
|
||||
expectedRows := []table.Row{{"Severity : High\nControl Name : Control1\nDocs : https://example.com/doc1\nAssisted Remediation : Path1"}}
|
||||
assert.Equal(t, expectedRows, actualRows)
|
||||
|
||||
actualRows = shortFormatResource(multipleResourceRows)
|
||||
expectedRows = [][]string{{"Severity : Medium\nControl Name : Control2\nDocs : https://example.com/doc2\nAssisted Remediation : Path2"},
|
||||
expectedRows = []table.Row{{"Severity : Medium\nControl Name : Control2\nDocs : https://example.com/doc2\nAssisted Remediation : Path2"},
|
||||
{"Severity : Low\nControl Name : Control3\nDocs : https://example.com/doc3\nAssisted Remediation : Path3"}}
|
||||
assert.Equal(t, expectedRows, actualRows)
|
||||
}
|
||||
@@ -355,33 +357,47 @@ func TestShortFormatResource(t *testing.T) {
|
||||
func TestGenerateResourceHeader(t *testing.T) {
|
||||
// Test case 1: Short headers
|
||||
shortHeaders := generateResourceHeader(true)
|
||||
expectedShortHeaders := []string{"Resources"}
|
||||
expectedShortHeaders := table.Row{"Resources"}
|
||||
assert.Equal(t, expectedShortHeaders, shortHeaders)
|
||||
|
||||
// Test case 2: Full headers
|
||||
fullHeaders := generateResourceHeader(false)
|
||||
expectedFullHeaders := []string{"Severity", "Control name", "Docs", "Assisted remediation"}
|
||||
expectedFullHeaders := table.Row{"Severity", "Control name", "Docs", "Assisted remediation"}
|
||||
assert.Equal(t, expectedFullHeaders, fullHeaders)
|
||||
}
|
||||
|
||||
func TestGenerateResourceRows_Loop(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
summaryDetails reportsummary.SummaryDetails
|
||||
controls []resourcesresults.ResourceAssociatedControl
|
||||
expectedLen int
|
||||
name string
|
||||
summaryDetails reportsummary.SummaryDetails
|
||||
controls []resourcesresults.ResourceAssociatedControl
|
||||
resource workloadinterface.IMetadata
|
||||
expectedLen int
|
||||
expectedContainerName string
|
||||
}{
|
||||
{
|
||||
name: "Empty controls",
|
||||
summaryDetails: reportsummary.SummaryDetails{},
|
||||
controls: []resourcesresults.ResourceAssociatedControl{},
|
||||
expectedLen: 0,
|
||||
resource: workloadinterface.NewWorkloadObj(map[string]interface{}{
|
||||
"kind": "Pod",
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "alpine-container",
|
||||
"image": "alpine:latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
expectedLen: 0,
|
||||
expectedContainerName: "",
|
||||
},
|
||||
{
|
||||
name: "2 Failed Controls",
|
||||
summaryDetails: reportsummary.SummaryDetails{},
|
||||
controls: []resourcesresults.ResourceAssociatedControl{
|
||||
resourcesresults.ResourceAssociatedControl{
|
||||
{
|
||||
ControlID: "control-1",
|
||||
Name: "Control 1",
|
||||
Status: apis.StatusInfo{},
|
||||
@@ -393,16 +409,16 @@ func TestGenerateResourceRows_Loop(t *testing.T) {
|
||||
|
||||
Paths: []armotypes.PosturePaths{
|
||||
{
|
||||
FailedPath: "some-path1",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsNonRoot=true",
|
||||
},
|
||||
{
|
||||
FailedPath: "random-path1",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsGroup=1000",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resourcesresults.ResourceAssociatedControl{
|
||||
{
|
||||
ControlID: "control-2",
|
||||
Name: "Control 2",
|
||||
Status: apis.StatusInfo{},
|
||||
@@ -413,23 +429,35 @@ func TestGenerateResourceRows_Loop(t *testing.T) {
|
||||
SubStatus: "configuration",
|
||||
Paths: []armotypes.PosturePaths{
|
||||
{
|
||||
FailedPath: "some-path2",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsNonRoot=true",
|
||||
},
|
||||
{
|
||||
FailedPath: "random-path2",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsGroup=true",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedLen: 2,
|
||||
resource: workloadinterface.NewWorkloadObj(map[string]interface{}{
|
||||
"kind": "Pod",
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "alpine-container",
|
||||
"image": "alpine:latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
expectedLen: 2,
|
||||
expectedContainerName: "alpine-container",
|
||||
},
|
||||
{
|
||||
name: "One failed control",
|
||||
summaryDetails: reportsummary.SummaryDetails{},
|
||||
controls: []resourcesresults.ResourceAssociatedControl{
|
||||
resourcesresults.ResourceAssociatedControl{
|
||||
{
|
||||
ControlID: "control-1",
|
||||
Name: "Control 1",
|
||||
Status: apis.StatusInfo{},
|
||||
@@ -441,16 +469,16 @@ func TestGenerateResourceRows_Loop(t *testing.T) {
|
||||
|
||||
Paths: []armotypes.PosturePaths{
|
||||
{
|
||||
FailedPath: "some-path1",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsNonRoot=true",
|
||||
},
|
||||
{
|
||||
FailedPath: "random-path1",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsGroup=true",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
resourcesresults.ResourceAssociatedControl{
|
||||
{
|
||||
ControlID: "control-2",
|
||||
Name: "Control 2",
|
||||
Status: apis.StatusInfo{},
|
||||
@@ -461,24 +489,42 @@ func TestGenerateResourceRows_Loop(t *testing.T) {
|
||||
SubStatus: "configuration",
|
||||
Paths: []armotypes.PosturePaths{
|
||||
{
|
||||
FailedPath: "some-path2",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsNonRoot=true",
|
||||
},
|
||||
{
|
||||
FailedPath: "random-path2",
|
||||
FailedPath: "spec.template.spec.containers[0].securityContext.runAsGroup=true",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedLen: 1,
|
||||
resource: workloadinterface.NewWorkloadObj(map[string]interface{}{
|
||||
"kind": "Pod",
|
||||
"spec": map[string]interface{}{
|
||||
"containers": []interface{}{
|
||||
map[string]interface{}{
|
||||
"name": "nginx-container",
|
||||
"image": "nginx:latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
expectedLen: 1,
|
||||
expectedContainerName: "nginx-container",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
rows := generateResourceRows(tt.controls, &tt.summaryDetails)
|
||||
rows := generateResourceRows(tt.controls, &tt.summaryDetails, tt.resource)
|
||||
assert.Equal(t, tt.expectedLen, len(rows))
|
||||
//remediation is the last column of the first row
|
||||
if len(rows) != 0 {
|
||||
remediation := rows[0][3]
|
||||
assert.Contains(t, remediation, tt.expectedContainerName)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter"
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
grypesarif "github.com/anchore/grype/grype/presenter/sarif"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
@@ -115,12 +116,14 @@ func (sp *SARIFPrinter) addResult(scanRun *sarif.Run, ctl reportsummary.IControl
|
||||
})
|
||||
}
|
||||
|
||||
func (sp *SARIFPrinter) printImageScan(ctx context.Context, scanResults *models.PresenterConfig) error {
|
||||
if scanResults == nil {
|
||||
return fmt.Errorf("no no image vulnerability data provided")
|
||||
func (sp *SARIFPrinter) printImageScan(ctx context.Context, scanResults cautils.ImageScanData) error {
|
||||
model, err := models.NewDocument(clio.Identification{}, scanResults.Packages, scanResults.Context,
|
||||
*scanResults.RemainingMatches, scanResults.IgnoredMatches, scanResults.VulnerabilityProvider, nil, nil, models.DefaultSortStrategy, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create document: %w", err)
|
||||
}
|
||||
|
||||
pres := presenter.GetPresenter(printer.SARIFFormat, "", false, *scanResults)
|
||||
pres := grypesarif.NewPresenter(models.PresenterConfig{Document: model, SBOM: scanResults.SBOM})
|
||||
if err := pres.Present(sp.writer); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -164,7 +167,7 @@ func (sp *SARIFPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.
|
||||
}
|
||||
|
||||
// image scan
|
||||
if err := sp.printImageScan(ctx, imageScanData[0].PresenterConfig); err != nil {
|
||||
if err := sp.printImageScan(ctx, imageScanData[0]); err != nil {
|
||||
logger.L().Ctx(ctx).Error("failed to write results in sarif format", helpers.Error(err))
|
||||
return
|
||||
}
|
||||
@@ -196,7 +199,7 @@ func (sp *SARIFPrinter) printConfigurationScan(ctx context.Context, opaSessionOb
|
||||
filepath := resourceSource.RelativePath
|
||||
|
||||
// Github Code Scanning considers results not associated to a file path meaningless and invalid when uploading
|
||||
if filepath == "" || basePath == "" {
|
||||
if filepath == "" && basePath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package printer
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
|
||||
)
|
||||
@@ -18,9 +17,6 @@ func (silentPrinter *SilentPrinter) PrintNextSteps() {
|
||||
|
||||
}
|
||||
|
||||
func (silentPrinter *SilentPrinter) PrintImageScan(context.Context, *models.PresenterConfig) {
|
||||
}
|
||||
|
||||
func (silentPrinter *SilentPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) {
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package printer
|
||||
|
||||
import (
|
||||
v5 "github.com/anchore/grype/grype/db/v5"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/kubescape/k8s-interface/workloadinterface"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
|
||||
@@ -103,39 +103,39 @@ func setSeverityToSummaryMap(cves []imageprinter.CVE, mapSeverityToSummary map[s
|
||||
}
|
||||
}
|
||||
|
||||
func setPkgNameToScoreMap(matches []models.Match, pkgScores map[string]*imageprinter.PackageScore) {
|
||||
for i := range matches {
|
||||
func setPkgNameToScoreMap(matches match.Matches, pkgScores map[string]*imageprinter.PackageScore) {
|
||||
for _, m := range matches.Sorted() {
|
||||
// key is pkg name + version to avoid version conflicts
|
||||
key := matches[i].Artifact.Name + matches[i].Artifact.Version
|
||||
key := m.Package.Name + m.Package.Version
|
||||
|
||||
if _, ok := pkgScores[key]; !ok {
|
||||
pkgScores[key] = &imageprinter.PackageScore{
|
||||
Version: matches[i].Artifact.Version,
|
||||
Name: matches[i].Artifact.Name,
|
||||
Version: m.Package.Version,
|
||||
Name: m.Package.Name,
|
||||
MapSeverityToCVEsNumber: make(map[string]int, 0),
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := pkgScores[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity]; !ok {
|
||||
pkgScores[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity] = 1
|
||||
if _, ok := pkgScores[key].MapSeverityToCVEsNumber[m.Vulnerability.Metadata.Severity]; !ok {
|
||||
pkgScores[key].MapSeverityToCVEsNumber[m.Vulnerability.Metadata.Severity] = 1
|
||||
} else {
|
||||
pkgScores[key].MapSeverityToCVEsNumber[matches[i].Vulnerability.Severity] += 1
|
||||
pkgScores[key].MapSeverityToCVEsNumber[m.Vulnerability.Metadata.Severity] += 1
|
||||
}
|
||||
|
||||
pkgScores[key].Score += utils.ImageSeverityToInt(matches[i].Vulnerability.Severity)
|
||||
pkgScores[key].Score += utils.ImageSeverityToInt(m.Vulnerability.Metadata.Severity)
|
||||
}
|
||||
}
|
||||
|
||||
func extractCVEs(matches []models.Match) []imageprinter.CVE {
|
||||
CVEs := []imageprinter.CVE{}
|
||||
for i := range matches {
|
||||
func extractCVEs(matches match.Matches) []imageprinter.CVE {
|
||||
var CVEs []imageprinter.CVE
|
||||
for _, m := range matches.Sorted() {
|
||||
cve := imageprinter.CVE{
|
||||
ID: matches[i].Vulnerability.ID,
|
||||
Severity: matches[i].Vulnerability.Severity,
|
||||
Package: matches[i].Artifact.Name,
|
||||
Version: matches[i].Artifact.Version,
|
||||
FixVersions: matches[i].Vulnerability.Fix.Versions,
|
||||
FixedState: matches[i].Vulnerability.Fix.State,
|
||||
ID: m.Vulnerability.Metadata.ID,
|
||||
Severity: m.Vulnerability.Metadata.Severity,
|
||||
Package: m.Package.Name,
|
||||
Version: m.Package.Version,
|
||||
FixVersions: m.Vulnerability.Fix.Versions,
|
||||
FixedState: m.Vulnerability.Fix.State.String(),
|
||||
}
|
||||
CVEs = append(CVEs, cve)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"testing"
|
||||
|
||||
v5 "github.com/anchore/grype/grype/db/v5"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/imageprinter"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -12,29 +14,30 @@ import (
|
||||
func TestExtractCVEs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
matches []models.Match
|
||||
matches match.Matches
|
||||
want []imageprinter.CVE
|
||||
}{
|
||||
{
|
||||
name: "single vuln",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "foo",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
ID: "CVE-2020-1234",
|
||||
Severity: "High",
|
||||
},
|
||||
Fix: models.Fix{
|
||||
Fix: vulnerability.Fix{
|
||||
Versions: []string{"1.2.3"},
|
||||
State: "Fixed",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
want: []imageprinter.CVE{
|
||||
{
|
||||
ID: "CVE-2020-1234",
|
||||
@@ -48,56 +51,59 @@ func TestExtractCVEs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "multiple vulns",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "foo",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
ID: "CVE-2020-1234",
|
||||
Severity: "High",
|
||||
},
|
||||
Fix: models.Fix{
|
||||
Fix: vulnerability.Fix{
|
||||
Versions: []string{"1.2.3"},
|
||||
State: "Fixed",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "2",
|
||||
Name: "test",
|
||||
Version: "1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
ID: "CVE-2020-1235",
|
||||
Severity: "Critical",
|
||||
},
|
||||
Fix: models.Fix{
|
||||
Fix: vulnerability.Fix{
|
||||
Versions: []string{"1"},
|
||||
State: "Fixed",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "3",
|
||||
Name: "test2",
|
||||
Version: "3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
ID: "CVE-2020-1236",
|
||||
Severity: "Low",
|
||||
},
|
||||
Fix: models.Fix{
|
||||
Fix: vulnerability.Fix{
|
||||
Versions: []string{"2", "3", "4"},
|
||||
State: "Not fixed",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
want: []imageprinter.CVE{
|
||||
{
|
||||
ID: "CVE-2020-1234",
|
||||
@@ -127,7 +133,7 @@ func TestExtractCVEs(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "empty vulns",
|
||||
matches: []models.Match{},
|
||||
matches: match.NewMatches([]match.Match{}...),
|
||||
want: []imageprinter.CVE{},
|
||||
},
|
||||
}
|
||||
@@ -171,25 +177,26 @@ func TestExtractCVEs(t *testing.T) {
|
||||
func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
matches []models.Match
|
||||
matches match.Matches
|
||||
originalMap map[string]*imageprinter.PackageScore
|
||||
want map[string]*imageprinter.PackageScore
|
||||
}{
|
||||
{
|
||||
name: "single package",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "foo",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
want: map[string]*imageprinter.PackageScore{
|
||||
"foo1.2.3": {
|
||||
Name: "foo",
|
||||
@@ -203,41 +210,44 @@ func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "multiple packages - different versions",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Critical",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "2",
|
||||
Name: "pkg2",
|
||||
Version: "1.2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Low",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "3",
|
||||
Name: "pkg3",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
want: map[string]*imageprinter.PackageScore{
|
||||
"pkg1version1": {
|
||||
Name: "pkg1",
|
||||
@@ -267,74 +277,80 @@ func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "multiple packages - mixed versions",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "2",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "3",
|
||||
Name: "pkg1",
|
||||
Version: "version2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Critical",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "4",
|
||||
Name: "pkg3",
|
||||
Version: "1.2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Medium",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "5",
|
||||
Name: "pkg3",
|
||||
Version: "1.2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Low",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "6",
|
||||
Name: "pkg4",
|
||||
Version: "1.2.3",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
want: map[string]*imageprinter.PackageScore{
|
||||
"pkg1version1": {
|
||||
Name: "pkg1",
|
||||
@@ -373,46 +389,49 @@ func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "empty packages",
|
||||
matches: []models.Match{},
|
||||
matches: match.NewMatches(),
|
||||
want: map[string]*imageprinter.PackageScore{},
|
||||
},
|
||||
{
|
||||
name: "original map not empty",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "pkg1",
|
||||
Version: "version2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Critical",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "2",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "3",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
originalMap: map[string]*imageprinter.PackageScore{
|
||||
"pkg41.2.3": {
|
||||
Name: "pkg4",
|
||||
@@ -452,41 +471,44 @@ func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "original map with same package",
|
||||
matches: []models.Match{
|
||||
matches: match.NewMatches([]match.Match{
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "1",
|
||||
Name: "pkg1",
|
||||
Version: "version2",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "Critical",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "2",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Artifact: models.Package{
|
||||
Package: pkg.Package{
|
||||
ID: "3",
|
||||
Name: "pkg1",
|
||||
Version: "version1",
|
||||
},
|
||||
Vulnerability: models.Vulnerability{
|
||||
VulnerabilityMetadata: models.VulnerabilityMetadata{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
Metadata: &vulnerability.Metadata{
|
||||
Severity: "High",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}...),
|
||||
originalMap: map[string]*imageprinter.PackageScore{
|
||||
"pkg1version1": {
|
||||
Name: "pkg1",
|
||||
@@ -518,37 +540,37 @@ func TestSetPkgNameToScoreMap(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for i := range tests {
|
||||
t.Run(tests[i].name, func(t *testing.T) {
|
||||
if tests[i].originalMap == nil {
|
||||
tests[i].originalMap = make(map[string]*imageprinter.PackageScore)
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.originalMap == nil {
|
||||
tt.originalMap = make(map[string]*imageprinter.PackageScore)
|
||||
}
|
||||
|
||||
setPkgNameToScoreMap(tests[i].matches, tests[i].originalMap)
|
||||
if len(tests[i].originalMap) == 0 {
|
||||
assert.Equal(t, tests[i].want, tests[i].originalMap)
|
||||
setPkgNameToScoreMap(tt.matches, tt.originalMap)
|
||||
if len(tt.originalMap) == 0 {
|
||||
assert.Equal(t, tt.want, tt.originalMap)
|
||||
return
|
||||
}
|
||||
|
||||
if len(tests[i].originalMap) != len(tests[i].want) {
|
||||
t.Errorf("%s failed for length, got = %v, want %v", tests[i].name, len(tests[i].originalMap), len(tests[i].want))
|
||||
if len(tt.originalMap) != len(tt.want) {
|
||||
t.Errorf("%s failed for length, got = %v, want %v", tt.name, len(tt.originalMap), len(tt.want))
|
||||
}
|
||||
|
||||
for k := range tests[i].originalMap {
|
||||
if tests[i].originalMap[k].Score != tests[i].want[k].Score {
|
||||
t.Errorf("%s failed for score, got = %v, want %v", tests[i].name, tests[i].want[k].Score, tests[i].originalMap[k].Score)
|
||||
for k := range tt.originalMap {
|
||||
if tt.originalMap[k].Score != tt.want[k].Score {
|
||||
t.Errorf("%s failed for score, got = %v, want %v", tt.name, tt.want[k].Score, tt.originalMap[k].Score)
|
||||
}
|
||||
if tests[i].originalMap[k].Version != tests[i].want[k].Version {
|
||||
t.Errorf("%s failed for version, got = %v, want %v", tests[i].name, tests[i].want[k].Version, tests[i].originalMap[k].Version)
|
||||
if tt.originalMap[k].Version != tt.want[k].Version {
|
||||
t.Errorf("%s failed for version, got = %v, want %v", tt.name, tt.want[k].Version, tt.originalMap[k].Version)
|
||||
|
||||
}
|
||||
if tests[i].originalMap[k].Name != tests[i].want[k].Name {
|
||||
t.Errorf("%s failed for name, got = %v, want %v", tests[i].name, tests[i].want[k].Name, tests[i].originalMap[k].Name)
|
||||
if tt.originalMap[k].Name != tt.want[k].Name {
|
||||
t.Errorf("%s failed for name, got = %v, want %v", tt.name, tt.want[k].Name, tt.originalMap[k].Name)
|
||||
}
|
||||
|
||||
for s := range tests[i].originalMap[k].MapSeverityToCVEsNumber {
|
||||
if tests[i].originalMap[k].MapSeverityToCVEsNumber[s] != tests[i].want[k].MapSeverityToCVEsNumber[s] {
|
||||
t.Errorf("%s failed for severity %s, got = %v, want %v", tests[i].name, s, tests[i].want[k].MapSeverityToCVEsNumber[s], tests[i].originalMap[k].MapSeverityToCVEsNumber[s])
|
||||
for s := range tt.originalMap[k].MapSeverityToCVEsNumber {
|
||||
if tt.originalMap[k].MapSeverityToCVEsNumber[s] != tt.want[k].MapSeverityToCVEsNumber[s] {
|
||||
t.Errorf("%s failed for severity %s, got = %v, want %v", tt.name, s, tt.want[k].MapSeverityToCVEsNumber[s], tt.originalMap[k].MapSeverityToCVEsNumber[s])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func (rh *ResultsHandler) GetResults() *reporthandlingv2.PostureReport {
|
||||
}
|
||||
|
||||
// HandleResults handles all necessary actions for the scan results
|
||||
func (rh *ResultsHandler) HandleResults(ctx context.Context) error {
|
||||
func (rh *ResultsHandler) HandleResults(ctx context.Context, scanInfo *cautils.ScanInfo) error {
|
||||
// Display scan results in the UI first to give immediate value.
|
||||
|
||||
rh.UiPrinter.ActionPrint(ctx, rh.ScanData, rh.ImageScanData)
|
||||
@@ -92,7 +92,7 @@ func (rh *ResultsHandler) HandleResults(ctx context.Context) error {
|
||||
|
||||
// We should submit only after printing results, so a user can see
|
||||
// results at all times, even if submission fails
|
||||
if rh.ReporterObj != nil {
|
||||
if rh.ReporterObj != nil && scanInfo.Submit {
|
||||
if err := rh.ReporterObj.Submit(ctx, rh.ScanData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func TestResultsHandlerHandleResultsPrintsResultsToUI(t *testing.T) {
|
||||
rh := NewResultsHandler(reporter, printers, uiPrinter)
|
||||
rh.SetData(fakeScanData)
|
||||
|
||||
err := rh.HandleResults(context.TODO())
|
||||
err := rh.HandleResults(context.TODO(), &cautils.ScanInfo{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
want := 1
|
||||
|
||||
@@ -28,18 +28,18 @@ Kubescape security posture overview for cluster: minikube
|
||||
In this overview, Kubescape shows you a summary of your cluster security posture, including the number of users who can perform administrative actions. For each result greater than 0, you should evaluate its need, and then define an exception to allow it. This baseline can be used to detect drift in future.
|
||||
|
||||
Control plane
|
||||
┌────┬─────────────────────────────────────┬────────────────────────────────────┐
|
||||
│ │ Control Name │ Docs │
|
||||
├────┼─────────────────────────────────────┼────────────────────────────────────┤
|
||||
│ ✅ │ API server insecure port is enabled │ https://hub.armosec.io/docs/c-0005 │
|
||||
│ ❌ │ Anonymous access enabled │ https://hub.armosec.io/docs/c-0262 │
|
||||
│ ❌ │ Audit logs enabled │ https://hub.armosec.io/docs/c-0067 │
|
||||
│ ✅ │ RBAC enabled │ https://hub.armosec.io/docs/c-0088 │
|
||||
│ ❌ │ Secret/etcd encryption enabled │ https://hub.armosec.io/docs/c-0066 │
|
||||
└────┴─────────────────────────────────────┴────────────────────────────────────┘
|
||||
╭────┬─────────────────────────────────────┬──────────────────────────────────────────────╮
|
||||
│ │ Control Name │ Docs │
|
||||
├────┼─────────────────────────────────────┼──────────────────────────────────────────────┤
|
||||
│ ✅ │ API server insecure port is enabled │ https://kubescape.io/docs/controls/c-0005/ │
|
||||
│ ❌ │ Anonymous access enabled │ https://kubescape.io/docs/controls/c-0262/ │
|
||||
│ ❌ │ Audit logs enabled │ https://kubescape.io/docs/controls/c-0067/ │
|
||||
│ ✅ │ RBAC enabled │ https://kubescape.io/docs/controls/c-0088/ │
|
||||
│ ❌ │ Secret/etcd encryption enabled │ https://kubescape.io/docs/controls/c-0066/ │
|
||||
╰────┴─────────────────────────────────────┴──────────────────────────────────────────────╯
|
||||
|
||||
Access control
|
||||
┌─────────────────────────────────────────────────┬───────────┬────────────────────────────────────┐
|
||||
╭─────────────────────────────────────────────────┬───────────┬────────────────────────────────────╮
|
||||
│ Control Name │ Resources │ View Details │
|
||||
├─────────────────────────────────────────────────┼───────────┼────────────────────────────────────┤
|
||||
│ Cluster-admin binding │ 1 │ $ kubescape scan control C-0035 -v │
|
||||
@@ -51,24 +51,24 @@ Access control
|
||||
│ Portforwarding privileges │ 1 │ $ kubescape scan control C-0063 -v │
|
||||
│ Validate admission controller (mutating) │ 0 │ $ kubescape scan control C-0039 -v │
|
||||
│ Validate admission controller (validating) │ 0 │ $ kubescape scan control C-0036 -v │
|
||||
└─────────────────────────────────────────────────┴───────────┴────────────────────────────────────┘
|
||||
╰─────────────────────────────────────────────────┴───────────┴────────────────────────────────────╯
|
||||
|
||||
Secrets
|
||||
┌─────────────────────────────────────────────────┬───────────┬────────────────────────────────────┐
|
||||
╭─────────────────────────────────────────────────┬───────────┬────────────────────────────────────╮
|
||||
│ Control Name │ Resources │ View Details │
|
||||
├─────────────────────────────────────────────────┼───────────┼────────────────────────────────────┤
|
||||
│ Applications credentials in configuration files │ 1 │ $ kubescape scan control C-0012 -v │
|
||||
└─────────────────────────────────────────────────┴───────────┴────────────────────────────────────┘
|
||||
╰─────────────────────────────────────────────────┴───────────┴────────────────────────────────────╯
|
||||
|
||||
Network
|
||||
┌────────────────────────┬───────────┬────────────────────────────────────┐
|
||||
╭────────────────────────┬───────────┬────────────────────────────────────╮
|
||||
│ Control Name │ Resources │ View Details │
|
||||
├────────────────────────┼───────────┼────────────────────────────────────┤
|
||||
│ Missing network policy │ 13 │ $ kubescape scan control C-0260 -v │
|
||||
└────────────────────────┴───────────┴────────────────────────────────────┘
|
||||
╰────────────────────────┴───────────┴────────────────────────────────────╯
|
||||
|
||||
Workload
|
||||
┌─────────────────────────┬───────────┬────────────────────────────────────┐
|
||||
╭─────────────────────────┬───────────┬────────────────────────────────────╮
|
||||
│ Control Name │ Resources │ View Details │
|
||||
├─────────────────────────┼───────────┼────────────────────────────────────┤
|
||||
│ Host PID/IPC privileges │ 2 │ $ kubescape scan control C-0038 -v │
|
||||
@@ -76,7 +76,7 @@ Workload
|
||||
│ HostPath mount │ 1 │ $ kubescape scan control C-0048 -v │
|
||||
│ Non-root containers │ 6 │ $ kubescape scan control C-0013 -v │
|
||||
│ Privileged container │ 1 │ $ kubescape scan control C-0057 -v │
|
||||
└─────────────────────────┴───────────┴────────────────────────────────────┘
|
||||
╰─────────────────────────┴───────────┴────────────────────────────────────╯
|
||||
|
||||
Highest-stake workloads
|
||||
────────────────────────
|
||||
@@ -144,7 +144,7 @@ kubescape scan framework mitre
|
||||
```
|
||||
|
||||
#### Scan a control
|
||||
Scan for a specific control, using the control name or control ID. [See the list of controls](https://hub.armosec.io/docs/controls?utm_source=github&utm_medium=repository).
|
||||
Scan for a specific control, using the control name or control ID. [See the list of controls](https://kubescape.io/docs/controls/).
|
||||
|
||||
```bash
|
||||
kubescape scan control c-0005 -v
|
||||
@@ -331,7 +331,7 @@ kubescape scan image nginx:1.19.6 -v
|
||||
|
||||
### Scan periodically using Helm
|
||||
|
||||
We publish [a Helm chart](https://github.com/kubescape/helm-charts) for our in-cluster components. [Please follow the instructions here](https://hub.armosec.io/docs/installation-of-armo-in-cluster?utm_source=github&utm_medium=repository)
|
||||
We publish [a Helm chart](https://github.com/kubescape/helm-charts) for our in-cluster components. [Please follow the instructions here](https://kubescape.io/docs/install-operator/)
|
||||
|
||||
### VS Code Extension
|
||||
|
||||
|
||||
@@ -708,14 +708,14 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Network mapping</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0049">C-0049</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0049/">C-0049</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Cluster internal networking</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0054">C-0054</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0054/">C-0054</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
@@ -742,77 +742,77 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Allow privilege escalation</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0016">C-0016</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0016/">C-0016</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Non-root containers</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0013">C-0013</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0013/">C-0013</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.runAsNonRoot=true</p> <p>spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Automatic mapping of service account</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0034">C-0034</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0034/">C-0034</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.automountServiceAccountToken=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">K8s common labels usage</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0077">C-0077</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0077/">C-0077</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.labels=YOUR_VALUE</p> <p>spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Pods in default namespace</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0061">C-0061</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0061/">C-0061</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.namespace</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Immutable container filesystem</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0017">C-0017</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0017/">C-0017</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem=true</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -839,7 +839,7 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Access container service account</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0053">C-0053</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0053/">C-0053</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
@@ -866,7 +866,7 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Automatic mapping of service account</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0034">C-0034</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0034/">C-0034</a></td>
|
||||
<td class="resourceRemediationCell"> <p>automountServiceAccountToken=false</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -893,77 +893,77 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Allow privilege escalation</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0016">C-0016</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0016/">C-0016</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Non-root containers</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0013">C-0013</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0013/">C-0013</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.runAsNonRoot=true</p> <p>spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Automatic mapping of service account</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0034">C-0034</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0034/">C-0034</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.automountServiceAccountToken=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">K8s common labels usage</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0077">C-0077</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0077/">C-0077</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.labels=YOUR_VALUE</p> <p>spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Pods in default namespace</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0061">C-0061</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0061/">C-0061</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.namespace</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Immutable container filesystem</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0017">C-0017</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0017/">C-0017</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem=true</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -990,21 +990,21 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Audit logs enabled</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0067">C-0067</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0067/">C-0067</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.containers[0].command</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">PSP enabled</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0068">C-0068</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0068/">C-0068</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.containers[0].command[5]</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Secret/ETCD encryption enabled</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0066">C-0066</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0066/">C-0066</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.containers[0].command</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1031,14 +1031,14 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Data Destruction</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0007">C-0007</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0007/">C-0007</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[1].resources[1]</p> <p>relatedObjects[1].rules[1].verbs[0]</p> <p>relatedObjects[1].rules[1].apiGroups[0]</p> <p>relatedObjects[1].rules[1].apiGroups[1]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">List Kubernetes secrets</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0015">C-0015</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0015/">C-0015</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[0].resources[0]</p> <p>relatedObjects[1].rules[0].verbs[0]</p> <p>relatedObjects[1].rules[0].verbs[1]</p> <p>relatedObjects[1].rules[0].verbs[3]</p> <p>relatedObjects[1].rules[0].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1065,7 +1065,7 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Automatic mapping of service account</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0034">C-0034</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0034/">C-0034</a></td>
|
||||
<td class="resourceRemediationCell"> <p>automountServiceAccountToken=false</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1092,56 +1092,56 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Kubernetes CronJob</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0026">C-0026</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0026/">C-0026</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Label usage for resources</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0076">C-0076</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0076/">C-0076</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">K8s common labels usage</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0077">C-0077</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0077/">C-0077</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.labels=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1168,63 +1168,63 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Allow privilege escalation</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0016">C-0016</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0016/">C-0016</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Kubernetes CronJob</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0026">C-0026</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0026/">C-0026</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Non-root containers</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0013">C-0013</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0013/">C-0013</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsNonRoot=true</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Immutable container filesystem</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0017">C-0017</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0017/">C-0017</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem=true</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1251,21 +1251,21 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Data Destruction</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0007">C-0007</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0007/">C-0007</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[1].resources[0]</p> <p>relatedObjects[1].rules[1].verbs[0]</p> <p>relatedObjects[1].rules[1].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> <p>relatedObjects[1].rules[2].resources[1]</p> <p>relatedObjects[1].rules[2].verbs[0]</p> <p>relatedObjects[1].rules[2].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">CoreDNS poisoning</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0037">C-0037</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0037/">C-0037</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[2].resources[0]</p> <p>relatedObjects[1].rules[2].verbs[0]</p> <p>relatedObjects[1].rules[2].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">List Kubernetes secrets</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0015">C-0015</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0015/">C-0015</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[0].resources[0]</p> <p>relatedObjects[1].rules[0].verbs[0]</p> <p>relatedObjects[1].rules[0].verbs[1]</p> <p>relatedObjects[1].rules[0].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> <p>relatedObjects[1].rules[2].resources[1]</p> <p>relatedObjects[1].rules[2].verbs[0]</p> <p>relatedObjects[1].rules[2].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1292,56 +1292,56 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Kubernetes CronJob</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0026">C-0026</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0026/">C-0026</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Label usage for resources</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0076">C-0076</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0076/">C-0076</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">K8s common labels usage</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0077">C-0077</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0077/">C-0077</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.labels=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1368,56 +1368,56 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Kubernetes CronJob</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0026">C-0026</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0026/">C-0026</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Label usage for resources</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0076">C-0076</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0076/">C-0076</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">K8s common labels usage</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0077">C-0077</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0077/">C-0077</a></td>
|
||||
<td class="resourceRemediationCell"> <p>metadata.labels=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.metadata.labels=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1444,7 +1444,7 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">List Kubernetes secrets</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0015">C-0015</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0015/">C-0015</a></td>
|
||||
<td class="resourceRemediationCell"> <p>relatedObjects[1].rules[0].resources[0]</p> <p>relatedObjects[1].rules[0].verbs[0]</p> <p>relatedObjects[1].rules[0].verbs[1]</p> <p>relatedObjects[1].rules[0].verbs[2]</p> <p>relatedObjects[1].rules[0].apiGroups[0]</p> <p>relatedObjects[0].subjects[0]</p> <p>relatedObjects[0].roleRef.name</p> </td>
|
||||
</tr>
|
||||
|
||||
@@ -1471,63 +1471,63 @@
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Allow privilege escalation</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0016">C-0016</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0016/">C-0016</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Ingress and Egress blocked</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0030">C-0030</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0030/">C-0030</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">High</td>
|
||||
<td class="resourceNameCell">Resource limits</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0009">C-0009</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0009/">C-0009</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.cpu=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].resources.limits.memory=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Configured readiness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0018">C-0018</a></td>
|
||||
<td class="resourceURLCell"><a href=" https://kubescape.io/docs/controls/c-0018/">C-0018</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].readinessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Kubernetes CronJob</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0026">C-0026</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0026/">C-0026</a></td>
|
||||
<td class="resourceRemediationCell"></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Non-root containers</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0013">C-0013</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0013/">C-0013</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.runAsNonRoot=true</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation=false</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Linux hardening</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0055">C-0055</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0055/">C-0055</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seccompProfile=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.seLinuxOptions=YOUR_VALUE</p> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.capabilities.drop[0]=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Medium</td>
|
||||
<td class="resourceNameCell">Configured liveness probe</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0056">C-0056</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0056/">C-0056</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].livenessProbe=YOUR_VALUE</p> </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="resourceSeverityCell">Low</td>
|
||||
<td class="resourceNameCell">Immutable container filesystem</td>
|
||||
<td class="resourceURLCell"><a href="https://hub.armosec.io/docs/c-0017">C-0017</a></td>
|
||||
<td class="resourceURLCell"><a href="https://kubescape.io/docs/controls/c-0017/">C-0017</a></td>
|
||||
<td class="resourceRemediationCell"> <p>spec.jobTemplate.spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem=true</p> </td>
|
||||
</tr>
|
||||
|
||||
|
||||
462
go.mod
462
go.mod
@@ -1,35 +1,38 @@
|
||||
module github.com/kubescape/kubescape/v3
|
||||
|
||||
go 1.23.6
|
||||
go 1.24.1
|
||||
|
||||
toolchain go1.24.2
|
||||
toolchain go1.24.6
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.5.3
|
||||
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
|
||||
github.com/anchore/grype v0.81.0
|
||||
github.com/anchore/stereoscope v0.0.11
|
||||
github.com/anchore/syft v1.18.1
|
||||
github.com/anchore/clio v0.0.0-20250715152405-a0fa658e5084
|
||||
github.com/anchore/grype v0.99.1
|
||||
github.com/anchore/stereoscope v0.1.9
|
||||
github.com/anchore/syft v1.32.0
|
||||
github.com/anubhav06/copa-grype v1.0.3-alpha.1
|
||||
github.com/armosec/armoapi-go v0.0.562
|
||||
github.com/armosec/utils-go v0.0.58
|
||||
github.com/armosec/utils-k8s-go v0.0.30
|
||||
github.com/briandowns/spinner v1.23.1
|
||||
github.com/briandowns/spinner v1.23.2
|
||||
github.com/chainguard-dev/git-urls v1.0.2
|
||||
github.com/containerd/platforms v1.0.0-rc.1
|
||||
github.com/distribution/reference v0.6.0
|
||||
github.com/docker/distribution v2.8.3+incompatible
|
||||
github.com/docker/buildx v0.21.3
|
||||
github.com/docker/cli v28.3.3+incompatible
|
||||
github.com/enescakir/emoji v1.0.0
|
||||
github.com/francoispqt/gojay v1.2.13
|
||||
github.com/go-git/go-git/v5 v5.13.0
|
||||
github.com/google/go-containerregistry v0.20.3
|
||||
github.com/go-git/go-git/v5 v5.16.2
|
||||
github.com/google/go-containerregistry v0.20.6
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.8
|
||||
github.com/johnfercher/go-tree v1.1.0
|
||||
github.com/johnfercher/maroto/v2 v2.2.2
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/jwalton/gchalk v1.3.0
|
||||
github.com/kubescape/backend v0.0.20
|
||||
github.com/kubescape/go-git-url v0.0.30
|
||||
github.com/kubescape/go-logger v0.0.23
|
||||
github.com/kubescape/go-logger v0.0.25
|
||||
github.com/kubescape/k8s-interface v0.0.195
|
||||
github.com/kubescape/opa-utils v0.0.288
|
||||
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520
|
||||
@@ -41,48 +44,47 @@ require (
|
||||
github.com/matthyx/go-gitlog v0.0.0-20231005131906-9ffabe3c5bcd
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mikefarah/yq/v4 v4.29.1
|
||||
github.com/olekukonko/tablewriter v0.0.6-0.20230417144759-edd1a71a5576
|
||||
github.com/open-policy-agent/opa v1.3.0
|
||||
github.com/moby/buildkit v0.21.0
|
||||
github.com/open-policy-agent/opa v1.4.0
|
||||
github.com/owenrumney/go-sarif/v2 v2.2.0
|
||||
github.com/project-copacetic/copacetic v0.4.1-0.20231017020916-013c118454b8
|
||||
github.com/project-copacetic/copacetic v0.10.0
|
||||
github.com/quay/claircore v1.5.35
|
||||
github.com/schollz/progressbar/v3 v3.13.0
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
|
||||
github.com/sergi/go-diff v1.4.0
|
||||
github.com/sigstore/cosign/v2 v2.2.4
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/otel/metric v1.35.0
|
||||
golang.org/x/mod v0.24.0
|
||||
golang.org/x/term v0.31.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.opentelemetry.io/otel v1.37.0
|
||||
go.opentelemetry.io/otel/metric v1.37.0
|
||||
golang.org/x/mod v0.27.0
|
||||
golang.org/x/term v0.34.0
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.17.3
|
||||
k8s.io/api v0.32.3
|
||||
k8s.io/apimachinery v0.32.3
|
||||
k8s.io/client-go v0.32.3
|
||||
helm.sh/helm/v3 v3.18.5
|
||||
k8s.io/api v0.33.3
|
||||
k8s.io/apimachinery v0.33.3
|
||||
k8s.io/client-go v0.33.3
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||
sigs.k8s.io/kustomize/api v0.18.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.18.1
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
sigs.k8s.io/kustomize/api v0.19.0
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0
|
||||
sigs.k8s.io/yaml v1.5.0
|
||||
)
|
||||
|
||||
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go v0.121.3 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/container v1.42.2 // indirect
|
||||
cloud.google.com/go/iam v1.4.1 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.0 // indirect
|
||||
cloud.google.com/go/storage v1.50.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/container v1.43.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
cloud.google.com/go/storage v1.55.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20250520111509-a70c2aa677fa // indirect
|
||||
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
|
||||
@@ -91,7 +93,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.1.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
|
||||
@@ -102,22 +104,27 @@ require (
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.1 // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
|
||||
github.com/Intevation/gval v1.3.0 // indirect
|
||||
github.com/Intevation/jsonpath v0.2.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.9 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/Microsoft/hcsshim v0.13.0 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/a8m/envsubst v1.3.0 // indirect
|
||||
github.com/acobaugh/osrelease v0.1.0 // indirect
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/agnivade/levenshtein v1.2.1 // indirect
|
||||
github.com/alecthomas/participle/v2 v2.1.0 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
|
||||
@@ -132,126 +139,136 @@ require (
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/aliyun/credentials-go v1.3.1 // indirect
|
||||
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20241014201141-b6e4b3469f10 // indirect
|
||||
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 // indirect
|
||||
github.com/anchore/go-logger v0.0.0-20241205183533-4fc29b5832e7 // indirect
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20250716230140-94c22408c232 // indirect
|
||||
github.com/anchore/go-collections v0.0.0-20241211140901-567f400e9a46 // indirect
|
||||
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d // indirect
|
||||
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 // indirect
|
||||
github.com/anchore/go-lzo v0.1.0 // indirect
|
||||
github.com/anchore/go-macholibre v0.0.0-20250320151634-807da7ad2331 // indirect
|
||||
github.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20250211213226-cce56d595160 // indirect
|
||||
github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1 // indirect
|
||||
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.1 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.1 // indirect
|
||||
github.com/armosec/gojay v1.2.17 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.63 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.34.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.48.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.35.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.10.1 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607 // indirect
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/bugsnag/bugsnag-go/v2 v2.3.0 // indirect
|
||||
github.com/bugsnag/panicwrap v1.3.4 // indirect
|
||||
github.com/buildkite/agent/v3 v3.62.0 // indirect
|
||||
github.com/buildkite/go-pipeline v0.3.2 // indirect
|
||||
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.1 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
|
||||
github.com/cilium/cilium v1.16.9 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.5 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/containerd/containerd/api v1.8.0 // indirect
|
||||
github.com/containerd/continuity v0.4.4 // indirect
|
||||
github.com/containerd/containerd v1.7.28 // indirect
|
||||
github.com/containerd/containerd/api v1.9.0 // indirect
|
||||
github.com/containerd/containerd/v2 v2.0.5 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/fifo v1.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
|
||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/containers/common v0.63.0 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-docker v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/cpuguy83/go-docker v0.3.0 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
|
||||
github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect
|
||||
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
|
||||
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/buildx v0.11.2 // indirect
|
||||
github.com/docker/cli v27.5.0+incompatible // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/diskfs/go-diskfs v1.7.0 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v28.3.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-connections v0.6.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
github.com/elliotchance/orderedmap v1.5.0 // indirect
|
||||
github.com/elliotchance/phpserialize v1.4.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/f-amaral/go-async v0.3.0 // indirect
|
||||
github.com/facebookincubator/nvdtools v0.1.5 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
|
||||
github.com/github/go-spdx/v2 v2.3.2 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/github/go-spdx/v2 v2.3.3 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/glebarez/sqlite v1.11.0 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-gota/gota v0.12.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
@@ -265,44 +282,46 @@ require (
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-piv/piv-go v1.11.0 // indirect
|
||||
github.com/go-restruct/restruct v1.2.0-alpha // indirect
|
||||
github.com/go-test/deep v1.1.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-yaml v1.9.6 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/gocsaf/csaf/v3 v3.3.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gofrs/uuid v4.3.1+incompatible // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/gohugoio/hashstructure v0.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-github/v55 v55.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/licensecheck v0.3.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gookit/color v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.6 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.9 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
|
||||
github.com/hhrutter/lzw v1.0.0 // indirect
|
||||
github.com/hhrutter/tiff v1.0.1 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
@@ -323,53 +342,59 @@ require (
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20230223133812-3ed183d23422 // indirect
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 // indirect
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 // indirect
|
||||
github.com/knqyf263/go-rpmdb v0.1.1 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20250131095131-f4974fa13b8a // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1 // indirect
|
||||
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 // indirect
|
||||
github.com/mholt/archives v0.1.5 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||
github.com/minio/minlz v1.0.1 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/buildkit v0.12.5 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.5.0 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.1 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 // indirect
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/oleiade/reflections v1.0.1 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.0.9 // indirect
|
||||
github.com/olvrng/ujson v1.1.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
@@ -378,36 +403,42 @@ require (
|
||||
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
|
||||
github.com/openvex/go-vex v0.2.5 // indirect
|
||||
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect
|
||||
github.com/package-url/packageurl-go v0.1.2-0.20230812223828-f8bb31c1f10b // indirect
|
||||
github.com/package-url/packageurl-go v0.1.3 // indirect
|
||||
github.com/pandatix/go-cvss v0.6.2 // indirect
|
||||
github.com/pborman/indent v1.2.1 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pdfcpu/pdfcpu v0.9.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.4.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
github.com/pkg/xattr v0.4.12 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.21.1 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/quay/claircore/toolkit v1.2.4 // indirect
|
||||
github.com/quay/zlog v1.1.8 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.3.5 // indirect
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 // indirect
|
||||
github.com/sassoftware/relic v7.2.1+incompatible // indirect
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
|
||||
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
@@ -416,136 +447,133 @@ require (
|
||||
github.com/sigstore/fulcio v1.6.6 // indirect
|
||||
github.com/sigstore/protobuf-specs v0.4.1 // indirect
|
||||
github.com/sigstore/rekor v1.3.10 // indirect
|
||||
github.com/sigstore/sigstore v1.9.3 // indirect
|
||||
github.com/sigstore/sigstore v1.9.5 // indirect
|
||||
github.com/sigstore/timestamp-authority v1.2.2 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb // indirect
|
||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spf13/viper v1.19.0 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.4.0 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/stripe/stripe-go/v74 v74.30.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.21.1 // indirect
|
||||
github.com/sylabs/squashfs v1.0.4 // indirect
|
||||
github.com/sylabs/sif/v2 v2.22.0 // indirect
|
||||
github.com/sylabs/squashfs v1.0.6 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.7.0 // indirect
|
||||
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250410151801-5b74a7ad7583 // indirect
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
|
||||
github.com/transparency-dev/merkle v0.0.2 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect
|
||||
github.com/uptrace/uptrace-go v1.30.1 // indirect
|
||||
github.com/uptrace/uptrace-go v1.37.0 // indirect
|
||||
github.com/vbatts/go-mtree v0.5.4 // indirect
|
||||
github.com/vbatts/tar-split v0.12.1 // indirect
|
||||
github.com/vifraa/gopom v1.0.0 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect
|
||||
github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect
|
||||
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/go-gitlab v0.102.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
github.com/zclconf/go-cty v1.14.0 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
github.com/zclconf/go-cty v1.16.3 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.etcd.io/bbolt v1.4.2 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.55.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.41.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.37.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.step.sm/crypto v0.60.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.228.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
gonum.org/v1/gonum v0.12.0 // indirect
|
||||
google.golang.org/api v0.242.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/grpc v1.74.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gorm.io/gorm v1.25.12 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.32.2 // indirect
|
||||
k8s.io/apiserver v0.32.3 // indirect
|
||||
k8s.io/component-base v0.32.3 // indirect
|
||||
gorm.io/gorm v1.30.2 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.3 // indirect
|
||||
k8s.io/apiserver v0.33.3 // indirect
|
||||
k8s.io/cli-runtime v0.33.3 // indirect
|
||||
k8s.io/component-base v0.33.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/kubectl v0.33.3 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.2 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.38.2 // indirect
|
||||
oras.land/oras-go/v2 v2.6.0 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.18.4 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/release-utils v0.9.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
)
|
||||
|
||||
// Using the forked version of tablewriter
|
||||
replace github.com/olekukonko/tablewriter => github.com/kubescape/tablewriter v0.0.6-0.20231106230230-aac7d2659c94
|
||||
replace github.com/anchore/stereoscope => github.com/matthyx/stereoscope v0.0.0-20250916161743-dd57158479de
|
||||
|
||||
replace github.com/anchore/stereoscope => github.com/matthyx/stereoscope v0.0.0-20240426103125-b762a3538c32
|
||||
|
||||
replace github.com/google/go-containerregistry => github.com/matthyx/go-containerregistry v0.0.0-20240227132928-63ceb71ae0b9
|
||||
|
||||
replace github.com/docker/distribution v2.8.3+incompatible => github.com/docker/distribution v2.8.2+incompatible
|
||||
|
||||
replace github.com/mholt/archiver/v3 v3.5.1 => github.com/anchore/archiver/v3 v3.5.2
|
||||
|
||||
replace github.com/docker/docker => github.com/docker/docker v26.1.5+incompatible
|
||||
|
||||
replace github.com/docker/cli => github.com/docker/cli v26.1.0+incompatible
|
||||
|
||||
replace github.com/sylabs/squashfs => github.com/sylabs/squashfs v0.6.1
|
||||
replace github.com/google/go-containerregistry => github.com/matthyx/go-containerregistry v0.0.0-20250916162850-293c5b36a9f8
|
||||
|
||||
@@ -99,7 +99,7 @@ spec:
|
||||
fieldPath: metadata.namespace
|
||||
- name: "KS_SKIP_UPDATE_CHECK" # do not check latest version
|
||||
value: "true"
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://hub.armosec.io/docs/host-sensor
|
||||
- name: KS_ENABLE_HOST_SCANNER # enable host scanner -> https://kubescape.io/docs/components/host-sensor/
|
||||
value: "true"
|
||||
- name: KS_DOWNLOAD_ARTIFACTS # When set to true the artifacts will be downloaded every scan execution
|
||||
value: "true"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module github.com/kubescape/kubescape/v3/httphandler
|
||||
|
||||
go 1.23.6
|
||||
go 1.24.1
|
||||
|
||||
toolchain go1.24.2
|
||||
toolchain go1.24.6
|
||||
|
||||
replace github.com/kubescape/kubescape/v3 => ../
|
||||
|
||||
@@ -15,47 +15,47 @@ require (
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/schema v1.4.1
|
||||
github.com/kubescape/backend v0.0.20
|
||||
github.com/kubescape/go-logger v0.0.23
|
||||
github.com/kubescape/go-logger v0.0.25
|
||||
github.com/kubescape/k8s-interface v0.0.195
|
||||
github.com/kubescape/kubescape/v3 v3.0.4
|
||||
github.com/kubescape/opa-utils v0.0.288
|
||||
github.com/kubescape/storage v0.0.184
|
||||
github.com/spf13/viper v1.19.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/stretchr/testify v1.11.1
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
k8s.io/apimachinery v0.32.3
|
||||
k8s.io/client-go v0.32.3
|
||||
go.opentelemetry.io/otel v1.37.0
|
||||
k8s.io/apimachinery v0.33.3
|
||||
k8s.io/client-go v0.33.3
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||
)
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
go.opentelemetry.io/otel/trace v1.37.0
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/grpc v1.71.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/grpc v1.74.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go v0.121.3 // indirect
|
||||
cloud.google.com/go/auth v0.16.2 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/container v1.42.2 // indirect
|
||||
cloud.google.com/go/iam v1.4.1 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.0 // indirect
|
||||
cloud.google.com/go/storage v1.50.0 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.7.0 // indirect
|
||||
cloud.google.com/go/container v1.43.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
cloud.google.com/go/storage v1.55.0 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
|
||||
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect
|
||||
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20250520111509-a70c2aa677fa // indirect
|
||||
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
|
||||
@@ -64,7 +64,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.1.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
|
||||
@@ -75,23 +75,28 @@ require (
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.1 // indirect
|
||||
github.com/DataDog/zstd v1.5.5 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
|
||||
github.com/Intevation/gval v1.3.0 // indirect
|
||||
github.com/Intevation/jsonpath v0.2.1 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.9 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/Microsoft/hcsshim v0.13.0 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // indirect
|
||||
github.com/STARRY-S/zip v0.2.3 // indirect
|
||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||
github.com/a8m/envsubst v1.3.0 // indirect
|
||||
github.com/acobaugh/osrelease v0.1.0 // indirect
|
||||
github.com/adrg/xdg v0.5.3 // indirect
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/agnivade/levenshtein v1.2.1 // indirect
|
||||
github.com/alecthomas/participle/v2 v2.1.0 // indirect
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
|
||||
@@ -106,105 +111,118 @@ require (
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/aliyun/credentials-go v1.3.1 // indirect
|
||||
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 // indirect
|
||||
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20241014201141-b6e4b3469f10 // indirect
|
||||
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 // indirect
|
||||
github.com/anchore/go-logger v0.0.0-20241205183533-4fc29b5832e7 // indirect
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
|
||||
github.com/anchore/clio v0.0.0-20250715152405-a0fa658e5084 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20250716230140-94c22408c232 // indirect
|
||||
github.com/anchore/go-collections v0.0.0-20241211140901-567f400e9a46 // indirect
|
||||
github.com/anchore/go-homedir v0.0.0-20250319154043-c29668562e4d // indirect
|
||||
github.com/anchore/go-logger v0.0.0-20250318195838-07ae343dd722 // indirect
|
||||
github.com/anchore/go-lzo v0.1.0 // indirect
|
||||
github.com/anchore/go-macholibre v0.0.0-20250320151634-807da7ad2331 // indirect
|
||||
github.com/anchore/go-rpmdb v0.0.0-20250516171929-f77691e1faec // indirect
|
||||
github.com/anchore/go-struct-converter v0.0.0-20250211213226-cce56d595160 // indirect
|
||||
github.com/anchore/go-sync v0.0.0-20250714163430-add63db73ad1 // indirect
|
||||
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
|
||||
github.com/anchore/grype v0.81.0 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f // indirect
|
||||
github.com/anchore/stereoscope v0.0.11 // indirect
|
||||
github.com/anchore/syft v1.18.1 // indirect
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/anchore/grype v0.99.1 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20250220190351-d62adb6e1115 // indirect
|
||||
github.com/anchore/stereoscope v0.1.9 // indirect
|
||||
github.com/anchore/syft v1.32.0 // indirect
|
||||
github.com/andybalholm/brotli v1.2.0 // indirect
|
||||
github.com/anubhav06/copa-grype v1.0.3-alpha.1 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
|
||||
github.com/aquasecurity/go-pep440-version v0.0.1 // indirect
|
||||
github.com/aquasecurity/go-version v0.0.1 // indirect
|
||||
github.com/armosec/gojay v1.2.17 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.63 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.34.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/eks v1.48.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.35.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.2 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
|
||||
github.com/aws/smithy-go v1.22.2 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.10.1 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/becheran/wildmatch-go v1.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bitnami/go-version v0.0.0-20250505154626-452e8c5ee607 // indirect
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
|
||||
github.com/bodgit/plumbing v1.3.0 // indirect
|
||||
github.com/bodgit/sevenzip v1.6.1 // indirect
|
||||
github.com/bodgit/windows v1.0.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/briandowns/spinner v1.23.1 // indirect
|
||||
github.com/briandowns/spinner v1.23.2 // indirect
|
||||
github.com/buildkite/agent/v3 v3.62.0 // indirect
|
||||
github.com/buildkite/go-pipeline v0.3.2 // indirect
|
||||
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/chainguard-dev/git-urls v1.0.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.1 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
|
||||
github.com/cilium/cilium v1.16.9 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/cloudflare/circl v1.3.8 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.5 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/containerd/containerd v1.7.27 // indirect
|
||||
github.com/containerd/containerd/api v1.8.0 // indirect
|
||||
github.com/containerd/continuity v0.4.4 // indirect
|
||||
github.com/containerd/containerd v1.7.28 // indirect
|
||||
github.com/containerd/containerd/api v1.9.0 // indirect
|
||||
github.com/containerd/containerd/v2 v2.0.5 // indirect
|
||||
github.com/containerd/continuity v0.4.5 // indirect
|
||||
github.com/containerd/errdefs v1.0.0 // indirect
|
||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||
github.com/containerd/fifo v1.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/containerd/platforms v1.0.0-rc.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
|
||||
github.com/containerd/ttrpc v1.2.7 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.2.3 // indirect
|
||||
github.com/containers/common v0.63.0 // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-docker v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/cpuguy83/go-docker v0.3.0 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
|
||||
github.com/deitch/magic v0.0.0-20240306090643-c67ab88f10cb // indirect
|
||||
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
|
||||
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/diskfs/go-diskfs v1.7.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/buildx v0.11.2 // indirect
|
||||
github.com/docker/cli v27.5.0+incompatible // indirect
|
||||
github.com/docker/buildx v0.21.3 // indirect
|
||||
github.com/docker/cli v28.3.3+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/docker/docker v28.3.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
|
||||
github.com/docker/go-metrics v0.0.1 // indirect
|
||||
github.com/docker/go-connections v0.6.0 // indirect
|
||||
github.com/docker/go-events v0.0.0-20250114142523-c867878c5e32 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
github.com/elliotchance/orderedmap v1.5.0 // indirect
|
||||
github.com/elliotchance/phpserialize v1.4.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
@@ -212,29 +230,31 @@ require (
|
||||
github.com/enescakir/emoji v1.0.0 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
|
||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||
github.com/f-amaral/go-async v0.3.0 // indirect
|
||||
github.com/facebookincubator/nvdtools v0.1.5 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
|
||||
github.com/github/go-spdx/v2 v2.3.2 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/github/go-spdx/v2 v2.3.3 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/glebarez/sqlite v1.11.0 // indirect
|
||||
github.com/go-chi/chi v4.1.2+incompatible // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.0 // indirect
|
||||
github.com/go-git/go-git/v5 v5.13.0 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-git/go-git/v5 v5.16.2 // indirect
|
||||
github.com/go-gota/gota v0.12.0 // indirect
|
||||
github.com/go-ini/ini v1.67.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
@@ -247,44 +267,46 @@ require (
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-piv/piv-go v1.11.0 // indirect
|
||||
github.com/go-restruct/restruct v1.2.0-alpha // indirect
|
||||
github.com/go-test/deep v1.1.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-yaml v1.9.6 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/gocsaf/csaf/v3 v3.3.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/gohugoio/hashstructure v0.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/btree v1.1.3 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.3 // indirect
|
||||
github.com/google/go-containerregistry v0.20.6 // indirect
|
||||
github.com/google/go-github/v55 v55.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/licensecheck v0.3.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/pprof v0.0.0-20250630185457-6e76a2b096b5 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/gookit/color v1.5.4 // indirect
|
||||
github.com/gorilla/websocket v1.5.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gookit/color v1.6.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect
|
||||
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.6 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.9 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.24.0 // indirect
|
||||
github.com/hhrutter/lzw v1.0.0 // indirect
|
||||
github.com/hhrutter/tiff v1.0.1 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
@@ -292,6 +314,7 @@ require (
|
||||
github.com/in-toto/in-toto-golang v0.9.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.8 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
@@ -309,63 +332,69 @@ require (
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20230223133812-3ed183d23422 // indirect
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20241115132648-6f4aee6ccd23 // indirect
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 // indirect
|
||||
github.com/knqyf263/go-rpmdb v0.1.1 // indirect
|
||||
github.com/kubescape/go-git-url v0.0.30 // indirect
|
||||
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520 // indirect
|
||||
github.com/kubescape/regolibrary/v2 v2.0.1 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/maruel/natural v1.1.1 // indirect
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20250131095131-f4974fa13b8a // indirect
|
||||
github.com/matthyx/go-gitlog v0.0.0-20231005131906-9ffabe3c5bcd // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1 // indirect
|
||||
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 // indirect
|
||||
github.com/mholt/archives v0.1.5 // indirect
|
||||
github.com/miekg/pkcs11 v1.1.1 // indirect
|
||||
github.com/mikefarah/yq/v4 v4.29.1 // indirect
|
||||
github.com/mikelolasagasti/xz v1.0.1 // indirect
|
||||
github.com/minio/minlz v1.0.1 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/buildkit v0.12.5 // indirect
|
||||
github.com/moby/buildkit v0.21.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/patternmatcher v0.6.0 // indirect
|
||||
github.com/moby/spdystream v0.5.0 // indirect
|
||||
github.com/moby/sys/atomicwriter v0.1.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/sequential v0.6.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.1 // indirect
|
||||
github.com/moby/sys/user v0.4.0 // indirect
|
||||
github.com/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/moby/term v0.5.2 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/nix-community/go-nix v0.0.0-20250101154619-4bdde671e0a1 // indirect
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/oleiade/reflections v1.0.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.6-0.20230417144759-edd1a71a5576 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.0.9 // indirect
|
||||
github.com/olvrng/ujson v1.1.0 // indirect
|
||||
github.com/open-policy-agent/opa v1.3.0 // indirect
|
||||
github.com/open-policy-agent/opa v1.4.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.1 // indirect
|
||||
@@ -374,136 +403,149 @@ require (
|
||||
github.com/openvex/go-vex v0.2.5 // indirect
|
||||
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect
|
||||
github.com/owenrumney/go-sarif/v2 v2.3.0 // indirect
|
||||
github.com/package-url/packageurl-go v0.1.2 // indirect
|
||||
github.com/package-url/packageurl-go v0.1.3 // indirect
|
||||
github.com/pandatix/go-cvss v0.6.2 // indirect
|
||||
github.com/pborman/indent v1.2.1 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pdfcpu/pdfcpu v0.9.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pjbgf/sha1cd v0.4.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkg/profile v1.7.0 // indirect
|
||||
github.com/pkg/xattr v0.4.12 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/project-copacetic/copacetic v0.4.1-0.20231017020916-013c118454b8 // indirect
|
||||
github.com/prometheus/client_golang v1.21.1 // indirect
|
||||
github.com/project-copacetic/copacetic v0.10.0 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/quay/claircore v1.5.35 // indirect
|
||||
github.com/quay/claircore/toolkit v1.2.4 // indirect
|
||||
github.com/quay/zlog v1.1.8 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
github.com/sagikazarmark/locafero v0.6.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/rust-secure-code/go-rustaudit v0.0.0-20250226111315-e20ec32e963c // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.3.5 // indirect
|
||||
github.com/sassoftware/go-rpmutils v0.4.0 // indirect
|
||||
github.com/sassoftware/relic v7.2.1+incompatible // indirect
|
||||
github.com/schollz/progressbar/v3 v3.13.0 // indirect
|
||||
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect
|
||||
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
|
||||
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
|
||||
github.com/segmentio/ksuid v1.0.4 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/sergi/go-diff v1.4.0 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sigstore/cosign/v2 v2.2.4 // indirect
|
||||
github.com/sigstore/fulcio v1.6.6 // indirect
|
||||
github.com/sigstore/protobuf-specs v0.4.1 // indirect
|
||||
github.com/sigstore/rekor v1.3.10 // indirect
|
||||
github.com/sigstore/sigstore v1.9.3 // indirect
|
||||
github.com/sigstore/sigstore v1.9.5 // indirect
|
||||
github.com/sigstore/timestamp-authority v1.2.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/sorairolake/lzip-go v0.3.8 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spdx/gordf v0.0.0-20250128162952-000978ccd6fb // indirect
|
||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.4.0 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
|
||||
github.com/stripe/stripe-go/v74 v74.30.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/sylabs/sif/v2 v2.21.1 // indirect
|
||||
github.com/sylabs/squashfs v1.0.4 // indirect
|
||||
github.com/sylabs/sif/v2 v2.22.0 // indirect
|
||||
github.com/sylabs/squashfs v1.0.6 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
|
||||
github.com/thales-e-security/pool v0.0.2 // indirect
|
||||
github.com/therootcompany/xz v1.0.1 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.7.0 // indirect
|
||||
github.com/theupdateframework/notary v0.6.1 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect
|
||||
github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 // indirect
|
||||
github.com/tonistiigi/fsutil v0.0.0-20250410151801-5b74a7ad7583 // indirect
|
||||
github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect
|
||||
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
|
||||
github.com/tonistiigi/vt100 v0.0.0-20240514184818-90bafcd6abab // indirect
|
||||
github.com/transparency-dev/merkle v0.0.2 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect
|
||||
github.com/uptrace/uptrace-go v1.30.1 // indirect
|
||||
github.com/uptrace/uptrace-go v1.37.0 // indirect
|
||||
github.com/vbatts/go-mtree v0.5.4 // indirect
|
||||
github.com/vbatts/tar-split v0.12.1 // indirect
|
||||
github.com/vifraa/gopom v1.0.0 // indirect
|
||||
github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 // indirect
|
||||
github.com/vishvananda/netns v0.0.5 // indirect
|
||||
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect
|
||||
github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect
|
||||
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/go-gitlab v0.102.0 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xlab/treeprint v1.2.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
github.com/zclconf/go-cty v1.16.3 // indirect
|
||||
github.com/zeebo/errs v1.4.0 // indirect
|
||||
go.etcd.io/bbolt v1.4.2 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.55.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.41.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.37.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.56.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/runtime v0.62.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.step.sm/crypto v0.60.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/term v0.31.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.228.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/term v0.34.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.36.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
|
||||
gonum.org/v1/gonum v0.12.0 // indirect
|
||||
google.golang.org/api v0.242.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
@@ -512,38 +554,31 @@ require (
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/gorm v1.25.12 // indirect
|
||||
helm.sh/helm/v3 v3.17.3 // indirect
|
||||
k8s.io/api v0.32.3 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.32.2 // indirect
|
||||
k8s.io/apiserver v0.32.3 // indirect
|
||||
k8s.io/component-base v0.32.3 // indirect
|
||||
gorm.io/gorm v1.30.2 // indirect
|
||||
helm.sh/helm/v3 v3.18.5 // indirect
|
||||
k8s.io/api v0.33.3 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.3 // indirect
|
||||
k8s.io/apiserver v0.33.3 // indirect
|
||||
k8s.io/cli-runtime v0.33.3 // indirect
|
||||
k8s.io/component-base v0.33.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
k8s.io/kubectl v0.33.3 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.2 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.38.2 // indirect
|
||||
oras.land/oras-go/v2 v2.6.0 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.18.4 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.18.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.19.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/release-utils v0.9.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
||||
// Using the forked version of tablewriter
|
||||
replace github.com/olekukonko/tablewriter => github.com/kubescape/tablewriter v0.0.6-0.20231106230230-aac7d2659c94
|
||||
|
||||
replace github.com/docker/distribution v2.8.3+incompatible => github.com/docker/distribution v2.8.2+incompatible
|
||||
|
||||
replace github.com/docker/docker v27.1.1+incompatible => github.com/docker/docker v26.1.5+incompatible
|
||||
|
||||
replace github.com/mholt/archiver/v3 v3.5.1 => github.com/anchore/archiver/v3 v3.5.2
|
||||
|
||||
replace github.com/docker/docker => github.com/docker/docker v26.1.5+incompatible
|
||||
|
||||
replace github.com/docker/cli => github.com/docker/cli v26.1.0+incompatible
|
||||
|
||||
replace github.com/sylabs/squashfs => github.com/sylabs/squashfs v0.6.1
|
||||
|
||||
1741
httphandler/go.sum
1741
httphandler/go.sum
File diff suppressed because it is too large
Load Diff
@@ -83,7 +83,7 @@ func scan(ctx context.Context, scanInfo *cautils.ScanInfo, scanID string) (*repo
|
||||
if err != nil {
|
||||
return nil, writeScanErrorToFile(err, scanID)
|
||||
}
|
||||
if err := result.HandleResults(ctx); err != nil {
|
||||
if err := result.HandleResults(ctx, scanInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storage := storage.GetStorage()
|
||||
|
||||
@@ -96,5 +96,6 @@ if ! kubectl get nodes &> /dev/null; then
|
||||
fi
|
||||
|
||||
echo -e "\033[0;37;40m"
|
||||
echo -e "\033[0;37;32mExecuting Kubescape."
|
||||
$KUBESCAPE_EXEC scan
|
||||
echo -e "\033[0;37;32mFinished Installation.\n"
|
||||
$KUBESCAPE_EXEC version
|
||||
echo -e "\033[0;37;35m\nUsage: $ kubescape scan"
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
// CurrentDir returns the directory of the file where this function is defined.
|
||||
func CurrentDir() string {
|
||||
_, filename, ok := runtime.Caller(0)
|
||||
_, filename, _, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
panic("failed to get current file info")
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/grype/grype"
|
||||
"github.com/anchore/grype/grype/db"
|
||||
"github.com/anchore/grype/grype/db/v6/distribution"
|
||||
"github.com/anchore/grype/grype/db/v6/installation"
|
||||
"github.com/anchore/grype/grype/grypeerr"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/matcher"
|
||||
@@ -21,15 +22,14 @@ import (
|
||||
"github.com/anchore/grype/grype/matcher/ruby"
|
||||
"github.com/anchore/grype/grype/matcher/stock"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/anchore/grype/grype/store"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
"github.com/anchore/syft/syft"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultGrypeListingURL = "https://toolbox-data.anchore.io/grype/databases/listing.json"
|
||||
defaultGrypeListingURL = "https://grype.anchore.io/databases"
|
||||
defaultDBDirName = "grypedb"
|
||||
)
|
||||
|
||||
@@ -42,29 +42,22 @@ func (c RegistryCredentials) IsEmpty() bool {
|
||||
return c.Username == "" || c.Password == ""
|
||||
}
|
||||
|
||||
// ExceedsSeverityThreshold returns true if vulnerabilities in the scan results exceed the severity threshold, false otherwise.
|
||||
//
|
||||
// Values equal to the threshold are considered failing, too.
|
||||
func ExceedsSeverityThreshold(scanResults *models.PresenterConfig, severity vulnerability.Severity) bool {
|
||||
if scanResults.MetadataProvider == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return grype.HasSeverityAtOrAbove(scanResults.MetadataProvider, severity, scanResults.Matches)
|
||||
}
|
||||
|
||||
func NewDefaultDBConfig() (db.Config, bool) {
|
||||
func NewDefaultDBConfig() (distribution.Config, installation.Config, bool) {
|
||||
dir := filepath.Join(xdg.CacheHome, defaultDBDirName)
|
||||
url := defaultGrypeListingURL
|
||||
shouldUpdate := true
|
||||
|
||||
return db.Config{
|
||||
DBRootDir: dir,
|
||||
ListingURL: url,
|
||||
}, shouldUpdate
|
||||
return distribution.Config{
|
||||
LatestURL: url,
|
||||
}, installation.Config{
|
||||
DBRootDir: dir,
|
||||
}, shouldUpdate
|
||||
}
|
||||
|
||||
func getMatchers() []matcher.Matcher {
|
||||
func getMatchers(useDefaultMatchers bool) []match.Matcher {
|
||||
if useDefaultMatchers {
|
||||
return matcher.NewDefaultMatchers(defaultMatcherConfig())
|
||||
}
|
||||
return matcher.NewDefaultMatchers(
|
||||
matcher.Config{
|
||||
Java: java.MatcherConfig{
|
||||
@@ -81,15 +74,34 @@ func getMatchers() []matcher.Matcher {
|
||||
)
|
||||
}
|
||||
|
||||
func validateDBLoad(loadErr error, status *db.Status) error {
|
||||
func defaultMatcherConfig() matcher.Config {
|
||||
return matcher.Config{
|
||||
Java: java.MatcherConfig{
|
||||
ExternalSearchConfig: java.ExternalSearchConfig{MavenBaseURL: "https://search.maven.org/solrsearch/select"},
|
||||
UseCPEs: false,
|
||||
},
|
||||
Ruby: ruby.MatcherConfig{UseCPEs: false},
|
||||
Python: python.MatcherConfig{UseCPEs: false},
|
||||
Dotnet: dotnet.MatcherConfig{UseCPEs: false},
|
||||
Javascript: javascript.MatcherConfig{UseCPEs: false},
|
||||
Golang: golang.MatcherConfig{
|
||||
UseCPEs: false,
|
||||
AlwaysUseCPEForStdlib: true,
|
||||
AllowMainModulePseudoVersionComparison: false,
|
||||
},
|
||||
Stock: stock.MatcherConfig{UseCPEs: true},
|
||||
}
|
||||
}
|
||||
|
||||
func validateDBLoad(loadErr error, status *vulnerability.ProviderStatus) error {
|
||||
if loadErr != nil {
|
||||
return fmt.Errorf("failed to load vulnerability db: %w", loadErr)
|
||||
}
|
||||
if status == nil {
|
||||
return fmt.Errorf("unable to determine the status of the vulnerability db")
|
||||
}
|
||||
if status.Err != nil {
|
||||
return fmt.Errorf("db could not be loaded: %w", status.Err)
|
||||
if status.Error != nil {
|
||||
return fmt.Errorf("db could not be loaded: %w", status.Error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -115,10 +127,11 @@ func getProviderConfig(creds RegistryCredentials) pkg.ProviderConfig {
|
||||
//
|
||||
// It performs image scanning and everything needed in between.
|
||||
type Service struct {
|
||||
dbCfg db.Config
|
||||
useDefaultMatchers bool
|
||||
vp vulnerability.Provider
|
||||
}
|
||||
|
||||
func getIgnoredMatches(vulnerabilityExceptions []string, store *store.Store, packages []pkg.Package, pkgContext pkg.Context) (*match.Matches, []match.IgnoredMatch, error) {
|
||||
func getIgnoredMatches(vulnerabilityExceptions []string, vp vulnerability.Provider, packages []pkg.Package, pkgContext pkg.Context, useDefaultMatchers bool) (*match.Matches, []match.IgnoredMatch, error) {
|
||||
if vulnerabilityExceptions == nil {
|
||||
vulnerabilityExceptions = []string{}
|
||||
}
|
||||
@@ -131,13 +144,13 @@ func getIgnoredMatches(vulnerabilityExceptions []string, store *store.Store, pac
|
||||
ignoreRules = append(ignoreRules, rule)
|
||||
}
|
||||
|
||||
matcher := grype.VulnerabilityMatcher{
|
||||
Store: *store,
|
||||
Matchers: getMatchers(),
|
||||
IgnoreRules: ignoreRules,
|
||||
vulnMatcher := grype.VulnerabilityMatcher{
|
||||
VulnerabilityProvider: vp,
|
||||
Matchers: getMatchers(useDefaultMatchers),
|
||||
IgnoreRules: ignoreRules,
|
||||
}
|
||||
|
||||
remainingMatches, ignoredMatches, err := matcher.FindMatches(packages, pkgContext)
|
||||
remainingMatches, ignoredMatches, err := vulnMatcher.FindMatches(packages, pkgContext)
|
||||
if err != nil {
|
||||
if !errors.Is(err, grypeerr.ErrAboveSeverityThreshold) {
|
||||
return nil, nil, err
|
||||
@@ -147,8 +160,8 @@ func getIgnoredMatches(vulnerabilityExceptions []string, store *store.Store, pac
|
||||
return remainingMatches, ignoredMatches, nil
|
||||
}
|
||||
|
||||
// Filter the remaing matches based on severity exceptions.
|
||||
func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches match.Matches, store *store.Store) match.Matches {
|
||||
// Filter the remaining matches based on severity exceptions.
|
||||
func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches match.Matches, vp vulnerability.Provider) match.Matches {
|
||||
if severityExceptions == nil {
|
||||
return remainingMatches
|
||||
}
|
||||
@@ -156,7 +169,7 @@ func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches
|
||||
filteredMatches := match.NewMatches()
|
||||
|
||||
for m := range remainingMatches.Enumerate() {
|
||||
metadata, err := store.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
|
||||
metadata, err := vp.VulnerabilityMetadata(m.Vulnerability.Reference)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@@ -178,47 +191,73 @@ func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches
|
||||
return filteredMatches
|
||||
}
|
||||
|
||||
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials, vulnerabilityExceptions, severityExceptions []string) (*models.PresenterConfig, error) {
|
||||
store, status, dbCloser, err := NewVulnerabilityDB(s.dbCfg, true)
|
||||
if err = validateDBLoad(err, status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *Service) Scan(_ context.Context, userInput string, creds RegistryCredentials, vulnerabilityExceptions, severityExceptions []string) (*cautils.ImageScanData, error) {
|
||||
packages, pkgContext, sbom, err := pkg.Provide(userInput, getProviderConfig(creds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dbCloser != nil {
|
||||
defer dbCloser.Close()
|
||||
}
|
||||
|
||||
remainingMatches, ignoredMatches, err := getIgnoredMatches(vulnerabilityExceptions, store, packages, pkgContext)
|
||||
remainingMatches, ignoredMatches, err := getIgnoredMatches(vulnerabilityExceptions, s.vp, packages, pkgContext, s.useDefaultMatchers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filteredMatches := filterMatchesBasedOnSeverity(severityExceptions, *remainingMatches, store)
|
||||
filteredMatches := filterMatchesBasedOnSeverity(severityExceptions, *remainingMatches, s.vp)
|
||||
|
||||
pb := models.PresenterConfig{
|
||||
Matches: filteredMatches,
|
||||
IgnoredMatches: ignoredMatches,
|
||||
Packages: packages,
|
||||
Context: pkgContext,
|
||||
MetadataProvider: store,
|
||||
SBOM: sbom,
|
||||
AppConfig: nil,
|
||||
DBStatus: status,
|
||||
pb := cautils.ImageScanData{
|
||||
Context: pkgContext,
|
||||
IgnoredMatches: ignoredMatches,
|
||||
Image: userInput,
|
||||
Matches: filteredMatches,
|
||||
Packages: packages,
|
||||
RemainingMatches: remainingMatches,
|
||||
SBOM: sbom,
|
||||
VulnerabilityProvider: s.vp,
|
||||
}
|
||||
return &pb, nil
|
||||
}
|
||||
|
||||
func NewVulnerabilityDB(cfg db.Config, update bool) (*store.Store, *db.Status, *db.Closer, error) {
|
||||
return grype.LoadVulnerabilityDB(cfg, update)
|
||||
// ExceedsSeverityThreshold returns true if vulnerabilities in the scan results exceed the severity threshold, false otherwise.
|
||||
//
|
||||
// Values equal to the threshold are considered failing, too.
|
||||
func (s *Service) ExceedsSeverityThreshold(severity vulnerability.Severity, matches match.Matches) bool {
|
||||
if severity == vulnerability.UnknownSeverity {
|
||||
return false
|
||||
}
|
||||
for m := range matches.Enumerate() {
|
||||
metadata, err := s.vp.VulnerabilityMetadata(m.Vulnerability.Reference)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if vulnerability.ParseSeverity(metadata.Severity) >= severity {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewScanService(dbCfg db.Config) Service {
|
||||
return Service{dbCfg: dbCfg}
|
||||
func (s *Service) Close() {
|
||||
_ = s.vp.Close()
|
||||
}
|
||||
|
||||
func NewVulnerabilityDB(distCfg distribution.Config, installCfg installation.Config, update bool) (vulnerability.Provider, *vulnerability.ProviderStatus, error) {
|
||||
return grype.LoadVulnerabilityDB(distCfg, installCfg, update)
|
||||
}
|
||||
|
||||
func NewScanService(distCfg distribution.Config, installCfg installation.Config) (*Service, error) {
|
||||
return NewScanServiceWithMatchers(distCfg, installCfg, true)
|
||||
}
|
||||
|
||||
func NewScanServiceWithMatchers(distCfg distribution.Config, installCfg installation.Config, useDefaultMatchers bool) (*Service, error) {
|
||||
vp, status, err := NewVulnerabilityDB(distCfg, installCfg, true)
|
||||
if err = validateDBLoad(err, status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{
|
||||
vp: vp,
|
||||
useDefaultMatchers: useDefaultMatchers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSeverity returns a Grype severity given a severity string
|
||||
|
||||
@@ -1,134 +1,13 @@
|
||||
package imagescan
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/grype/grype/db"
|
||||
grypedb "github.com/anchore/grype/grype/db/v5"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/pkg"
|
||||
"github.com/anchore/grype/grype/presenter/models"
|
||||
"github.com/anchore/grype/grype/vulnerability"
|
||||
syftPkg "github.com/anchore/syft/syft/pkg"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestVulnerabilityAndSeverityExceptions(t *testing.T) {
|
||||
go func() {
|
||||
_ = http.ListenAndServe(":8000", http.FileServer(http.Dir("testdata"))) //nolint:gosec
|
||||
}()
|
||||
dbCfg := db.Config{
|
||||
DBRootDir: path.Join(xdg.CacheHome, "grype-light", "db"),
|
||||
ListingURL: "http://localhost:8000/listing.json",
|
||||
}
|
||||
svc := NewScanService(dbCfg)
|
||||
creds := RegistryCredentials{}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
image string
|
||||
vulnerabilityExceptions []string
|
||||
ignoredLen int
|
||||
severityExceptions []string
|
||||
filteredLen int
|
||||
}{
|
||||
{
|
||||
name: "alpine:3.19.1 without medium vulnerabilities",
|
||||
image: "alpine:3.19.1",
|
||||
ignoredLen: 0,
|
||||
severityExceptions: []string{"MEDIUM"},
|
||||
filteredLen: 0,
|
||||
},
|
||||
{
|
||||
name: "alpine:3.9.6",
|
||||
image: "alpine:3.9.6",
|
||||
vulnerabilityExceptions: []string{"CVE-2020-1971", "CVE-2020-28928", "CVE-2021-23840"},
|
||||
ignoredLen: 6,
|
||||
severityExceptions: []string{"HIGH", "MEDIUM"},
|
||||
filteredLen: 8,
|
||||
},
|
||||
{
|
||||
name: "alpine:3.9.6 with invalid vulnerability and severity exceptions",
|
||||
image: "alpine:3.9.6",
|
||||
vulnerabilityExceptions: []string{"invalid-cve", "CVE-2020-28928", "CVE-2021-23840"},
|
||||
ignoredLen: 4,
|
||||
severityExceptions: []string{"CRITICAL", "MEDIUM", "invalid-severity"},
|
||||
filteredLen: 10,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
store, status, dbCloser, err := NewVulnerabilityDB(svc.dbCfg, true)
|
||||
assert.NoError(t, validateDBLoad(err, status))
|
||||
|
||||
packages, pkgContext, _, err := pkg.Provide(tc.image, getProviderConfig(creds))
|
||||
assert.NoError(t, err)
|
||||
|
||||
if dbCloser != nil {
|
||||
defer dbCloser.Close()
|
||||
}
|
||||
|
||||
remainingMatches, ignoredMatches, err := getIgnoredMatches(tc.vulnerabilityExceptions, store, packages, pkgContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.ignoredLen, len(ignoredMatches))
|
||||
|
||||
filteredMatches := filterMatchesBasedOnSeverity(tc.severityExceptions, *remainingMatches, store)
|
||||
assert.Equal(t, tc.filteredLen, filteredMatches.Count())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// fakeMetaProvider is a test double that fakes an actual MetadataProvider
|
||||
type fakeMetaProvider struct {
|
||||
vulnerabilities map[string]map[string][]grypedb.Vulnerability
|
||||
metadata map[string]map[string]*grypedb.VulnerabilityMetadata
|
||||
}
|
||||
|
||||
func newFakeMetaProvider() *fakeMetaProvider {
|
||||
d := fakeMetaProvider{
|
||||
vulnerabilities: make(map[string]map[string][]grypedb.Vulnerability),
|
||||
metadata: make(map[string]map[string]*grypedb.VulnerabilityMetadata),
|
||||
}
|
||||
d.fillWithData()
|
||||
return &d
|
||||
}
|
||||
func (d *fakeMetaProvider) GetAllVulnerabilityMetadata() (*[]grypedb.VulnerabilityMetadata, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *fakeMetaProvider) GetVulnerabilityMatchExclusion(id string) ([]grypedb.VulnerabilityMatchExclusion, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (d *fakeMetaProvider) GetVulnerabilityMetadata(id, namespace string) (*grypedb.VulnerabilityMetadata, error) {
|
||||
return d.metadata[id][namespace], nil
|
||||
}
|
||||
func (d *fakeMetaProvider) fillWithData() {
|
||||
d.metadata["CVE-2014-fake-1"] = map[string]*grypedb.VulnerabilityMetadata{
|
||||
"debian:distro:debian:8": {
|
||||
ID: "CVE-2014-fake-1",
|
||||
Namespace: "debian:distro:debian:8",
|
||||
Severity: "medium",
|
||||
},
|
||||
}
|
||||
d.vulnerabilities["debian:distro:debian:8"] = map[string][]grypedb.Vulnerability{
|
||||
"neutron": {
|
||||
{
|
||||
PackageName: "neutron",
|
||||
Namespace: "debian:distro:debian:8",
|
||||
VersionConstraint: "< 2014.1.3-6",
|
||||
ID: "CVE-2014-fake-1",
|
||||
VersionFormat: "deb",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSeverity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -218,81 +97,6 @@ func TestIsEmpty(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDefaultDBConfig(t *testing.T) {
|
||||
config, shouldUpdate := NewDefaultDBConfig()
|
||||
assert.NotNil(t, config)
|
||||
assert.Equal(t, true, shouldUpdate)
|
||||
assert.Contains(t, config.DBRootDir, "grypedb")
|
||||
assert.Equal(t, "https://toolbox-data.anchore.io/grype/databases/listing.json", config.ListingURL)
|
||||
}
|
||||
|
||||
func TestValidateDBLoad(t *testing.T) {
|
||||
currentTime := time.Now()
|
||||
tests := []struct {
|
||||
name string
|
||||
loadErr error
|
||||
status *db.Status
|
||||
expectedErrMessage string
|
||||
}{
|
||||
{
|
||||
name: "status nil",
|
||||
loadErr: nil,
|
||||
status: nil,
|
||||
expectedErrMessage: "unable to determine the status of the vulnerability db",
|
||||
},
|
||||
{
|
||||
name: "loadErr nil and status error nil",
|
||||
loadErr: nil,
|
||||
status: &db.Status{
|
||||
Built: currentTime,
|
||||
SchemaVersion: 7,
|
||||
Location: "New Delhi",
|
||||
Checksum: "invalid",
|
||||
Err: nil,
|
||||
},
|
||||
expectedErrMessage: "",
|
||||
},
|
||||
{
|
||||
name: "loadErr nil but status error not nil",
|
||||
loadErr: nil,
|
||||
status: &db.Status{
|
||||
Built: currentTime,
|
||||
SchemaVersion: 7,
|
||||
Location: "New Delhi",
|
||||
Checksum: "invalid",
|
||||
Err: errors.New("Some error"),
|
||||
},
|
||||
expectedErrMessage: "db could not be loaded: Some error",
|
||||
},
|
||||
{
|
||||
name: "loadErr not nil",
|
||||
loadErr: errors.New("Some error"),
|
||||
status: &db.Status{
|
||||
Built: currentTime,
|
||||
SchemaVersion: 7,
|
||||
Location: "New Delhi",
|
||||
Checksum: "invalid",
|
||||
Err: errors.New("Some error"),
|
||||
},
|
||||
expectedErrMessage: "failed to load vulnerability db: Some error",
|
||||
},
|
||||
{
|
||||
name: "load Error, no db status",
|
||||
loadErr: errors.New("Some error"),
|
||||
status: nil,
|
||||
expectedErrMessage: "failed to load vulnerability db: Some error",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateDBLoad(tt.loadErr, tt.status)
|
||||
if err != nil {
|
||||
assert.Equal(t, tt.expectedErrMessage, err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetProviderConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -336,105 +140,53 @@ func TestGetProviderConfig(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewScanService(t *testing.T) {
|
||||
defaultConfig, _ := NewDefaultDBConfig()
|
||||
svc := NewScanService(defaultConfig)
|
||||
assert.Equal(t, defaultConfig, svc.dbCfg)
|
||||
func TestNewScanServiceWithDefaultMatchers(t *testing.T) {
|
||||
// Test the Service struct creation with different useDefaultMatchers values
|
||||
// This test doesn't require a real database
|
||||
|
||||
// Test with default matchers enabled
|
||||
svcWithDefault := &Service{
|
||||
useDefaultMatchers: true,
|
||||
}
|
||||
assert.True(t, svcWithDefault.useDefaultMatchers)
|
||||
|
||||
// Test with default matchers disabled
|
||||
svcWithoutDefault := &Service{
|
||||
useDefaultMatchers: false,
|
||||
}
|
||||
assert.False(t, svcWithoutDefault.useDefaultMatchers)
|
||||
}
|
||||
|
||||
func TestExceedsSeverityThreshold(t *testing.T) {
|
||||
my_matches := match.NewMatches()
|
||||
my_matches.Add(match.Match{
|
||||
Vulnerability: vulnerability.Vulnerability{
|
||||
ID: "CVE-2014-fake-1",
|
||||
Namespace: "debian:distro:debian:8",
|
||||
},
|
||||
Package: pkg.Package{
|
||||
ID: pkg.ID(uuid.NewString()),
|
||||
Name: "the-package",
|
||||
Version: "v0.1",
|
||||
Type: syftPkg.RpmPkg,
|
||||
},
|
||||
Details: match.Details{
|
||||
{
|
||||
Type: match.ExactDirectMatch,
|
||||
},
|
||||
},
|
||||
})
|
||||
my_metadataProvider := db.NewVulnerabilityMetadataProvider(newFakeMetaProvider())
|
||||
func TestNewScanServiceWithMatchers(t *testing.T) {
|
||||
// Test the Service struct creation with different useDefaultMatchers values
|
||||
// This test doesn't require a real database
|
||||
|
||||
type args struct {
|
||||
scanResults *models.PresenterConfig
|
||||
severity vulnerability.Severity
|
||||
// Test with default matchers enabled
|
||||
svcWithDefault := &Service{
|
||||
useDefaultMatchers: true,
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "No severity set",
|
||||
args: args{
|
||||
scanResults: &models.PresenterConfig{
|
||||
Matches: match.NewMatches(),
|
||||
MetadataProvider: nil,
|
||||
},
|
||||
severity: vulnerability.UnknownSeverity,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "No MetadataProvider",
|
||||
args: args{
|
||||
scanResults: &models.PresenterConfig{
|
||||
Matches: my_matches,
|
||||
MetadataProvider: nil,
|
||||
},
|
||||
severity: vulnerability.MediumSeverity,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "Severity higher than vulnerability",
|
||||
args: args{
|
||||
scanResults: &models.PresenterConfig{
|
||||
Matches: my_matches,
|
||||
MetadataProvider: my_metadataProvider,
|
||||
},
|
||||
severity: vulnerability.HighSeverity,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "Severity equal to vulnerability",
|
||||
args: args{
|
||||
scanResults: &models.PresenterConfig{
|
||||
Matches: my_matches,
|
||||
MetadataProvider: my_metadataProvider,
|
||||
},
|
||||
severity: vulnerability.MediumSeverity,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "Fail severity below found vulnerability",
|
||||
args: args{
|
||||
scanResults: &models.PresenterConfig{
|
||||
Matches: my_matches,
|
||||
MetadataProvider: my_metadataProvider,
|
||||
},
|
||||
severity: vulnerability.LowSeverity,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
got := ExceedsSeverityThreshold(tt.args.scanResults, tt.args.severity)
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
assert.True(t, svcWithDefault.useDefaultMatchers)
|
||||
|
||||
// Test with default matchers disabled
|
||||
svcWithoutDefault := &Service{
|
||||
useDefaultMatchers: false,
|
||||
}
|
||||
assert.False(t, svcWithoutDefault.useDefaultMatchers)
|
||||
}
|
||||
|
||||
func TestNewScanServiceWithMatchersIntegration(t *testing.T) {
|
||||
// Test the actual NewScanServiceWithMatchers function
|
||||
distCfg, installCfg, _ := NewDefaultDBConfig()
|
||||
|
||||
// Test with default matchers enabled
|
||||
svcWithDefault, err := NewScanServiceWithMatchers(distCfg, installCfg, true)
|
||||
require.NoError(t, err)
|
||||
defer svcWithDefault.Close()
|
||||
assert.True(t, svcWithDefault.useDefaultMatchers)
|
||||
|
||||
// Test with default matchers disabled
|
||||
svcWithoutDefault, err := NewScanServiceWithMatchers(distCfg, installCfg, false)
|
||||
require.NoError(t, err)
|
||||
defer svcWithoutDefault.Close()
|
||||
assert.False(t, svcWithoutDefault.useDefaultMatchers)
|
||||
}
|
||||
|
||||
12
pkg/imagescan/testdata/listing.json
vendored
12
pkg/imagescan/testdata/listing.json
vendored
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"available": {
|
||||
"5": [
|
||||
{
|
||||
"built": "2023-12-13T01:27:01Z",
|
||||
"version": 5,
|
||||
"url": "http://localhost:8000/vulnerability-db_v5_2023-03-24T06_54_57Z_fab15e5405c096d82dfd.tar.gz",
|
||||
"checksum": "sha256:99ad9fd54be5295351555a02a0fb6986a461a9d23eb8ae3b34ea892c252a8c80"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user