mirror of
https://github.com/kubescape/kubescape.git
synced 2026-03-03 02:00:27 +00:00
Compare commits
126 Commits
v3.0.25-rc
...
v3.0.38-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c7422355 | ||
|
|
e41b5d77a0 | ||
|
|
5afaae8847 | ||
|
|
011fc0689d | ||
|
|
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 | ||
|
|
b37c20aed9 | ||
|
|
3de8204c43 | ||
|
|
d5bd3708b8 | ||
|
|
2bd686131e | ||
|
|
1ea4e0c304 | ||
|
|
b3251306d0 | ||
|
|
91ecdaba4e | ||
|
|
fa05dcd00d | ||
|
|
1c2c928732 | ||
|
|
69ac490006 | ||
|
|
b67b9f3af2 | ||
|
|
628ed4a374 | ||
|
|
a6fe34b466 | ||
|
|
2e9406d96a | ||
|
|
6b1bf07f7f | ||
|
|
318c2c7ae6 | ||
|
|
45f60b6fe0 | ||
|
|
20557bc721 | ||
|
|
d8bfb27bc3 | ||
|
|
9776691816 | ||
|
|
80e419df24 | ||
|
|
143f831f5b | ||
|
|
a4897304e8 | ||
|
|
80d1165e2c | ||
|
|
31ed7d5160 | ||
|
|
d62e9ce207 | ||
|
|
3b10443ff5 | ||
|
|
218e3914b1 | ||
|
|
2b07fbe782 | ||
|
|
0655d0496b | ||
|
|
02bf31fbc9 | ||
|
|
4d8a3f51e3 | ||
|
|
43d29f7b8b | ||
|
|
ee0d4cba98 | ||
|
|
d860c0234a | ||
|
|
f13ded61bf | ||
|
|
fe8fc700f4 | ||
|
|
47b670637b | ||
|
|
97c83a652b | ||
|
|
a089831720 | ||
|
|
e4f1720a0c | ||
|
|
233eb2134c | ||
|
|
06da926455 | ||
|
|
37f6193fe0 | ||
|
|
27ac036b7d | ||
|
|
321d335b39 | ||
|
|
91b7d8fc2b | ||
|
|
2b28911db0 | ||
|
|
667e5e8258 | ||
|
|
728b341048 | ||
|
|
75b295d579 | ||
|
|
75298eabf2 | ||
|
|
2458f2ceb9 | ||
|
|
f57948ad97 | ||
|
|
d0befc5f16 | ||
|
|
5d4bd2e94e | ||
|
|
ae37fdc295 | ||
|
|
3dd95ff3a3 | ||
|
|
daadb5b804 | ||
|
|
d250017faf | ||
|
|
835bcbeb12 | ||
|
|
2e4f7c4477 | ||
|
|
66bf93eb0c | ||
|
|
3a036ed0e3 | ||
|
|
fe7dad4560 | ||
|
|
fb36b09f3a | ||
|
|
e71b0c75a9 | ||
|
|
d615099ce1 | ||
|
|
f265b91939 | ||
|
|
825694ade1 | ||
|
|
979a30aea7 | ||
|
|
39c4aa4faa | ||
|
|
475b672a7a | ||
|
|
815c87b532 | ||
|
|
82120f9d31 | ||
|
|
0545818f82 | ||
|
|
046da1940c | ||
|
|
a31154897f | ||
|
|
199c57be30 | ||
|
|
7d55c79f11 | ||
|
|
ee76364371 | ||
|
|
4f2c7ac1de | ||
|
|
00340827be | ||
|
|
708fe64240 | ||
|
|
8985bbe3a9 | ||
|
|
1ffca5648e | ||
|
|
76b1ecb022 | ||
|
|
fc69a3692e | ||
|
|
e159458129 | ||
|
|
b259f117ff | ||
|
|
13cf34bffd | ||
|
|
0300fee38b |
5
.github/workflows/00-pr-scanner.yaml
vendored
5
.github/workflows/00-pr-scanner.yaml
vendored
@@ -1,6 +1,7 @@
|
||||
name: 00-pr_scanner
|
||||
permissions: read-all
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
paths-ignore:
|
||||
@@ -26,6 +27,7 @@ jobs:
|
||||
deployments: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
discussions: read
|
||||
packages: read
|
||||
pages: read
|
||||
@@ -53,6 +55,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: write
|
||||
pages: read
|
||||
pull-requests: read
|
||||
@@ -65,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
@@ -23,6 +23,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: write
|
||||
pages: read
|
||||
pull-requests: read
|
||||
@@ -37,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
|
||||
@@ -50,6 +51,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: read
|
||||
pages: read
|
||||
pull-requests: read
|
||||
@@ -72,6 +74,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: write
|
||||
pages: read
|
||||
pull-requests: read
|
||||
@@ -97,6 +100,7 @@ jobs:
|
||||
discussions: read
|
||||
id-token: write
|
||||
issues: read
|
||||
models: read
|
||||
packages: write
|
||||
pages: read
|
||||
pull-requests: read
|
||||
|
||||
10
.github/workflows/a-pr-scanner.yaml
vendored
10
.github/workflows/a-pr-scanner.yaml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
- uses: anchore/sbom-action/download-syft@v0.15.2
|
||||
name: Setup Syft
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v5
|
||||
- uses: goreleaser/goreleaser-action@v6
|
||||
name: Build
|
||||
with:
|
||||
distribution: goreleaser
|
||||
@@ -92,7 +92,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
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
if: ${{ env.GITGUARDIAN_API_KEY }}
|
||||
continue-on-error: true
|
||||
id: credentials-scan
|
||||
uses: GitGuardian/ggshield-action@4ab2994172fadab959240525e6b833d9ae3aca61 # ratchet:GitGuardian/ggshield-action@master
|
||||
uses: GitGuardian/ggshield-action@master
|
||||
with:
|
||||
args: -v --all-policies
|
||||
env:
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
if: ${{ env.SNYK_TOKEN }}
|
||||
id: vulnerabilities-scan
|
||||
continue-on-error: true
|
||||
uses: snyk/actions/golang@806182742461562b67788a64410098c9d9b96adb # ratchet:snyk/actions/golang@master
|
||||
uses: snyk/actions/golang@master
|
||||
with:
|
||||
command: test --all-projects
|
||||
env:
|
||||
@@ -140,7 +140,7 @@ jobs:
|
||||
|
||||
- name: Comment results to PR
|
||||
continue-on-error: true # Warning: This might break opening PRs from forks
|
||||
uses: peter-evans/create-or-update-comment@5adcb0bb0f9fb3f95ef05400558bdb3f329ee808 # ratchet:peter-evans/create-or-update-comment@v2.1.0
|
||||
uses: peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
|
||||
@@ -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
|
||||
@@ -181,13 +181,13 @@ jobs:
|
||||
- name: (debug) Step 5 - Check disk space before setting up Syft
|
||||
run: df -h
|
||||
|
||||
- uses: anchore/sbom-action/download-syft@v0.15.2
|
||||
- uses: anchore/sbom-action/download-syft@v0
|
||||
name: Setup Syft
|
||||
|
||||
- name: (debug) Step 6 - Check disk space before goreleaser
|
||||
run: df -h
|
||||
|
||||
- uses: goreleaser/goreleaser-action@v5
|
||||
- uses: goreleaser/goreleaser-action@v6
|
||||
name: Build
|
||||
with:
|
||||
distribution: goreleaser
|
||||
@@ -227,7 +227,7 @@ jobs:
|
||||
name: Upload artifacts
|
||||
with:
|
||||
name: kubescape
|
||||
path: dist/kubescape*
|
||||
path: dist/*
|
||||
if-no-files-found: error
|
||||
|
||||
- name: (debug) Step 10 - Check disk space after uploading artifacts
|
||||
@@ -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",
|
||||
@@ -289,7 +289,7 @@ jobs:
|
||||
if: ${{ (needs.wf-preparation.outputs.is-secret-set == 'true') && (always() && (contains(needs.*.result, 'success') || contains(needs.*.result, 'skipped')) && !(contains(needs.*.result, 'failure')) && !(contains(needs.*.result, 'cancelled'))) }}
|
||||
runs-on: ubuntu-latest # This cannot change
|
||||
steps:
|
||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
|
||||
- uses: actions/download-artifact@v4
|
||||
id: download-artifact
|
||||
with:
|
||||
name: kubescape
|
||||
@@ -306,7 +306,7 @@ jobs:
|
||||
repository: armosec/system-tests
|
||||
path: .
|
||||
|
||||
- uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # ratchet:actions/setup-python@v4
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.8.13'
|
||||
cache: 'pip'
|
||||
@@ -351,7 +351,7 @@ jobs:
|
||||
deactivate
|
||||
|
||||
- name: Test Report
|
||||
uses: mikepenz/action-junit-report@6e9933f4a97f4d2b99acef4d7b97924466037882 # ratchet:mikepenz/action-junit-report@v3.6.1
|
||||
uses: mikepenz/action-junit-report@v5
|
||||
if: always() # always run even if the previous step fails
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
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
|
||||
|
||||
59
.github/workflows/c-create-release.yaml
vendored
59
.github/workflows/c-create-release.yaml
vendored
@@ -27,14 +27,15 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
|
||||
- uses: actions/download-artifact@v4
|
||||
id: download-artifact
|
||||
with:
|
||||
name: kubescape
|
||||
path: .
|
||||
|
||||
# TODO: kubescape-windows-latest is deprecated and should be removed
|
||||
- name: Get kubescape.exe from kubescape-windows-latest.exe
|
||||
run: cp ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-${{ env.WINDOWS_OS }}.exe ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape.exe
|
||||
run: cp ${{steps.download-artifact.outputs.download-path}}/kubescape-${{ env.WINDOWS_OS }}.exe ${{steps.download-artifact.outputs.download-path}}/kubescape.exe
|
||||
|
||||
- name: Set release token
|
||||
id: set-token
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
find . -type f -print
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
token: ${{ steps.set-token.outputs.token }}
|
||||
name: ${{ inputs.RELEASE_NAME }}
|
||||
@@ -60,32 +61,26 @@ jobs:
|
||||
prerelease: false
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
./kubescape/kubescape-${{ env.MAC_OS }}
|
||||
./kubescape/kubescape-${{ env.MAC_OS }}.sbom
|
||||
./kubescape/kubescape-${{ env.MAC_OS }}.sha256
|
||||
./kubescape/kubescape-${{ env.MAC_OS }}.tar.gz
|
||||
./kubescape/kubescape-${{ env.UBUNTU_OS }}
|
||||
./kubescape/kubescape-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape/kubescape-${{ env.UBUNTU_OS }}.sha256
|
||||
./kubescape/kubescape-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe
|
||||
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe.sbom
|
||||
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe.sha256
|
||||
./kubescape/kubescape-${{ env.WINDOWS_OS }}.tar.gz
|
||||
./kubescape/kubescape-arm64-${{ env.MAC_OS }}
|
||||
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.sbom
|
||||
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.sha256
|
||||
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.tar.gz
|
||||
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}
|
||||
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.sha256
|
||||
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe
|
||||
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sbom
|
||||
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sha256
|
||||
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.tar.gz
|
||||
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}
|
||||
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.sha256
|
||||
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape/kubescape.exe
|
||||
./checksums.sha256
|
||||
./kubescape-${{ env.MAC_OS }}
|
||||
./kubescape-${{ env.MAC_OS }}.sbom
|
||||
./kubescape-${{ env.MAC_OS }}.tar.gz
|
||||
./kubescape-${{ env.UBUNTU_OS }}
|
||||
./kubescape-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape-${{ env.WINDOWS_OS }}.exe
|
||||
./kubescape-${{ env.WINDOWS_OS }}.exe.sbom
|
||||
./kubescape-${{ env.WINDOWS_OS }}.tar.gz
|
||||
./kubescape-arm64-${{ env.MAC_OS }}
|
||||
./kubescape-arm64-${{ env.MAC_OS }}.sbom
|
||||
./kubescape-arm64-${{ env.MAC_OS }}.tar.gz
|
||||
./kubescape-arm64-${{ env.UBUNTU_OS }}
|
||||
./kubescape-arm64-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape-arm64-${{ env.WINDOWS_OS }}.exe
|
||||
./kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sbom
|
||||
./kubescape-arm64-${{ env.WINDOWS_OS }}.tar.gz
|
||||
./kubescape-riscv64-${{ env.UBUNTU_OS }}
|
||||
./kubescape-riscv64-${{ env.UBUNTU_OS }}.sbom
|
||||
./kubescape-riscv64-${{ env.UBUNTU_OS }}.tar.gz
|
||||
./kubescape.exe
|
||||
|
||||
13
.github/workflows/d-publish-image.yaml
vendored
13
.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
|
||||
@@ -63,22 +64,21 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # ratchet:docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # ratchet:docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Quay.io
|
||||
env:
|
||||
QUAY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
|
||||
QUAY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
|
||||
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
|
||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
|
||||
- uses: actions/download-artifact@v4
|
||||
id: download-artifact
|
||||
with:
|
||||
name: kubescape
|
||||
path: .
|
||||
- name: mv kubescape amd64 binary
|
||||
run: mv ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-ubuntu-latest kubescape-amd64-ubuntu-latest
|
||||
- name: mv kubescape arm64 binary
|
||||
run: mv ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-arm64-ubuntu-latest kubescape-arm64-ubuntu-latest
|
||||
run: mv kubescape-ubuntu-latest kubescape-amd64-ubuntu-latest
|
||||
- name: chmod +x
|
||||
run: chmod +x -v kubescape-a*
|
||||
- name: Build and push images
|
||||
@@ -106,4 +106,3 @@ jobs:
|
||||
# Verify the image
|
||||
echo "$COSIGN_PUBLIC_KEY" > cosign.pub
|
||||
cosign verify -key cosign.pub ${{ inputs.image_name }}:${{ inputs.image_tag }}
|
||||
|
||||
|
||||
8
.github/workflows/scorecard.yml
vendored
8
.github/workflows/scorecard.yml
vendored
@@ -32,12 +32,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -67,6 +67,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
4
.github/workflows/z-close-typos-issues.yaml
vendored
4
.github/workflows/z-close-typos-issues.yaml
vendored
@@ -7,14 +7,14 @@ jobs:
|
||||
if: github.event.label.name == 'typo'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: ben-z/actions-comment-on-issue@10be23f9c43ac792663043420fda29dde07e2f0f # ratchet:ben-z/actions-comment-on-issue@1.0.2
|
||||
- uses: ben-z/actions-comment-on-issue@1.0.2
|
||||
with:
|
||||
message: "Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
auto_close_issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: lee-dohm/close-matching-issues@e9e43aad2fa6f06a058cedfd8fb975fd93b56d8f # ratchet:lee-dohm/close-matching-issues@v2
|
||||
- uses: lee-dohm/close-matching-issues@v2
|
||||
with:
|
||||
query: 'label:typo'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
# This is an example .goreleaser.yml file with some sensible defaults.
|
||||
# Make sure to check the documentation at https://goreleaser.com
|
||||
|
||||
# The lines bellow are called `modelines`. See `:help modeline`
|
||||
# The lines below are called `modelines`. See `:help modeline`
|
||||
# Feel free to remove those if you don't want/need to use them.
|
||||
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
# You may remove this if you don't use go modules.
|
||||
- go mod tidy
|
||||
|
||||
archives:
|
||||
- id: binaries
|
||||
formats:
|
||||
- binary
|
||||
name_template: >-
|
||||
{{ .Binary }}
|
||||
- id: default
|
||||
formats:
|
||||
- tar.gz
|
||||
name_template: >-
|
||||
{{ .Binary }}
|
||||
|
||||
builds:
|
||||
- goos:
|
||||
- linux
|
||||
@@ -33,15 +46,6 @@ builds:
|
||||
{{- else }}{{ .Os }}{{ end }}-latest
|
||||
no_unique_dist_dir: true
|
||||
|
||||
archives:
|
||||
- format: binary
|
||||
id: binaries
|
||||
name_template: >-
|
||||
{{ .Binary }}
|
||||
- format: tar.gz
|
||||
name_template: >-
|
||||
{{ .Binary }}
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
@@ -50,9 +54,7 @@ changelog:
|
||||
- "^test:"
|
||||
|
||||
checksum:
|
||||
ids:
|
||||
- binaries
|
||||
split: true
|
||||
name_template: "checksums.sha256"
|
||||
|
||||
sboms:
|
||||
- artifacts: binary
|
||||
|
||||
@@ -112,7 +112,7 @@ Kubescape changes are tracked on the [release](https://github.com/kubescape/kube
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2021-2024, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
||||
Copyright 2021-2025, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
|
||||
|
||||
Kubescape is a [Cloud Native Computing Foundation (CNCF) incubating project](https://www.cncf.io/projects/kubescape/) and was contributed by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository).
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
@@ -15,7 +13,7 @@ func getDeleteCmd(ks meta.IKubescape) *cobra.Command {
|
||||
Short: "Delete cached configurations",
|
||||
Long: ``,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := ks.DeleteCachedConfig(context.TODO(), &v1.DeleteConfig{}); err != nil {
|
||||
if err := ks.DeleteCachedConfig(&v1.DeleteConfig{}); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
@@ -74,11 +73,9 @@ func GetDownloadCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
downloadInfo.Target = args[0]
|
||||
if len(args) >= 2 {
|
||||
|
||||
downloadInfo.Identifier = args[1]
|
||||
|
||||
}
|
||||
if err := ks.Download(context.TODO(), &downloadInfo); err != nil {
|
||||
if err := ks.Download(&downloadInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package fix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -35,7 +34,7 @@ func GetFixCmd(ks meta.IKubescape) *cobra.Command {
|
||||
}
|
||||
fixInfo.ReportFile = args[0]
|
||||
|
||||
return ks.Fix(context.TODO(), &fixInfo)
|
||||
return ks.Fix(&fixInfo)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
@@ -27,7 +26,7 @@ var (
|
||||
%[1]s list controls
|
||||
|
||||
Control documentation:
|
||||
https://hub.armosec.io/docs/controls
|
||||
https://kubescape.io/docs/controls/
|
||||
`, cautils.ExecName())
|
||||
)
|
||||
|
||||
@@ -62,7 +61,7 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
listPolicies.Target = args[0]
|
||||
|
||||
if err := ks.List(context.TODO(), &listPolicies); err != nil {
|
||||
if err := ks.List(&listPolicies); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
return nil
|
||||
|
||||
466
cmd/mcpserver/mcpserver.go
Normal file
466
cmd/mcpserver/mcpserver.go
Normal file
@@ -0,0 +1,466 @@
|
||||
package mcpserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kubescape/go-logger"
|
||||
helpersv1 "github.com/kubescape/k8s-interface/instanceidhandler/v1/helpers"
|
||||
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
|
||||
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
"github.com/mark3labs/mcp-go/server"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type KubescapeMcpserver struct {
|
||||
s *server.MCPServer
|
||||
ksClient spdxv1beta1.SpdxV1beta1Interface
|
||||
}
|
||||
|
||||
func createVulnerabilityToolsAndResources(ksServer *KubescapeMcpserver) {
|
||||
// Tool to list vulnerability manifests
|
||||
listManifestsTool := mcp.NewTool(
|
||||
"list_vulnerability_manifests",
|
||||
mcp.WithDescription("Discover available vulnerability manifests at image and workload levels"),
|
||||
mcp.WithString("namespace",
|
||||
mcp.Description("Filter by namespace (optional)"),
|
||||
),
|
||||
mcp.WithString("level",
|
||||
mcp.Description("Type of vulnerability manifests to list"),
|
||||
mcp.Enum("image", "workload", "both"),
|
||||
),
|
||||
)
|
||||
|
||||
ksServer.s.AddTool(listManifestsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return ksServer.CallTool("list_vulnerability_manifests", request.Params.Arguments.(map[string]interface{}))
|
||||
})
|
||||
|
||||
listVulnerabilitiesTool := mcp.NewTool(
|
||||
"list_vulnerabilities_in_manifest",
|
||||
mcp.WithDescription("List all vulnerabilities in a given manifest"),
|
||||
mcp.WithString("namespace",
|
||||
mcp.Description("Filter by namespace (optional)"),
|
||||
),
|
||||
mcp.WithString("manifest_name",
|
||||
mcp.Required(),
|
||||
mcp.Description("Name of the manifest to list vulnerabilities from"),
|
||||
),
|
||||
)
|
||||
|
||||
ksServer.s.AddTool(listVulnerabilitiesTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return ksServer.CallTool("list_vulnerabilities_in_manifest", request.Params.Arguments.(map[string]interface{}))
|
||||
})
|
||||
|
||||
listVulnerabilityMatchesForCVE := mcp.NewTool(
|
||||
"list_vulnerability_matches_for_cve",
|
||||
mcp.WithDescription("List all vulnerability matches for a given CVE in a given manifest"),
|
||||
mcp.WithString("namespace",
|
||||
mcp.Description("Filter by namespace (optional)"),
|
||||
),
|
||||
mcp.WithString("manifest_name",
|
||||
mcp.Required(),
|
||||
mcp.Description("Name of the manifest to list vulnerabilities from"),
|
||||
),
|
||||
mcp.WithString("cve_id",
|
||||
mcp.Required(),
|
||||
mcp.Description("ID of the CVE to list matches for"),
|
||||
),
|
||||
)
|
||||
|
||||
ksServer.s.AddTool(listVulnerabilityMatchesForCVE, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return ksServer.CallTool("list_vulnerability_matches_for_cve", request.Params.Arguments.(map[string]interface{}))
|
||||
})
|
||||
|
||||
vulnerabilityManifestTemplate := mcp.NewResourceTemplate(
|
||||
"kubescape://vulnerability-manifests/{namespace}/{manifest_name}",
|
||||
"Vulnerability Manifest",
|
||||
mcp.WithTemplateDescription("Complete vulnerability manifest either for a specific workload or image. Use 'list_vulnerability_manifests' tool to discover available manifests."),
|
||||
mcp.WithTemplateMIMEType("application/json"),
|
||||
)
|
||||
|
||||
ksServer.s.AddResourceTemplate(vulnerabilityManifestTemplate, ksServer.ReadResource)
|
||||
|
||||
}
|
||||
|
||||
func createConfigurationsToolsAndResources(ksServer *KubescapeMcpserver) {
|
||||
// Tool to list configuration manifests
|
||||
listConfigsTool := mcp.NewTool(
|
||||
"list_configuration_security_scan_manifests",
|
||||
mcp.WithDescription("Discover available security configuration scan results at workload level (this returns a list of manifests, not the scan results themselves, to get the scan results, use the get_configuration_security_scan_manifest tool)"),
|
||||
mcp.WithString("namespace",
|
||||
mcp.Description("Filter by namespace (optional)"),
|
||||
),
|
||||
)
|
||||
|
||||
ksServer.s.AddTool(listConfigsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return ksServer.CallTool("list_configuration_security_scan_manifests", request.Params.Arguments.(map[string]interface{}))
|
||||
})
|
||||
|
||||
getConfigDetailsTool := mcp.NewTool(
|
||||
"get_configuration_security_scan_manifest",
|
||||
mcp.WithDescription("Get details of a specific security configuration scan result"),
|
||||
mcp.WithString("namespace",
|
||||
mcp.Description("Namespace of the manifest (optional, defaults to 'kubescape')"),
|
||||
),
|
||||
mcp.WithString("manifest_name",
|
||||
mcp.Required(),
|
||||
mcp.Description("Name of the configuration manifest to get details for (get this from the list_configuration_security_scan_manifests tool)"),
|
||||
),
|
||||
)
|
||||
|
||||
ksServer.s.AddTool(getConfigDetailsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return ksServer.CallTool("get_configuration_security_scan_manifest", request.Params.Arguments.(map[string]interface{}))
|
||||
})
|
||||
|
||||
configManifestTemplate := mcp.NewResourceTemplate(
|
||||
"kubescape://configuration-manifests/{namespace}/{manifest_name}",
|
||||
"Configuration Security Scan Manifest",
|
||||
mcp.WithTemplateDescription("Complete configuration scan manifest for a specific workload. Use 'list_configuration_security_scan_manifests' tool to discover available manifests."),
|
||||
mcp.WithTemplateMIMEType("application/json"),
|
||||
)
|
||||
|
||||
ksServer.s.AddResourceTemplate(configManifestTemplate, ksServer.ReadConfigurationResource)
|
||||
}
|
||||
|
||||
func (ksServer *KubescapeMcpserver) ReadResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
|
||||
uri := request.Params.URI
|
||||
// Validate the URI and check if it starts with kubescape://vulnerability-manifests/
|
||||
if !strings.HasPrefix(uri, "kubescape://vulnerability-manifests/") {
|
||||
return nil, fmt.Errorf("invalid URI: %s", uri)
|
||||
}
|
||||
|
||||
// Verify that the URI is either the CVE list or CVE details
|
||||
if !strings.HasSuffix(uri, "/cve_list") && !strings.Contains(uri, "/cve_details/") {
|
||||
return nil, fmt.Errorf("invalid URI: %s", uri)
|
||||
}
|
||||
|
||||
// Split the URI into namespace and manifest name
|
||||
parts := strings.Split(uri, "/")
|
||||
if len(parts) != 4 && len(parts) != 5 {
|
||||
return nil, fmt.Errorf("invalid URI: %s", uri)
|
||||
}
|
||||
|
||||
namespace := parts[1]
|
||||
manifestName := parts[2]
|
||||
cveID := ""
|
||||
if len(parts) == 5 {
|
||||
cveID = parts[3]
|
||||
}
|
||||
|
||||
// Get the vulnerability manifest
|
||||
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace).Get(ctx, manifestName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
|
||||
}
|
||||
|
||||
var responseJson []byte
|
||||
if cveID == "" {
|
||||
// CVE list
|
||||
var cveList []v1beta1.Vulnerability
|
||||
for _, match := range manifest.Spec.Payload.Matches {
|
||||
cveList = append(cveList, match.Vulnerability)
|
||||
}
|
||||
responseJson, err = json.Marshal(cveList)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal cve list: %s", err)
|
||||
}
|
||||
} else {
|
||||
// CVE details
|
||||
var match []v1beta1.Match
|
||||
for _, m := range manifest.Spec.Payload.Matches {
|
||||
if m.Vulnerability.ID == cveID {
|
||||
match = append(match, m)
|
||||
}
|
||||
}
|
||||
responseJson, err = json.Marshal(match)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal cve details: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return []mcp.ResourceContents{mcp.TextResourceContents{
|
||||
URI: uri,
|
||||
Text: string(responseJson),
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (ksServer *KubescapeMcpserver) ReadConfigurationResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
|
||||
uri := request.Params.URI
|
||||
if !strings.HasPrefix(uri, "kubescape://configuration-manifests/") {
|
||||
return nil, fmt.Errorf("invalid URI: %s", uri)
|
||||
}
|
||||
parts := strings.Split(uri[len("kubescape://configuration-manifests/"):], "/")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid URI: %s", uri)
|
||||
}
|
||||
namespace := parts[0]
|
||||
manifestName := parts[1]
|
||||
manifest, err := ksServer.ksClient.WorkloadConfigurationScans(namespace).Get(ctx, manifestName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get configuration manifest: %s", err)
|
||||
}
|
||||
responseJson, err := json.Marshal(manifest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal configuration manifest: %s", err)
|
||||
}
|
||||
return []mcp.ResourceContents{mcp.TextResourceContents{
|
||||
URI: uri,
|
||||
Text: string(responseJson),
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (ksServer *KubescapeMcpserver) CallTool(name string, arguments map[string]interface{}) (*mcp.CallToolResult, error) {
|
||||
switch name {
|
||||
case "list_vulnerability_manifests":
|
||||
//namespace, ok := arguments["namespace"]
|
||||
//if !ok {
|
||||
// namespace = ""
|
||||
//}
|
||||
level, ok := arguments["level"]
|
||||
if !ok {
|
||||
level = "both"
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"vulnerability_manifests": map[string]interface{}{},
|
||||
}
|
||||
|
||||
// Get workload-level manifests
|
||||
labelSelector := ""
|
||||
if level == "workload" {
|
||||
labelSelector = "kubescape.io/context=filtered"
|
||||
} else if level == "image" {
|
||||
labelSelector = "kubescape.io/context=non-filtered"
|
||||
}
|
||||
|
||||
var manifests *v1beta1.VulnerabilityManifestList
|
||||
var err error
|
||||
if labelSelector == "" {
|
||||
manifests, err = ksServer.ksClient.VulnerabilityManifests(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{})
|
||||
} else {
|
||||
manifests, err = ksServer.ksClient.VulnerabilityManifests(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{
|
||||
LabelSelector: labelSelector,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Printf("Found %d manifests", len(manifests.Items))
|
||||
|
||||
vulnerabilityManifests := []map[string]interface{}{}
|
||||
for _, manifest := range manifests.Items {
|
||||
isImageLevel := manifest.Annotations[helpersv1.WlidMetadataKey] == ""
|
||||
manifestMap := map[string]interface{}{
|
||||
"type": "workload",
|
||||
"namespace": manifest.Namespace,
|
||||
"manifest_name": manifest.Name,
|
||||
"image-level": isImageLevel,
|
||||
"workload-level": !isImageLevel,
|
||||
"image-id": manifest.Annotations[helpersv1.ImageIDMetadataKey],
|
||||
"image-tag": manifest.Annotations[helpersv1.ImageTagMetadataKey],
|
||||
"workload-id": manifest.Annotations[helpersv1.WlidMetadataKey],
|
||||
"workload-container-name": manifest.Annotations[helpersv1.ContainerNameMetadataKey],
|
||||
"resource_uri": fmt.Sprintf("kubescape://vulnerability-manifests/%s/%s",
|
||||
manifest.Namespace, manifest.Name),
|
||||
}
|
||||
vulnerabilityManifests = append(vulnerabilityManifests, manifestMap)
|
||||
}
|
||||
result["vulnerability_manifests"].(map[string]interface{})["manifests"] = vulnerabilityManifests
|
||||
|
||||
// Add template information
|
||||
result["available_templates"] = map[string]string{
|
||||
"vulnerability_manifest_cve_list": "kubescape://vulnerability-manifests/{namespace}/{manifest_name}/cve_list",
|
||||
"vulnerability_manifest_cve_details": "kubescape://vulnerability-manifests/{namespace}/{manifest_name}/cve_details/{cve_id}",
|
||||
}
|
||||
|
||||
content, _ := json.Marshal(result)
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(content),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "list_vulnerabilities_in_manifest":
|
||||
namespace, ok := arguments["namespace"]
|
||||
if !ok {
|
||||
namespace = "kubescape"
|
||||
}
|
||||
manifestName, ok := arguments["manifest_name"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("manifest_name is required")
|
||||
}
|
||||
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
|
||||
}
|
||||
var cveList []v1beta1.Vulnerability
|
||||
for _, match := range manifest.Spec.Payload.Matches {
|
||||
cveList = append(cveList, match.Vulnerability)
|
||||
}
|
||||
responseJson, err := json.Marshal(cveList)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal cve list: %s", err)
|
||||
}
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(responseJson),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "list_vulnerability_matches_for_cve":
|
||||
namespace, ok := arguments["namespace"]
|
||||
if !ok {
|
||||
namespace = "kubescape"
|
||||
}
|
||||
manifestName, ok := arguments["manifest_name"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("manifest_name is required")
|
||||
}
|
||||
cveID, ok := arguments["cve_id"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cve_id is required")
|
||||
}
|
||||
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
|
||||
}
|
||||
var match []v1beta1.Match
|
||||
for _, m := range manifest.Spec.Payload.Matches {
|
||||
if m.Vulnerability.ID == cveID.(string) {
|
||||
match = append(match, m)
|
||||
}
|
||||
}
|
||||
responseJson, err := json.Marshal(match)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal cve details: %s", err)
|
||||
}
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(responseJson),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "list_configuration_security_scan_manifests":
|
||||
namespace, ok := arguments["namespace"]
|
||||
if !ok {
|
||||
namespace = "kubescape"
|
||||
}
|
||||
manifests, err := ksServer.ksClient.WorkloadConfigurationScans(namespace.(string)).List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("Found %d configuration manifests", len(manifests.Items))
|
||||
configManifests := []map[string]interface{}{}
|
||||
for _, manifest := range manifests.Items {
|
||||
item := map[string]interface{}{
|
||||
"namespace": manifest.Namespace,
|
||||
"manifest_name": manifest.Name,
|
||||
"resource_uri": fmt.Sprintf("kubescape://configuration-manifests/%s/%s", manifest.Namespace, manifest.Name),
|
||||
}
|
||||
configManifests = append(configManifests, item)
|
||||
}
|
||||
result := map[string]interface{}{
|
||||
"configuration_manifests": map[string]interface{}{
|
||||
"manifests": configManifests,
|
||||
},
|
||||
"available_templates": map[string]string{
|
||||
"configuration_manifest_details": "kubescape://configuration-manifests/{namespace}/{manifest_name}",
|
||||
},
|
||||
}
|
||||
content, _ := json.Marshal(result)
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(content),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "get_configuration_security_scan_manifest":
|
||||
namespace, ok := arguments["namespace"]
|
||||
if !ok {
|
||||
namespace = "kubescape"
|
||||
}
|
||||
manifestName, ok := arguments["manifest_name"]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("manifest_name is required")
|
||||
}
|
||||
manifest, err := ksServer.ksClient.WorkloadConfigurationScans(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get configuration manifest: %s", err)
|
||||
}
|
||||
responseJson, err := json.Marshal(manifest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal configuration manifest: %s", err)
|
||||
}
|
||||
return &mcp.CallToolResult{
|
||||
Content: []mcp.Content{
|
||||
mcp.TextContent{
|
||||
Type: "text",
|
||||
Text: string(responseJson),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown tool: %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func mcpServerEntrypoint() error {
|
||||
logger.L().Info("Starting MCP server...")
|
||||
|
||||
// Create a kubernetes client and verify it's working
|
||||
client, err := CreateKsObjectConnection("default", 10*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create kubernetes client: %v", err)
|
||||
}
|
||||
|
||||
// Create a new MCP server
|
||||
s := server.NewMCPServer(
|
||||
"Kubescape MCP Server",
|
||||
"0.0.1",
|
||||
server.WithToolCapabilities(false),
|
||||
server.WithRecovery(),
|
||||
)
|
||||
|
||||
ksServer := &KubescapeMcpserver{
|
||||
s: s,
|
||||
ksClient: client,
|
||||
}
|
||||
|
||||
// Creating Kubescape tools and resources
|
||||
|
||||
createVulnerabilityToolsAndResources(ksServer)
|
||||
createConfigurationsToolsAndResources(ksServer)
|
||||
|
||||
// Start the server
|
||||
if err := server.ServeStdio(s); err != nil {
|
||||
return fmt.Errorf("Server error: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetMCPServerCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "mcpserver",
|
||||
Short: "Start the Kubescape MCP server",
|
||||
Long: `Start the Kubescape MCP server`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return mcpServerEntrypoint()
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
14
cmd/mcpserver/storage.go
Normal file
14
cmd/mcpserver/storage.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package mcpserver
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/pkg/ksinit"
|
||||
|
||||
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
|
||||
)
|
||||
|
||||
// CreateKsObjectConnection delegates to the shared ksinit package
|
||||
func CreateKsObjectConnection(namespace string, maxElapsedTime time.Duration) (spdxv1beta1.SpdxV1beta1Interface, error) {
|
||||
return ksinit.CreateKsObjectConnection(namespace, maxElapsedTime)
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
package patch
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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"
|
||||
@@ -50,7 +49,7 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
results, err := ks.Patch(context.Background(), &patchInfo, &scanInfo)
|
||||
results, err := ks.Patch(&patchInfo, &scanInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package patch
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/mocks"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -50,3 +52,18 @@ func TestGetPatchCmdWithNonExistentImage(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, expectedErrorMessage, err.Error())
|
||||
}
|
||||
|
||||
func Test_validateImagePatchInfo_EmptyImage(t *testing.T) {
|
||||
patchInfo := &metav1.PatchInfo{}
|
||||
err := validateImagePatchInfo(patchInfo)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "image tag is required", err.Error())
|
||||
}
|
||||
|
||||
func Test_validateImagePatchInfo_Image(t *testing.T) {
|
||||
patchInfo := &metav1.PatchInfo{
|
||||
Image: "testing",
|
||||
}
|
||||
err := validateImagePatchInfo(patchInfo)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,51 @@
|
||||
package prerequisites
|
||||
|
||||
import (
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
"github.com/kubescape/sizing-checker/pkg/sizingchecker"
|
||||
"github.com/kubescape/sizing-checker/pkg/checks/connectivitycheck"
|
||||
"github.com/kubescape/sizing-checker/pkg/checks/ebpfcheck"
|
||||
"github.com/kubescape/sizing-checker/pkg/checks/pvcheck"
|
||||
"github.com/kubescape/sizing-checker/pkg/checks/sizing"
|
||||
"github.com/kubescape/sizing-checker/pkg/common"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func GetPreReqCmd(ks meta.IKubescape) *cobra.Command {
|
||||
var kubeconfigPath *string
|
||||
|
||||
// preReqCmd represents the prerequisites command
|
||||
preReqCmd := &cobra.Command{
|
||||
Use: "prerequisites",
|
||||
Short: "Check prerequisites for installing Kubescape Operator",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
sizingchecker.RunSizingChecker()
|
||||
clientSet, inCluster := common.BuildKubeClient(*kubeconfigPath)
|
||||
if clientSet == nil {
|
||||
logger.L().Fatal("Could not create kube client. Exiting.")
|
||||
}
|
||||
|
||||
// 1) Collect cluster data
|
||||
clusterData, err := common.CollectClusterData(ks.Context(), clientSet)
|
||||
if err != nil {
|
||||
logger.L().Error("Failed to collect cluster data", helpers.Error(err))
|
||||
}
|
||||
|
||||
// 2) Run checks
|
||||
sizingResult := sizing.RunSizingChecker(clusterData)
|
||||
pvResult := pvcheck.RunPVProvisioningCheck(ks.Context(), clientSet, clusterData, inCluster)
|
||||
connectivityResult := connectivitycheck.RunConnectivityChecks(ks.Context(), clientSet, clusterData, inCluster)
|
||||
ebpfResult := ebpfcheck.RunEbpfCheck(ks.Context(), clientSet, clusterData, inCluster)
|
||||
|
||||
// 3) Build and export the final ReportData
|
||||
finalReport := common.BuildReportData(clusterData, sizingResult, pvResult, connectivityResult, ebpfResult)
|
||||
finalReport.InCluster = inCluster
|
||||
|
||||
common.GenerateOutput(finalReport, inCluster)
|
||||
},
|
||||
}
|
||||
|
||||
kubeconfigPath = preReqCmd.PersistentFlags().String("kubeconfig", "", "Path to the kubeconfig file. If not set, in-cluster config is used or $HOME/.kube/config if outside a cluster.")
|
||||
|
||||
return preReqCmd
|
||||
}
|
||||
|
||||
19
cmd/root.go
19
cmd/root.go
@@ -1,6 +1,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/cmd/download"
|
||||
"github.com/kubescape/kubescape/v3/cmd/fix"
|
||||
"github.com/kubescape/kubescape/v3/cmd/list"
|
||||
"github.com/kubescape/kubescape/v3/cmd/mcpserver"
|
||||
"github.com/kubescape/kubescape/v3/cmd/operator"
|
||||
"github.com/kubescape/kubescape/v3/cmd/patch"
|
||||
"github.com/kubescape/kubescape/v3/cmd/prerequisites"
|
||||
@@ -42,8 +44,8 @@ var ksExamples = fmt.Sprintf(`
|
||||
%[1]s config view
|
||||
`, cautils.ExecName())
|
||||
|
||||
func NewDefaultKubescapeCommand() *cobra.Command {
|
||||
ks := core.NewKubescape()
|
||||
func NewDefaultKubescapeCommand(ctx context.Context) *cobra.Command {
|
||||
ks := core.NewKubescape(ctx)
|
||||
return getRootCmd(ks)
|
||||
}
|
||||
|
||||
@@ -51,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)
|
||||
@@ -84,8 +86,6 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&rootInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/")))
|
||||
rootCmd.PersistentFlags().StringVar(&rootInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
|
||||
rootCmd.PersistentFlags().BoolVarP(&rootInfo.DisableColor, "disable-color", "", false, "Disable color output for logging")
|
||||
rootCmd.PersistentFlags().BoolVarP(&rootInfo.EnableColor, "enable-color", "", false, "Force enable color output for logging")
|
||||
|
||||
rootCmd.PersistentFlags().StringVarP(&rootInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context")
|
||||
// Supported commands
|
||||
@@ -93,14 +93,15 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
rootCmd.AddCommand(download.GetDownloadCmd(ks))
|
||||
rootCmd.AddCommand(list.GetListCmd(ks))
|
||||
rootCmd.AddCommand(completion.GetCompletionCmd())
|
||||
rootCmd.AddCommand(version.GetVersionCmd())
|
||||
rootCmd.AddCommand(version.GetVersionCmd(ks))
|
||||
rootCmd.AddCommand(config.GetConfigCmd(ks))
|
||||
rootCmd.AddCommand(update.GetUpdateCmd())
|
||||
rootCmd.AddCommand(update.GetUpdateCmd(ks))
|
||||
rootCmd.AddCommand(fix.GetFixCmd(ks))
|
||||
rootCmd.AddCommand(patch.GetPatchCmd(ks))
|
||||
rootCmd.AddCommand(vap.GetVapHelperCmd())
|
||||
rootCmd.AddCommand(operator.GetOperatorCmd(ks))
|
||||
rootCmd.AddCommand(prerequisites.GetPreReqCmd(ks))
|
||||
rootCmd.AddCommand(mcpserver.GetMCPServerCmd())
|
||||
|
||||
// deprecated commands
|
||||
rootCmd.AddCommand(&cobra.Command{
|
||||
@@ -115,7 +116,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
|
||||
return rootCmd
|
||||
}
|
||||
|
||||
func Execute() error {
|
||||
ks := NewDefaultKubescapeCommand()
|
||||
func Execute(ctx context.Context) error {
|
||||
ks := NewDefaultKubescapeCommand(ctx)
|
||||
return ks.Execute()
|
||||
}
|
||||
|
||||
24
cmd/root_test.go
Normal file
24
cmd/root_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewDefaultKubescapeCommand(t *testing.T) {
|
||||
t.Run("NewDefaultKubescapeCommand", func(t *testing.T) {
|
||||
cmd := NewDefaultKubescapeCommand(context.Background())
|
||||
assert.NotNil(t, cmd)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
t.Run("Execute", func(t *testing.T) {
|
||||
err := Execute(context.Background())
|
||||
if err != nil {
|
||||
assert.EqualErrorf(t, err, "unknown command \"^\\\\QTestExecute\\\\E$\" for \"kubescape\"", err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -18,9 +18,6 @@ import (
|
||||
)
|
||||
|
||||
func initLogger() {
|
||||
logger.DisableColor(rootInfo.DisableColor)
|
||||
logger.EnableColor(rootInfo.EnableColor)
|
||||
|
||||
if rootInfo.LoggerName == "" {
|
||||
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
|
||||
rootInfo.LoggerName = l
|
||||
@@ -34,8 +31,8 @@ func initLogger() {
|
||||
}
|
||||
|
||||
logger.InitLogger(rootInfo.LoggerName)
|
||||
|
||||
}
|
||||
|
||||
func initLoggerLevel() {
|
||||
if rootInfo.Logger == helpers.InfoLevel.String() {
|
||||
} else if l := os.Getenv("KS_LOGGER"); l != "" {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -30,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())
|
||||
)
|
||||
|
||||
@@ -96,12 +95,11 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
results, err := ks.Scan(ctx, scanInfo)
|
||||
results, err := ks.Scan(scanInfo)
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if err := results.HandleResults(ctx); err != nil {
|
||||
if err := results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
if !scanInfo.VerboseMode {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -113,13 +112,12 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
|
||||
|
||||
scanInfo.SetPolicyIdentifiers(frameworks, apisv1.KindFramework)
|
||||
|
||||
ctx := context.TODO()
|
||||
results, err := ks.Scan(ctx, scanInfo)
|
||||
results, err := ks.Scan(scanInfo)
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ctx); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubescape/go-logger"
|
||||
@@ -9,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"
|
||||
)
|
||||
|
||||
@@ -24,12 +22,17 @@ var (
|
||||
# Scan the 'nginx' image and see the full report
|
||||
%[1]s scan image "nginx" -v
|
||||
|
||||
# Scan the 'nginx' image and use exceptions
|
||||
%[1]s scan image "nginx" --exceptions exceptions.json
|
||||
|
||||
`, cautils.ExecName())
|
||||
)
|
||||
|
||||
// getImageCmd returns the scan image command
|
||||
func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
|
||||
var imgCredentials shared.ImageCredentials
|
||||
var exceptions string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "image <image>:<tag> [flags]",
|
||||
Short: "Scan an image for vulnerabilities",
|
||||
@@ -50,17 +53,18 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
|
||||
}
|
||||
|
||||
imgScanInfo := &metav1.ImageScanInfo{
|
||||
Image: args[0],
|
||||
Username: imgCredentials.Username,
|
||||
Password: imgCredentials.Password,
|
||||
Image: args[0],
|
||||
Username: imgCredentials.Username,
|
||||
Password: imgCredentials.Password,
|
||||
Exceptions: exceptions,
|
||||
}
|
||||
|
||||
results, err := ks.ScanImage(context.Background(), 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())
|
||||
}
|
||||
|
||||
@@ -68,6 +72,8 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
|
||||
},
|
||||
}
|
||||
|
||||
// The exceptions flag
|
||||
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")
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -135,15 +134,12 @@ func setSecurityViewScanInfo(args []string, scanInfo *cautils.ScanInfo) {
|
||||
}
|
||||
|
||||
func securityScan(scanInfo cautils.ScanInfo, ks meta.IKubescape) error {
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
results, err := ks.Scan(ctx, &scanInfo)
|
||||
results, err := ks.Scan(&scanInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ctx); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), &scanInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -66,13 +65,12 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma
|
||||
setWorkloadScanInfo(scanInfo, kind, name)
|
||||
|
||||
// todo: add api version if provided
|
||||
ctx := context.TODO()
|
||||
results, err := ks.Scan(ctx, scanInfo)
|
||||
results, err := ks.Scan(scanInfo)
|
||||
if err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
if err = results.HandleResults(ctx); err != nil {
|
||||
if err = results.HandleResults(ks.Context(), scanInfo); err != nil {
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
|
||||
@@ -94,3 +94,17 @@ func TestGetWorkloadCmd_ChartPathAndFilePathEmpty(t *testing.T) {
|
||||
expectedErrorMessage = "invalid workload identifier"
|
||||
assert.Equal(t, expectedErrorMessage, err.Error())
|
||||
}
|
||||
|
||||
func Test_parseWorkloadIdentifierString_Empty(t *testing.T) {
|
||||
t.Run("empty identifier", func(t *testing.T) {
|
||||
_, _, err := parseWorkloadIdentifierString("")
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_parseWorkloadIdentifierString_NoError(t *testing.T) {
|
||||
t.Run("valid identifier", func(t *testing.T) {
|
||||
_, _, err := parseWorkloadIdentifierString("default/Deployment")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,10 +5,11 @@ package update
|
||||
// kubescape update
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
|
||||
"github.com/kubescape/backend/pkg/versioncheck"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
@@ -25,17 +26,18 @@ var updateCmdExamples = fmt.Sprintf(`
|
||||
%[1]s update
|
||||
`, cautils.ExecName())
|
||||
|
||||
func GetUpdateCmd() *cobra.Command {
|
||||
func GetUpdateCmd(ks meta.IKubescape) *cobra.Command {
|
||||
updateCmd := &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Update to latest release version",
|
||||
Long: ``,
|
||||
Example: updateCmdExamples,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
ctx := context.TODO()
|
||||
v := versioncheck.NewVersionCheckHandler()
|
||||
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "update", nil)
|
||||
v.CheckLatestVersion(ctx, versionCheckRequest)
|
||||
if err := v.CheckLatestVersion(ks.Context(), versionCheckRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//Checking the user's version of kubescape to the latest release
|
||||
if versioncheck.BuildNumber == "" || strings.Contains(versioncheck.BuildNumber, "rc") {
|
||||
|
||||
18
cmd/update/update_test.go
Normal file
18
cmd/update/update_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetUpdateCmd(t *testing.T) {
|
||||
ks := core.NewKubescape(context.TODO())
|
||||
cmd := GetUpdateCmd(ks)
|
||||
assert.NotNil(t, cmd)
|
||||
|
||||
err := cmd.RunE(cmd, []string{})
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/meta"
|
||||
|
||||
"github.com/kubescape/backend/pkg/versioncheck"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func GetVersionCmd() *cobra.Command {
|
||||
func GetVersionCmd(ks meta.IKubescape) *cobra.Command {
|
||||
versionCmd := &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Get current version",
|
||||
Long: ``,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := context.TODO()
|
||||
v := versioncheck.NewIVersionCheckHandler(ctx)
|
||||
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil)
|
||||
v.CheckLatestVersion(ctx, versionCheckRequest)
|
||||
fmt.Fprintf(cmd.OutOrStdout(),
|
||||
v := versioncheck.NewIVersionCheckHandler(ks.Context())
|
||||
_ = v.CheckLatestVersion(ks.Context(), versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil))
|
||||
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(),
|
||||
"Your current version is: %s\n",
|
||||
versionCheckRequest.ClientVersion,
|
||||
versioncheck.BuildNumber,
|
||||
)
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -2,9 +2,12 @@ package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/core"
|
||||
|
||||
"github.com/kubescape/backend/pkg/versioncheck"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -17,7 +20,7 @@ func TestGetVersionCmd(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "Undefined Build Number",
|
||||
buildNumber: "",
|
||||
buildNumber: "unknown",
|
||||
want: "Your current version is: unknown\n",
|
||||
},
|
||||
{
|
||||
@@ -30,7 +33,8 @@ func TestGetVersionCmd(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
versioncheck.BuildNumber = tt.buildNumber
|
||||
|
||||
if cmd := GetVersionCmd(); cmd != nil {
|
||||
ks := core.NewKubescape(context.TODO())
|
||||
if cmd := GetVersionCmd(ks); cmd != nil {
|
||||
buf := bytes.NewBufferString("")
|
||||
cmd.SetOut(buf)
|
||||
cmd.Execute()
|
||||
|
||||
@@ -10,8 +10,6 @@ type RootInfo struct {
|
||||
Logger string // logger level
|
||||
LoggerName string // logger name ("pretty"/"zap"/"none")
|
||||
CacheDir string // cached dir
|
||||
DisableColor bool // Disable Color
|
||||
EnableColor bool // Force enable Color
|
||||
DiscoveryServerURL string // Discovery Server URL (See https://github.com/kubescape/backend/tree/main/pkg/servicediscovery)
|
||||
KubeContext string // context name
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
@@ -35,8 +34,8 @@ func (ks *Kubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ks *Kubescape) DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error {
|
||||
func (ks *Kubescape) DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error {
|
||||
|
||||
tenant := cautils.GetTenantConfig("", "", "", "", nil) // change k8sinterface
|
||||
return tenant.DeleteCachedConfig(ctx)
|
||||
return tenant.DeleteCachedConfig(ks.Context())
|
||||
}
|
||||
|
||||
@@ -44,12 +44,12 @@ func DownloadSupportCommands() []string {
|
||||
return commands
|
||||
}
|
||||
|
||||
func (ks *Kubescape) Download(ctx context.Context, downloadInfo *metav1.DownloadInfo) error {
|
||||
func (ks *Kubescape) Download(downloadInfo *metav1.DownloadInfo) error {
|
||||
setPathAndFilename(downloadInfo)
|
||||
if err := os.MkdirAll(downloadInfo.Path, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := downloadArtifact(ctx, downloadInfo, downloadFunc); err != nil {
|
||||
if err := downloadArtifact(ks.Context(), downloadInfo, downloadFunc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -16,14 +15,14 @@ const (
|
||||
confirmationQuestion = "Would you like to apply the changes to the files above? [y|n]: "
|
||||
)
|
||||
|
||||
func (ks *Kubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
|
||||
func (ks *Kubescape) Fix(fixInfo *metav1.FixInfo) error {
|
||||
logger.L().Info("Reading report file...")
|
||||
handler, err := fixhandler.NewFixHandler(fixInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resourcesToFix := handler.PrepareResourcesToFix(ctx)
|
||||
resourcesToFix := handler.PrepareResourcesToFix(ks.Context())
|
||||
|
||||
if len(resourcesToFix) == 0 {
|
||||
logger.L().Info(noResourcesToFix)
|
||||
@@ -42,12 +41,12 @@ func (ks *Kubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
updatedFilesCount, errors := handler.ApplyChanges(ctx, resourcesToFix)
|
||||
updatedFilesCount, errors := handler.ApplyChanges(ks.Context(), resourcesToFix)
|
||||
logger.L().Info(fmt.Sprintf("Fixed resources in %d files.", updatedFilesCount))
|
||||
|
||||
if len(errors) > 0 {
|
||||
for _, err := range errors {
|
||||
logger.L().Ctx(ctx).Warning(err.Error())
|
||||
logger.L().Ctx(ks.Context()).Warning(err.Error())
|
||||
}
|
||||
return fmt.Errorf("Failed to fix some resources, check the logs for more details")
|
||||
}
|
||||
|
||||
@@ -33,10 +33,11 @@ func TestUserConfirmed(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(string(tt.input), func(t *testing.T) {
|
||||
originalStdin := os.Stdin
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdin = r
|
||||
defer func() {
|
||||
os.Stdin = os.Stdin
|
||||
os.Stdin = originalStdin
|
||||
}()
|
||||
|
||||
go func() {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"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"
|
||||
@@ -12,30 +14,193 @@ import (
|
||||
"github.com/kubescape/kubescape/v3/pkg/imagescan"
|
||||
)
|
||||
|
||||
func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
// Data structure to represent attributes
|
||||
type Attributes struct {
|
||||
Registry string `json:"registry"`
|
||||
Organization string `json:"organization,omitempty"`
|
||||
ImageName string `json:"imageName"`
|
||||
ImageTag string `json:"imageTag,omitempty"`
|
||||
}
|
||||
|
||||
// Data structure for a target
|
||||
type Target struct {
|
||||
DesignatorType string `json:"designatorType"`
|
||||
Attributes Attributes `json:"attributes"`
|
||||
}
|
||||
|
||||
// Data structure for metadata
|
||||
type Metadata struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Data structure for vulnerabilities and severities
|
||||
type VulnerabilitiesIgnorePolicy struct {
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Kind string `json:"kind"`
|
||||
Targets []Target `json:"targets"`
|
||||
Vulnerabilities []string `json:"vulnerabilities"`
|
||||
Severities []string `json:"severities"`
|
||||
}
|
||||
|
||||
// Loads excpetion policies from exceptions json object.
|
||||
func GetImageExceptionsFromFile(filePath string) ([]VulnerabilitiesIgnorePolicy, error) {
|
||||
// Read the JSON file
|
||||
jsonFile, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading exceptions file: %w", err)
|
||||
}
|
||||
|
||||
// Unmarshal the JSON data into an array of VulnerabilitiesIgnorePolicy
|
||||
var policies []VulnerabilitiesIgnorePolicy
|
||||
err = json.Unmarshal(jsonFile, &policies)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshaling exceptions file: %w", err)
|
||||
}
|
||||
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
// This function will identify the registry, organization and image tag from the image name
|
||||
func getAttributesFromImage(imgName string) (Attributes, error) {
|
||||
canonicalImageName, err := cautils.NormalizeImageName(imgName)
|
||||
if err != nil {
|
||||
return Attributes{}, err
|
||||
}
|
||||
|
||||
tokens := strings.Split(canonicalImageName, "/")
|
||||
registry := tokens[0]
|
||||
organization := tokens[1]
|
||||
|
||||
imageNameAndTag := strings.Split(tokens[2], ":")
|
||||
imageName := imageNameAndTag[0]
|
||||
|
||||
// Intialize the image tag with default value
|
||||
imageTag := "latest"
|
||||
if len(imageNameAndTag) > 1 {
|
||||
imageTag = imageNameAndTag[1]
|
||||
}
|
||||
|
||||
attributes := Attributes{
|
||||
Registry: registry,
|
||||
Organization: organization,
|
||||
ImageName: imageName,
|
||||
ImageTag: imageTag,
|
||||
}
|
||||
|
||||
return attributes, nil
|
||||
}
|
||||
|
||||
// Checks if the target string matches the regex pattern
|
||||
func regexStringMatch(pattern, target string) bool {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to generate regular expression: %s", err))
|
||||
return false
|
||||
}
|
||||
|
||||
if re.MatchString(target) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Compares the registry, organization, image name, image tag against the targets specified
|
||||
// in the exception policy object to check if the image being scanned qualifies for an
|
||||
// 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)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Generates a list of unique CVE-IDs and the severities which are to be excluded for
|
||||
// the image being scanned.
|
||||
func getUniqueVulnerabilitiesAndSeverities(policies []VulnerabilitiesIgnorePolicy, image string) ([]string, []string) {
|
||||
// Create maps with slices as values to store unique vulnerabilities and severities (case-insensitive)
|
||||
uniqueVulns := make(map[string][]string)
|
||||
uniqueSevers := make(map[string][]string)
|
||||
|
||||
imageAttributes, err := getAttributesFromImage(image)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to generate image attributes: %s", err))
|
||||
}
|
||||
|
||||
// Iterate over each policy and its vulnerabilities/severities
|
||||
for _, policy := range policies {
|
||||
// Include the exceptions only if the image is one of the targets
|
||||
if isTargetImage(policy.Targets, imageAttributes) {
|
||||
for _, vulnerability := range policy.Vulnerabilities {
|
||||
// Add to slice directly
|
||||
vulnerabilityUppercase := strings.ToUpper(vulnerability)
|
||||
uniqueVulns[vulnerabilityUppercase] = append(uniqueVulns[vulnerabilityUppercase], vulnerability)
|
||||
}
|
||||
|
||||
for _, severity := range policy.Severities {
|
||||
// Add to slice directly
|
||||
severityUppercase := strings.ToUpper(severity)
|
||||
uniqueSevers[severityUppercase] = append(uniqueSevers[severityUppercase], severity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract unique keys (which are unique vulnerabilities/severities) and their slices
|
||||
uniqueVulnsList := make([]string, 0, len(uniqueVulns))
|
||||
for vuln := range uniqueVulns {
|
||||
uniqueVulnsList = append(uniqueVulnsList, vuln)
|
||||
}
|
||||
|
||||
uniqueSeversList := make([]string, 0, len(uniqueSevers))
|
||||
for sever := range uniqueSevers {
|
||||
uniqueSeversList = append(uniqueSeversList, sever)
|
||||
}
|
||||
|
||||
return uniqueVulnsList, uniqueSeversList
|
||||
}
|
||||
|
||||
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)
|
||||
svc, err := imagescan.NewScanService(dbCfg)
|
||||
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,
|
||||
Password: imgScanInfo.Password,
|
||||
}
|
||||
|
||||
scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds)
|
||||
var vulnerabilityExceptions []string
|
||||
var severityExceptions []string
|
||||
if imgScanInfo.Exceptions != "" {
|
||||
exceptionPolicies, err := GetImageExceptionsFromFile(imgScanInfo.Exceptions)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to load exceptions from file: %s", imgScanInfo.Exceptions))
|
||||
return false, err
|
||||
}
|
||||
|
||||
vulnerabilityExceptions, severityExceptions = getUniqueVulnerabilitiesAndSeverities(exceptionPolicies, imgScanInfo.Image)
|
||||
}
|
||||
|
||||
scanResults, 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))
|
||||
|
||||
scanInfo.SetScanType(cautils.ScanTypeImage)
|
||||
|
||||
outputPrinters := GetOutputPrinters(scanInfo, ctx, "")
|
||||
outputPrinters := GetOutputPrinters(scanInfo, ks.Context(), "")
|
||||
|
||||
uiPrinter := GetUIPrinter(ctx, scanInfo, "")
|
||||
uiPrinter := GetUIPrinter(ks.Context(), scanInfo, "")
|
||||
|
||||
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
|
||||
|
||||
@@ -46,5 +211,5 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
|
||||
},
|
||||
}
|
||||
|
||||
return scanResults, resultsHandler.HandleResults(ctx)
|
||||
return imagescan.ExceedsSeverityThreshold(scanResults, imagescan.ParseSeverity(scanInfo.FailThresholdSeverity)), resultsHandler.HandleResults(ks.Context(), scanInfo)
|
||||
}
|
||||
|
||||
420
core/core/image_scan_test.go
Normal file
420
core/core/image_scan_test.go
Normal file
@@ -0,0 +1,420 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetImageExceptionsFromFile(t *testing.T) {
|
||||
tests := []struct {
|
||||
filePath string
|
||||
expectedPolicies []VulnerabilitiesIgnorePolicy
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
filePath: "./testdata/exceptions.json",
|
||||
expectedPolicies: []VulnerabilitiesIgnorePolicy{
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "medium-severity-vulnerabilites-exceptions",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: "",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{},
|
||||
Severities: []string{"medium"},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "exclude-allowed-hostPath-control",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "",
|
||||
Organization: "",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
|
||||
Severities: []string{"critical", "low"},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "regex-example",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "quay.*",
|
||||
Organization: "kube*",
|
||||
ImageName: "kubescape*",
|
||||
ImageTag: "v2*",
|
||||
},
|
||||
},
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: ".*",
|
||||
ImageName: "kube*",
|
||||
ImageTag: "v3*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-6879", "CVE-2023-44487"},
|
||||
Severities: []string{"critical", "low"},
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
filePath: "./testdata/empty_exceptions.json",
|
||||
expectedPolicies: []VulnerabilitiesIgnorePolicy{},
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.filePath, func(t *testing.T) {
|
||||
policies, err := GetImageExceptionsFromFile(tt.filePath)
|
||||
assert.Equal(t, tt.expectedPolicies, policies)
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAttributesFromImage(t *testing.T) {
|
||||
tests := []struct {
|
||||
imageName string
|
||||
expectedAttributes Attributes
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
imageName: "quay.io/kubescape/kubescape-cli:v3.0.0",
|
||||
expectedAttributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kubescape",
|
||||
ImageName: "kubescape-cli",
|
||||
ImageTag: "v3.0.0",
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
imageName: "alpine",
|
||||
expectedAttributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: "library",
|
||||
ImageName: "alpine",
|
||||
ImageTag: "latest",
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.imageName, func(t *testing.T) {
|
||||
attributes, err := getAttributesFromImage(tt.imageName)
|
||||
assert.Equal(t, tt.expectedErr, err)
|
||||
assert.Equal(t, tt.expectedAttributes, attributes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegexStringMatch(t *testing.T) {
|
||||
tests := []struct {
|
||||
pattern string
|
||||
target string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
pattern: ".*",
|
||||
target: "quay.io",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "kubescape",
|
||||
target: "kubescape",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "kubescape*",
|
||||
target: "kubescape-cli",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "",
|
||||
target: "v3.0.0",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
pattern: "docker.io",
|
||||
target: "quay.io",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.target+"/"+tt.pattern, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, regexStringMatch(tt.pattern, tt.target))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsTargetImage(t *testing.T) {
|
||||
tests := []struct {
|
||||
targets []Target
|
||||
attributes Attributes
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
targets: []Target{
|
||||
{
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: ".*",
|
||||
ImageName: ".*",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kubescape",
|
||||
ImageName: "kubescape-cli",
|
||||
ImageTag: "v3.0.0",
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
targets: []Target{
|
||||
{
|
||||
Attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kubescape",
|
||||
ImageName: "kubescape*",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kubescape",
|
||||
ImageName: "kubescape-cli",
|
||||
ImageTag: "v3.0.0",
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
targets: []Target{
|
||||
{
|
||||
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 {
|
||||
t.Run(tt.attributes.Registry+"/"+tt.attributes.ImageName, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, isTargetImage(tt.targets, tt.attributes))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVulnerabilitiesAndSeverities(t *testing.T) {
|
||||
tests := []struct {
|
||||
policies []VulnerabilitiesIgnorePolicy
|
||||
image string
|
||||
expectedVulnerabilities []string
|
||||
expectedSeverities []string
|
||||
}{
|
||||
{
|
||||
policies: []VulnerabilitiesIgnorePolicy{
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "vulnerabilites-exceptions",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "",
|
||||
Organization: "kubescape*",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-42365"},
|
||||
Severities: []string{},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "exclude-allowed-hostPath-control",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
Organization: "",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
|
||||
Severities: []string{"critical", "low"},
|
||||
},
|
||||
},
|
||||
image: "quay.io/kubescape/kubescape-cli:v3.0.0",
|
||||
expectedVulnerabilities: []string{"CVE-2023-42365"},
|
||||
expectedSeverities: []string{},
|
||||
},
|
||||
{
|
||||
policies: []VulnerabilitiesIgnorePolicy{
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "medium-severity-vulnerabilites-exceptions",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "",
|
||||
Organization: "",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{},
|
||||
Severities: []string{"medium"},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "exclude-allowed-hostPath-control",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "",
|
||||
ImageName: "",
|
||||
ImageTag: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
|
||||
Severities: []string{},
|
||||
},
|
||||
},
|
||||
image: "alpine",
|
||||
expectedVulnerabilities: []string{},
|
||||
expectedSeverities: []string{"MEDIUM"},
|
||||
},
|
||||
{
|
||||
policies: []VulnerabilitiesIgnorePolicy{
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "regex-example",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "quay.io",
|
||||
Organization: "kube*",
|
||||
ImageName: "kubescape*",
|
||||
ImageTag: ".*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{},
|
||||
Severities: []string{"critical"},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "only-for-docker-registry",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
Registry: "docker.io",
|
||||
ImageTag: "v3*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2022-28391"},
|
||||
Severities: []string{"high"},
|
||||
},
|
||||
{
|
||||
Metadata: Metadata{
|
||||
Name: "exclude-allowed-hostPath-control",
|
||||
},
|
||||
Kind: "VulnerabilitiesIgnorePolicy",
|
||||
Targets: []Target{
|
||||
{
|
||||
DesignatorType: "Attributes",
|
||||
Attributes: Attributes{
|
||||
ImageTag: "v3*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Vulnerabilities: []string{"CVE-2022-30065", "CVE-2022-28391"},
|
||||
Severities: []string{},
|
||||
},
|
||||
},
|
||||
image: "quay.io/kubescape/kubescape-cli:v3.0.0",
|
||||
expectedVulnerabilities: []string{"CVE-2022-30065", "CVE-2022-28391"},
|
||||
expectedSeverities: []string{"CRITICAL"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.image, func(t *testing.T) {
|
||||
vulnerabilities, severities := getUniqueVulnerabilitiesAndSeverities(tt.policies, tt.image)
|
||||
sort.Strings(tt.expectedVulnerabilities)
|
||||
sort.Strings(vulnerabilities)
|
||||
assert.Equal(t, tt.expectedVulnerabilities, vulnerabilities)
|
||||
assert.Equal(t, tt.expectedSeverities, severities)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,17 @@
|
||||
package core
|
||||
|
||||
type Kubescape struct{}
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func NewKubescape() *Kubescape {
|
||||
return &Kubescape{}
|
||||
type Kubescape struct {
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (ks *Kubescape) Context() context.Context {
|
||||
return ks.Ctx
|
||||
}
|
||||
|
||||
func NewKubescape(ctx context.Context) *Kubescape {
|
||||
return &Kubescape{Ctx: ctx}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -8,7 +9,8 @@ import (
|
||||
|
||||
// The function should return a non-nil pointer.
|
||||
func TestNewKubescape_ReturnsNonNilPointer(t *testing.T) {
|
||||
k := NewKubescape()
|
||||
ctx := context.TODO()
|
||||
k := NewKubescape(ctx)
|
||||
assert.NotNil(t, k)
|
||||
}
|
||||
|
||||
@@ -19,5 +21,6 @@ func TestNewKubescape_DoesNotPanic(t *testing.T) {
|
||||
t.Errorf("Function panicked: %v", r)
|
||||
}
|
||||
}()
|
||||
NewKubescape()
|
||||
ctx := context.TODO()
|
||||
NewKubescape(ctx)
|
||||
}
|
||||
|
||||
@@ -38,16 +38,16 @@ func ListSupportActions() []string {
|
||||
sort.Strings(commands)
|
||||
return commands
|
||||
}
|
||||
func (ks *Kubescape) List(ctx context.Context, listPolicies *metav1.ListPolicies) error {
|
||||
func (ks *Kubescape) List(listPolicies *metav1.ListPolicies) error {
|
||||
if policyListerFunc, ok := listFunc[listPolicies.Target]; ok {
|
||||
policies, err := policyListerFunc(ctx, listPolicies)
|
||||
policies, err := policyListerFunc(ks.Context(), listPolicies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
policies = naturalSortPolicies(policies)
|
||||
|
||||
if listFormatFunction, ok := listFormatFunc[listPolicies.Format]; ok {
|
||||
listFormatFunction(ctx, listPolicies.Target, policies)
|
||||
listFormatFunction(ks.Context(), listPolicies.Target, policies)
|
||||
} else {
|
||||
return fmt.Errorf("Invalid format \"%s\", Supported formats: 'pretty-print'/'json' ", listPolicies.Format)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/grype/grype/presenter"
|
||||
"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,27 +23,43 @@ 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(ctx context.Context, patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
const (
|
||||
copaProduct = "copa"
|
||||
)
|
||||
|
||||
func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, 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)
|
||||
svc, err := imagescan.NewScanService(dbCfg)
|
||||
if err != nil {
|
||||
logger.L().StopError(fmt.Sprintf("Failed to initialize image scanner: %s", err))
|
||||
return nil, err
|
||||
}
|
||||
defer svc.Close()
|
||||
creds := imagescan.RegistryCredentials{
|
||||
Username: patchInfo.Username,
|
||||
Password: patchInfo.Password,
|
||||
}
|
||||
// Scan the image
|
||||
scanResults, err := svc.Scan(ctx, patchInfo.Image, creds)
|
||||
scanResults, err := svc.Scan(ks.Context(), patchInfo.Image, creds, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -52,7 +74,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
|
||||
fileName := fmt.Sprintf("%s:%s.json", patchInfo.ImageName, patchInfo.ImageTag)
|
||||
fileName = strings.ReplaceAll(fileName, "/", "-")
|
||||
|
||||
writer := printer.GetWriter(ctx, fileName)
|
||||
writer := printer.GetWriter(ks.Context(), fileName)
|
||||
|
||||
if err = pres.Present(writer); err != nil {
|
||||
return nil, err
|
||||
@@ -68,7 +90,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
|
||||
disableCopaLogger()
|
||||
}
|
||||
|
||||
if err = copaPatch(ctx, patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
|
||||
if err = copaPatch(ks.Context(), patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -81,7 +103,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
|
||||
|
||||
logger.L().Start(fmt.Sprintf("Re-scanning image: %s", patchedImageName))
|
||||
|
||||
scanResultsPatched, err := svc.Scan(ctx, patchedImageName, creds)
|
||||
scanResultsPatched, err := svc.Scan(ks.Context(), patchedImageName, creds, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -96,8 +118,8 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
|
||||
// ===================== Results Handling =====================
|
||||
|
||||
scanInfo.SetScanType(cautils.ScanTypeImage)
|
||||
outputPrinters := GetOutputPrinters(scanInfo, ctx, "")
|
||||
uiPrinter := GetUIPrinter(ctx, scanInfo, "")
|
||||
outputPrinters := GetOutputPrinters(scanInfo, ks.Context(), "")
|
||||
uiPrinter := GetUIPrinter(ks.Context(), scanInfo, "")
|
||||
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
|
||||
resultsHandler.ImageScanData = []cautils.ImageScanData{
|
||||
{
|
||||
@@ -106,7 +128,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
|
||||
},
|
||||
}
|
||||
|
||||
return scanResultsPatched, resultsHandler.HandleResults(ctx)
|
||||
return scanResultsPatched, resultsHandler.HandleResults(ks.Context(), scanInfo)
|
||||
}
|
||||
|
||||
func disableCopaLogger() {
|
||||
@@ -160,43 +182,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) {
|
||||
|
||||
|
||||
@@ -121,8 +121,8 @@ func GetOutputPrinters(scanInfo *cautils.ScanInfo, ctx context.Context, clusterN
|
||||
return outputPrinters
|
||||
}
|
||||
|
||||
func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
ctxInit, spanInit := otel.Tracer("").Start(ctx, "initialization")
|
||||
func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
ctxInit, spanInit := otel.Tracer("").Start(ks.Context(), "initialization")
|
||||
logger.L().Start("Kubescape scanner initializing...")
|
||||
|
||||
// ===================== Initialization =====================
|
||||
@@ -148,7 +148,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
|
||||
// remove host scanner components
|
||||
defer func() {
|
||||
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
|
||||
logger.L().Ctx(ctx).StopError("Failed to tear down host scanner", helpers.Error(err))
|
||||
logger.L().Ctx(ks.Context()).StopError("Failed to tear down host scanner", helpers.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -177,7 +177,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
|
||||
spanInit.End()
|
||||
|
||||
// ========================= opa testing =====================
|
||||
ctxOpa, spanOpa := otel.Tracer("").Start(ctx, "opa testing")
|
||||
ctxOpa, spanOpa := otel.Tracer("").Start(ks.Context(), "opa testing")
|
||||
defer spanOpa.End()
|
||||
|
||||
deps := resources.NewRegoDependenciesData(k8sinterface.GetK8sConfig(), interfaces.tenantConfig.GetContextName())
|
||||
@@ -191,7 +191,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
|
||||
if scanInfo.PrintAttackTree || isPrioritizationScanType(scanInfo.ScanType) {
|
||||
_, spanPrioritization := otel.Tracer("").Start(ctxOpa, "prioritization")
|
||||
if priotizationHandler, err := resourcesprioritization.NewResourcesPrioritizationHandler(ctxOpa, scanInfo.Getters.AttackTracksGetter, scanInfo.PrintAttackTree); err != nil {
|
||||
logger.L().Ctx(ctx).Warning("failed to get attack tracks, this may affect the scanning results", helpers.Error(err))
|
||||
logger.L().Ctx(ks.Context()).Warning("failed to get attack tracks, this may affect the scanning results", helpers.Error(err))
|
||||
} else if err := priotizationHandler.PrioritizeResources(scanData); err != nil {
|
||||
return resultsHandling, fmt.Errorf("%w", err)
|
||||
}
|
||||
@@ -202,7 +202,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
|
||||
}
|
||||
|
||||
if scanInfo.ScanImages {
|
||||
scanImages(scanInfo.ScanType, scanData, ctx, resultsHandling)
|
||||
scanImages(scanInfo.ScanType, scanData, ks.Context(), resultsHandling)
|
||||
}
|
||||
// ========================= results handling =====================
|
||||
resultsHandling.SetData(scanData)
|
||||
@@ -244,7 +244,12 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx
|
||||
}
|
||||
|
||||
dbCfg, _ := imagescan.NewDefaultDBConfig()
|
||||
svc := imagescan.NewScanService(dbCfg)
|
||||
svc, err := imagescan.NewScanService(dbCfg)
|
||||
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,9 +260,9 @@ 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{})
|
||||
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{}, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
67
core/core/testdata/alpine-nginx-exceptions.json
vendored
Normal file
67
core/core/testdata/alpine-nginx-exceptions.json
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
[
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alpine-exceptions"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"imageName": "alpine*"
|
||||
}
|
||||
}
|
||||
],
|
||||
"severities": [
|
||||
"medium"
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "nginx-exceptions"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"imageName": "nginx*"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vulnerabilities": [
|
||||
"invalid-cve",
|
||||
"CVE-2023-45853",
|
||||
"CVE-2023-49463"
|
||||
],
|
||||
"severities": [
|
||||
"critical",
|
||||
"medium",
|
||||
"invalid-severity"
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "applicable-only-to-quay-registry-images"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"registry": "quay.io"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vulnerabilities": [
|
||||
"CVE-2023-42365"
|
||||
],
|
||||
"severities": [
|
||||
"critical",
|
||||
"medium",
|
||||
"high",
|
||||
"low"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
1
core/core/testdata/empty_exceptions.json
vendored
Normal file
1
core/core/testdata/empty_exceptions.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[]
|
||||
78
core/core/testdata/exceptions.json
vendored
Normal file
78
core/core/testdata/exceptions.json
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
[
|
||||
{
|
||||
"metadata": {
|
||||
"name": "medium-severity-vulnerabilites-exceptions"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"Registry": "docker.io",
|
||||
"Organization": "",
|
||||
"ImageName": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"vulnerabilities": [
|
||||
],
|
||||
"severities": [
|
||||
"medium"
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "exclude-allowed-hostPath-control"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"vulnerabilities": [
|
||||
"CVE-2023-42366",
|
||||
"CVE-2023-42365"
|
||||
],
|
||||
"severities": [
|
||||
"critical",
|
||||
"low"
|
||||
]
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "regex-example"
|
||||
},
|
||||
"kind": "VulnerabilitiesIgnorePolicy",
|
||||
"targets": [
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"Registry": "quay.*",
|
||||
"Organization": "kube*",
|
||||
"ImageName": "kubescape*",
|
||||
"ImageTag": "v2*"
|
||||
}
|
||||
},
|
||||
{
|
||||
"designatorType": "Attributes",
|
||||
"attributes": {
|
||||
"Registry": "docker.io",
|
||||
"Organization": ".*",
|
||||
"ImageName": "kube*",
|
||||
"ImageTag": "v3*"
|
||||
}
|
||||
}
|
||||
],
|
||||
"vulnerabilities": [
|
||||
"CVE-2023-6879",
|
||||
"CVE-2023-44487"
|
||||
],
|
||||
"severities": [
|
||||
"critical",
|
||||
"low"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,7 +1,8 @@
|
||||
package v1
|
||||
|
||||
type ImageScanInfo struct {
|
||||
Username string
|
||||
Password string
|
||||
Image string
|
||||
Username string
|
||||
Password string
|
||||
Image string
|
||||
Exceptions string
|
||||
}
|
||||
|
||||
@@ -10,23 +10,25 @@ import (
|
||||
)
|
||||
|
||||
type IKubescape interface {
|
||||
Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) // TODO - use scanInfo from v1
|
||||
Context() context.Context
|
||||
|
||||
Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) // TODO - use scanInfo from v1
|
||||
|
||||
// policies
|
||||
List(ctx context.Context, listPolicies *metav1.ListPolicies) error // TODO - return list response
|
||||
Download(ctx context.Context, downloadInfo *metav1.DownloadInfo) error // TODO - return downloaded policies
|
||||
List(listPolicies *metav1.ListPolicies) error // TODO - return list response
|
||||
Download(downloadInfo *metav1.DownloadInfo) error // TODO - return downloaded policies
|
||||
|
||||
// config
|
||||
SetCachedConfig(setConfig *metav1.SetConfig) error
|
||||
ViewCachedConfig(viewConfig *metav1.ViewConfig) error
|
||||
DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error
|
||||
DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error
|
||||
|
||||
// fix
|
||||
Fix(ctx context.Context, fixInfo *metav1.FixInfo) error
|
||||
Fix(fixInfo *metav1.FixInfo) error
|
||||
|
||||
// patch
|
||||
Patch(ctx context.Context, patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
|
||||
Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
|
||||
|
||||
// scan image
|
||||
ScanImage(ctx context.Context, imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
|
||||
ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (bool, error)
|
||||
}
|
||||
|
||||
@@ -11,38 +11,42 @@ import (
|
||||
|
||||
type MockIKubescape struct{}
|
||||
|
||||
func (m *MockIKubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
func (m *MockIKubescape) Context() context.Context {
|
||||
return context.TODO()
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Scan(_ *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) List(ctx context.Context, listPolicies *metav1.ListPolicies) error {
|
||||
func (m *MockIKubescape) List(_ *metav1.ListPolicies) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Download(ctx context.Context, 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(ctx context.Context, deleteConfig *metav1.DeleteConfig) error {
|
||||
func (m *MockIKubescape) DeleteCachedConfig(_ *metav1.DeleteConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
|
||||
func (m *MockIKubescape) Fix(_ *metav1.FixInfo) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) Patch(ctx context.Context, patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
func (m *MockIKubescape) Patch(_ *metav1.PatchInfo, _ *cautils.ScanInfo) (*models.PresenterConfig, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MockIKubescape) ScanImage(ctx context.Context, 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
|
||||
}
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
|
||||
"github.com/kubescape/opa-utils/resources"
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
"github.com/open-policy-agent/opa/storage"
|
||||
opaprint "github.com/open-policy-agent/opa/topdown/print"
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
"github.com/open-policy-agent/opa/v1/rego"
|
||||
"github.com/open-policy-agent/opa/v1/storage"
|
||||
opaprint "github.com/open-policy-agent/opa/v1/topdown/print"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
@@ -324,6 +324,7 @@ func (opap *OPAProcessor) runRegoOnK8s(ctx context.Context, rule *reporthandling
|
||||
// NOTE: OPA module compilation is the most resource-intensive operation.
|
||||
compiled, err := ast.CompileModulesWithOpt(modules, ast.CompileOpts{
|
||||
EnablePrintStatements: opap.printEnabled,
|
||||
ParserOptions: ast.ParserOptions{RegoVersion: ast.RegoV0},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("in 'runRegoOnK8s', failed to compile rule, name: %s, reason: %w", rule.Name, err)
|
||||
@@ -351,6 +352,7 @@ func (opap *OPAProcessor) Print(ctx opaprint.Context, str string) error {
|
||||
|
||||
func (opap *OPAProcessor) regoEval(ctx context.Context, inputObj []map[string]interface{}, compiledRego *ast.Compiler, store *storage.Store) ([]reporthandling.RuleResponse, error) {
|
||||
rego := rego.New(
|
||||
rego.SetRegoVersion(ast.RegoV0),
|
||||
rego.Query("data.armo_builtins"), // get package name from rule
|
||||
rego.Compiler(compiledRego),
|
||||
rego.Input(inputObj),
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"github.com/kubescape/opa-utils/reporthandling"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/open-policy-agent/opa/ast"
|
||||
"github.com/open-policy-agent/opa/rego"
|
||||
"github.com/open-policy-agent/opa/topdown/builtins"
|
||||
"github.com/open-policy-agent/opa/types"
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
"github.com/open-policy-agent/opa/v1/rego"
|
||||
"github.com/open-policy-agent/opa/v1/topdown/builtins"
|
||||
"github.com/open-policy-agent/opa/v1/types"
|
||||
)
|
||||
|
||||
// convertFrameworksToPolicies convert list of frameworks to list of policies
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,78 +3,39 @@ package printer
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/jwalton/gchalk"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/apis"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
columnSeverity = iota
|
||||
columnRef = iota
|
||||
columnName = iota
|
||||
columnCounterFailed = iota
|
||||
columnCounterAll = iota
|
||||
columnComplianceScore = iota
|
||||
_rowLen = iota
|
||||
controlNameMaxLength = 70
|
||||
)
|
||||
const controlNameMaxLength = 70
|
||||
|
||||
func generateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars, verbose bool) []string {
|
||||
row := make([]string, _rowLen)
|
||||
|
||||
// ignore passed results
|
||||
if !verbose && (controlSummary.GetStatus().IsPassed()) {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
row[columnSeverity] = getSeverityColumn(controlSummary)
|
||||
if len(controlSummary.GetName()) > controlNameMaxLength {
|
||||
row[columnName] = controlSummary.GetName()[:controlNameMaxLength] + "..."
|
||||
} else {
|
||||
row[columnName] = controlSummary.GetName()
|
||||
}
|
||||
row[columnCounterFailed] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed())
|
||||
row[columnCounterAll] = fmt.Sprintf("%d", controlSummary.NumberOfResources().All())
|
||||
row[columnComplianceScore] = getComplianceScoreColumn(controlSummary, infoToPrintInfo)
|
||||
if row[columnComplianceScore] == "-1%" {
|
||||
row[columnComplianceScore] = "N/A"
|
||||
}
|
||||
|
||||
return row
|
||||
type TableRow struct {
|
||||
ref string
|
||||
name string
|
||||
counterFailed string
|
||||
counterAll string
|
||||
severity string
|
||||
complianceScore string
|
||||
}
|
||||
|
||||
func shortFormatRow(dataRows [][]string) [][]string {
|
||||
rows := [][]string{}
|
||||
for _, dataRow := range dataRows {
|
||||
rows = append(rows, []string{fmt.Sprintf("Severity"+strings.Repeat(" ", 11)+": %+v\nControl Name"+strings.Repeat(" ", 7)+": %+v\nFailed Resources"+strings.Repeat(" ", 3)+": %+v\nAll Resources"+strings.Repeat(" ", 6)+": %+v\n%% Compliance-Score"+strings.Repeat(" ", 1)+": %+v", dataRow[columnSeverity], dataRow[columnName], dataRow[columnCounterFailed], dataRow[columnCounterAll], dataRow[columnComplianceScore])})
|
||||
// generateTableRow is responsible for generating the row that will be printed in the table
|
||||
func generateTableRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) *TableRow {
|
||||
tableRow := &TableRow{
|
||||
ref: controlSummary.GetID(),
|
||||
name: controlSummary.GetName(),
|
||||
counterFailed: fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed()),
|
||||
counterAll: fmt.Sprintf("%d", controlSummary.NumberOfResources().All()),
|
||||
severity: apis.ControlSeverityToString(controlSummary.GetScoreFactor()),
|
||||
complianceScore: getComplianceScoreColumn(controlSummary, infoToPrintInfo),
|
||||
}
|
||||
return rows
|
||||
}
|
||||
|
||||
func generateRowPdf(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars, verbose bool) []string {
|
||||
row := make([]string, _rowLen)
|
||||
|
||||
// ignore passed results
|
||||
if !verbose && (controlSummary.GetStatus().IsPassed()) {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
row[columnSeverity] = apis.ControlSeverityToString(controlSummary.GetScoreFactor())
|
||||
row[columnRef] = controlSummary.GetID()
|
||||
if len(controlSummary.GetName()) > controlNameMaxLength {
|
||||
row[columnName] = controlSummary.GetName()[:controlNameMaxLength] + "..."
|
||||
} else {
|
||||
row[columnName] = controlSummary.GetName()
|
||||
tableRow.name = controlSummary.GetName()[:controlNameMaxLength] + "..."
|
||||
}
|
||||
row[columnCounterFailed] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed())
|
||||
row[columnCounterAll] = fmt.Sprintf("%d", controlSummary.NumberOfResources().All())
|
||||
row[columnComplianceScore] = getComplianceScoreColumn(controlSummary, infoToPrintInfo)
|
||||
|
||||
return row
|
||||
return tableRow
|
||||
}
|
||||
|
||||
func getInfoColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) string {
|
||||
@@ -90,7 +51,12 @@ func getComplianceScoreColumn(controlSummary reportsummary.IControlSummary, info
|
||||
if controlSummary.GetStatus().IsSkipped() {
|
||||
return fmt.Sprintf("%s %s", "Action Required", getInfoColumn(controlSummary, infoToPrintInfo))
|
||||
}
|
||||
return fmt.Sprintf("%d", cautils.Float32ToInt(controlSummary.GetComplianceScore())) + "%"
|
||||
if compliance := cautils.Float32ToInt(controlSummary.GetComplianceScore()); compliance < 0 {
|
||||
return "N/A"
|
||||
} else {
|
||||
return fmt.Sprintf("%d", cautils.Float32ToInt(controlSummary.GetComplianceScore())) + "%"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getSeverityColumn(controlSummary reportsummary.IControlSummary) string {
|
||||
@@ -124,45 +90,3 @@ func getSortedControlsIDs(controls reportsummary.ControlSummaries) [][]string {
|
||||
}
|
||||
return controlIDs
|
||||
}
|
||||
|
||||
/* unused for now
|
||||
func getSortedControlsNames(controls reportsummary.ControlSummaries) [][]string {
|
||||
controlNames := make([][]string, 5)
|
||||
for k := range controls {
|
||||
c := controls[k]
|
||||
i := apis.ControlSeverityToInt(c.GetScoreFactor())
|
||||
controlNames[i] = append(controlNames[i], c.GetName())
|
||||
}
|
||||
for i := range controlNames {
|
||||
sort.Strings(controlNames[i])
|
||||
}
|
||||
return controlNames
|
||||
}
|
||||
*/
|
||||
|
||||
func getControlTableHeaders(short bool) []string {
|
||||
var headers []string
|
||||
if short {
|
||||
headers = make([]string, 1)
|
||||
headers[0] = "Controls"
|
||||
} else {
|
||||
headers = make([]string, _rowLen)
|
||||
headers[columnRef] = "Control reference"
|
||||
headers[columnName] = "Control name"
|
||||
headers[columnCounterFailed] = "Failed resources"
|
||||
headers[columnCounterAll] = "All resources"
|
||||
headers[columnSeverity] = "Severity"
|
||||
headers[columnComplianceScore] = "Compliance score"
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func getColumnsAlignments() []int {
|
||||
alignments := make([]int, _rowLen)
|
||||
alignments[columnName] = tablewriter.ALIGN_LEFT
|
||||
alignments[columnCounterFailed] = tablewriter.ALIGN_CENTER
|
||||
alignments[columnCounterAll] = tablewriter.ALIGN_CENTER
|
||||
alignments[columnSeverity] = tablewriter.ALIGN_LEFT
|
||||
alignments[columnComplianceScore] = tablewriter.ALIGN_CENTER
|
||||
return alignments
|
||||
}
|
||||
|
||||
@@ -23,45 +23,43 @@ func Test_generateRowPdf(t *testing.T) {
|
||||
infoToPrintInfoMap := mapInfoToPrintInfo(mockSummary.Controls)
|
||||
sortedControlIDs := getSortedControlsIDs(mockSummary.Controls)
|
||||
|
||||
var results [][]string
|
||||
var rows []TableRow
|
||||
|
||||
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlIDs[i] {
|
||||
result := generateRowPdf(mockSummary.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap, true)
|
||||
if len(result) > 0 {
|
||||
results = append(results, result)
|
||||
}
|
||||
row := *generateTableRow(mockSummary.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap)
|
||||
rows = append(rows, row)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range results {
|
||||
for _, row := range rows {
|
||||
//validating severity column
|
||||
if c[0] != "Low" && c[0] != "Medium" && c[0] != "High" && c[0] != "Critical" {
|
||||
t.Errorf("got %s, want either of these: %s", c[0], "Low, Medium, High, Critical")
|
||||
if row.severity != "Low" && row.severity != "Medium" && row.severity != "High" && row.severity != "Critical" {
|
||||
t.Errorf("got %s, want either of these: %s", row.severity, "Low, Medium, High, Critical")
|
||||
}
|
||||
|
||||
// Validating length of control ID
|
||||
if len(c[1]) > 6 {
|
||||
t.Errorf("got %s, want %s", c[1], "less than 7 characters")
|
||||
if len(row.ref) > 6 {
|
||||
t.Errorf("got %s, want %s", row.ref, "less than 7 characters")
|
||||
}
|
||||
|
||||
// Validating length of control name
|
||||
if len(c[2]) > controlNameMaxLength {
|
||||
t.Errorf("got %s, want %s", c[1], fmt.Sprintf("less than %d characters", controlNameMaxLength))
|
||||
if len(row.name) > controlNameMaxLength {
|
||||
t.Errorf("got %s, want %s", row.name, fmt.Sprintf("less than %d characters", controlNameMaxLength))
|
||||
}
|
||||
|
||||
// Validating numeric fields
|
||||
_, err := strconv.Atoi(c[3])
|
||||
_, err := strconv.Atoi(row.counterFailed)
|
||||
if err != nil {
|
||||
t.Errorf("got %s, want an integer %s", c[2], err)
|
||||
t.Errorf("got %s, want an integer %s", row.counterFailed, err)
|
||||
}
|
||||
|
||||
_, err = strconv.Atoi(c[4])
|
||||
_, err = strconv.Atoi(row.counterAll)
|
||||
if err != nil {
|
||||
t.Errorf("got %s, want an integer %s", c[3], err)
|
||||
t.Errorf("got %s, want an integer %s", row.counterAll, err)
|
||||
}
|
||||
|
||||
assert.NotEmpty(t, c[5], "expected a non-empty string")
|
||||
assert.NotEmpty(t, row.complianceScore, "expected a non-empty string")
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,18 @@ package printer
|
||||
import (
|
||||
"context"
|
||||
_ "embed"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/johnfercher/maroto/pkg/color"
|
||||
"github.com/johnfercher/maroto/pkg/consts"
|
||||
"github.com/johnfercher/maroto/pkg/pdf"
|
||||
"github.com/johnfercher/maroto/pkg/props"
|
||||
"github.com/johnfercher/maroto/v2/pkg/props"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/pdf"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
|
||||
)
|
||||
@@ -27,11 +24,6 @@ const (
|
||||
pdfOutputExt = ".pdf"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed pdf/logo.png
|
||||
kubescapeLogo []byte
|
||||
)
|
||||
|
||||
var _ printer.IPrinter = &PdfPrinter{}
|
||||
|
||||
type PdfPrinter struct {
|
||||
@@ -66,219 +58,79 @@ func (pp *PdfPrinter) Score(score float32) {
|
||||
|
||||
fmt.Fprintf(os.Stderr, "\nOverall compliance-score (100- Excellent, 0- All failed): %d\n", cautils.Float32ToInt(score))
|
||||
}
|
||||
func (pp *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap []infoStars) {
|
||||
emptyRowCounter := 1
|
||||
for i := range infoMap {
|
||||
if infoMap[i].info != "" {
|
||||
m.Row(5, func() {
|
||||
m.Col(12, func() {
|
||||
m.Text(fmt.Sprintf("%v %v", infoMap[i].stars, infoMap[i].info), props.Text{
|
||||
Style: consts.Bold,
|
||||
Align: consts.Left,
|
||||
Size: 8,
|
||||
Extrapolate: false,
|
||||
Color: color.Color{
|
||||
Red: 0,
|
||||
Green: 0,
|
||||
Blue: 255,
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
if emptyRowCounter < len(infoMap) {
|
||||
m.Row(2.5, func() {})
|
||||
emptyRowCounter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (pp *PdfPrinter) PrintNextSteps() {
|
||||
|
||||
}
|
||||
|
||||
// ActionPrint is responsible for generating a report in pdf format
|
||||
func (pp *PdfPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) {
|
||||
if opaSessionObj == nil {
|
||||
logger.L().Ctx(ctx).Error("failed to print results, missing data")
|
||||
return
|
||||
}
|
||||
|
||||
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
|
||||
infoToPrintInfo := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls)
|
||||
m := pdf.NewMaroto(consts.Portrait, consts.A4)
|
||||
pp.printHeader(m)
|
||||
pp.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks())
|
||||
pp.printTable(m, &opaSessionObj.Report.SummaryDetails, sortedControlIDs)
|
||||
pp.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
|
||||
pp.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfo)
|
||||
|
||||
// Extrat output buffer.
|
||||
outBuff, err := m.Output()
|
||||
outBuff, err := pp.generatePdf(&opaSessionObj.Report.SummaryDetails)
|
||||
if err != nil {
|
||||
logger.L().Ctx(ctx).Error("failed to generate pdf format", helpers.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := pp.writer.Write(outBuff.Bytes()); err != nil {
|
||||
if _, err := pp.writer.Write(outBuff); err != nil {
|
||||
logger.L().Ctx(ctx).Error("failed to write results", helpers.Error(err))
|
||||
return
|
||||
}
|
||||
printer.LogOutputFile(pp.writer.Name())
|
||||
}
|
||||
|
||||
// printHeader prints the Kubescape logo and report date
|
||||
func (pp *PdfPrinter) printHeader(m pdf.Maroto) {
|
||||
// Retrieve current time (we need it for the report timestamp).
|
||||
t := time.Now()
|
||||
// Enconde PNG into Base64 to embed it into the pdf.
|
||||
kubescapeLogoEnc := b64.StdEncoding.EncodeToString(kubescapeLogo)
|
||||
func (pp *PdfPrinter) generatePdf(summaryDetails *reportsummary.SummaryDetails) ([]byte, error) {
|
||||
sortedControlIDs := getSortedControlsIDs(summaryDetails.Controls)
|
||||
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
|
||||
m.SetPageMargins(10, 15, 10)
|
||||
m.Row(40, func() {
|
||||
//m.Text(fmt.Sprintf("Security Assessment"), props.Text{
|
||||
// Align: consts.Center,
|
||||
// Size: 24,
|
||||
// Family: consts.Arial,
|
||||
// Style: consts.Bold,
|
||||
//})
|
||||
_ = m.Base64Image(kubescapeLogoEnc, consts.Png, props.Rect{
|
||||
Center: true,
|
||||
Percent: 100,
|
||||
})
|
||||
})
|
||||
m.Row(6, func() {
|
||||
m.Text(fmt.Sprintf("Report date: %d-%02d-%02dT%02d:%02d:%02d",
|
||||
t.Year(),
|
||||
t.Month(),
|
||||
t.Day(),
|
||||
t.Hour(),
|
||||
t.Minute(),
|
||||
t.Second()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 6.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Line(1)
|
||||
template := pdf.NewReportTemplate()
|
||||
template.GenerateHeader(utils.FrameworksScoresToString(summaryDetails.ListFrameworks()), time.Now().Format(time.DateTime))
|
||||
err := template.GenerateTable(pp.getTableObjects(summaryDetails, sortedControlIDs),
|
||||
summaryDetails.NumberOfResources().Failed(), summaryDetails.NumberOfResources().All(), summaryDetails.ComplianceScore)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
template.GenerateInfoRows(pp.getFormattedInformation(infoToPrintInfo))
|
||||
return template.GetPdf()
|
||||
}
|
||||
|
||||
// printFramework prints the PDF frameworks after the PDF header
|
||||
func (pp *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsummary.IFrameworkSummary) {
|
||||
m.Row(10, func() {
|
||||
m.Text(utils.FrameworksScoresToString(frameworks), props.Text{
|
||||
Align: consts.Center,
|
||||
Size: 8,
|
||||
Family: consts.Arial,
|
||||
Style: consts.Bold,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// printTable creates the PDF table
|
||||
func (pp *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
|
||||
headers := getControlTableHeaders(false)
|
||||
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
var controls [][]string
|
||||
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlIDs[i] {
|
||||
row := generateRowPdf(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap, true)
|
||||
if len(row) > 0 {
|
||||
controls = append(controls, row)
|
||||
}
|
||||
func (pp *PdfPrinter) getFormattedInformation(infoMap []infoStars) []string {
|
||||
rows := make([]string, 0, len(infoMap))
|
||||
for i := range infoMap {
|
||||
if infoMap[i].info != "" {
|
||||
rows = append(rows, fmt.Sprintf("%v %v", infoMap[i].stars, infoMap[i].info))
|
||||
}
|
||||
}
|
||||
|
||||
size := 6.0
|
||||
gridSize := []uint{1, 1, 6, 1, 1, 2}
|
||||
|
||||
m.TableList(headers, controls, props.TableList{
|
||||
HeaderProp: props.TableListContent{
|
||||
Family: consts.Arial,
|
||||
Style: consts.Bold,
|
||||
Size: size,
|
||||
GridSizes: gridSize,
|
||||
},
|
||||
ContentProp: props.TableListContent{
|
||||
Family: consts.Courier,
|
||||
Style: consts.Normal,
|
||||
Size: size,
|
||||
GridSizes: gridSize,
|
||||
CellTextColorChangerColumnIndex: 0,
|
||||
CellTextColorChangerFunc: func(cellValue string) color.Color {
|
||||
if cellValue == "Critical" {
|
||||
return color.Color{
|
||||
Red: 255,
|
||||
Green: 0,
|
||||
Blue: 0,
|
||||
}
|
||||
} else if cellValue == "High" {
|
||||
return color.Color{
|
||||
Red: 0,
|
||||
Green: 0,
|
||||
Blue: 255,
|
||||
}
|
||||
} else if cellValue == "Medium" {
|
||||
return color.Color{
|
||||
Red: 252,
|
||||
Green: 186,
|
||||
Blue: 3,
|
||||
}
|
||||
}
|
||||
return color.NewBlack()
|
||||
},
|
||||
},
|
||||
Align: consts.Left,
|
||||
AlternatedBackground: &color.Color{
|
||||
Red: 224,
|
||||
Green: 224,
|
||||
Blue: 224,
|
||||
},
|
||||
HeaderContentSpace: 2.0,
|
||||
Line: false,
|
||||
})
|
||||
m.Line(1)
|
||||
m.Row(2, func() {})
|
||||
return rows
|
||||
}
|
||||
|
||||
// printFinalResult adds the final results
|
||||
func (pp *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
|
||||
m.Row(_rowLen, func() {
|
||||
m.Col(1, func() {
|
||||
})
|
||||
m.Col(5, func() {
|
||||
m.Text("Resource summary", props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().All()), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
m.Col(2, func() {
|
||||
m.Text(fmt.Sprintf("%.2f%s", summaryDetails.ComplianceScore, "%"), props.Text{
|
||||
Align: consts.Left,
|
||||
Size: 8.0,
|
||||
Style: consts.Bold,
|
||||
Family: consts.Arial,
|
||||
})
|
||||
})
|
||||
})
|
||||
// getTableData is responsible for getting the table data in a standardized format
|
||||
func (pp *PdfPrinter) getTableObjects(summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) *[]pdf.TableObject {
|
||||
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
|
||||
var controls []pdf.TableObject
|
||||
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
|
||||
for _, c := range sortedControlIDs[i] {
|
||||
row := generateTableRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap)
|
||||
controls = append(controls, *pdf.NewTableRow(
|
||||
row.ref, row.name, row.counterFailed, row.counterAll, row.severity, row.complianceScore, getSeverityColor,
|
||||
))
|
||||
}
|
||||
}
|
||||
return &controls
|
||||
}
|
||||
|
||||
func getSeverityColor(severity string) *props.Color {
|
||||
if severity == "Critical" {
|
||||
return &props.Color{Red: 255, Green: 0, Blue: 0}
|
||||
} else if severity == "High" {
|
||||
return &props.Color{Red: 0, Green: 0, Blue: 255}
|
||||
} else if severity == "Medium" {
|
||||
return &props.Color{Red: 252, Green: 186, Blue: 3}
|
||||
}
|
||||
return &props.BlackColor
|
||||
}
|
||||
|
||||
1
core/pkg/resultshandling/printer/v2/pdf/.maroto.yml
Normal file
1
core/pkg/resultshandling/printer/v2/pdf/.maroto.yml
Normal file
@@ -0,0 +1 @@
|
||||
test_path: "testStructure/"
|
||||
195
core/pkg/resultshandling/printer/v2/pdf/report_template.go
Normal file
195
core/pkg/resultshandling/printer/v2/pdf/report_template.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package pdf
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
|
||||
"github.com/johnfercher/go-tree/node"
|
||||
"github.com/johnfercher/maroto/v2"
|
||||
"github.com/johnfercher/maroto/v2/pkg/components/image"
|
||||
"github.com/johnfercher/maroto/v2/pkg/components/line"
|
||||
"github.com/johnfercher/maroto/v2/pkg/components/list"
|
||||
"github.com/johnfercher/maroto/v2/pkg/components/row"
|
||||
"github.com/johnfercher/maroto/v2/pkg/components/text"
|
||||
"github.com/johnfercher/maroto/v2/pkg/config"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/align"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/extension"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/fontfamily"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/fontstyle"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/orientation"
|
||||
"github.com/johnfercher/maroto/v2/pkg/consts/pagesize"
|
||||
"github.com/johnfercher/maroto/v2/pkg/core"
|
||||
"github.com/johnfercher/maroto/v2/pkg/props"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed logo.png
|
||||
kubescapeLogo []byte
|
||||
)
|
||||
|
||||
type getTextColorFunc func(severity string) *props.Color
|
||||
|
||||
type Template struct {
|
||||
maroto core.Maroto
|
||||
}
|
||||
|
||||
// New Report Template is responsible for creating an object that generates a report with the submitted data
|
||||
func NewReportTemplate() *Template {
|
||||
return &Template{
|
||||
maroto: maroto.New(
|
||||
config.NewBuilder().
|
||||
WithPageSize(pagesize.A4).
|
||||
WithOrientation(orientation.Vertical).
|
||||
WithLeftMargin(10).
|
||||
WithTopMargin(15).
|
||||
WithRightMargin(10).
|
||||
Build()),
|
||||
}
|
||||
}
|
||||
|
||||
// GetPdf is responsible for generating the pdf and returning the file's bytes
|
||||
func (t *Template) GetPdf() ([]byte, error) {
|
||||
doc, err := t.maroto.Generate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return doc.GetBytes(), nil
|
||||
}
|
||||
|
||||
// printHeader prints the Kubescape logo, report date and framework
|
||||
func (t *Template) GenerateHeader(scoreOfScannedFrameworks, reportDate string) *Template {
|
||||
t.maroto.AddRow(40, image.NewFromBytesCol(12, kubescapeLogo, extension.Png, props.Rect{
|
||||
Center: true,
|
||||
Percent: 100,
|
||||
}))
|
||||
|
||||
t.maroto.AddRow(6, text.NewCol(12, fmt.Sprintf("Report date: %s", reportDate),
|
||||
props.Text{
|
||||
Align: align.Left,
|
||||
Size: 6.0,
|
||||
Style: fontstyle.Bold,
|
||||
Family: fontfamily.Arial,
|
||||
}))
|
||||
|
||||
t.maroto.AddAutoRow(line.NewCol(12, props.Line{Thickness: 0.3, SizePercent: 100}))
|
||||
|
||||
t.maroto.AddRow(10, text.NewCol(12, scoreOfScannedFrameworks, props.Text{
|
||||
Align: align.Center,
|
||||
Size: 8,
|
||||
Family: fontfamily.Arial,
|
||||
Style: fontstyle.Bold,
|
||||
}))
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// GenerateTable is responsible for adding data in table format to the pdf
|
||||
func (t *Template) GenerateTable(tableRows *[]TableObject, totalFailed, total int, score float32) error {
|
||||
rows, err := list.Build[TableObject](*tableRows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.maroto.AddRows(rows...)
|
||||
t.maroto.AddRows(
|
||||
line.NewAutoRow(props.Line{Thickness: 0.3, SizePercent: 100}),
|
||||
row.New(2),
|
||||
)
|
||||
t.generateTableTableResult(totalFailed, total, score)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateInfoRows is responsible for adding the information in pdf
|
||||
func (t *Template) GenerateInfoRows(rows []string) *Template {
|
||||
for _, row := range rows {
|
||||
t.maroto.AddAutoRow(text.NewCol(12, row, props.Text{
|
||||
Style: fontstyle.Bold,
|
||||
Align: align.Left,
|
||||
Top: 2.5,
|
||||
Size: 8,
|
||||
Color: &props.Color{
|
||||
Red: 0,
|
||||
Green: 0,
|
||||
Blue: 255,
|
||||
},
|
||||
}))
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *Template) generateTableTableResult(totalFailed, total int, score float32) {
|
||||
defaultProps := props.Text{
|
||||
Align: align.Left,
|
||||
Size: 8,
|
||||
Style: fontstyle.Bold,
|
||||
Family: fontfamily.Arial,
|
||||
}
|
||||
|
||||
t.maroto.AddRow(10,
|
||||
text.NewCol(5, "Resource summary", defaultProps),
|
||||
text.NewCol(2, fmt.Sprintf("%d", totalFailed), defaultProps),
|
||||
text.NewCol(2, fmt.Sprintf("%d", total), defaultProps),
|
||||
text.NewCol(2, fmt.Sprintf("%.2f%s", score, "%"), defaultProps),
|
||||
)
|
||||
}
|
||||
|
||||
func (t *Template) GetStructure() *node.Node[core.Structure] {
|
||||
return t.maroto.GetStructure()
|
||||
}
|
||||
|
||||
// TableObject is responsible for mapping the table data, it will be sent to Maroto and will make it possible to generate the table
|
||||
type TableObject struct {
|
||||
ref string
|
||||
name string
|
||||
counterFailed string
|
||||
counterAll string
|
||||
severity string
|
||||
complianceScore string
|
||||
getTextColor getTextColorFunc
|
||||
}
|
||||
|
||||
func NewTableRow(ref, name, counterFailed, counterAll, severity, score string, getTextColor getTextColorFunc) *TableObject {
|
||||
return &TableObject{
|
||||
ref: ref,
|
||||
name: name,
|
||||
counterFailed: counterFailed,
|
||||
counterAll: counterAll,
|
||||
severity: severity,
|
||||
complianceScore: score,
|
||||
getTextColor: getTextColor,
|
||||
}
|
||||
}
|
||||
|
||||
func (t TableObject) GetHeader() core.Row {
|
||||
return row.New(10).Add(
|
||||
text.NewCol(1, "Severity", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
text.NewCol(1, "Control reference", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
text.NewCol(6, "Control name", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
text.NewCol(1, "Failed resources", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
text.NewCol(1, "All resources", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
text.NewCol(2, "Compliance score", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
|
||||
)
|
||||
}
|
||||
|
||||
func (t TableObject) GetContent(i int) core.Row {
|
||||
r := row.New(3).Add(
|
||||
text.NewCol(1, t.severity, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6, Color: t.getTextColor(t.severity)}),
|
||||
text.NewCol(1, t.ref, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6, Color: &props.Color{}}),
|
||||
text.NewCol(6, t.name, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
|
||||
text.NewCol(1, t.counterFailed, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
|
||||
text.NewCol(1, t.counterAll, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
|
||||
text.NewCol(2, t.complianceScore, props.Text{VerticalPadding: 1, Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
|
||||
)
|
||||
|
||||
if i%2 == 0 {
|
||||
r.WithStyle(&props.Cell{
|
||||
BackgroundColor: &props.Color{
|
||||
Red: 224,
|
||||
Green: 224,
|
||||
Blue: 224,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package pdf_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/johnfercher/maroto/v2/pkg/props"
|
||||
"github.com/johnfercher/maroto/v2/pkg/test"
|
||||
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/pdf"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetPdf(t *testing.T) {
|
||||
t.Run("when GetPdf is called, it should return pdf bytes", func(t *testing.T) {
|
||||
|
||||
template := pdf.NewReportTemplate().GenerateHeader("Framework test 1, Framework test 2", "2024-04-01 20:31:00")
|
||||
bytes, err := template.GetPdf()
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, bytes)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateHeader(t *testing.T) {
|
||||
t.Run("when generateHeader is called, it should set the header in the pdf", func(t *testing.T) {
|
||||
template := pdf.NewReportTemplate().GenerateHeader("Framework test 1, Framework test 2", "2024-04-01 20:31:00")
|
||||
|
||||
node := template.GetStructure()
|
||||
|
||||
assert.NotNil(t, node)
|
||||
test.New(t).Assert(node).Equals("headerTemplate.json")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateTable(t *testing.T) {
|
||||
t.Run("when generateTable is called, it should set the table in the pdf", func(t *testing.T) {
|
||||
TableObjectMock := pdf.NewTableRow(
|
||||
"ref", "name", "failed", "all", "severity", "score",
|
||||
func(severity string) *props.Color { return &props.Color{Red: 0, Blue: 0, Green: 0} },
|
||||
)
|
||||
|
||||
template := pdf.NewReportTemplate()
|
||||
|
||||
err := template.GenerateTable(&[]pdf.TableObject{*TableObjectMock}, 100, 10, 10.0)
|
||||
|
||||
assert.Nil(t, err)
|
||||
test.New(t).Assert(template.GetStructure()).Equals("tableTemplate.json")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateInfoRows(t *testing.T) {
|
||||
t.Run("when generateInfoRows is called, it should set the info rows in the pdf", func(t *testing.T) {
|
||||
|
||||
template := pdf.NewReportTemplate().GenerateInfoRows([]string{"row info 1", "row info 2", "row info 3"})
|
||||
|
||||
assert.NotNil(t, template)
|
||||
test.New(t).Assert(template.GetStructure()).Equals("infoTemplate.json")
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"type": "maroto",
|
||||
"details": {
|
||||
"chunk_workers": 1,
|
||||
"config_margin_bottom": 20.0025,
|
||||
"config_margin_left": 10,
|
||||
"config_margin_right": 10,
|
||||
"config_margin_top": 15,
|
||||
"config_max_grid_sum": 12,
|
||||
"config_provider_type": "gofpdf",
|
||||
"generation_mode": "sequential",
|
||||
"maroto_dimension_height": 297,
|
||||
"maroto_dimension_width": 210,
|
||||
"prop_font_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 10
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"type": "page",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 40,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "iVBORw0KGgoAAA==",
|
||||
"type": "bytesImage",
|
||||
"details": {
|
||||
"bytes_size": 54270,
|
||||
"extension": "png",
|
||||
"prop_center": true,
|
||||
"prop_percent": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 6,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Report date: 2024-04-01 20:31:00",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 0.3,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"type": "line",
|
||||
"details": {
|
||||
"prop_offset_percent": 5,
|
||||
"prop_orientation": "horizontal",
|
||||
"prop_size_percent": 100,
|
||||
"prop_style": "solid",
|
||||
"prop_thickness": 0.3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 10,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Framework test 1, Framework test 2",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "C",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 205.6975,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"type": "maroto",
|
||||
"details": {
|
||||
"chunk_workers": 1,
|
||||
"config_margin_bottom": 20.0025,
|
||||
"config_margin_left": 10,
|
||||
"config_margin_right": 10,
|
||||
"config_margin_top": 15,
|
||||
"config_max_grid_sum": 12,
|
||||
"config_provider_type": "gofpdf",
|
||||
"generation_mode": "sequential",
|
||||
"maroto_dimension_height": 297,
|
||||
"maroto_dimension_width": 210,
|
||||
"prop_font_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 10
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"type": "page",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 5.322222222222223,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "row info 1",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 255)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B",
|
||||
"prop_top": 2.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 5.322222222222223,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "row info 2",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 255)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B",
|
||||
"prop_top": 2.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 5.322222222222223,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "row info 3",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 255)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B",
|
||||
"prop_top": 2.5
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 246.03083333333333,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
{
|
||||
"type": "maroto",
|
||||
"details": {
|
||||
"chunk_workers": 1,
|
||||
"config_margin_bottom": 20.0025,
|
||||
"config_margin_left": 10,
|
||||
"config_margin_right": 10,
|
||||
"config_margin_top": 15,
|
||||
"config_max_grid_sum": 12,
|
||||
"config_provider_type": "gofpdf",
|
||||
"generation_mode": "sequential",
|
||||
"maroto_dimension_height": 297,
|
||||
"maroto_dimension_width": 210,
|
||||
"prop_font_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 10
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"type": "page",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 10,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Severity",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Control reference",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 6,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Control name",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Failed resources",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "All resources",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Compliance score",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 6,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 3,
|
||||
"type": "row",
|
||||
"details": {
|
||||
"prop_background_color": "RGB(224, 224, 224)"
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "severity",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "ref",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 6,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "name",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "failed",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "all",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "score",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "courier",
|
||||
"prop_font_size": 6,
|
||||
"prop_vertical_padding": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 0.3,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 0,
|
||||
"type": "col",
|
||||
"details": {
|
||||
"is_max": true
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"type": "line",
|
||||
"details": {
|
||||
"prop_offset_percent": 5,
|
||||
"prop_orientation": "horizontal",
|
||||
"prop_size_percent": 100,
|
||||
"prop_style": "solid",
|
||||
"prop_thickness": 0.3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 0,
|
||||
"type": "col",
|
||||
"details": {
|
||||
"is_max": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 10,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 5,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "Resource summary",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "100",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "10",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"type": "col",
|
||||
"nodes": [
|
||||
{
|
||||
"value": "10.00%",
|
||||
"type": "text",
|
||||
"details": {
|
||||
"prop_align": "L",
|
||||
"prop_breakline_strategy": "empty_space_strategy",
|
||||
"prop_color": "RGB(0, 0, 0)",
|
||||
"prop_font_family": "arial",
|
||||
"prop_font_size": 8,
|
||||
"prop_font_style": "B"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"value": 236.6975,
|
||||
"type": "row",
|
||||
"nodes": [
|
||||
{
|
||||
"value": 12,
|
||||
"type": "col"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
docsPrefix = "https://hub.armosec.io/docs"
|
||||
docsPrefix = "https://kubescape.io/docs"
|
||||
scanControlPrefix = "$ kubescape scan control"
|
||||
controlNameHeader = "Control name"
|
||||
statusHeader = ""
|
||||
|
||||
@@ -142,7 +142,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusFailed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"❌", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: []string{"❌", "test", "https://kubescape.io/docs/ctrlid"},
|
||||
},
|
||||
{
|
||||
name: "skipped control",
|
||||
@@ -154,7 +154,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
},
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"⚠️", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: []string{"⚠️", "test", "https://kubescape.io/docs/ctrlid"},
|
||||
infoToPrintInfo: []utils.InfoStars{
|
||||
{
|
||||
Info: "testInfo",
|
||||
@@ -169,7 +169,7 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusPassed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"✅", "test", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: []string{"✅", "test", "https://kubescape.io/docs/ctrlid"},
|
||||
},
|
||||
{
|
||||
name: "big name",
|
||||
@@ -178,14 +178,14 @@ func TestGenerateCategoryStatusRow(t *testing.T) {
|
||||
Status: apis.StatusFailed,
|
||||
ControlID: "ctrlID",
|
||||
},
|
||||
expectedRows: []string{"❌", "testtesttesttesttesttesttesttesttesttesttesttestte...", "https://hub.armosec.io/docs/ctrlid"},
|
||||
expectedRows: []string{"❌", "testtesttesttesttesttesttesttesttesttesttesttestte...", "https://kubescape.io/docs/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))
|
||||
assert.Equal(t, tt.expectedRows, row)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/ctrlid1",
|
||||
},
|
||||
{
|
||||
name: "control with lowercase ID",
|
||||
controlSummary: &reportsummary.ControlSummary{
|
||||
ControlID: "ctrlid1",
|
||||
},
|
||||
expectedDocsLink: "https://hub.armosec.io/docs/ctrlid1",
|
||||
expectedDocsLink: "https://kubescape.io/docs/ctrlid1",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -209,8 +209,7 @@ func (sp *SARIFPrinter) printConfigurationScan(ctx context.Context, opaSessionOb
|
||||
rsrcAbsPath := path.Join(basePath, filepath)
|
||||
locationResolver, err := locationresolver.NewFixPathLocationResolver(rsrcAbsPath) //
|
||||
if err != nil && !helmChartFileType {
|
||||
logger.L().Debug("failed to create location resolver", helpers.Error(err))
|
||||
continue
|
||||
logger.L().Debug("failed to create location resolver, will use default location", helpers.Error(err))
|
||||
}
|
||||
|
||||
for _, toPin := range result.AssociatedControls {
|
||||
|
||||
@@ -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,15 +28,15 @@ 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
|
||||
┌─────────────────────────────────────────────────┬───────────┬────────────────────────────────────┐
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -10,13 +10,14 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ks := core.NewKubescape()
|
||||
ctx := context.TODO()
|
||||
ks := core.NewKubescape(ctx)
|
||||
downloads := []metav1.DownloadInfo{
|
||||
{Target: "artifacts"}, // download all artifacts
|
||||
{Target: "framework", Identifier: "security"}, // force add the "security" framework
|
||||
}
|
||||
for _, download := range downloads {
|
||||
if err := ks.Download(context.Background(), &download); err != nil {
|
||||
if err := ks.Download(&download); err != nil {
|
||||
logger.L().Error("failed to download artifact", helpers.Error(err), helpers.String("target", download.Target))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
538
go.mod
538
go.mod
@@ -1,116 +1,126 @@
|
||||
module github.com/kubescape/kubescape/v3
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.23.4
|
||||
toolchain go1.24.6
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65
|
||||
github.com/anchore/grype v0.77.1
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240423181235-8b297badafd5
|
||||
github.com/anchore/syft v1.3.0
|
||||
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/anubhav06/copa-grype v1.0.3-alpha.1
|
||||
github.com/armosec/armoapi-go v0.0.330
|
||||
github.com/armosec/utils-go v0.0.57
|
||||
github.com/armosec/utils-k8s-go v0.0.26
|
||||
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/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.0.4+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.19.1
|
||||
github.com/go-git/go-git/v5 v5.13.2
|
||||
github.com/google/go-containerregistry v0.20.3
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/johnfercher/maroto v1.0.0
|
||||
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/k8s-interface v0.0.174
|
||||
github.com/kubescape/opa-utils v0.0.284
|
||||
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
|
||||
github.com/kubescape/regolibrary/v2 v2.0.1
|
||||
github.com/kubescape/sizing-checker v0.0.0-20250116130326-857b8213eca8
|
||||
github.com/kubescape/sizing-checker v0.0.0-20250323151332-73a18561dc73
|
||||
github.com/kubescape/storage v0.0.184
|
||||
github.com/mark3labs/mcp-go v0.29.0
|
||||
github.com/maruel/natural v1.1.1
|
||||
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/moby/buildkit v0.21.0
|
||||
github.com/olekukonko/tablewriter v0.0.6-0.20230417144759-edd1a71a5576
|
||||
github.com/open-policy-agent/opa v0.68.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/sigstore/cosign/v2 v2.2.4
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.opentelemetry.io/otel v1.30.0
|
||||
go.opentelemetry.io/otel/metric v1.30.0
|
||||
golang.org/x/mod v0.20.0
|
||||
golang.org/x/term v0.27.0
|
||||
go.opentelemetry.io/otel v1.35.0
|
||||
go.opentelemetry.io/otel/metric v1.35.0
|
||||
golang.org/x/mod v0.25.0
|
||||
golang.org/x/term v0.33.0
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.14.4
|
||||
k8s.io/api v0.32.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
k8s.io/client-go v0.32.0
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
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.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 (
|
||||
cloud.google.com/go v0.112.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||
cloud.google.com/go/container v1.33.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.6 // indirect
|
||||
cloud.google.com/go/storage v1.39.1 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // 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
|
||||
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-20231105174938-2b5cbb29f3e2 // 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.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
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.23 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.8.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/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.11.7 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.9 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // 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/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // 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
|
||||
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
|
||||
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
|
||||
@@ -122,89 +132,89 @@ require (
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/aliyun/credentials-go v1.3.1 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b // 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-20230725134548-c21dafa1ec5a // 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/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f // indirect
|
||||
github.com/andybalholm/brotli v1.1.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/armosec/gojay v1.2.15 // 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-0.20240912145455-7112c0a0c2d0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // 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-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/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.11.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/kms v1.35.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.8 // indirect
|
||||
github.com/aws/smithy-go v1.20.4 // 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/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/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.6.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bugsnag/bugsnag-go/v2 v2.3.0 // indirect
|
||||
github.com/bugsnag/panicwrap v1.3.4 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.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 v2.2.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.10.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.4.5 // 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.7 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/containerd/containerd v1.7.21 // indirect
|
||||
github.com/containerd/containerd/api v1.7.19 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // 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/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.14.3 // indirect
|
||||
github.com/containerd/ttrpc v1.2.5 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-docker v0.2.1 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.5 // 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.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/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 v26.1.0+incompatible // indirect
|
||||
github.com/docker/docker v26.1.5+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.0 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // 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-units v0.5.0 // indirect
|
||||
@@ -214,83 +224,83 @@ require (
|
||||
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.11.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // 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/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // 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.3 // indirect
|
||||
github.com/github/go-spdx/v2 v2.2.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/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.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 // 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/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
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.0 // indirect
|
||||
github.com/go-test/deep v1.1.1 // 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/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.3.1+incompatible // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/goccy/go-yaml v1.11.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // 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/google/certificate-transparency-go v1.1.8 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // 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-20241029153458-d1b30febd7db // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // 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/mux v1.8.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.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.5 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.8 // 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.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // 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
|
||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
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
|
||||
@@ -298,26 +308,27 @@ require (
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/jung-kurt/gofpdf v1.16.2 // indirect
|
||||
github.com/jwalton/go-supportscolor v1.1.0 // indirect
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
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.0 // 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-20231026200631-000cd05d5491 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // 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/mattn/go-runewidth v0.0.15 // 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
|
||||
@@ -329,106 +340,116 @@ require (
|
||||
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/mountinfo v0.7.1 // indirect
|
||||
github.com/moby/sys/sequential v0.5.0 // indirect
|
||||
github.com/moby/sys/signal v0.7.0 // indirect
|
||||
github.com/moby/sys/user v0.3.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.7.2 // 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/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // 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/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/oleiade/reflections v1.0.1 // 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.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.1.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.1 // indirect
|
||||
github.com/opencontainers/selinux v1.12.0 // indirect
|
||||
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/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.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // 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.2 // 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/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||
github.com/prometheus/client_golang v1.20.2 // indirect
|
||||
github.com/prometheus/client_golang v1.22.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // 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/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
|
||||
github.com/saferwall/pe v1.5.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
|
||||
github.com/sassoftware/go-rpmutils v0.3.0 // 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/secure-systems-lab/go-securesystemslib v0.8.0 // 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/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/sigstore/fulcio v1.4.5 // indirect
|
||||
github.com/sigstore/rekor v1.3.6 // indirect
|
||||
github.com/sigstore/sigstore v1.8.3 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // 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/timestamp-authority v1.2.2 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spdx/tools-golang v0.5.4 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.18.2 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
|
||||
github.com/stripe/stripe-go/v74 v74.28.0 // indirect
|
||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.4.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.11.5 // indirect
|
||||
github.com/sylabs/squashfs v0.6.1 // indirect
|
||||
github.com/sylabs/sif/v2 v2.21.1 // indirect
|
||||
github.com/sylabs/squashfs v1.0.4 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 // 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.11 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // 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/vbatts/go-mtree v0.5.3 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // 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
|
||||
@@ -437,82 +458,89 @@ require (
|
||||
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-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.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.16.2 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.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.56.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.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.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.30.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.30.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.step.sm/crypto v0.44.2 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.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.32.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.8.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.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
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.172.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/grpc v1.67.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.3 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
|
||||
gonum.org/v1/gonum v0.12.0 // 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.1 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gorm.io/gorm v1.25.10 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.29.0 // indirect
|
||||
gorm.io/gorm v1.25.12 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.33.3 // indirect
|
||||
k8s.io/apiserver 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-20241105132330-32ad38e42d3f // indirect
|
||||
modernc.org/libc v1.49.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.29.8 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.15.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/release-utils v0.7.7 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.2 // 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.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-20240426103125-b762a3538c32
|
||||
replace github.com/anchore/stereoscope => github.com/matthyx/stereoscope v0.0.0-20250211130420-468901f0e973
|
||||
|
||||
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/spf13/viper => github.com/spf13/viper v1.19.0
|
||||
|
||||
@@ -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,93 +1,98 @@
|
||||
module github.com/kubescape/kubescape/v3/httphandler
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.23.4
|
||||
toolchain go1.24.6
|
||||
|
||||
replace github.com/kubescape/kubescape/v3 => ../
|
||||
|
||||
require (
|
||||
github.com/armosec/armoapi-go v0.0.330
|
||||
github.com/armosec/utils-go v0.0.57
|
||||
github.com/armosec/utils-k8s-go v0.0.26
|
||||
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/go-openapi/runtime v0.28.0
|
||||
github.com/google/uuid v1.6.0
|
||||
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/k8s-interface v0.0.174
|
||||
github.com/kubescape/k8s-interface v0.0.195
|
||||
github.com/kubescape/kubescape/v3 v3.0.4
|
||||
github.com/kubescape/opa-utils v0.0.284
|
||||
github.com/kubescape/storage v0.0.111
|
||||
github.com/spf13/viper v1.18.2
|
||||
github.com/kubescape/opa-utils v0.0.288
|
||||
github.com/kubescape/storage v0.0.184
|
||||
github.com/spf13/viper v1.20.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0
|
||||
go.opentelemetry.io/otel v1.30.0
|
||||
k8s.io/apimachinery v0.32.0
|
||||
k8s.io/client-go v0.32.0
|
||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738
|
||||
go.opentelemetry.io/otel v1.35.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.30.0
|
||||
go.opentelemetry.io/otel/trace v1.35.0
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/crypto v0.31.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/oauth2 v0.23.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
|
||||
google.golang.org/grpc v1.67.0 // indirect
|
||||
golang.org/x/crypto v0.40.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/net v0.41.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.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.112.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.5.0 // indirect
|
||||
cloud.google.com/go/container v1.33.0 // indirect
|
||||
cloud.google.com/go/iam v1.1.6 // indirect
|
||||
cloud.google.com/go/storage v1.39.1 // indirect
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
cel.dev/expr v0.19.1 // indirect
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // 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
|
||||
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-20231105174938-2b5cbb29f3e2 // 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.11.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
|
||||
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.23 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
|
||||
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
|
||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/CycloneDX/cyclonedx-go v0.8.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/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // 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.5 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.9 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // 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.4.0 // indirect
|
||||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.1 // indirect
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect
|
||||
github.com/adrg/xdg v0.5.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
|
||||
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
|
||||
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
|
||||
@@ -99,95 +104,99 @@ require (
|
||||
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
|
||||
github.com/aliyun/credentials-go v1.3.1 // indirect
|
||||
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65 // indirect
|
||||
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b // 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-20230725134548-c21dafa1ec5a // 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/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
|
||||
github.com/anchore/grype v0.77.1 // indirect
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4 // indirect
|
||||
github.com/anchore/stereoscope v0.0.3-0.20240423181235-8b297badafd5 // indirect
|
||||
github.com/anchore/syft v1.3.0 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // 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/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/armosec/gojay v1.2.15 // 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-0.20240912145455-7112c0a0c2d0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/config v1.27.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.33 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // 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-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/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.11.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.22.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.8 // indirect
|
||||
github.com/aws/smithy-go v1.20.4 // 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/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/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.6.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/briandowns/spinner v1.23.1 // 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 v2.2.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chainguard-dev/git-urls v1.0.2 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.10.0 // indirect
|
||||
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.4.5 // 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.7 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
|
||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/containerd/containerd v1.7.21 // indirect
|
||||
github.com/containerd/containerd/api v1.7.19 // indirect
|
||||
github.com/containerd/continuity v0.4.2 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // 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/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.15.1 // indirect
|
||||
github.com/containerd/ttrpc v1.2.5 // indirect
|
||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||
github.com/containers/common v0.60.4 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-docker v0.2.1 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.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.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/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/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/buildx v0.11.2 // indirect
|
||||
github.com/docker/cli v26.1.0+incompatible // indirect
|
||||
github.com/docker/buildx v0.21.3 // indirect
|
||||
github.com/docker/cli v28.0.4+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.8.2 // indirect
|
||||
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
|
||||
github.com/docker/docker v28.0.4+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // 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
|
||||
@@ -197,85 +206,85 @@ require (
|
||||
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.11.0 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/enescakir/emoji v1.0.0 // indirect
|
||||
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // 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/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/fgprof v0.9.3 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // 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.3 // indirect
|
||||
github.com/github/go-spdx/v2 v2.2.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/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.13.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.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // 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/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.1 // indirect
|
||||
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.0 // indirect
|
||||
github.com/go-test/deep v1.1.1 // 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/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/googleapis v1.4.1 // indirect
|
||||
github.com/goccy/go-yaml v1.11.0 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // 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/google/certificate-transparency-go v1.1.8 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-containerregistry v0.20.0 // 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-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-20241029153458-d1b30febd7db // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // 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.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.3 // 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.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.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.5 // indirect
|
||||
github.com/hashicorp/go-getter v1.7.8 // 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.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // 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
|
||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||
github.com/imdario/mergo v0.3.16 // indirect
|
||||
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
|
||||
@@ -283,8 +292,9 @@ require (
|
||||
github.com/jinzhu/copier v0.4.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/johnfercher/maroto v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
|
||||
github.com/johnfercher/go-tree v1.1.0 // indirect
|
||||
github.com/johnfercher/maroto/v2 v2.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/jung-kurt/gofpdf v1.16.2 // indirect
|
||||
@@ -292,24 +302,25 @@ require (
|
||||
github.com/jwalton/go-supportscolor v1.1.0 // indirect
|
||||
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
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.0 // 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-20240418210053-89b07f4543e0 // indirect
|
||||
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mackerelio/go-osstat v0.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // 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/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
|
||||
@@ -324,115 +335,126 @@ require (
|
||||
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/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/user v0.3.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/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // 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/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // 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/olvrng/ujson v1.1.0 // indirect
|
||||
github.com/open-policy-agent/opa v0.68.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.0 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.0 // indirect
|
||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.2.1 // indirect
|
||||
github.com/opencontainers/selinux v1.12.0 // indirect
|
||||
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/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/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.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // 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.2 // 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/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pquerna/cachecontrol v0.2.0 // indirect
|
||||
github.com/project-copacetic/copacetic v0.4.1-0.20231017020916-013c118454b8 // indirect
|
||||
github.com/prometheus/client_golang v1.20.2 // 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.55.0 // 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/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
|
||||
github.com/saferwall/pe v1.5.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/rs/zerolog v1.30.0 // indirect
|
||||
github.com/saferwall/pe v1.5.6 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
|
||||
github.com/sassoftware/go-rpmutils v0.3.0 // 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.8.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/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sigstore/cosign/v2 v2.2.4 // indirect
|
||||
github.com/sigstore/fulcio v1.4.5 // indirect
|
||||
github.com/sigstore/rekor v1.3.6 // indirect
|
||||
github.com/sigstore/sigstore v1.8.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/timestamp-authority v1.2.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spdx/tools-golang v0.5.4 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/cobra v1.8.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
|
||||
github.com/stripe/stripe-go/v74 v74.28.0 // indirect
|
||||
github.com/spdx/tools-golang v0.5.5 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/cobra v1.9.1 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.4.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.18.0 // indirect
|
||||
github.com/sylabs/squashfs v0.6.1 // indirect
|
||||
github.com/sylabs/sif/v2 v2.21.1 // indirect
|
||||
github.com/sylabs/squashfs v1.0.4 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tchap/go-patricia/v2 v2.3.1 // 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/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/vbatts/go-mtree v0.5.3 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // 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
|
||||
@@ -441,72 +463,79 @@ require (
|
||||
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-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/zclconf/go-cty v1.16.2 // indirect
|
||||
github.com/zeebo/errs v1.3.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.14.0 // indirect
|
||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.1 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.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.56.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.30.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.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.30.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.step.sm/crypto v0.44.2 // indirect
|
||||
golang.org/x/sync v0.10.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/term v0.27.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
gonum.org/v1/gonum v0.9.1 // indirect
|
||||
google.golang.org/api v0.172.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.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.32.0 // indirect
|
||||
go.opentelemetry.io/otel/log v0.8.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.8.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.5.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.3 // indirect
|
||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
|
||||
golang.org/x/image v0.24.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/term v0.33.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
|
||||
gonum.org/v1/gonum v0.12.0 // 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
|
||||
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/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
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.10 // indirect
|
||||
helm.sh/helm/v3 v3.14.4 // indirect
|
||||
k8s.io/api v0.32.0 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.29.0 // indirect
|
||||
gorm.io/gorm v1.25.12 // 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/component-base v0.33.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect
|
||||
modernc.org/libc v1.49.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/sqlite v1.29.8 // indirect
|
||||
sigs.k8s.io/controller-runtime v0.15.0 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
|
||||
sigs.k8s.io/release-utils v0.7.7 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.2 // 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.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.6.0 // indirect
|
||||
sigs.k8s.io/yaml v1.5.0 // indirect
|
||||
)
|
||||
|
||||
// Using the forked version of tablewriter
|
||||
@@ -517,3 +546,5 @@ replace github.com/docker/distribution v2.8.3+incompatible => github.com/docker/
|
||||
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/spf13/viper => github.com/spf13/viper v1.19.0
|
||||
|
||||
3045
httphandler/go.sum
3045
httphandler/go.sum
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,15 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/armosec/armoapi-go/armotypes"
|
||||
"github.com/kubescape/go-logger"
|
||||
"github.com/kubescape/go-logger/helpers"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils"
|
||||
"github.com/kubescape/kubescape/v3/core/cautils/getter"
|
||||
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
|
||||
@@ -67,6 +74,15 @@ func ToScanInfo(scanRequest *utilsmetav1.PostScanRequest) *cautils.ScanInfo {
|
||||
scanInfo.IsDeletedScanObject = *scanRequest.IsDeletedScanObject
|
||||
}
|
||||
|
||||
if scanRequest.Exceptions != nil {
|
||||
path, err := saveExceptions(scanRequest.Exceptions)
|
||||
if err != nil {
|
||||
logger.L().Warning("failed to save exceptions, scanning without them", helpers.Error(err))
|
||||
} else {
|
||||
scanInfo.UseExceptions = path
|
||||
}
|
||||
}
|
||||
|
||||
return scanInfo
|
||||
}
|
||||
|
||||
@@ -92,3 +108,15 @@ func setTargetInScanInfo(scanRequest *utilsmetav1.PostScanRequest, scanInfo *cau
|
||||
scanInfo.ScanAll = true
|
||||
}
|
||||
}
|
||||
|
||||
func saveExceptions(exceptions []armotypes.PostureExceptionPolicy) (string, error) {
|
||||
exceptionsJSON, err := json.Marshal(exceptions)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal exceptions: %w", err)
|
||||
}
|
||||
exceptionsPath := filepath.Join("/tmp", "exceptions.json") // FIXME potential race condition
|
||||
if err := os.WriteFile(exceptionsPath, exceptionsJSON, 0644); err != nil {
|
||||
return "", fmt.Errorf("failed to write exceptions file to disk: %w", err)
|
||||
}
|
||||
return exceptionsPath, nil
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func scan(ctx context.Context, scanInfo *cautils.ScanInfo, scanID string) (*repo
|
||||
ctx, spanScan := otel.Tracer("").Start(ctx, "kubescape.scan")
|
||||
defer spanScan.End()
|
||||
|
||||
ks := core.NewKubescape()
|
||||
ks := core.NewKubescape(ctx)
|
||||
|
||||
spanScan.AddEvent("scanning metadata",
|
||||
trace.WithAttributes(attribute.String("version", versioncheck.BuildNumber)),
|
||||
@@ -79,11 +79,11 @@ func scan(ctx context.Context, scanInfo *cautils.ScanInfo, scanID string) (*repo
|
||||
trace.WithAttributes(attribute.String("hostSensorYamlPath", scanInfo.HostSensorYamlPath)),
|
||||
)
|
||||
|
||||
result, err := ks.Scan(ctx, scanInfo)
|
||||
result, err := ks.Scan(scanInfo)
|
||||
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()
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
_ "github.com/kubescape/kubescape/v3/httphandler/docs"
|
||||
"github.com/kubescape/kubescape/v3/httphandler/listener"
|
||||
"github.com/kubescape/kubescape/v3/httphandler/storage"
|
||||
"k8s.io/client-go/rest"
|
||||
"github.com/kubescape/kubescape/v3/pkg/ksinit"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -68,19 +68,13 @@ func initializeStorage(clusterName string, cfg config.Config) {
|
||||
namespace := getNamespace(cfg)
|
||||
logger.L().Debug("initializing storage", helpers.String("namespace", namespace))
|
||||
|
||||
// for local storage, use the k8s config
|
||||
var config *rest.Config
|
||||
if os.Getenv("LOCAL_STORAGE") == "true" {
|
||||
config = k8sinterface.GetK8sConfig()
|
||||
} else {
|
||||
var err error
|
||||
config, err = rest.InClusterConfig()
|
||||
if err != nil {
|
||||
logger.L().Fatal("storage initialization error", helpers.Error(err))
|
||||
}
|
||||
// Use shared ksinit logic for storage connection
|
||||
ksClient, err := ksinit.CreateKsObjectConnection(namespace, 0)
|
||||
if err != nil {
|
||||
logger.L().Fatal("storage initialization error", helpers.Error(err))
|
||||
}
|
||||
|
||||
s, err := storage.NewAPIServerStorage(clusterName, namespace, config)
|
||||
s, err := storage.NewAPIServerStorage(clusterName, namespace, ksClient)
|
||||
if err != nil {
|
||||
logger.L().Fatal("storage initialization error", helpers.Error(err))
|
||||
}
|
||||
|
||||
@@ -19,12 +19,10 @@ import (
|
||||
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
|
||||
v2 "github.com/kubescape/opa-utils/reporthandling/v2"
|
||||
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
|
||||
"github.com/kubescape/storage/pkg/generated/clientset/versioned"
|
||||
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
|
||||
"go.opentelemetry.io/otel"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/retry"
|
||||
)
|
||||
|
||||
@@ -54,19 +52,9 @@ func GetStorage() *APIServerStore {
|
||||
}
|
||||
|
||||
// NewAPIServerStorage initializes the APIServerStore struct
|
||||
func NewAPIServerStorage(clusterName string, namespace string, config *rest.Config) (*APIServerStore, error) {
|
||||
// disable rate limiting
|
||||
config.QPS = 0
|
||||
config.RateLimiter = nil
|
||||
// force GRPC
|
||||
config.AcceptContentTypes = "application/vnd.kubernetes.protobuf"
|
||||
config.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
clientset, err := versioned.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func NewAPIServerStorage(clusterName string, namespace string, ksClient spdxv1beta1.SpdxV1beta1Interface) (*APIServerStore, error) {
|
||||
return &APIServerStore{
|
||||
StorageClient: clientset.SpdxV1beta1(),
|
||||
StorageClient: ksClient,
|
||||
clusterName: clusterName,
|
||||
namespace: namespace,
|
||||
}, nil
|
||||
@@ -178,15 +166,6 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
|
||||
},
|
||||
}
|
||||
|
||||
// This is a workaround for the fact that the apiserver does not return already exist error on Create
|
||||
existing, err := a.StorageClient.WorkloadConfigurationScans(namespace).Get(context.Background(), manifest.Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
logger.L().Debug("found existing WorkloadConfigurationScan manifest in storage - merging manifests", helpers.String("name", manifest.Name))
|
||||
manifest.Annotations = existing.Annotations
|
||||
manifest.Labels = existing.Labels
|
||||
manifest.Spec = mergeWorkloadConfigurationScanSpec(existing.Spec, manifest.Spec)
|
||||
}
|
||||
|
||||
_, err = a.StorageClient.WorkloadConfigurationScans(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
|
||||
switch {
|
||||
case errors.IsAlreadyExists(err):
|
||||
@@ -198,8 +177,8 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
|
||||
return getErr
|
||||
}
|
||||
// update the workload configuration scan manifest
|
||||
result.Annotations = manifest.Annotations
|
||||
result.Labels = manifest.Labels
|
||||
mergeMaps(result.Annotations, manifest.Annotations)
|
||||
mergeMaps(result.Labels, manifest.Labels)
|
||||
result.Spec = mergeWorkloadConfigurationScanSpec(result.Spec, manifest.Spec)
|
||||
// try to send the updated workload configuration scan manifest
|
||||
_, updateErr := a.StorageClient.WorkloadConfigurationScans(namespace).Update(context.Background(), result, metav1.UpdateOptions{})
|
||||
@@ -221,6 +200,9 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
|
||||
}
|
||||
|
||||
func mergeWorkloadConfigurationScanSpec(existingSpec v1beta1.WorkloadConfigurationScanSpec, newSpec v1beta1.WorkloadConfigurationScanSpec) v1beta1.WorkloadConfigurationScanSpec {
|
||||
if existingSpec.Controls == nil {
|
||||
existingSpec.Controls = make(map[string]v1beta1.ScannedControl)
|
||||
}
|
||||
for ctrlID := range newSpec.Controls {
|
||||
newCtrl := newSpec.Controls[ctrlID]
|
||||
_, found := existingSpec.Controls[ctrlID]
|
||||
@@ -241,6 +223,9 @@ func mergeWorkloadConfigurationScanSpec(existingSpec v1beta1.WorkloadConfigurati
|
||||
}
|
||||
|
||||
func mergeWorkloadConfigurationScanSummarySpec(existingSpec v1beta1.WorkloadConfigurationScanSummarySpec, newSpec v1beta1.WorkloadConfigurationScanSummarySpec) v1beta1.WorkloadConfigurationScanSummarySpec {
|
||||
if existingSpec.Controls == nil {
|
||||
existingSpec.Controls = make(map[string]v1beta1.ScannedControlSummary)
|
||||
}
|
||||
for ctrlID := range newSpec.Controls {
|
||||
newCtrl := newSpec.Controls[ctrlID]
|
||||
_, found := existingSpec.Controls[ctrlID]
|
||||
@@ -280,16 +265,7 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResultSummary(ctx context
|
||||
},
|
||||
}
|
||||
|
||||
// This is a workaround for the fact that the apiserver does not return already exist error on Create
|
||||
existing, err := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Get(context.Background(), manifest.Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
logger.L().Debug("found existing WorkloadConfigurationScanSummary manifest in storage - merging manifests", helpers.String("name", manifest.Name))
|
||||
manifest.Annotations = existing.Annotations
|
||||
manifest.Labels = existing.Labels
|
||||
manifest.Spec = mergeWorkloadConfigurationScanSummarySpec(existing.Spec, manifest.Spec)
|
||||
}
|
||||
|
||||
_, err = a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
|
||||
_, err := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
|
||||
switch {
|
||||
case errors.IsAlreadyExists(err):
|
||||
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||
@@ -300,8 +276,8 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResultSummary(ctx context
|
||||
return getErr
|
||||
}
|
||||
// update the manifest
|
||||
result.Annotations = manifest.Annotations
|
||||
result.Labels = manifest.Labels
|
||||
mergeMaps(result.Annotations, manifest.Annotations)
|
||||
mergeMaps(result.Labels, manifest.Labels)
|
||||
result.Spec = mergeWorkloadConfigurationScanSummarySpec(result.Spec, manifest.Spec)
|
||||
// try to send the updated manifest
|
||||
_, updateErr := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Update(context.Background(), result, metav1.UpdateOptions{})
|
||||
@@ -544,3 +520,10 @@ func parseWorkloadScanRelatedObjectList(relatedObjects []workloadinterface.IMeta
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// mergeMaps merges new into existing, overwriting existing keys with new values
|
||||
func mergeMaps(existing, new map[string]string) {
|
||||
for k, v := range new {
|
||||
existing[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,5 +484,51 @@ func Test_RoleBindingResourceTripletToSlug(t *testing.T) {
|
||||
assert.ElementsMatch(t, tt.expectedSlugs, slugs)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMergeMaps(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
existing map[string]string
|
||||
new map[string]string
|
||||
expected map[string]string
|
||||
}{
|
||||
{
|
||||
name: "merge with no conflicts",
|
||||
existing: map[string]string{"key1": "value1"},
|
||||
new: map[string]string{"key2": "value2"},
|
||||
expected: map[string]string{"key1": "value1", "key2": "value2"},
|
||||
},
|
||||
{
|
||||
name: "merge with conflicts",
|
||||
existing: map[string]string{"key1": "value1"},
|
||||
new: map[string]string{"key1": "newValue1", "key2": "value2"},
|
||||
expected: map[string]string{"key1": "newValue1", "key2": "value2"},
|
||||
},
|
||||
{
|
||||
name: "merge with empty new map",
|
||||
existing: map[string]string{"key1": "value1"},
|
||||
new: map[string]string{},
|
||||
expected: map[string]string{"key1": "value1"},
|
||||
},
|
||||
{
|
||||
name: "merge with empty existing map",
|
||||
existing: map[string]string{},
|
||||
new: map[string]string{"key1": "value1"},
|
||||
expected: map[string]string{"key1": "value1"},
|
||||
},
|
||||
{
|
||||
name: "merge with both maps empty",
|
||||
existing: map[string]string{},
|
||||
new: map[string]string{},
|
||||
expected: map[string]string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mergeMaps(tt.existing, tt.new)
|
||||
assert.Equal(t, tt.expected, tt.existing)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// CurrentDir returns the directory of the file where this function is defined.
|
||||
func CurrentDir() string {
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
|
||||
_, filename, _, ok := runtime.Caller(1)
|
||||
if !ok {
|
||||
panic("failed to get current file info")
|
||||
}
|
||||
return filepath.Dir(filename)
|
||||
}
|
||||
|
||||
16
main.go
16
main.go
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
@@ -11,21 +12,20 @@ import (
|
||||
|
||||
func main() {
|
||||
// Capture interrupt signal
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
// Handle interrupt signal
|
||||
go func() {
|
||||
<-signalChan
|
||||
<-ctx.Done()
|
||||
// Perform cleanup or graceful shutdown here
|
||||
logger.L().StopError("Received interrupt signal, exiting...")
|
||||
|
||||
// Exit the program with proper exit code for SIGINT
|
||||
os.Exit(130)
|
||||
// Clear the signal handler so that a second interrupt signal shuts down immediately
|
||||
stop()
|
||||
}()
|
||||
|
||||
if err := cmd.Execute(); err != nil {
|
||||
if err := cmd.Execute(ctx); err != nil {
|
||||
stop()
|
||||
logger.L().Fatal(err.Error())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/grype/grype"
|
||||
"github.com/anchore/grype/grype/db"
|
||||
"github.com/anchore/grype/grype/grypeerr"
|
||||
"github.com/anchore/grype/grype/match"
|
||||
"github.com/anchore/grype/grype/matcher"
|
||||
"github.com/anchore/grype/grype/matcher/dotnet"
|
||||
"github.com/anchore/grype/grype/matcher/golang"
|
||||
@@ -113,57 +115,117 @@ func getProviderConfig(creds RegistryCredentials) pkg.ProviderConfig {
|
||||
//
|
||||
// It performs image scanning and everything needed in between.
|
||||
type Service struct {
|
||||
dbCfg db.Config
|
||||
dbCfg db.Config
|
||||
dbCloser *db.Closer
|
||||
dbStatus *db.Status
|
||||
dbStore *store.Store
|
||||
}
|
||||
|
||||
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials) (*models.PresenterConfig, error) {
|
||||
var err error
|
||||
|
||||
store, status, dbCloser, err := NewVulnerabilityDB(s.dbCfg, true)
|
||||
if err = validateDBLoad(err, status); err != nil {
|
||||
return nil, err
|
||||
func getIgnoredMatches(vulnerabilityExceptions []string, store *store.Store, packages []pkg.Package, pkgContext pkg.Context) (*match.Matches, []match.IgnoredMatch, error) {
|
||||
if vulnerabilityExceptions == nil {
|
||||
vulnerabilityExceptions = []string{}
|
||||
}
|
||||
|
||||
packages, pkgContext, sbom, err := pkg.Provide(userInput, getProviderConfig(creds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dbCloser != nil {
|
||||
defer dbCloser.Close()
|
||||
var ignoreRules []match.IgnoreRule
|
||||
for _, exception := range vulnerabilityExceptions {
|
||||
rule := match.IgnoreRule{
|
||||
Vulnerability: exception,
|
||||
}
|
||||
ignoreRules = append(ignoreRules, rule)
|
||||
}
|
||||
|
||||
matcher := grype.VulnerabilityMatcher{
|
||||
Store: *store,
|
||||
Matchers: getMatchers(),
|
||||
Store: *store,
|
||||
Matchers: getMatchers(),
|
||||
IgnoreRules: ignoreRules,
|
||||
}
|
||||
|
||||
remainingMatches, ignoredMatches, err := matcher.FindMatches(packages, pkgContext)
|
||||
if err != nil {
|
||||
if !errors.Is(err, grypeerr.ErrAboveSeverityThreshold) {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return remainingMatches, ignoredMatches, nil
|
||||
}
|
||||
|
||||
// Filter the remaing matches based on severity exceptions.
|
||||
func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches match.Matches, store *store.Store) match.Matches {
|
||||
if severityExceptions == nil {
|
||||
return remainingMatches
|
||||
}
|
||||
|
||||
filteredMatches := match.NewMatches()
|
||||
|
||||
for m := range remainingMatches.Enumerate() {
|
||||
metadata, err := store.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip this match if the severity of this match is present in severityExceptions.
|
||||
excludeSeverity := false
|
||||
for _, sever := range severityExceptions {
|
||||
if strings.ToUpper(metadata.Severity) == sever {
|
||||
excludeSeverity = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !excludeSeverity {
|
||||
filteredMatches.Add(m)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredMatches
|
||||
}
|
||||
|
||||
func (s *Service) Scan(_ context.Context, userInput string, creds RegistryCredentials, vulnerabilityExceptions, severityExceptions []string) (*models.PresenterConfig, error) {
|
||||
packages, pkgContext, sbom, err := pkg.Provide(userInput, getProviderConfig(creds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
remainingMatches, ignoredMatches, err := getIgnoredMatches(vulnerabilityExceptions, s.dbStore, packages, pkgContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filteredMatches := filterMatchesBasedOnSeverity(severityExceptions, *remainingMatches, s.dbStore)
|
||||
|
||||
pb := models.PresenterConfig{
|
||||
Matches: *remainingMatches,
|
||||
Matches: filteredMatches,
|
||||
IgnoredMatches: ignoredMatches,
|
||||
Packages: packages,
|
||||
Context: pkgContext,
|
||||
MetadataProvider: store,
|
||||
MetadataProvider: s.dbStore,
|
||||
SBOM: sbom,
|
||||
AppConfig: nil,
|
||||
DBStatus: status,
|
||||
DBStatus: s.dbStatus,
|
||||
}
|
||||
return &pb, nil
|
||||
}
|
||||
|
||||
func (s *Service) Close() {
|
||||
s.dbCloser.Close()
|
||||
}
|
||||
|
||||
func NewVulnerabilityDB(cfg db.Config, update bool) (*store.Store, *db.Status, *db.Closer, error) {
|
||||
return grype.LoadVulnerabilityDB(cfg, update)
|
||||
}
|
||||
|
||||
func NewScanService(dbCfg db.Config) Service {
|
||||
return Service{dbCfg: dbCfg}
|
||||
func NewScanService(dbCfg db.Config) (*Service, error) {
|
||||
dbStore, dbStatus, dbCloser, err := NewVulnerabilityDB(dbCfg, true)
|
||||
if err = validateDBLoad(err, dbStatus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Service{
|
||||
dbCfg: dbCfg,
|
||||
dbCloser: dbCloser,
|
||||
dbStatus: dbStatus,
|
||||
dbStore: dbStore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseSeverity returns a Grype severity given a severity string
|
||||
|
||||
@@ -2,9 +2,12 @@ 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"
|
||||
@@ -14,65 +17,76 @@ import (
|
||||
syftPkg "github.com/anchore/syft/syft/pkg"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// import (
|
||||
// "context"
|
||||
// "testing"
|
||||
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, err := NewScanService(dbCfg)
|
||||
require.NoError(t, err)
|
||||
defer svc.Close()
|
||||
creds := RegistryCredentials{}
|
||||
|
||||
// "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"
|
||||
// )
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
// func TestNewScanService(t *testing.T) {
|
||||
// dbCfg, _ := NewDefaultDBConfig()
|
||||
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))
|
||||
|
||||
// svc := NewScanService(dbCfg)
|
||||
packages, pkgContext, _, err := pkg.Provide(tc.image, getProviderConfig(creds))
|
||||
assert.NoError(t, err)
|
||||
|
||||
// assert.IsType(t, Service{}, svc)
|
||||
// }
|
||||
if dbCloser != nil {
|
||||
defer dbCloser.Close()
|
||||
}
|
||||
|
||||
// func TestScan(t *testing.T) {
|
||||
// tt := []struct {
|
||||
// name string
|
||||
// image string
|
||||
// creds RegistryCredentials
|
||||
// }{
|
||||
// {
|
||||
// name: "Valid image name produces a non-nil scan result",
|
||||
// image: "nginx",
|
||||
// },
|
||||
// {
|
||||
// name: "Scanning a valid image with provided credentials should produce a non-nil scan result",
|
||||
// image: "nginx",
|
||||
// creds: RegistryCredentials{
|
||||
// Username: "test",
|
||||
// Password: "password",
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
remainingMatches, ignoredMatches, err := getIgnoredMatches(tc.vulnerabilityExceptions, store, packages, pkgContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.ignoredLen, len(ignoredMatches))
|
||||
|
||||
// for _, tc := range tt {
|
||||
// t.Run(tc.name, func(t *testing.T) {
|
||||
// ctx := context.Background()
|
||||
// dbCfg, _ := NewDefaultDBConfig()
|
||||
// svc := NewScanService(dbCfg)
|
||||
// creds := RegistryCredentials{}
|
||||
|
||||
// scanResults, err := svc.Scan(ctx, tc.image, creds)
|
||||
|
||||
// assert.NoError(t, err)
|
||||
// assert.IsType(t, &models.PresenterConfig{}, scanResults)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
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 {
|
||||
@@ -327,7 +341,9 @@ func TestGetProviderConfig(t *testing.T) {
|
||||
|
||||
func TestNewScanService(t *testing.T) {
|
||||
defaultConfig, _ := NewDefaultDBConfig()
|
||||
svc := NewScanService(defaultConfig)
|
||||
svc, err := NewScanService(defaultConfig)
|
||||
require.NoError(t, err)
|
||||
defer svc.Close()
|
||||
assert.Equal(t, defaultConfig, svc.dbCfg)
|
||||
}
|
||||
|
||||
|
||||
12
pkg/imagescan/testdata/listing.json
vendored
Normal file
12
pkg/imagescan/testdata/listing.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
pkg/imagescan/testdata/vulnerability-db_v5_2023-03-24T06_54_57Z_fab15e5405c096d82dfd.tar.gz
vendored
Executable file
BIN
pkg/imagescan/testdata/vulnerability-db_v5_2023-03-24T06_54_57Z_fab15e5405c096d82dfd.tar.gz
vendored
Executable file
Binary file not shown.
40
pkg/ksinit/ksinit.go
Normal file
40
pkg/ksinit/ksinit.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package ksinit
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// CreateKsObjectConnection initializes a KS object connection, shared by mcpserver and httphandler
|
||||
func CreateKsObjectConnection(namespace string, maxElapsedTime time.Duration) (spdxv1beta1.SpdxV1beta1Interface, error) {
|
||||
var cfg *rest.Config
|
||||
var err error
|
||||
|
||||
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
|
||||
cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
|
||||
} else {
|
||||
home := os.Getenv("HOME")
|
||||
kubeconfigPath := filepath.Join(home, ".kube", "config")
|
||||
cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
|
||||
if err != nil {
|
||||
cfg, err = rest.InClusterConfig()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// disable rate limiting
|
||||
cfg.QPS = 0
|
||||
cfg.RateLimiter = nil
|
||||
// force GRPC
|
||||
cfg.AcceptContentTypes = "application/vnd.kubernetes.protobuf"
|
||||
cfg.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
|
||||
return spdxv1beta1.NewForConfig(cfg)
|
||||
}
|
||||
Reference in New Issue
Block a user