Compare commits

..

1 Commits

Author SHA1 Message Date
YiscahLevySilas1
945516f840 fix backslashes
Signed-off-by: YiscahLevySilas1 <yiscahls@armosec.io>
2024-01-16 11:55:05 +02:00
182 changed files with 5121 additions and 5406 deletions

View File

@@ -23,6 +23,7 @@ jobs:
permissions:
actions: read
checks: read
contents: read
deployments: read
id-token: write
issues: read
@@ -33,22 +34,18 @@ jobs:
repository-projects: read
security-events: read
statuses: read
attestations: read
contents: write
uses: ./.github/workflows/a-pr-scanner.yaml
with:
RELEASE: ""
CLIENT: test
CGO_ENABLED: 0
GO111MODULE: ""
secrets: inherit
binary-build:
if: ${{ github.actor == 'kubescape' }}
if: ${{ github.repository_owner == 'kubescape' }}
permissions:
actions: read
checks: read
contents: write
contents: read
deployments: read
discussions: read
id-token: write
@@ -59,7 +56,6 @@ jobs:
repository-projects: read
security-events: read
statuses: read
attestations: read
uses: ./.github/workflows/b-binary-build-and-e2e-tests.yaml
with:
COMPONENT_NAME: kubescape

View File

@@ -10,7 +10,7 @@ jobs:
NEW_TAG: ${{ steps.tag-calculator.outputs.NEW_TAG }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
- id: tag-calculator
uses: ./.github/actions/tag-action
with:
@@ -19,6 +19,7 @@ jobs:
permissions:
actions: read
checks: read
contents: read
deployments: read
discussions: read
id-token: write
@@ -29,8 +30,6 @@ jobs:
repository-projects: read
security-events: read
statuses: read
contents: write
attestations: write
needs: [retag]
uses: ./.github/workflows/b-binary-build-and-e2e-tests.yaml
with:
@@ -56,7 +55,6 @@ jobs:
repository-projects: read
statuses: read
security-events: read
attestations: read
needs: [retag, binary-build]
uses: ./.github/workflows/c-create-release.yaml
with:
@@ -68,6 +66,7 @@ jobs:
permissions:
actions: read
checks: read
contents: read
deployments: read
discussions: read
id-token: write
@@ -78,8 +77,6 @@ jobs:
repository-projects: read
security-events: read
statuses: read
attestations: read
contents: write
uses: ./.github/workflows/d-publish-image.yaml
needs: [create-release, retag]
with:
@@ -89,22 +86,3 @@ jobs:
support_platforms: true
cosign: true
secrets: inherit
post-release:
permissions:
actions: read
checks: read
deployments: read
discussions: read
id-token: write
issues: read
packages: write
pages: read
pull-requests: read
repository-projects: read
security-events: read
statuses: read
attestations: read
contents: write
uses: ./.github/workflows/e-post-release.yaml
needs: [publish-image]
secrets: inherit

View File

@@ -1,17 +1,21 @@
name: e-post_release
name: 03-post_release
permissions: read-all
on:
workflow_call: {}
release:
types: [published]
branches:
- 'master'
- 'main'
jobs:
post_release:
name: Post release jobs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Digest
uses: MCJack123/ghaction-generate-release-hashes@c03f3111b39432dde3edebe401c5a8d1ffbbf917 # ratchet:MCJack123/ghaction-generate-release-hashes@v1
with:
submodules: recursive
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@92da038bbf995803124a8e50ebd438b2f37bbbb0 # ratchet:rajatjindal/krew-release-bot@v0.0.43
hash-type: sha1
file-name: kubescape-release-digests
- name: Invoke workflow to update packaging
uses: benc-uk/workflow-dispatch@v1
if: github.repository_owner == 'kubescape'

View File

@@ -0,0 +1,17 @@
name: 04-publish_krew_plugin
permissions: read-all
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
jobs:
publish_krew_plugin:
name: Publish Krew plugin
runs-on: ubuntu-latest
if: github.repository_owner == 'kubescape'
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
submodules: recursive
- name: Update new version in krew-index
uses: rajatjindal/krew-release-bot@92da038bbf995803124a8e50ebd438b2f37bbbb0 # ratchet:rajatjindal/krew-release-bot@v0.0.43

View File

@@ -15,70 +15,7 @@ on:
required: false
type: string
default: "./..."
GO111MODULE:
required: true
type: string
CGO_ENABLED:
type: number
default: 1
jobs:
unit-tests:
if: ${{ github.actor != 'kubescape' }}
name: Create cross-platform build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
- uses: actions/setup-go@v4
name: Installing go
with:
go-version: ${{ inputs.GO_VERSION }}
cache: true
- name: Test core pkg
run: ${{ env.DOCKER_CMD }} go test -v ./...
if: startsWith(github.ref, 'refs/tags')
- name: Test httphandler pkg
run: ${{ env.DOCKER_CMD }} sh -c 'cd httphandler && go test -v ./...'
if: startsWith(github.ref, 'refs/tags')
- uses: anchore/sbom-action/download-syft@v0.15.2
name: Setup Syft
- uses: goreleaser/goreleaser-action@v5
name: Build
with:
distribution: goreleaser
version: latest
args: release --clean --snapshot
env:
RELEASE: ${{ inputs.RELEASE }}
CLIENT: ${{ inputs.CLIENT }}
CGO_ENABLED: ${{ inputs.CGO_ENABLED }}
- name: Smoke Testing
env:
RELEASE: ${{ inputs.RELEASE }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: ${{ env.DOCKER_CMD }} python3 smoke_testing/init.py ${PWD}/dist/kubescape-ubuntu-latest
- name: golangci-lint
continue-on-error: false
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout 10m
only-new-issues: true
skip-pkg-cache: true
skip-build-cache: true
scanners:
env:
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}

View File

@@ -18,7 +18,7 @@ on:
GO_VERSION:
required: false
type: string
default: "1.23"
default: "1.21"
GO111MODULE:
required: false
type: string
@@ -30,32 +30,7 @@ on:
BINARY_TESTS:
type: string
required: false
default: '[
"ks_microservice_create_2_cronjob_mitre_and_nsa_proxy",
"ks_microservice_triggering_with_cron_job",
"ks_microservice_update_cronjob_schedule",
"ks_microservice_delete_cronjob",
"ks_microservice_create_2_cronjob_mitre_and_nsa",
"ks_microservice_ns_creation",
"ks_microservice_on_demand",
"ks_microservice_mitre_framework_on_demand",
"ks_microservice_nsa_and_mitre_framework_demand",
"scan_nsa",
"scan_mitre",
"scan_with_exceptions",
"scan_repository",
"scan_local_file",
"scan_local_glob_files",
"scan_local_list_of_files",
"scan_with_exception_to_backend",
"scan_nsa_and_submit_to_backend",
"scan_mitre_and_submit_to_backend",
"scan_local_repository_and_submit_to_backend",
"scan_repository_from_url_and_submit_to_backend",
"scan_with_custom_framework",
"scan_customer_configuration",
"scan_compliance_score"
]'
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "control_cluster_from_CLI_config_scan_exclude_namespaces", "control_cluster_from_CLI_config_scan_include_namespaces", "control_cluster_from_CLI_config_scan_host_scanner_enabled", "control_cluster_from_CLI_config_scan_MITRE_framework", "control_cluster_from_CLI_vulnerabilities_scan_default", "control_cluster_from_CLI_vulnerabilities_scan_include_namespaces" ]'
workflow_call:
inputs:
@@ -70,7 +45,7 @@ on:
type: string
GO_VERSION:
type: string
default: "1.23"
default: "1.21"
GO111MODULE:
required: true
type: string
@@ -79,25 +54,7 @@ on:
default: 1
BINARY_TESTS:
type: string
default: '[
"scan_nsa",
"scan_mitre",
"scan_with_exceptions",
"scan_repository",
"scan_local_file",
"scan_local_glob_files",
"scan_local_list_of_files",
"scan_nsa_and_submit_to_backend",
"scan_mitre_and_submit_to_backend",
"scan_local_repository_and_submit_to_backend",
"scan_repository_from_url_and_submit_to_backend",
"scan_with_custom_framework",
"scan_customer_configuration",
"scan_compliance_score",
"scan_custom_framework_scanning_file_scope_testing",
"scan_custom_framework_scanning_cluster_scope_testing",
"scan_custom_framework_scanning_cluster_and_file_scope_testing"
]'
default: '[ "scan_nsa", "scan_mitre", "scan_with_exceptions", "scan_repository", "scan_local_file", "scan_local_glob_files", "scan_local_list_of_files", "scan_nsa_and_submit_to_backend", "scan_mitre_and_submit_to_backend", "scan_local_repository_and_submit_to_backend", "scan_repository_from_url_and_submit_to_backend", "scan_with_exception_to_backend", "scan_with_custom_framework", "scan_customer_configuration", "host_scanner", "scan_compliance_score", "scan_custom_framework_scanning_file_scope_testing", "scan_custom_framework_scanning_cluster_scope_testing", "scan_custom_framework_scanning_cluster_and_file_scope_testing" ]'
jobs:
wf-preparation:
@@ -118,7 +75,7 @@ jobs:
SECRET_KEY: ${{ secrets.SECRET_KEY_PROD }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
run: "echo \"is-secret-set=${{ env.CUSTOMER != '' && env.USERNAME != '' && env.PASSWORD != '' && env.CLIENT_ID != '' && env.SECRET_KEY != '' && env.REGISTRY_USERNAME != '' && env.REGISTRY_PASSWORD != '' }}\" >> $GITHUB_OUTPUT\n"
run: "echo \"is-secret-set=${{ env.CUSTOMER != '' && \n env.USERNAME != '' &&\n env.PASSWORD != '' &&\n env.CLIENT_ID != '' &&\n env.SECRET_KEY != '' &&\n env.REGISTRY_USERNAME != '' &&\n env.REGISTRY_PASSWORD != ''\n }}\" >> $GITHUB_OUTPUT\n"
- id: export_tests_to_env
name: set test name
@@ -146,48 +103,31 @@ jobs:
needs: wf-preparation
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: ubuntu-large
runs-on: ubuntu-latest
steps:
- name: (debug) Step 1 - Check disk space before checkout
run: df -h
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: (debug) Step 2 - Check disk space before installing Go
run: df -h
- uses: actions/setup-go@v4
name: Installing go
with:
go-version: ${{ inputs.GO_VERSION }}
cache: true
- name: (debug) Step 3 - Check disk space before build
run: df -h
- name: Test core pkg
run: ${{ env.DOCKER_CMD }} go test -v ./...
if: startsWith(github.ref, 'refs/tags')
- name: (debug) Step 4 - Check disk space before testing httphandler pkg
run: df -h
- name: Test httphandler pkg
run: ${{ env.DOCKER_CMD }} sh -c 'cd httphandler && go test -v ./...'
if: startsWith(github.ref, 'refs/tags')
- name: (debug) Step 5 - Check disk space before setting up Syft
run: df -h
- uses: anchore/sbom-action/download-syft@v0.15.2
name: Setup Syft
- name: (debug) Step 6 - Check disk space before goreleaser
run: df -h
- uses: goreleaser/goreleaser-action@v5
name: Build
with:
@@ -199,30 +139,19 @@ jobs:
CLIENT: ${{ inputs.CLIENT }}
CGO_ENABLED: ${{ inputs.CGO_ENABLED }}
- name: (debug) Step 7 - Check disk space before smoke testing
run: df -h
- name: Smoke Testing
env:
RELEASE: ${{ inputs.RELEASE }}
KUBESCAPE_SKIP_UPDATE_CHECK: "true"
run: ${{ env.DOCKER_CMD }} python3 smoke_testing/init.py ${PWD}/dist/kubescape-ubuntu-latest
- name: (debug) Step 8 - Check disk space before golangci-lint
run: df -h
- name: golangci-lint
continue-on-error: true
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # ratchet:golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout 10m
args: --timeout 10m --build-tags=static
only-new-issues: true
skip-pkg-cache: true
skip-build-cache: true
- name: (debug) Step 9 - Check disk space before uploading artifacts
run: df -h
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # ratchet:actions/upload-artifact@v3.1.1
name: Upload artifacts
@@ -231,12 +160,9 @@ jobs:
path: dist/kubescape*
if-no-files-found: error
- name: (debug) Step 10 - Check disk space after uploading artifacts
run: df -h
build-http-image:
permissions:
contents: write
contents: read
id-token: write
packages: write
pull-requests: read
@@ -249,7 +175,7 @@ jobs:
CGO_ENABLED: 0
GO111MODULE: "on"
BUILD_PLATFORM: linux/amd64,linux/arm64
GO_VERSION: "1.23"
GO_VERSION: "1.21"
REQUIRED_TESTS: '[
"ks_microservice_create_2_cronjob_mitre_and_nsa_proxy",
"ks_microservice_triggering_with_cron_job",
@@ -260,22 +186,8 @@ jobs:
"ks_microservice_on_demand",
"ks_microservice_mitre_framework_on_demand",
"ks_microservice_nsa_and_mitre_framework_demand",
"scan_nsa",
"scan_mitre",
"scan_with_exceptions",
"scan_repository",
"scan_local_file",
"scan_local_glob_files",
"scan_local_list_of_files",
"scan_with_exception_to_backend",
"scan_nsa_and_submit_to_backend",
"scan_mitre_and_submit_to_backend",
"scan_local_repository_and_submit_to_backend",
"scan_repository_from_url_and_submit_to_backend",
"scan_with_custom_framework",
"scan_customer_configuration",
"scan_compliance_score"
]'
]'
COSIGN: true
HELM_E2E_TEST: true
FORCE: true
@@ -293,7 +205,7 @@ jobs:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
id: download-artifact
with:
name: kubescape
name: kubescape-ubuntu-latest
path: "~"
- run: ls -laR
@@ -302,7 +214,7 @@ jobs:
run: chmod +x -R ${{steps.download-artifact.outputs.download-path}}/kubescape-ubuntu-latest
- name: Checkout systests repo
uses: actions/checkout@v4
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
repository: armosec/system-tests
path: .
@@ -355,6 +267,5 @@ jobs:
uses: mikepenz/action-junit-report@6e9933f4a97f4d2b99acef4d7b97924466037882 # ratchet:mikepenz/action-junit-report@v3.6.1
if: always() # always run even if the previous step fails
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
report_paths: '**/results_xml_format/**.xml'
commit: ${{github.event.workflow_run.head_sha}}

View File

@@ -23,7 +23,7 @@ jobs:
permissions:
id-token: write
packages: write
contents: write
contents: read
pull-requests: read
uses: kubescape/workflows/.github/workflows/incluster-comp-pr-merged.yaml@main
with:

View File

@@ -24,8 +24,8 @@ jobs:
MAC_OS: macos-latest
UBUNTU_OS: ubuntu-latest
WINDOWS_OS: windows-latest
permissions:
contents: write
# permissions:
# contents: write
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
id: download-artifact
@@ -33,59 +33,41 @@ jobs:
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
- name: Get kubescape.exe from kubescape-windows-latest
run: cp ./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }} ./kubescape-${{ env.WINDOWS_OS }}/kubescape.exe
- name: Set release token
id: set-token
run: |
if [ "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" != "" ]; then
echo "token=${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" >> $GITHUB_OUTPUT;
echo "TOKEN=${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" >> $GITHUB_ENV;
else
echo "token=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_OUTPUT;
echo "TOKEN=${{ secrets.GITHUB_TOKEN }}" >> $GITHUB_ENV;
fi
- name: List artifacts
run: |
find . -type f -print
- name: Release
uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # ratchet:softprops/action-gh-release@v1
with:
token: ${{ steps.set-token.outputs.token }}
token: ${{ env.TOKEN }}
name: ${{ inputs.RELEASE_NAME }}
tag_name: ${{ inputs.TAG }}
body: ${{ github.event.pull_request.body }}
draft: ${{ inputs.DRAFT }}
prerelease: false
fail_on_unmatched_files: true
prerelease: false
# TODO: kubescape-windows-latest is deprecated and should be removed
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
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}.sha256
./kubescape-${{ env.MAC_OS }}/kubescape-${{ env.MAC_OS }}.tar.gz
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}.sha256
./kubescape-${{ env.UBUNTU_OS }}/kubescape-${{ env.UBUNTU_OS }}.tar.gz
./kubescape-${{ env.WINDOWS_OS }}/kubescape.exe
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}.sha256
./kubescape-${{ env.WINDOWS_OS }}/kubescape-${{ env.WINDOWS_OS }}.tar.gz
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}.sha256
./kubescapearm64-${{ env.MAC_OS }}/kubescape-arm64-${{ env.MAC_OS }}.tar.gz
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}.sha256
./kubescapearm64-${{ env.UBUNTU_OS }}/kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz

View File

@@ -1,18 +1,5 @@
name: d-publish-image
permissions:
actions: read
checks: read
contents: write
deployments: read
discussions: read
id-token: write
issues: read
packages: read
pages: read
pull-requests: read
repository-projects: read
statuses: read
security-events: read
permissions: read-all
on:
workflow_call:
inputs:
@@ -59,7 +46,7 @@ jobs:
name: Build image and upload to registry
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # ratchet:actions/checkout@v3
with:
submodules: recursive
- name: Set up QEMU
@@ -76,9 +63,9 @@ jobs:
with:
path: .
- name: mv kubescape amd64 binary
run: mv ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-ubuntu-latest kubescape-amd64-ubuntu-latest
run: mv kubescape-ubuntu-latest/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-arm64-ubuntu-latest kubescape-arm64-ubuntu-latest
- name: chmod +x
run: chmod +x -v kubescape-a*
- name: Build and push images

View File

@@ -37,7 +37,7 @@ jobs:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
with:
results_file: results.sarif
results_format: sarif

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "git2go"]
path = git2go
url = https://github.com/libgit2/git2go.git

View File

@@ -1,6 +1,6 @@
linters-settings:
govet:
shadow: true
check-shadowing: true
dupl:
threshold: 200
goconst:
@@ -24,6 +24,7 @@ linters:
- gosimple
disable:
# temporarily disabled
- varcheck
- errcheck
- dupl
- gocritic
@@ -35,6 +36,8 @@ linters:
- unparam
#- forbidigo # <- see later
# should remain disabled
- deadcode # deprecated linter
- maligned
- lll
- gochecknoinits
- gochecknoglobals
@@ -49,3 +52,6 @@ issues:
- linters:
- stylecheck
text: "ST1003"
run:
skip-dirs:
- git2go

View File

@@ -12,18 +12,14 @@ before:
- go mod tidy
builds:
- goos:
- id: "kubescape-cli"
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
- riscv64
ldflags:
- -s -w
- -X "github.com/kubescape/kubescape/v3/core/cautils.BuildNumber={{.Env.RELEASE}}"
- -X "github.com/kubescape/kubescape/v3/core/cautils.Client={{.Env.CLIENT}}"
binary: >-
{{ .ProjectName }}-
{{- if eq .Arch "amd64" }}
@@ -34,11 +30,8 @@ builds:
no_unique_dist_dir: true
archives:
- format: binary
id: binaries
name_template: >-
{{ .Binary }}
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .Binary }}
@@ -49,12 +42,5 @@ changelog:
- "^docs:"
- "^test:"
checksum:
ids:
- binaries
split: true
sboms:
- artifacts: binary
documents:
- "{{ .Binary }}.sbom"
- artifacts: archive

View File

@@ -1,16 +1,14 @@
# Adopters
# Well-known companies
List of well-known companies who are publicly acknowledge using and/or contributing to Kubescape are (in alphabetical order):
* AWS uses Kubescape in the security training material [link](https://catalog.workshops.aws/containersecurity/en-US/module2)
* Energi Danmark: Publicly talking about how they use Kubescape in their CI/CD pipeline [link](https://www.armosec.io/energi-danmark-business-support/)
* Gitpod: Used Kubescape in their SOC2 compliance process [link](https://www.armosec.io/gitpod/)
* Intel: using Kubescape for security prioritization [video](https://youtu.be/1iCW1KboypY?si=OjmnshWbpFNVPGJT)
* Orange Business: talking about Kubescape/ARMO service they are doing [video](https://www.youtube.com/watch?v=cbJYCUM8578)
* Rabobank: talked at KCD Amsterdam about having Kubescape in their technology stack [video](https://youtu.be/oa_YJmjwepI?si=vSrFW6seMKHj2Lze) [image](/docs/img/kcd-amsterdam-rabo.jpg)
* VMWare/Bitnami: listing Kubescape in their public image/helm repository [link](https://github.com/bitnami/containers/tree/main/bitnami/kubescape)
Well-known companies who are using and/or contributing to Kubescape are (in alphabetical order):
* Accenture
* Amazon.com
* IBM
* Intel
* Meetup
* RedHat
* Scaleway
# Users

View File

@@ -1,12 +1,28 @@
.PHONY: test all build
.PHONY: test all build libgit2
# default task invoked while running make
all: build
all: libgit2 build
export CGO_ENABLED=0
export CGO_ENABLED=1
# build and install libgit2
libgit2:
-git submodule update --init --recursive
cd git2go; make install-static
# build and install libgit2 for macOS m1
libgit2arm64:
git submodule update --init --recursive
if [ "$(shell uname -s)" = "Darwin" ]; then \
sed -i '' 's/cmake -D/cmake -DCMAKE_OSX_ARCHITECTURES="arm64" -D/' git2go/script/build-libgit2.sh; \
fi
cd git2go; make install-static
# go build tags
TAGS = "gitenabled,static"
build:
go build -v .
go build -v -tags=$(TAGS) .
test:
go test -v ./...
go test -v -tags=$(TAGS) ./...

View File

@@ -20,23 +20,13 @@
<img alt="Kubescape logo" align="right" src="https://raw.githubusercontent.com/cncf/artwork/master/projects/kubescape/stacked/color/kubescape-stacked-color.svg" width="150">
</picture>
_Comprehensive Kubernetes Security from Development to Runtime_
_An open-source Kubernetes security platform for your clusters, CI/CD pipelines, and IDE that seperates out the security signal from the scanner noise_
Kubescape is an open-source Kubernetes security platform that provides comprehensive security coverage from left to right across the entire development and deployment lifecycle. It offers hardening, posture management, and runtime security capabilities to ensure robust protection for Kubernetes environments.
Kubescape is an open-source Kubernetes security platform, built for use in your day-to-day workflow, by fitting into your clusters, CI/CD pipelines and IDE. It serves as a one-stop-shop for Kuberenetes security and includes vulnerability and misconfiguration scanning. You can run scans via the CLI, or add the Kubescape Helm chart, which gives an in-depth view of what is going on in the cluster.
**Key features of Kubescape include**
Kubescape includes misconfiguration and vulnerability scanning as well as risk analysis and security compliance indicators. All results are presented in context and users get many cues on what to do based on scan results.Targeted at the DevSecOps practitioner or platform engineer, it offers an easy-to-use CLI interface, flexible output formats, and automated scanning capabilities. It saves Kubernetes users and admins precious time, effort, and resources.
* **Shift-left security**: Kubescape enables developers to scan for misconfigurations as early as the manifest file submission stage, promoting a proactive approach to security.
* **IDE and CI/CD integration**: The tool integrates seamlessly with popular IDEs like VSCode and Lens, as well as CI/CD platforms such as GitHub and GitLab, allowing for security checks throughout the development process.
* **Cluster scanning**: Kubescape can scan active Kubernetes clusters for vulnerabilities, misconfigurations, and security issues
* **Multiple framework support**: Kubescape can test against various security frameworks, including NSA, MITRE, SOC2, and more.
* **YAML and Helm chart validation**: The tool checks YAML files and Helm charts for correct configuration according to the frameworks above, without requiring an active cluster.
* **Kubernetes hardening**: Kubescape ensures proactive identification and rapid remediation of misconfigurations and vulnerabilities through manual, recurring, or event-triggered scans.
* **Runtime security**: Kubescape extends its protection to the runtime environment, providing continuous monitoring and threat detection for deployed applications.
* **Compliance management**: The tool aids in maintaining compliance with recognized frameworks and standards, simplifying the process of meeting regulatory requirements.
* **Multi-cloud support**: Kubescape offers frictionless security across various cloud providers and Kubernetes distributions.
By providing this comprehensive security coverage from development to production, Kubescape enables organizations to implement a robust security posture throughout their Kubernetes deployment, addressing potential vulnerabilities and threats at every stage of the application lifecycle.
Kubescape scans clusters, YAML files, and Helm charts. It detects misconfigurations according to multiple frameworks (including [NSA-CISA](https://www.armosec.io/blog/kubernetes-hardening-guidance-summary-by-armo/?utm_source=github&utm_medium=repository), [MITRE ATT&CK®](https://www.microsoft.com/security/blog/2021/03/23/secure-containerized-environments-with-updated-threat-matrix-for-kubernetes/) and the [CIS Benchmark](https://www.armosec.io/blog/cis-kubernetes-benchmark-framework-scanning-tools-comparison/?utm_source=github&utm_medium=repository)).
Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) and is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/).
@@ -67,40 +57,23 @@ _Did you know you can use Kubescape in all these places?_
<img src="docs/img/ksfromcodetodeploy.png" alt="Places you can use Kubescape: in your IDE, CI, CD, or against a running cluster.">
</div>
## Kubescape-operator Helm-Chart
Besides the CLI, the Kubescape operator can also be installed via a Helm chart. Installing the Helm chart is an excellent way to begin using Kubescape, as it provides extensive features such as continuous scanning, image vulnerability scanning, runtime analysis, network policy generation, and more. You can find the Helm chart in the [Kubescape-operator documentation](https://kubescape.io/docs/install-operator/).
## Kubescape GitHub Action
Kubescape can be used as a GitHub Action. This is a great way to integrate Kubescape into your CI/CD pipeline. You can find the Kubescape GitHub Action in the [GitHub Action marketplace](https://github.com/marketplace/actions/kubescape).
## Under the hood
Kubescape uses [Open Policy Agent](https://github.com/open-policy-agent/opa) to verify Kubernetes objects against [a library of posture controls](https://github.com/kubescape/regolibrary).
For image scanning, it uses [Grype](https://github.com/anchore/grype).
For image patching, it uses [Copacetic](https://github.com/project-copacetic/copacetic).
By default, the results are printed in a console-friendly manner, but they can be:
* exported to JSON, junit XML or SARIF
* exported to JSON or junit XML
* rendered to HTML or PDF
* submitted to a [cloud service](docs/providers.md)
It retrieves Kubernetes objects from the API server and runs a set of [Rego snippets](https://www.openpolicyagent.org/docs/latest/policy-language/) developed by [ARMO](https://www.armosec.io?utm_source=github&utm_medium=repository).
## Architecture
![kubescape](docs/img/architecture-diagram.png)
**Otel collector** - is not built-in, Otel endpoint spec is need to be added at setup [Setting Otel](https://kubescape.io/docs/operator/telemetry/)
## Community
Kubescape is an open source project, we welcome your feedback and ideas for improvement. We are part of the cloud-native community and are enhancing the project as the ecosystem develops.
Kubescape is an open source project, we welcome your feedback and ideas for improvement. We are part of the Kubernetes community and are building more tests and controls as the ecosystem develops.
We hold [community meetings](https://zoom.us/j/95174063585) on Zoom, every other week, at 15:00 CET. ([See that in your local time zone](https://time.is/compare/1500_in_CET).
We hold [community meetings](https://zoom.us/j/95174063585) on Zoom, on the first Tuesday of every month, at 14:00 GMT. ([See that in your local time zone](https://time.is/compare/1400_in_GMT)).
The Kubescape project follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
@@ -128,7 +101,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-2023, 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) sandbox project](https://www.cncf.io/sandbox-projects/) and was contributed by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository).

78
build.ps1 Normal file
View File

@@ -0,0 +1,78 @@
# Defining input params
param (
[string]$mode = "error"
)
# Function to install MSYS
function Install {
Write-Host "Starting install..." -ForegroundColor Cyan
# Check to see if already installed
if (Test-Path "C:\MSYS64\") {
Write-Host "MSYS2 already installed" -ForegroundColor Green
} else {
# Create a temp directory
New-Item -Path "$PSScriptRoot\temp_install" -ItemType Directory > $null
# Download MSYS
Write-Host "Downloading MSYS2..." -ForegroundColor Cyan
$bitsJobObj = Start-BitsTransfer "https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-x86_64-20220603.exe" -Destination "$PSScriptRoot\temp_install\msys2-x86_64-20220603.exe"
switch ($bitsJobObj.JobState) {
"Transferred" {
Complete-BitsTransfer -BitsJob $bitsJobObj
break
}
"Error" {
throw "Error downloading"
}
}
Write-Host "MSYS2 download complete" -ForegroundColor Green
# Install MSYS
Write-Host "Installing MSYS2..." -ForegroundColor Cyan
Start-Process -Filepath "$PSScriptRoot\temp_install\msys2-x86_64-20220603.exe" -ArgumentList @("install", "--root", "C:\MSYS64", "--confirm-command") -Wait
Write-Host "MSYS2 install complete" -ForegroundColor Green
# Remove temp directory
Remove-Item "$PSScriptRoot\temp_install" -Recurse
}
# Set PATH
$env:Path = "C:\MSYS64\mingw64\bin;C:\MSYS64\usr\bin;" + $env:Path
# Install MSYS packages
Write-Host "Installing MSYS2 packages..." -ForegroundColor Cyan
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "make") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-cmake") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-gcc") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "mingw-w64-x86_64-pkg-config") -Wait
Start-Process -Filepath "pacman" -ArgumentList @("-S", "--needed", "--noconfirm", "msys2-w32api-runtime") -Wait
Write-Host "MSYS2 packages install complete" -ForegroundColor Green
Write-Host "Install complete" -ForegroundColor Green
}
# Function to build libgit2
function Build {
Write-Host "Starting build..." -ForegroundColor Cyan
# Set PATH
$env:Path = "C:\MSYS64\mingw64\bin;C:\MSYS64\usr\bin;" + $env:Path
# Build
Start-Process -Filepath "make" -ArgumentList @("libgit2") -Wait -NoNewWindow
Write-Host "Build complete" -ForegroundColor Green
}
# Check user call mode
if ($mode -eq "all") {
Install
Build
} elseif ($mode -eq "install") {
Install
} elseif ($mode -eq "build") {
Build
} else {
Write-Host "Error: -mode should be one of (all|install|build)" -ForegroundColor Red
}

97
build.py Normal file
View File

@@ -0,0 +1,97 @@
import os
import sys
import hashlib
import platform
import subprocess
import tarfile
BASE_GETTER_CONST = "github.com/kubescape/kubescape/v3/core/cautils/getter"
CURRENT_PLATFORM = platform.system()
platformSuffixes = {
"Windows": "windows-latest",
"Linux": "ubuntu-latest",
"Darwin": "macos-latest",
}
def check_status(status, msg):
if status != 0:
sys.stderr.write(msg)
exit(status)
def get_build_dir():
return "build"
def get_package_name():
if CURRENT_PLATFORM not in platformSuffixes: raise OSError("Platform %s is not supported!" % (CURRENT_PLATFORM))
# # TODO: kubescape-windows-latest is deprecated and should be removed
# if CURRENT_PLATFORM == "Windows": return "kubescape.exe"
package_name = "kubescape-"
if os.getenv("GOARCH"):
package_name += os.getenv("GOARCH") + "-"
return package_name + platformSuffixes[CURRENT_PLATFORM]
def main():
print("Building Kubescape")
# Set some variables
package_name = get_package_name()
build_url = "github.com/kubescape/kubescape/v3/core/cautils.BuildNumber"
release_version = os.getenv("RELEASE")
client_var = "github.com/kubescape/kubescape/v3/core/cautils.Client"
client_name = os.getenv("CLIENT")
# Create build directory
build_dir = get_build_dir()
ks_file = os.path.join(build_dir, package_name)
hash_file = ks_file + ".sha256"
tar_file = ks_file + ".tar.gz"
if not os.path.isdir(build_dir):
os.makedirs(build_dir)
# Build kubescape
ldflags = "-w -s"
if release_version:
ldflags += " -X {}={}".format(build_url, release_version)
if client_name:
ldflags += " -X {}={}".format(client_var, client_name)
build_command = ["go", "build", "-buildmode=pie", "-tags=static,gitenabled", "-o", ks_file, "-ldflags" ,ldflags]
if CURRENT_PLATFORM == "Windows":
os.putenv("CGO_ENABLED", "0")
build_command = ["go", "build", "-o", ks_file, "-ldflags", ldflags]
print("Building kubescape and saving here: {}".format(ks_file))
print("Build command: {}".format(" ".join(build_command)))
status = subprocess.call(build_command)
check_status(status, "Failed to build kubescape")
sha256 = hashlib.sha256()
with open(ks_file, "rb") as kube:
sha256.update(kube.read())
with open(hash_file, "w") as kube_sha:
hash = sha256.hexdigest()
print("kubescape hash: {}, file: {}".format(hash, hash_file))
kube_sha.write(sha256.hexdigest())
with tarfile.open(tar_file, 'w:gz') as archive:
name = "kubescape"
if CURRENT_PLATFORM == "Windows":
name += ".exe"
archive.add(ks_file, name)
archive.add("LICENSE", "LICENSE")
print("Build Done")
if __name__ == "__main__":
main()

View File

@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.23-bookworm AS builder
FROM --platform=$BUILDPLATFORM golang:1.21-bullseye as builder
ENV GO111MODULE=on CGO_ENABLED=0
WORKDIR /work
@@ -9,7 +9,7 @@ RUN --mount=target=. \
--mount=type=cache,target=/go/pkg \
cd httphandler && GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o /out/ksserver .
FROM gcr.io/distroless/static-debian12:nonroot
FROM gcr.io/distroless/static-debian11:nonroot
USER nonroot
WORKDIR /home/nonroot/

View File

@@ -1,2 +1,3 @@
.git
git2go
kubescape*

View File

@@ -1,4 +1,4 @@
FROM gcr.io/distroless/base-debian12:debug-nonroot
FROM gcr.io/distroless/base-debian11:debug-nonroot
USER nonroot
WORKDIR /home/nonroot/

View File

@@ -1 +1,2 @@
.git
git2go

View File

@@ -3,7 +3,7 @@ package config
import (
"context"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -5,7 +5,7 @@ import (
"sort"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/meta"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -3,7 +3,7 @@ package config
import (
"os"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"

View File

@@ -6,7 +6,7 @@ import (
"path/filepath"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"

View File

@@ -6,7 +6,7 @@ import (
"fmt"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/kubescape/v3/core/meta"

View File

@@ -47,7 +47,6 @@ The patch command can be run in 2 ways:
| -a, --addr | Address of the buildkitd service | No | unix:///run/buildkit/buildkitd.sock |
| -t, --tag | Tag of the resultant patched image | No | image_name-patched |
| --timeout | Timeout for the patching process | No | 5m |
| --ignore-errors| Ignore errors during patching | No | false |
| -u, --username | Username for the image registry login | No | |
| -p, --password | Password for the image registry login | No | |
| -f, --format | Output file format. | No | |

View File

@@ -7,6 +7,7 @@ import (
"strings"
"time"
ref "github.com/distribution/distribution/reference"
"github.com/docker/distribution/reference"
"github.com/kubescape/go-logger"
@@ -69,7 +70,6 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
patchCmd.PersistentFlags().StringVarP(&patchInfo.PatchedImageTag, "tag", "t", "", "Tag for the patched image. Defaults to '<image-tag>-patched' ")
patchCmd.PersistentFlags().StringVarP(&patchInfo.BuildkitAddress, "address", "a", "unix:///run/buildkit/buildkitd.sock", "Address of buildkitd service, defaults to local buildkitd.sock")
patchCmd.PersistentFlags().DurationVar(&patchInfo.Timeout, "timeout", 5*time.Minute, "Timeout for the operation, defaults to '5m'")
patchCmd.PersistentFlags().BoolVar(&patchInfo.IgnoreError, "ignore-errors", false, "Ignore errors and continue patching other images. Default to false")
patchCmd.PersistentFlags().StringVarP(&patchInfo.Username, "username", "u", "", "Username for registry login")
patchCmd.PersistentFlags().StringVarP(&patchInfo.Password, "password", "p", "", "Password for registry login")
@@ -97,22 +97,22 @@ func validateImagePatchInfo(patchInfo *metav1.PatchInfo) error {
}
// Parse the image full name to get image name and tag
named, err := reference.ParseNamed(patchInfoImage)
named, err := ref.ParseNamed(patchInfoImage)
if err != nil {
return err
}
// If no tag or digest is provided, default to 'latest'
if reference.IsNameOnly(named) {
if ref.IsNameOnly(named) {
logger.L().Warning("Image name has no tag or digest, using latest as tag")
named = reference.TagNameOnly(named)
named = ref.TagNameOnly(named)
}
patchInfo.Image = named.String()
// If no patched image tag is provided, default to '<image-tag>-patched'
if patchInfo.PatchedImageTag == "" {
taggedName, ok := named.(reference.Tagged)
taggedName, ok := named.(ref.Tagged)
if !ok {
return errors.New("unexpected error while parsing image tag")
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v3/cmd/completion"
@@ -16,7 +16,6 @@ import (
"github.com/kubescape/kubescape/v3/cmd/patch"
"github.com/kubescape/kubescape/v3/cmd/scan"
"github.com/kubescape/kubescape/v3/cmd/update"
"github.com/kubescape/kubescape/v3/cmd/vap"
"github.com/kubescape/kubescape/v3/cmd/version"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
@@ -98,7 +97,6 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.AddCommand(update.GetUpdateCmd())
rootCmd.AddCommand(fix.GetFixCmd(ks))
rootCmd.AddCommand(patch.GetPatchCmd(ks))
rootCmd.AddCommand(vap.GetVapHelperCmd())
rootCmd.AddCommand(operator.GetOperatorCmd(ks))
// deprecated commands

View File

@@ -8,7 +8,7 @@ import (
v1 "github.com/kubescape/backend/pkg/client/v1"
"github.com/kubescape/backend/pkg/servicediscovery"
sdClientV2 "github.com/kubescape/backend/pkg/servicediscovery/v2"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/go-logger/iconlogger"
"github.com/kubescape/go-logger/zaplogger"
@@ -77,7 +77,7 @@ func initEnvironment() {
)
if err != nil {
logger.L().Fatal("failed to get services from server", helpers.Error(err), helpers.String("server", rootInfo.DiscoveryServerURL))
logger.L().Fatal("failed to to get services from server", helpers.Error(err), helpers.String("server", rootInfo.DiscoveryServerURL))
return
}

View File

@@ -9,7 +9,7 @@ import (
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"

View File

@@ -13,7 +13,7 @@ import (
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"golang.org/x/exp/slices"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
@@ -94,7 +94,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
if len(args) > 1 {
if args[1] != "-" {
if len(args[1:]) == 0 || args[1] != "-" {
scanInfo.InputPatterns = args[1:]
logger.L().Debug("List of input files", helpers.Interface("patterns", scanInfo.InputPatterns))
} else { // store stdin to file - do NOT move to separate function !!
@@ -112,6 +112,7 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
}
}
scanInfo.SetScanType(cautils.ScanTypeFramework)
scanInfo.FrameworkScan = true
scanInfo.SetPolicyIdentifiers(frameworks, apisv1.KindFramework)
@@ -177,7 +178,7 @@ func countersExceedSeverityThreshold(severityCounters reportsummary.ISeverityCou
// terminateOnExceedingSeverity terminates the application on exceeding severity
func terminateOnExceedingSeverity(scanInfo *cautils.ScanInfo, l helpers.ILogger) {
l.Fatal("compliance result exceeds severity threshold", helpers.String("set severity threshold", scanInfo.FailThresholdSeverity))
l.Fatal("result exceeds severity threshold", helpers.String("set severity threshold", scanInfo.FailThresholdSeverity))
}
// enforceSeverityThresholds ensures that the scan results are below the defined severity threshold

View File

@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/cmd/shared"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"strings"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/kubescape/kubescape/v3/core/meta"
@@ -46,17 +45,12 @@ func GetScanCommand(ks meta.IKubescape) *cobra.Command {
if scanInfo.View == string(cautils.SecurityViewType) {
setSecurityViewScanInfo(args, &scanInfo)
if err := securityScan(scanInfo, ks); err != nil {
logger.L().Fatal(err.Error())
}
} else if len(args) == 0 || (args[0] != "framework" && args[0] != "control") {
if err := getFrameworkCmd(ks, &scanInfo).RunE(cmd, append([]string{strings.Join(getter.NativeFrameworks, ",")}, args...)); err != nil {
logger.L().Fatal(err.Error())
}
} else {
return fmt.Errorf("kubescape did not do anything")
return securityScan(scanInfo, ks)
}
if len(args) == 0 || (args[0] != "framework" && args[0] != "control") {
return getFrameworkCmd(ks, &scanInfo).RunE(cmd, append([]string{strings.Join(getter.NativeFrameworks, ",")}, args...))
}
return nil
},
PostRun: func(cmd *cobra.Command, args []string) {
@@ -124,11 +118,10 @@ func setSecurityViewScanInfo(args []string, scanInfo *cautils.ScanInfo) {
if len(args) > 0 {
scanInfo.SetScanType(cautils.ScanTypeRepo)
scanInfo.InputPatterns = args
scanInfo.SetPolicyIdentifiers([]string{"workloadscan", "allcontrols"}, v1.KindFramework)
} else {
scanInfo.SetScanType(cautils.ScanTypeCluster)
scanInfo.SetPolicyIdentifiers([]string{"clusterscan", "mitre", "nsa"}, v1.KindFramework)
}
scanInfo.SetPolicyIdentifiers([]string{"clusterscan", "mitre", "nsa"}, v1.KindFramework)
}
func securityScan(scanInfo cautils.ScanInfo, ks meta.IKubescape) error {

View File

@@ -216,7 +216,7 @@ func (l *spyLogger) GetSpiedItems() []spyLogMessage {
}
func Test_terminateOnExceedingSeverity(t *testing.T) {
expectedMessage := "compliance result exceeds severity threshold"
expectedMessage := "result exceeds severity threshold"
expectedKey := "set severity threshold"
testCases := []struct {
@@ -305,11 +305,15 @@ func TestSetSecurityViewScanInfo(t *testing.T) {
PolicyIdentifier: []cautils.PolicyIdentifier{
{
Kind: v1.KindFramework,
Identifier: "workloadscan",
Identifier: "clusterscan",
},
{
Kind: v1.KindFramework,
Identifier: "allcontrols",
Identifier: "mitre",
},
{
Kind: v1.KindFramework,
Identifier: "nsa",
},
},
},

View File

@@ -6,7 +6,7 @@ import (
"fmt"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
@@ -77,8 +77,6 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma
logger.L().Fatal(err.Error())
}
enforceSeverityThresholds(results.GetData().Report.SummaryDetails.GetResourcesSeverityCounters(), scanInfo, terminateOnExceedingSeverity)
return nil
},
}

View File

@@ -9,8 +9,7 @@ import (
"fmt"
"strings"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/spf13/cobra"
@@ -33,22 +32,22 @@ func GetUpdateCmd() *cobra.Command {
Example: updateCmdExamples,
RunE: func(_ *cobra.Command, args []string) error {
ctx := context.TODO()
v := versioncheck.NewVersionCheckHandler()
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "update", nil)
v := cautils.NewVersionCheckHandler()
versionCheckRequest := cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", "update")
v.CheckLatestVersion(ctx, versionCheckRequest)
//Checking the user's version of kubescape to the latest release
if versioncheck.BuildNumber == "" || strings.Contains(versioncheck.BuildNumber, "rc") {
if cautils.BuildNumber == "" || strings.Contains(cautils.BuildNumber, "rc") {
//your version is unknown
fmt.Printf("Nothing to update: you are running the development version\n")
} else if versioncheck.LatestReleaseVersion == "" {
} else if cautils.LatestReleaseVersion == "" {
//Failed to check for updates
logger.L().Info("Failed to check for updates")
} else if versioncheck.BuildNumber == versioncheck.LatestReleaseVersion {
logger.L().Info(("Failed to check for updates"))
} else if cautils.BuildNumber == cautils.LatestReleaseVersion {
//your version == latest version
logger.L().Info("Nothing to update: you are running the latest version", helpers.String("Version", versioncheck.BuildNumber))
logger.L().Info(("Nothing to update: you are running the latest version"), helpers.String("Version", cautils.BuildNumber))
} else {
fmt.Printf("Version %s is available. Please refer to our installation documentation: %s\n", versioncheck.LatestReleaseVersion, installationLink)
fmt.Printf("Version %s is available. Please refer to our installation documentation: %s\n", cautils.LatestReleaseVersion, installationLink)
}
return nil
},

View File

@@ -1,236 +0,0 @@
package vap
import (
"errors"
"fmt"
"io"
"net/http"
"regexp"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"sigs.k8s.io/yaml"
"github.com/spf13/cobra"
admissionv1 "k8s.io/api/admissionregistration/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
var vapHelperCmdExamples = fmt.Sprintf(`
vap command can be used for managing Validating Admission Policies in a Kubernetes cluster.
This is an experimental feature and it might change.
Examples:
# Install Kubescape CEL admission policy library
%[1]s vap deploy-library | kubectl apply -f -
# Create a policy binding
%[1]s vap create-policy-binding --name my-policy-binding --policy c-0016 --namespace=my-namespace | kubectl apply -f -
`, cautils.ExecName())
func GetVapHelperCmd() *cobra.Command {
vapHelperCmd := &cobra.Command{
Use: "vap",
Short: "Helper commands for managing Validating Admission Policies in a Kubernetes cluster",
Long: ``,
Example: vapHelperCmdExamples,
}
// Create subcommands
vapHelperCmd.AddCommand(getDeployLibraryCmd())
vapHelperCmd.AddCommand(getCreatePolicyBindingCmd())
return vapHelperCmd
}
func getDeployLibraryCmd() *cobra.Command {
return &cobra.Command{
Use: "deploy-library",
Short: "Install Kubescape CEL admission policy library",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
return deployLibrary()
},
}
}
func getCreatePolicyBindingCmd() *cobra.Command {
var policyBindingName string
var policyName string
var namespaceArr []string
var labelArr []string
var action string
var parameterReference string
createPolicyBindingCmd := &cobra.Command{
Use: "create-policy-binding",
Short: "Create a policy binding",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
// Validate the inputs
if err := isValidK8sObjectName(policyBindingName); err != nil {
return fmt.Errorf("invalid policy binding name %s: %w", policyBindingName, err)
}
if err := isValidK8sObjectName(policyName); err != nil {
return fmt.Errorf("invalid policy name %s: %w", policyName, err)
}
for _, namespace := range namespaceArr {
if err := isValidK8sObjectName(namespace); err != nil {
return fmt.Errorf("invalid namespace %s: %w", namespace, err)
}
}
for _, label := range labelArr {
// Label selector must be in the format key=value
if !regexp.MustCompile(`^[a-zA-Z0-9]+=[a-zA-Z0-9]+$`).MatchString(label) {
return fmt.Errorf("invalid label selector: %s", label)
}
}
if action != "Deny" && action != "Audit" && action != "Warn" {
return fmt.Errorf("invalid action: %s", action)
}
if parameterReference != "" {
if err := isValidK8sObjectName(parameterReference); err != nil {
return fmt.Errorf("invalid parameter reference %s: %w", parameterReference, err)
}
}
return createPolicyBinding(policyBindingName, policyName, action, parameterReference, namespaceArr, labelArr)
},
}
// Must specify the name of the policy binding
createPolicyBindingCmd.Flags().StringVarP(&policyBindingName, "name", "n", "", "Name of the policy binding")
createPolicyBindingCmd.MarkFlagRequired("name")
createPolicyBindingCmd.Flags().StringVarP(&policyName, "policy", "p", "", "Name of the policy to bind the resources to")
createPolicyBindingCmd.MarkFlagRequired("policy")
createPolicyBindingCmd.Flags().StringSliceVar(&namespaceArr, "namespace", []string{}, "Resource namespace selector")
createPolicyBindingCmd.Flags().StringSliceVar(&labelArr, "label", []string{}, "Resource label selector")
createPolicyBindingCmd.Flags().StringVarP(&action, "action", "a", "Deny", "Action to take when policy fails")
createPolicyBindingCmd.Flags().StringVarP(&parameterReference, "parameter-reference", "r", "", "Parameter reference object name")
return createPolicyBindingCmd
}
// Implementation of the VAP helper commands
// deploy-library
func deployLibrary() error {
logger.L().Info("Downloading the Kubescape CEL admission policy library")
// Download the policy-configuration-definition.yaml from the latest release URL
policyConfigurationDefinitionURL := "https://github.com/kubescape/cel-admission-library/releases/latest/download/policy-configuration-definition.yaml"
policyConfigurationDefinition, err := downloadFileToString(policyConfigurationDefinitionURL)
if err != nil {
return err
}
// Download the basic-control-configuration.yaml from the latest release URL
basicControlConfigurationURL := "https://github.com/kubescape/cel-admission-library/releases/latest/download/basic-control-configuration.yaml"
basicControlConfiguration, err := downloadFileToString(basicControlConfigurationURL)
if err != nil {
return err
}
// Download the kubescape-validating-admission-policies.yaml from the latest release URL
kubescapeValidatingAdmissionPoliciesURL := "https://github.com/kubescape/cel-admission-library/releases/latest/download/kubescape-validating-admission-policies.yaml"
kubescapeValidatingAdmissionPolicies, err := downloadFileToString(kubescapeValidatingAdmissionPoliciesURL)
if err != nil {
return err
}
logger.L().Info("Successfully downloaded admission policy library")
// Print the downloaded files to the STDOUT for the user to apply connecting them to a single YAML with ---
fmt.Println(policyConfigurationDefinition)
fmt.Println("---")
fmt.Println(basicControlConfiguration)
fmt.Println("---")
fmt.Println(kubescapeValidatingAdmissionPolicies)
return nil
}
func downloadFileToString(url string) (string, error) {
// Send an HTTP GET request to the URL
response, err := http.Get(url) //nolint:gosec
if err != nil {
return "", err // Return an empty string and the error if the request fails
}
defer response.Body.Close()
// Check for a successful response (HTTP 200 OK)
if response.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to download file: %s", response.Status)
}
// Read the response body
bodyBytes, err := io.ReadAll(response.Body)
if err != nil {
return "", err // Return an empty string and the error if reading fails
}
// Convert the byte slice to a string
bodyString := string(bodyBytes)
return bodyString, nil
}
func isValidK8sObjectName(name string) error {
// Kubernetes object names must consist of lower case alphanumeric characters, '-' or '.',
// and must start and end with an alphanumeric character (e.g., 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')
// Max length of 63 characters.
if len(name) > 63 {
return errors.New("name should be less than 63 characters")
}
regex := regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`)
if !regex.MatchString(name) {
return errors.New("name should consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character")
}
return nil
}
// Create a policy binding
func createPolicyBinding(bindingName string, policyName string, action string, paramRefName string, namespaceArr []string, labelMatch []string) error {
// Create a policy binding struct
policyBinding := &admissionv1.ValidatingAdmissionPolicyBinding{}
// Print the policy binding after marshalling it to YAML to the STDOUT
// The user can apply the output to the cluster
policyBinding.APIVersion = "admissionregistration.k8s.io/v1"
policyBinding.Name = bindingName
policyBinding.Kind = "ValidatingAdmissionPolicyBinding"
policyBinding.Spec.PolicyName = policyName
policyBinding.Spec.MatchResources = &admissionv1.MatchResources{}
if len(namespaceArr) > 0 {
policyBinding.Spec.MatchResources.NamespaceSelector = &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "kubernetes.io/metadata.name",
Operator: metav1.LabelSelectorOpIn,
Values: namespaceArr,
},
},
}
}
if len(labelMatch) > 0 {
policyBinding.Spec.MatchResources.ObjectSelector = &metav1.LabelSelector{}
policyBinding.Spec.MatchResources.ObjectSelector.MatchLabels = make(map[string]string)
for _, label := range labelMatch {
labelParts := regexp.MustCompile(`=`).Split(label, 2)
policyBinding.Spec.MatchResources.ObjectSelector.MatchLabels[labelParts[0]] = labelParts[1]
}
}
policyBinding.Spec.ValidationActions = []admissionv1.ValidationAction{admissionv1.ValidationAction(action)}
if paramRefName != "" {
policyBinding.Spec.ParamRef = &admissionv1.ParamRef{
Name: paramRefName,
}
}
// Marshal the policy binding to YAML
out, err := yaml.Marshal(policyBinding)
if err != nil {
return err
}
fmt.Println(string(out))
return nil
}

View File

@@ -1,10 +0,0 @@
package vap
import (
"testing"
)
func TestGetVapHelperCmd(t *testing.T) {
// Call the GetFixCmd function
_ = GetVapHelperCmd()
}

View File

@@ -0,0 +1,7 @@
//go:build !gitenabled
package version
func isGitEnabled() bool {
return false
}

View File

@@ -0,0 +1,7 @@
//go:build gitenabled
package version
func isGitEnabled() bool {
return true
}

View File

@@ -4,7 +4,8 @@ import (
"context"
"fmt"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/spf13/cobra"
)
@@ -15,13 +16,14 @@ func GetVersionCmd() *cobra.Command {
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.TODO()
v := versioncheck.NewIVersionCheckHandler(ctx)
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil)
v := cautils.NewIVersionCheckHandler(ctx)
versionCheckRequest := cautils.NewVersionCheckRequest(cautils.BuildNumber, "", "", "version")
v.CheckLatestVersion(ctx, versionCheckRequest)
fmt.Fprintf(cmd.OutOrStdout(),
"Your current version is: %s\n",
versionCheckRequest.ClientVersion,
)
logger.L().Debug(fmt.Sprintf("git enabled in build: %t", isGitEnabled()))
return nil
},
}

View File

@@ -5,7 +5,7 @@ import (
"io"
"testing"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/stretchr/testify/assert"
)
@@ -28,7 +28,7 @@ func TestGetVersionCmd(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
versioncheck.BuildNumber = tt.buildNumber
cautils.BuildNumber = tt.buildNumber
if cmd := GetVersionCmd(); cmd != nil {
buf := bytes.NewBufferString("")

View File

@@ -1,21 +0,0 @@
package cautils
import (
"os"
"github.com/kubescape/backend/pkg/versioncheck"
)
var BuildNumber string
var Client string
func init() {
if BuildNumber != "" {
versioncheck.BuildNumber = BuildNumber
} else {
versioncheck.BuildNumber = os.Getenv("RELEASE")
}
if Client != "" {
versioncheck.Client = Client
}
}

View File

@@ -14,7 +14,7 @@ import (
"github.com/kubescape/backend/pkg/servicediscovery"
servicediscoveryv1 "github.com/kubescape/backend/pkg/servicediscovery/v1"
servicediscoveryv2 "github.com/kubescape/backend/pkg/servicediscovery/v2"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/kubescape/v3/core/cautils/getter"

View File

@@ -58,7 +58,6 @@ type OPASessionObj struct {
OmitRawResources bool // omit raw resources from output
SingleResourceScan workloadinterface.IWorkload // single resource scan
TopWorkloadsByScore []reporthandling.IResource
TemplateMapping map[string]MappingNodes // Map chart obj to template (only for rendering from path)
}
func NewOPASessionObj(ctx context.Context, frameworks []reporthandling.Framework, k8sResources K8SResources, scanInfo *ScanInfo) *OPASessionObj {
@@ -75,7 +74,6 @@ func NewOPASessionObj(ctx context.Context, frameworks []reporthandling.Framework
SessionID: scanInfo.ScanID,
Metadata: scanInfoToScanMetadata(ctx, scanInfo),
OmitRawResources: scanInfo.OmitRawResources,
TemplateMapping: make(map[string]MappingNodes),
}
}

View File

@@ -3,7 +3,6 @@ package cautils
import (
"golang.org/x/mod/semver"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/apis"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
@@ -64,7 +63,7 @@ func (policies *Policies) Set(frameworks []reporthandling.Framework, excludedRul
// 1. Rule is compatible with the current kubescape version
// 2. Rule fits the current scanning scope
func ShouldSkipRule(control reporthandling.Control, rule reporthandling.PolicyRule, scanningScope reporthandling.ScanningScopeType) bool {
if !isRuleKubescapeVersionCompatible(rule.Attributes, versioncheck.BuildNumber) {
if !isRuleKubescapeVersionCompatible(rule.Attributes, BuildNumber) {
return true
}
if !isControlFitToScanScope(control, scanningScope) {

View File

@@ -239,59 +239,3 @@ func TestIsFrameworkFitToScanScope(t *testing.T) {
})
}
}
var rule_v1_0_131 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useUntilKubescapeVersion": "v1.0.132"}}}
var rule_v1_0_132 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.132", "useUntilKubescapeVersion": "v1.0.133"}}}
var rule_v1_0_133 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.133", "useUntilKubescapeVersion": "v1.0.134"}}}
var rule_v1_0_134 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.134"}}}
var rule_invalid_from = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": 1.0135, "useUntilKubescapeVersion": "v1.0.135"}}}
var rule_invalid_until = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.135", "useUntilKubescapeVersion": 1.0135}}}
func TestIsRuleKubescapeVersionCompatible(t *testing.T) {
// local build- no build number
// should not crash when the value of useUntilKubescapeVersion is not a string
buildNumberMock := "v1.0.135"
assert.False(t, isRuleKubescapeVersionCompatible(rule_invalid_from.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_invalid_until.Attributes, buildNumberMock))
// should use only rules that don't have "until"
buildNumberMock = ""
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.130"
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.132"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.133"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.135"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
}

View File

@@ -9,7 +9,7 @@ import (
spinnerpkg "github.com/briandowns/spinner"
"github.com/jwalton/gchalk"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/mattn/go-isatty"
"github.com/schollz/progressbar/v3"

View File

@@ -13,7 +13,7 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"golang.org/x/exp/slices"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/opa-utils/objectsenvelopes"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"
@@ -38,7 +38,7 @@ type Chart struct {
}
// LoadResourcesFromHelmCharts scans a given path (recursively) for helm charts, renders the templates and returns a map of workloads and a map of chart names
func LoadResourcesFromHelmCharts(ctx context.Context, basePath string) (map[string][]workloadinterface.IMetadata, map[string]Chart, map[string]MappingNodes) {
func LoadResourcesFromHelmCharts(ctx context.Context, basePath string) (map[string][]workloadinterface.IMetadata, map[string]Chart) {
directories, _ := listDirs(basePath)
helmDirectories := make([]string, 0)
for _, dir := range directories {
@@ -49,18 +49,14 @@ func LoadResourcesFromHelmCharts(ctx context.Context, basePath string) (map[stri
sourceToWorkloads := map[string][]workloadinterface.IMetadata{}
sourceToChart := make(map[string]Chart, 0)
sourceToNodes := map[string]MappingNodes{}
for _, helmDir := range helmDirectories {
chart, err := NewHelmChart(helmDir)
if err == nil {
wls, templateToNodes, errs := chart.GetWorkloadsWithDefaultValues()
wls, errs := chart.GetWorkloadsWithDefaultValues()
if len(errs) > 0 {
logger.L().Ctx(ctx).Warning(fmt.Sprintf("Rendering of Helm chart template '%s', failed: %v", chart.GetName(), errs))
continue
}
for k, v := range templateToNodes {
sourceToNodes[k] = v
}
chartName := chart.GetName()
for k, v := range wls {
@@ -72,7 +68,7 @@ func LoadResourcesFromHelmCharts(ctx context.Context, basePath string) (map[stri
}
}
}
return sourceToWorkloads, sourceToChart, sourceToNodes
return sourceToWorkloads, sourceToChart
}
// If the contents at given path is a Kustomize Directory, LoadResourcesFromKustomizeDirectory will

View File

@@ -45,11 +45,10 @@ func TestLoadResourcesFromFiles(t *testing.T) {
}
func TestLoadResourcesFromHelmCharts(t *testing.T) {
sourceToWorkloads, sourceToChartName, _ := LoadResourcesFromHelmCharts(context.TODO(), helmChartPath())
sourceToWorkloads, sourceToChartName := LoadResourcesFromHelmCharts(context.TODO(), helmChartPath())
assert.Equal(t, 6, len(sourceToWorkloads))
for file, workloads := range sourceToWorkloads {
assert.Equalf(t, 1, len(workloads), "expected 1 workload in file %s", file)
w := workloads[0]

View File

@@ -9,7 +9,7 @@ import (
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/attacktrack/v1alpha1"
"github.com/kubescape/regolibrary/v2/gitregostore"
"github.com/kubescape/regolibrary/gitregostore"
)
// =======================================================================================================================
@@ -29,7 +29,7 @@ type DownloadReleasedPolicy struct {
func NewDownloadReleasedPolicy() *DownloadReleasedPolicy {
return &DownloadReleasedPolicy{
gs: gitregostore.NewGitRegoStoreV2(-1),
gs: gitregostore.NewDefaultGitRegoStore(-1),
}
}

View File

@@ -1,3 +1,5 @@
//go:build !gitenabled
package cautils
import (

View File

@@ -0,0 +1,146 @@
//go:build gitenabled
package cautils
import (
"fmt"
"time"
"github.com/kubescape/go-git-url/apis"
git2go "github.com/libgit2/git2go/v33"
)
type gitRepository struct {
git2GoRepo *git2go.Repository
fileToLastCommit map[string]*git2go.Commit
}
func newGitRepository(root string) (*gitRepository, error) {
git2GoRepo, err := git2go.OpenRepository(root)
if err != nil {
return nil, err
}
return &gitRepository{
git2GoRepo: git2GoRepo,
}, nil
}
func (g *gitRepository) GetFileLastCommit(filePath string) (*apis.Commit, error) {
if len(g.fileToLastCommit) == 0 {
g.buildCommitMap()
}
if relevantCommit, exists := g.fileToLastCommit[filePath]; exists {
return g.getCommit(relevantCommit), nil
}
return nil, fmt.Errorf("failed to get commit information for file: %s", filePath)
}
func (g *gitRepository) buildCommitMap() {
filePathToCommitTime := map[string]time.Time{}
filePathToCommit := map[string]*git2go.Commit{}
allCommits, _ := g.getAllCommits()
// builds a map of all files to their last commit
for _, commit := range allCommits {
// Ignore merge commits (2+ parents)
if commit.ParentCount() <= 1 {
tree, err := commit.Tree()
if err != nil {
continue
}
// ParentCount can be either 1 or 0 (initial commit)
// In case it's the initial commit, prevTree is nil
var prevTree *git2go.Tree
if commit.ParentCount() == 1 {
prevCommit := commit.Parent(0)
prevTree, err = prevCommit.Tree()
if err != nil {
continue
}
}
diff, err := g.git2GoRepo.DiffTreeToTree(prevTree, tree, nil)
if err != nil {
continue
}
numDeltas, err := diff.NumDeltas()
if err != nil {
continue
}
for i := 0; i < numDeltas; i++ {
delta, err := diff.Delta(i)
if err != nil {
continue
}
deltaFilePath := delta.NewFile.Path
commitTime := commit.Author().When
// In case we have the commit information for the file which is not the latest - we override it
if currentCommitTime, exists := filePathToCommitTime[deltaFilePath]; exists {
if currentCommitTime.Before(commitTime) {
filePathToCommitTime[deltaFilePath] = commitTime
filePathToCommit[deltaFilePath] = commit
}
} else {
filePathToCommitTime[deltaFilePath] = commitTime
filePathToCommit[deltaFilePath] = commit
}
}
}
}
g.fileToLastCommit = filePathToCommit
}
func (g *gitRepository) getAllCommits() ([]*git2go.Commit, error) {
logItr, itrErr := g.git2GoRepo.Walk()
if itrErr != nil {
return nil, itrErr
}
pushErr := logItr.PushHead()
if pushErr != nil {
return nil, pushErr
}
var allCommits []*git2go.Commit
err := logItr.Iterate(func(commit *git2go.Commit) bool {
if commit != nil {
allCommits = append(allCommits, commit)
return true
}
return false
})
if err != nil {
return nil, err
}
if err != nil {
return nil, err
}
return allCommits, nil
}
func (g *gitRepository) getCommit(commit *git2go.Commit) *apis.Commit {
return &apis.Commit{
SHA: commit.Id().String(),
Author: apis.Committer{
Name: commit.Author().Name,
Email: commit.Author().Email,
Date: commit.Author().When,
},
Message: commit.Message(),
Committer: apis.Committer{},
Files: []apis.Files{},
}
}

View File

@@ -2,10 +2,9 @@ package cautils
import (
"path/filepath"
"strconv"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"
@@ -46,32 +45,22 @@ func (hc *HelmChart) GetDefaultValues() map[string]interface{} {
}
// GetWorkloads renders chart template using the default values and returns a map of source file to its workloads
func (hc *HelmChart) GetWorkloadsWithDefaultValues() (map[string][]workloadinterface.IMetadata, map[string]MappingNodes, []error) {
func (hc *HelmChart) GetWorkloadsWithDefaultValues() (map[string][]workloadinterface.IMetadata, []error) {
return hc.GetWorkloads(hc.GetDefaultValues())
}
// GetWorkloads renders chart template using the provided values and returns a map of source (absolute) file path to its workloads
func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]workloadinterface.IMetadata, map[string]MappingNodes, []error) {
func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]workloadinterface.IMetadata, []error) {
vals, err := helmchartutil.ToRenderValues(hc.chart, values, helmchartutil.ReleaseOptions{}, nil)
if err != nil {
return nil, nil, []error{err}
return nil, []error{err}
}
// change the chart to template with comment, only is template(.yaml added otherwise no)
hc.AddCommentToTemplate()
sourceToFile, err := helmengine.Render(hc.chart, vals)
if err != nil {
return nil, nil, []error{err}
return nil, []error{err}
}
// get the resouse and analysis and store it to the struct
fileMapping := make(map[string]MappingNodes)
GetTemplateMapping(sourceToFile, fileMapping)
// delete the comment from chart and from sourceToFile
RemoveComment(sourceToFile)
workloads := make(map[string][]workloadinterface.IMetadata, 0)
errs := []error{}
@@ -87,13 +76,10 @@ func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]w
if len(wls) == 0 {
continue
}
// separate base path and file name. We do not use the os.Separator because the paths returned from the helm engine are not OS specific (e.g. mychart/templates/myfile.yaml)
if firstPathSeparatorIndex := strings.Index(path, string("/")); firstPathSeparatorIndex != -1 {
absPath := filepath.Join(hc.path, path[firstPathSeparatorIndex:])
if nodes, ok := fileMapping[path]; ok {
fileMapping[absPath] = nodes
delete(fileMapping, path)
}
workloads[absPath] = []workloadinterface.IMetadata{}
for i := range wls {
lw := localworkload.NewLocalWorkload(wls[i].GetObject())
@@ -102,46 +88,5 @@ func (hc *HelmChart) GetWorkloads(values map[string]interface{}) (map[string][]w
}
}
}
return workloads, fileMapping, errs
}
func (hc *HelmChart) AddCommentToTemplate() {
for index, t := range hc.chart.Templates {
if IsYaml(strings.ToLower(t.Name)) {
var newLines []string
originalTemplate := string(t.Data)
lines := strings.Split(originalTemplate, "\n")
for index, line := range lines {
comment := " #This is the " + strconv.Itoa(index+1) + " line"
newLines = append(newLines, line+comment)
}
templateWithComment := strings.Join(newLines, "\n")
hc.chart.Templates[index].Data = []byte(templateWithComment)
}
}
}
func RemoveComment(sourceToFile map[string]string) {
// commentRe := regexp.MustCompile(CommentFormat)
for fileName, file := range sourceToFile {
if !IsYaml(strings.ToLower((fileName))) {
continue
}
sourceToFile[fileName] = commentRe.ReplaceAllLiteralString(file, "")
}
}
func GetTemplateMapping(sourceToFile map[string]string, fileMapping map[string]MappingNodes) {
for fileName, fileContent := range sourceToFile {
mappingNodes, err := GetMapping(fileName, fileContent)
if err != nil {
// if one file cannot get mapping nodes, generate error, then ignore it
logger.L().Warning("Failed to get File Mapping nodes", helpers.String("file name", fileName), helpers.Error(err))
continue
}
if len(mappingNodes.Nodes) != 0 {
fileMapping[fileName] = *mappingNodes
}
}
return workloads, errs
}

View File

@@ -83,7 +83,7 @@ func (s *HelmChartTestSuite) TestGetWorkloadsWithOverride() {
// Override default value
values["image"].(map[string]interface{})["pullPolicy"] = "Never"
fileToWorkloads, _, errs := chart.GetWorkloads(values)
fileToWorkloads, errs := chart.GetWorkloads(values)
s.Len(errs, 0)
s.Lenf(fileToWorkloads, len(s.expectedFiles), "Expected %d files", len(s.expectedFiles))
@@ -111,7 +111,7 @@ func (s *HelmChartTestSuite) TestGetWorkloadsMissingValue() {
values := chart.GetDefaultValues()
delete(values, "image")
fileToWorkloads, _, errs := chart.GetWorkloads(values)
fileToWorkloads, errs := chart.GetWorkloads(values)
s.Nil(fileToWorkloads)
s.Len(errs, 1, "Expected an error due to missing value")

View File

@@ -4,7 +4,7 @@ import (
"os"
"path/filepath"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"

View File

@@ -1,6 +1,7 @@
package cautils
import (
"errors"
"fmt"
"path"
"strings"
@@ -18,6 +19,8 @@ type LocalGitRepository struct {
config *configv5.Config
}
var ErrWarnNotSupportedByBuild = errors.New(`git commits retrieval not supported by this build. Build with tag "gitenabled" to enable the full git scan feature`)
func NewLocalGitRepository(path string) (*LocalGitRepository, error) {
goGitRepo, err := gitv5.PlainOpenWithOptions(path, &gitv5.PlainOpenOptions{DetectDotGit: true})
if err != nil {
@@ -50,7 +53,7 @@ func NewLocalGitRepository(path string) (*LocalGitRepository, error) {
if repoRoot, err := l.GetRootDir(); err == nil {
gitRepository, err := newGitRepository(repoRoot)
if err != nil {
if err != nil && !errors.Is(err, ErrWarnNotSupportedByBuild) {
return l, err
}

View File

@@ -1,34 +0,0 @@
package cautils
type ObjectID struct {
apiVersion string
kind string
}
type MappingNode struct {
ObjectID *ObjectID
Field string
Value string
TemplateFileName string
TemplateLineNumber int
}
type MappingNodes struct {
Nodes []map[string]MappingNode //Map line number of chart to template obj map[int]MappingNode
TemplateFileName string
}
func (node *MappingNode) writeInfoToNode(objectID *ObjectID, path string, lineNumber int, value string, fileName string) {
node.Field = path
node.TemplateLineNumber = lineNumber
node.ObjectID = objectID
node.Value = value
node.TemplateFileName = fileName
}
func NewMappingNodes() *MappingNodes {
mappingNodes := new(MappingNodes)
mappingNodes.TemplateFileName = ""
return mappingNodes
}

View File

@@ -1,7 +1,7 @@
package cautils
import (
"github.com/distribution/reference"
"github.com/docker/distribution/reference"
)
func NormalizeImageName(img string) (string, error) {

View File

@@ -1,266 +0,0 @@
package cautils
import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/kubescape/go-logger"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"gopkg.in/op/go-logging.v1"
)
const (
CommentFormat = `#This is the (?P<line>\d*) line`
)
var apiVersionRe = regexp.MustCompile(`apiVersion: (?P<apiVersion>\S*)`)
var kindRe = regexp.MustCompile(`kind: (?P<kind>\S*)`)
var pathRe = regexp.MustCompile(`path: (?P<path>\S*)`)
var typeRe = regexp.MustCompile(`type: '(?P<type>\S*)'`)
var valueRe = regexp.MustCompile(`value: (?P<value>\[.+\]|\S*)`)
var commentRe = regexp.MustCompile(CommentFormat)
var seqRe = regexp.MustCompile(`.(?P<number>\d+)(?P<point>\.?)`)
var newSeqRe = "[${number}]${point}"
var newFileSeperator = "---"
// change to use go func
func GetMapping(fileName string, fileContent string) (*MappingNodes, error) {
node := new(MappingNode)
objectID := new(ObjectID)
subFileNodes := make(map[string]MappingNode)
mappingNodes := NewMappingNodes()
mappingNodes.TemplateFileName = fileName
lines := strings.Split(fileContent, "\n")
lastNumber := -1
reducedNumber := -1 // uses to make sure line and line in yq is the same
isApiVersionEmpty := true
isKindEmpty := true
var err error
var lineExpression = `..| select(line == %d)| {"destpath": path | join("."),"type": type,"value": .}`
for i, line := range lines {
index := i
if apiVersionRe.MatchString(line) {
isApiVersionEmpty, err = extractApiVersion(line, objectID)
if err != nil {
return nil, fmt.Errorf("extractApiVersion error: err, %s", err.Error())
}
if reducedNumber == -1 {
reducedNumber = index + reducedNumber
}
continue
} else if kindRe.MatchString(line) {
isKindEmpty, err = extractKind(line, objectID)
if err != nil {
return nil, fmt.Errorf("extractKind error: err, %s", err.Error())
}
continue
} else if strings.Contains(line, newFileSeperator) { //At least two files in one yaml
mappingNodes.Nodes = append(mappingNodes.Nodes, subFileNodes)
// Restart a subfileNode
isApiVersionEmpty = false
isKindEmpty = false
subFileNodes = make(map[string]MappingNode)
continue
}
if !isApiVersionEmpty || !isKindEmpty {
// not sure if it can go to the end
index = index - reducedNumber
expression := fmt.Sprintf(lineExpression, index)
output, err := getYamlLineInfo(expression, fileContent)
if err != nil {
return nil, err
}
path := extractParameter(pathRe, output, "$path")
//if path is empty, continue
if path != "" && path != "\"\"" {
if isApiVersionEmpty || isKindEmpty {
return nil, fmt.Errorf("there is no enough objectID info")
}
splits := strings.Split(output, "dest")
if len(splits) < 2 {
return nil, fmt.Errorf("something wrong with the length of the splits, which is %d", len(splits))
} else {
// cut the redundant one
splits = splits[1:]
lastNumber, err = writeNodes(splits, lastNumber, fileName, node, objectID, subFileNodes)
if err != nil {
return nil, fmt.Errorf("writeNodes err: %s", err.Error())
}
}
}
}
if i == len(lines)-1 {
mappingNodes.Nodes = append(mappingNodes.Nodes, subFileNodes)
}
}
return mappingNodes, nil
}
func writeNodes(splits []string, lastNumber int, fileName string, node *MappingNode, objectID *ObjectID, subFileNodes map[string]MappingNode) (int, error) {
for _, split := range splits {
path := extractPath(split)
mapMatched, err := extractMapType(split)
if err != nil {
return -1, fmt.Errorf("extractMapType err: %s", err.Error())
}
if mapMatched {
lastNumber, err = writeNoteToMapping(split, lastNumber, path, fileName, node, objectID, true, subFileNodes)
if err != nil {
return -1, fmt.Errorf("map type: writeNoteToMapping, err: %s", err.Error())
}
} else {
lastNumber, err = writeNoteToMapping(split, lastNumber, path, fileName, node, objectID, false, subFileNodes)
if err != nil {
return -1, fmt.Errorf("not map type: writeNoteToMapping, err: %s", err.Error())
}
}
}
return lastNumber, nil
}
func writeNoteToMapping(split string, lastNumber int, path string, fileName string, node *MappingNode, objectID *ObjectID, isMapType bool, subFileNodes map[string]MappingNode) (int, error) {
newlastNumber, err := writeNodeInfo(split, lastNumber, path, fileName, node, objectID, isMapType)
if err != nil {
return 0, fmt.Errorf("isMapType: %v, writeNodeInfo wrong err: %s", isMapType, err.Error())
}
if _, ok := subFileNodes[path]; !ok { // Assume the path is unique in one subfile
subFileNodes[path] = *node
}
// else {
// return 0, fmt.Errorf("isMapType: %v, %s in mapping.Nodes exists", isMapType, path)
// }
return newlastNumber, nil
}
func writeNodeInfo(split string, lastNumber int, path string, fileName string, node *MappingNode, objectID *ObjectID, isMapType bool) (int, error) {
value, lineNumber, newLastNumber, err := getInfoFromOne(split, lastNumber, isMapType)
if err != nil {
return -1, fmt.Errorf("getInfoFromOne wrong err: %s", err.Error())
}
// lastNumber = newLastNumber
node.writeInfoToNode(objectID, path, lineNumber, value, fileName)
return newLastNumber, nil
}
func getInfoFromOne(output string, lastNumber int, isMapType bool) (value string, lineNumber int, newLastNumber int, err error) {
if isMapType {
value = ""
} else {
value = extractParameter(valueRe, output, "$value")
}
number := extractParameter(commentRe, output, "$line")
if number != "" {
lineNumber, err = strconv.Atoi(number)
if err != nil {
return "", -1, -1, fmt.Errorf("strconv.Atoi err: %s", err.Error())
}
if isMapType {
lineNumber = lineNumber - 1
}
lastNumber = lineNumber
// save to structure
} else {
lineNumber = lastNumber
// use the last one number
}
newLastNumber = lineNumber
return value, lineNumber, newLastNumber, nil
}
func getYamlLineInfo(expression string, yamlFile string) (string, error) {
out, err := exectuateYq(expression, yamlFile)
if err != nil {
return "", fmt.Errorf("exectuate yqlib err: %s", err.Error())
}
return out, nil
}
func exectuateYq(expression string, yamlContent string) (string, error) {
backendLoggerLeveled := logging.AddModuleLevel(logging.NewLogBackend(logger.L().GetWriter(), "", 0))
backendLoggerLeveled.SetLevel(logging.ERROR, "")
yqlib.GetLogger().SetBackend(backendLoggerLeveled)
encoder := configureEncoder()
decoder := configureDecoder(false)
stringEvaluator := yqlib.NewStringEvaluator()
out, err := stringEvaluator.Evaluate(expression, yamlContent, encoder, decoder)
if err != nil {
return "", fmt.Errorf("no matches found")
}
return out, err
}
func extractApiVersion(line string, objectID *ObjectID) (bool, error) {
apiVersion := extractParameter(apiVersionRe, line, "$apiVersion")
if apiVersion == "" {
return true, fmt.Errorf("something wrong when extracting the apiVersion, the line is %s", line)
}
objectID.apiVersion = apiVersion
return false, nil
}
func extractKind(line string, objectID *ObjectID) (bool, error) {
kind := extractParameter(kindRe, line, "$kind")
if kind == "" {
return true, fmt.Errorf("something wrong when extracting the kind, the line is %s", line)
}
objectID.kind = kind
return false, nil
}
func extractPath(split string) string {
path := extractParameter(pathRe, split, "$path")
// For each match of the regex in the content.
path = seqRe.ReplaceAllString(path, newSeqRe)
return path
}
func extractMapType(split string) (bool, error) {
pathType := extractParameter(typeRe, split, "$type")
mapMatched, err := regexp.MatchString(`!!map`, pathType)
if err != nil {
err = fmt.Errorf("regexp.MatchString err: %s", err.Error())
return false, err
}
return mapMatched, nil
}
func extractParameter(re *regexp.Regexp, line string, keyword string) string {
submatch := re.FindStringSubmatchIndex(line)
result := []byte{}
result = re.ExpandString(result, keyword, line, submatch)
parameter := string(result)
return parameter
}
//yqlib configuration
func configureEncoder() yqlib.Encoder {
indent := 2
colorsEnabled := false
yqlibEncoder := yqlib.NewYamlEncoder(indent, colorsEnabled, yqlib.ConfiguredYamlPreferences)
return yqlibEncoder
}
func configureDecoder(evaluateTogether bool) yqlib.Decoder {
prefs := yqlib.ConfiguredYamlPreferences
prefs.EvaluateTogether = evaluateTogether
yqlibDecoder := yqlib.NewYamlDecoder(prefs)
return yqlibDecoder
}

View File

@@ -1,79 +0,0 @@
package cautils
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/suite"
helmchartutil "helm.sh/helm/v3/pkg/chartutil"
helmengine "helm.sh/helm/v3/pkg/engine"
)
type HelmChartGetMappingSuite struct {
suite.Suite
helmChartPath string
expectedFiles []string
fileContent map[string]string
}
func TestHelmChartGetMappingSuite(t *testing.T) {
suite.Run(t, new(HelmChartGetMappingSuite))
}
func (s *HelmChartGetMappingSuite) SetupSuite() {
o, _ := os.Getwd()
s.helmChartPath = filepath.Join(filepath.Dir(o), "..", "examples", "helm_chart_mapping_node")
s.expectedFiles = []string{
filepath.Join(s.helmChartPath, "templates", "clusterrolebinding.yaml"),
filepath.Join(s.helmChartPath, "templates", "clusterrole.yaml"),
filepath.Join(s.helmChartPath, "templates", "serviceaccount.yaml"),
filepath.Join(s.helmChartPath, "templates", "rolebinding.yaml"),
filepath.Join(s.helmChartPath, "templates", "role.yaml"),
filepath.Join(s.helmChartPath, "templates", "cronjob.yaml"),
}
s.fileContent = make(map[string]string)
hc, _ := NewHelmChart(s.helmChartPath)
values := hc.GetDefaultValues()
vals, _ := helmchartutil.ToRenderValues(hc.chart, values, helmchartutil.ReleaseOptions{}, nil)
sourceToFile, _ := helmengine.Render(hc.chart, vals)
s.fileContent = sourceToFile
}
func (s *HelmChartGetMappingSuite) TestGetMapping() {
fileNodes, err := GetMapping("rolebinding.yaml", s.fileContent["kubescape/templates/rolebinding.yaml"])
s.NoError(err, "Get Mapping nodes correctly")
s.Equal(fileNodes.TemplateFileName, "rolebinding.yaml")
s.Len(fileNodes.Nodes, 1)
s.Len(fileNodes.Nodes[0], 13)
}
func (s *HelmChartGetMappingSuite) TestGetMappingFromFileContainsMultipleSubFiles() {
fileNodes, err := GetMapping("serviceaccount.yaml", s.fileContent["kubescape/templates/serviceaccount.yaml"])
s.NoError(err, "Get Mapping nodes correctly")
s.Equal(fileNodes.TemplateFileName, "serviceaccount.yaml")
s.Len(fileNodes.Nodes, 2)
s.Len(fileNodes.Nodes[0], 8)
s.Len(fileNodes.Nodes[1], 2)
}
func (s *HelmChartGetMappingSuite) TestGetMappingFromFileCWithoutKindOrApiVersion() {
fileNodes, err := GetMapping("clusterrole.yaml", s.fileContent["kubescape/templates/clusterrole.yaml"])
s.Contains(err.Error(), "there is no enough objectID info")
s.Nil(fileNodes)
}
func (s *HelmChartGetMappingSuite) TestGetMappingFromFileCWithoutApiVersion() {
fileNodes, err := GetMapping("clusterrolebinding.yaml", s.fileContent["kubescape/templates/clusterrolebinding.yaml"])
s.Contains(err.Error(), "there is no enough objectID info")
s.Nil(fileNodes)
}

View File

@@ -85,7 +85,7 @@ func (rbacObjects *RBACObjects) rbacObjectsToResources(resources *rbacutils.Rbac
if err != nil {
return nil, err
}
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the correct apiVersion?
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the the correct apiVersion?
crIMeta := workloadinterface.NewWorkloadObj(crmap)
crIMeta.SetKind("ClusterRole")
allresources[crIMeta.GetID()] = crIMeta
@@ -95,7 +95,7 @@ func (rbacObjects *RBACObjects) rbacObjectsToResources(resources *rbacutils.Rbac
if err != nil {
return nil, err
}
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the correct apiVersion?
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the the correct apiVersion?
crIMeta := workloadinterface.NewWorkloadObj(crmap)
crIMeta.SetKind("Role")
allresources[crIMeta.GetID()] = crIMeta
@@ -105,7 +105,7 @@ func (rbacObjects *RBACObjects) rbacObjectsToResources(resources *rbacutils.Rbac
if err != nil {
return nil, err
}
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the correct apiVersion?
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the the correct apiVersion?
crIMeta := workloadinterface.NewWorkloadObj(crmap)
crIMeta.SetKind("ClusterRoleBinding")
allresources[crIMeta.GetID()] = crIMeta
@@ -115,7 +115,7 @@ func (rbacObjects *RBACObjects) rbacObjectsToResources(resources *rbacutils.Rbac
if err != nil {
return nil, err
}
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the correct apiVersion?
crmap["apiVersion"] = "rbac.authorization.k8s.io/v1" // TODO - is the the correct apiVersion?
crIMeta := workloadinterface.NewWorkloadObj(crmap)
crIMeta.SetKind("RoleBinding")
allresources[crIMeta.GetID()] = crIMeta

View File

@@ -8,7 +8,6 @@ import (
"path/filepath"
"strings"
"github.com/kubescape/backend/pkg/versioncheck"
giturl "github.com/kubescape/go-git-url"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
@@ -25,17 +24,20 @@ import (
type ScanningContext string
const (
ContextCluster ScanningContext = "cluster"
ContextFile ScanningContext = "single-file"
ContextDir ScanningContext = "local-dir"
ContextGitLocal ScanningContext = "git-local"
ContextGitRemote ScanningContext = "git-remote"
ContextCluster ScanningContext = "cluster"
ContextFile ScanningContext = "single-file"
ContextDir ScanningContext = "local-dir"
ContextGitURL ScanningContext = "git-url"
ContextGitLocal ScanningContext = "git-local"
)
const ( // deprecated
ScopeCluster = "cluster"
ScopeYAML = "yaml"
)
const (
// ScanCluster string = "cluster"
// ScanLocalFiles string = "yaml"
localControlInputsFilename string = "controls-inputs.json"
LocalExceptionsFilename string = "exceptions.json"
LocalAttackTracksFilename string = "attack-tracks.json"
@@ -108,8 +110,8 @@ type ScanInfo struct {
UseFrom []string // Load framework from local file (instead of download). Use when running offline
UseDefault bool // Load framework from cached file (instead of download). Use when running offline
UseArtifactsFrom string // Load artifacts from local path. Use when running offline
VerboseMode bool // Display all the input resources and not only failed resources
View string //
VerboseMode bool // Display all of the input resources and not only failed resources
View string // Display all of the input resources and not only failed resources
Format string // Format results (table, json, junit ...)
Output string // Store results in an output file, Output file name
FormatVersion string // Output object can be different between versions, this is for testing and backward compatibility
@@ -138,8 +140,6 @@ type ScanInfo struct {
ScanImages bool
ChartPath string
FilePath string
scanningContext *ScanningContext
cleanups []func()
}
type Getters struct {
@@ -155,12 +155,7 @@ func (scanInfo *ScanInfo) Init(ctx context.Context) {
if scanInfo.ScanID == "" {
scanInfo.ScanID = uuid.NewString()
}
}
func (scanInfo *ScanInfo) Cleanup() {
for _, cleanup := range scanInfo.cleanups {
cleanup()
}
}
func (scanInfo *ScanInfo) setUseArtifactsFrom(ctx context.Context) {
@@ -264,7 +259,7 @@ func scanInfoToScanMetadata(ctx context.Context, scanInfo *ScanInfo) *reporthand
metadata.ScanMetadata.TargetNames = append(metadata.ScanMetadata.TargetNames, policy.Identifier)
}
metadata.ScanMetadata.KubescapeVersion = versioncheck.BuildNumber
metadata.ScanMetadata.KubescapeVersion = BuildNumber
metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
metadata.ScanMetadata.FailThreshold = scanInfo.FailThreshold
metadata.ScanMetadata.ComplianceThreshold = scanInfo.ComplianceThreshold
@@ -272,63 +267,51 @@ func scanInfoToScanMetadata(ctx context.Context, scanInfo *ScanInfo) *reporthand
metadata.ScanMetadata.VerboseMode = scanInfo.VerboseMode
metadata.ScanMetadata.ControlsInputs = scanInfo.ControlsInputs
switch scanInfo.GetScanningContext() {
inputFiles := ""
if len(scanInfo.InputPatterns) > 0 {
inputFiles = scanInfo.InputPatterns[0]
}
switch GetScanningContext(inputFiles) {
case ContextCluster:
// cluster
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Cluster
case ContextFile:
// local file
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.File
case ContextGitURL:
// url
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Repo
case ContextGitLocal:
// local-git
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.GitLocal
case ContextGitRemote:
// remote
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Repo
case ContextDir:
// directory
metadata.ScanMetadata.ScanningTarget = reporthandlingv2.Directory
}
scanInfo.setContextMetadata(ctx, &metadata.ContextMetadata)
setContextMetadata(ctx, &metadata.ContextMetadata, inputFiles)
return metadata
}
func (scanInfo *ScanInfo) GetInputFiles() string {
if len(scanInfo.InputPatterns) > 0 {
return scanInfo.InputPatterns[0]
}
return ""
}
func (scanInfo *ScanInfo) GetScanningContext() ScanningContext {
if scanInfo.scanningContext == nil {
scanningContext := scanInfo.getScanningContext(scanInfo.GetInputFiles())
scanInfo.scanningContext = &scanningContext
if len(scanInfo.InputPatterns) > 0 {
return GetScanningContext(scanInfo.InputPatterns[0])
}
return *scanInfo.scanningContext
return GetScanningContext("")
}
// getScanningContext get scanning context from the input param
// this function should be called only once. Call GetScanningContext() to get the scanning context
func (scanInfo *ScanInfo) getScanningContext(input string) ScanningContext {
// GetScanningContext get scanning context from the input param
func GetScanningContext(input string) ScanningContext {
// cluster
if input == "" {
return ContextCluster
}
// git url
// url
if _, err := giturl.NewGitURL(input); err == nil {
if repo, err := CloneGitRepo(&input); err == nil {
if _, err := NewLocalGitRepository(repo); err == nil {
scanInfo.cleanups = append(scanInfo.cleanups, func() {
_ = os.RemoveAll(repo)
})
return ContextGitRemote
}
}
return ContextGitURL
}
if !filepath.IsAbs(input) { // parse path
@@ -350,14 +333,19 @@ func (scanInfo *ScanInfo) getScanningContext(input string) ScanningContext {
// dir/glob
return ContextDir
}
func (scanInfo *ScanInfo) setContextMetadata(ctx context.Context, contextMetadata *reporthandlingv2.ContextMetadata) {
input := scanInfo.GetInputFiles()
switch scanInfo.GetScanningContext() {
func setContextMetadata(ctx context.Context, contextMetadata *reporthandlingv2.ContextMetadata, input string) {
switch GetScanningContext(input) {
case ContextCluster:
contextMetadata.ClusterContextMetadata = &reporthandlingv2.ClusterMetadata{
ContextName: k8sinterface.GetContextName(),
}
case ContextGitURL:
// url
context, err := metadataGitURL(input)
if err != nil {
logger.L().Ctx(ctx).Warning("in setContextMetadata", helpers.Interface("case", ContextGitURL), helpers.Error(err))
}
contextMetadata.RepoContextMetadata = context
case ContextDir:
contextMetadata.DirectoryContextMetadata = &reporthandlingv2.DirectoryContextMetadata{
BasePath: getAbsPath(input),
@@ -389,21 +377,43 @@ func (scanInfo *ScanInfo) setContextMetadata(ctx context.Context, contextMetadat
}
case ContextGitLocal:
// local
repoContext, err := metadataGitLocal(input)
context, err := metadataGitLocal(input)
if err != nil {
logger.L().Ctx(ctx).Warning("in setContextMetadata", helpers.Interface("case", ContextGitLocal), helpers.Error(err))
logger.L().Ctx(ctx).Warning("in setContextMetadata", helpers.Interface("case", ContextGitURL), helpers.Error(err))
}
contextMetadata.RepoContextMetadata = repoContext
case ContextGitRemote:
// remote
repoContext, err := metadataGitLocal(GetClonedPath(input))
if err != nil {
logger.L().Ctx(ctx).Warning("in setContextMetadata", helpers.Interface("case", ContextGitRemote), helpers.Error(err))
}
contextMetadata.RepoContextMetadata = repoContext
contextMetadata.RepoContextMetadata = context
}
}
func metadataGitURL(input string) (*reporthandlingv2.RepoContextMetadata, error) {
context := &reporthandlingv2.RepoContextMetadata{}
gitParser, err := giturl.NewGitAPI(input)
if err != nil {
return context, fmt.Errorf("%w", err)
}
if gitParser.GetBranchName() == "" {
gitParser.SetDefaultBranchName()
}
context.Provider = gitParser.GetProvider()
context.Repo = gitParser.GetRepoName()
context.Owner = gitParser.GetOwnerName()
context.Branch = gitParser.GetBranchName()
context.RemoteURL = gitParser.GetURL().String()
commit, err := gitParser.GetLatestCommit()
if err != nil {
return context, fmt.Errorf("%w", err)
}
context.LastCommit = reporthandling.LastCommit{
Hash: commit.SHA,
Date: commit.Committer.Date,
CommitterName: commit.Committer.Name,
}
return context, nil
}
func metadataGitLocal(input string) (*reporthandlingv2.RepoContextMetadata, error) {
gitParser, err := NewLocalGitRepository(input)
if err != nil {
@@ -413,31 +423,31 @@ func metadataGitLocal(input string) (*reporthandlingv2.RepoContextMetadata, erro
if err != nil {
return nil, fmt.Errorf("%w", err)
}
repoContext := &reporthandlingv2.RepoContextMetadata{}
context := &reporthandlingv2.RepoContextMetadata{}
gitParserURL, err := giturl.NewGitURL(remoteURL)
if err != nil {
return repoContext, fmt.Errorf("%w", err)
return context, fmt.Errorf("%w", err)
}
gitParserURL.SetBranchName(gitParser.GetBranchName())
repoContext.Provider = gitParserURL.GetProvider()
repoContext.Repo = gitParserURL.GetRepoName()
repoContext.Owner = gitParserURL.GetOwnerName()
repoContext.Branch = gitParserURL.GetBranchName()
repoContext.RemoteURL = gitParserURL.GetURL().String()
context.Provider = gitParserURL.GetProvider()
context.Repo = gitParserURL.GetRepoName()
context.Owner = gitParserURL.GetOwnerName()
context.Branch = gitParserURL.GetBranchName()
context.RemoteURL = gitParserURL.GetURL().String()
commit, err := gitParser.GetLastCommit()
if err != nil {
return repoContext, fmt.Errorf("%w", err)
return context, fmt.Errorf("%w", err)
}
repoContext.LastCommit = reporthandling.LastCommit{
context.LastCommit = reporthandling.LastCommit{
Hash: commit.SHA,
Date: commit.Committer.Date,
CommitterName: commit.Committer.Name,
}
repoContext.LocalRootPath, _ = gitParser.GetRootDir()
context.LocalRootPath, _ = gitParser.GetRootDir()
return repoContext, nil
return context, nil
}
func getHostname() string {
if h, e := os.Hostname(); e == nil {
@@ -454,3 +464,11 @@ func getAbsPath(p string) string {
}
return p
}
// ScanningContextToScanningScope convert the context to the deprecated scope
func ScanningContextToScanningScope(scanningContext ScanningContext) string {
if scanningContext == ContextCluster {
return ScopeCluster
}
return ScopeYAML
}

View File

@@ -3,19 +3,17 @@ package cautils
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/go-git/go-git/v5"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSetContextMetadata(t *testing.T) {
{
ctx := reporthandlingv2.ContextMetadata{}
scanInfo := &ScanInfo{}
scanInfo.setContextMetadata(context.TODO(), &ctx)
setContextMetadata(context.TODO(), &ctx, "")
assert.NotNil(t, ctx.ClusterContextMetadata)
assert.Nil(t, ctx.DirectoryContextMetadata)
@@ -44,57 +42,13 @@ func TestGetHostname(t *testing.T) {
}
func TestGetScanningContext(t *testing.T) {
repoRoot, err := os.MkdirTemp("", "repo")
require.NoError(t, err)
defer func(name string) {
_ = os.Remove(name)
}(repoRoot)
_, err = git.PlainClone(repoRoot, false, &git.CloneOptions{
URL: "https://github.com/kubescape/http-request",
})
require.NoError(t, err)
tmpFile, err := os.CreateTemp("", "single.*.txt")
require.NoError(t, err)
defer func(name string) {
_ = os.Remove(name)
}(tmpFile.Name())
tests := []struct {
name string
input string
want ScanningContext
}{
{
name: "empty input",
input: "",
want: ContextCluster,
},
{
name: "git URL input",
input: "https://github.com/kubescape/http-request",
want: ContextGitRemote,
},
{
name: "local git input",
input: repoRoot,
want: ContextGitLocal,
},
{
name: "single file input",
input: tmpFile.Name(),
want: ContextFile,
},
{
name: "directory input",
input: os.TempDir(),
want: ContextDir,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
scanInfo := &ScanInfo{}
assert.Equalf(t, tt.want, scanInfo.getScanningContext(tt.input), "GetScanningContext(%v)", tt.input)
})
}
// Test with empty input
assert.Equal(t, ContextCluster, GetScanningContext(""))
// Test with Git URL input
assert.Equal(t, ContextGitURL, GetScanningContext("https://github.com/kubescape/kubescape"))
// TODO: Add more tests with other input types
}
func TestScanInfoFormats(t *testing.T) {
@@ -123,3 +77,30 @@ func TestScanInfoFormats(t *testing.T) {
})
}
}
func TestGetScanningContextWithFile(t *testing.T) {
// Test with a file
dir, err := os.MkdirTemp("", "example")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
filePath := filepath.Join(dir, "file.txt")
if _, err := os.Create(filePath); err != nil {
t.Fatal(err)
}
assert.Equal(t, ContextFile, GetScanningContext(filePath))
}
func TestGetScanningContextWithDir(t *testing.T) {
// Test with a directory
dir, err := os.MkdirTemp("", "example")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
assert.Equal(t, ContextDir, GetScanningContext(dir))
}

View File

@@ -0,0 +1,186 @@
package cautils
import (
"context"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"github.com/armosec/utils-go/boolutils"
utils "github.com/kubescape/backend/pkg/utils"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
"github.com/mattn/go-isatty"
"go.opentelemetry.io/otel"
"golang.org/x/mod/semver"
)
const SKIP_VERSION_CHECK_DEPRECATED_ENV = "KUBESCAPE_SKIP_UPDATE_CHECK"
const SKIP_VERSION_CHECK_ENV = "KS_SKIP_UPDATE_CHECK"
const CLIENT_ENV = "KS_CLIENT"
var BuildNumber string
var Client string
var LatestReleaseVersion string
const UnknownBuildNumber = "unknown"
type IVersionCheckHandler interface {
CheckLatestVersion(context.Context, *VersionCheckRequest) error
}
func NewIVersionCheckHandler(ctx context.Context) IVersionCheckHandler {
if BuildNumber == "" {
logger.L().Ctx(ctx).Warning("Unknown build number: this might affect your scan results. Please ensure that you are running the latest version.")
}
if v, ok := os.LookupEnv(CLIENT_ENV); ok && v != "" {
Client = v
}
if v, ok := os.LookupEnv(SKIP_VERSION_CHECK_ENV); ok && boolutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
} else if v, ok := os.LookupEnv(SKIP_VERSION_CHECK_DEPRECATED_ENV); ok && boolutils.StringToBool(v) {
return NewVersionCheckHandlerMock()
}
return NewVersionCheckHandler()
}
type VersionCheckHandlerMock struct {
}
func NewVersionCheckHandlerMock() *VersionCheckHandlerMock {
return &VersionCheckHandlerMock{}
}
type VersionCheckHandler struct {
versionURL string
}
type VersionCheckRequest struct {
Client string `json:"client"` // kubescape
ClientBuild string `json:"clientBuild"` // client build environment
ClientVersion string `json:"clientVersion"` // kubescape version
Framework string `json:"framework"` // framework name
FrameworkVersion string `json:"frameworkVersion"` // framework version
ScanningTarget string `json:"target"` // Deprecated
ScanningContext string `json:"context"` // scanning context- cluster/file/gitURL/localGit/dir
TriggeredBy string `json:"triggeredBy"` // triggered by - cli/ ci / microservice
}
type VersionCheckResponse struct {
Client string `json:"client"` // kubescape
ClientUpdate string `json:"clientUpdate"` // kubescape latest version
Framework string `json:"framework"` // framework name
FrameworkUpdate string `json:"frameworkUpdate"` // framework latest version
Message string `json:"message"` // alert message
}
func NewVersionCheckHandler() *VersionCheckHandler {
return &VersionCheckHandler{
versionURL: "https://us-central1-elated-pottery-310110.cloudfunctions.net/ksgf1v1",
}
}
func getTriggerSource() string {
if strings.Contains(os.Args[0], "ksserver") {
return "microservice"
}
if !isatty.IsTerminal(os.Stdin.Fd()) && !isatty.IsCygwinTerminal(os.Stdin.Fd()) {
// non-interactive shell
return "pipeline"
}
if os.Getenv("GITHUB_ACTIONS") == "true" {
return "pipeline"
}
return "cli"
}
func NewVersionCheckRequest(buildNumber, frameworkName, frameworkVersion, scanningTarget string) *VersionCheckRequest {
if buildNumber == "" {
buildNumber = UnknownBuildNumber
}
if scanningTarget == "" {
scanningTarget = "unknown"
}
if Client == "" {
Client = "local-build"
}
return &VersionCheckRequest{
Client: "kubescape",
ClientBuild: Client,
ClientVersion: buildNumber,
Framework: frameworkName,
FrameworkVersion: frameworkVersion,
ScanningTarget: scanningTarget,
TriggeredBy: getTriggerSource(),
}
}
func (v *VersionCheckHandlerMock) CheckLatestVersion(_ context.Context, _ *VersionCheckRequest) error {
logger.L().Info("Skipping version check")
return nil
}
func (v *VersionCheckHandler) CheckLatestVersion(ctx context.Context, versionData *VersionCheckRequest) error {
ctx, span := otel.Tracer("").Start(ctx, "versionCheckHandler.CheckLatestVersion")
defer span.End()
defer func() {
if err := recover(); err != nil {
logger.L().Ctx(ctx).Warning("failed to get latest version", helpers.Interface("error", err))
}
}()
latestVersion, err := v.getLatestVersion(versionData)
if err != nil || latestVersion == nil {
return fmt.Errorf("failed to get latest version")
}
LatestReleaseVersion = latestVersion.ClientUpdate
if latestVersion.ClientUpdate != "" {
if BuildNumber != "" && semver.Compare(BuildNumber, LatestReleaseVersion) == -1 {
logger.L().Ctx(ctx).Warning(warningMessage(LatestReleaseVersion))
}
}
// TODO - Enable after supporting framework version
// if latestVersion.FrameworkUpdate != "" {
// fmt.Println(warningMessage(latestVersion.Framework, latestVersion.FrameworkUpdate))
// }
if latestVersion.Message != "" {
logger.L().Info(latestVersion.Message)
}
return nil
}
func (v *VersionCheckHandler) getLatestVersion(versionData *VersionCheckRequest) (*VersionCheckResponse, error) {
reqBody, err := json.Marshal(*versionData)
if err != nil {
return nil, fmt.Errorf("in 'CheckLatestVersion' failed to json.Marshal, reason: %s", err.Error())
}
rdr, _, err := getter.HTTPPost(http.DefaultClient, v.versionURL, reqBody, map[string]string{"Content-Type": "application/json"})
vResp, err := utils.Decode[*VersionCheckResponse](rdr)
if err != nil {
return nil, err
}
return vResp, nil
}
func warningMessage(release string) string {
return fmt.Sprintf("current version '%s' is not updated to the latest release: '%s'", BuildNumber, release)
}

View File

@@ -0,0 +1,193 @@
package cautils
import (
"context"
"fmt"
"os"
"reflect"
"testing"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/opa-utils/reporthandling"
"github.com/stretchr/testify/assert"
"golang.org/x/mod/semver"
)
func TestGetKubernetesObjects(t *testing.T) {
}
var rule_v1_0_131 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useUntilKubescapeVersion": "v1.0.132"}}}
var rule_v1_0_132 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.132", "useUntilKubescapeVersion": "v1.0.133"}}}
var rule_v1_0_133 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.133", "useUntilKubescapeVersion": "v1.0.134"}}}
var rule_v1_0_134 = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.134"}}}
var rule_invalid_from = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": 1.0135, "useUntilKubescapeVersion": "v1.0.135"}}}
var rule_invalid_until = &reporthandling.PolicyRule{PortalBase: armotypes.PortalBase{
Attributes: map[string]interface{}{"useFromKubescapeVersion": "v1.0.135", "useUntilKubescapeVersion": 1.0135}}}
func TestIsRuleKubescapeVersionCompatible(t *testing.T) {
// local build- no build number
// should not crash when the value of useUntilKubescapeVersion is not a string
buildNumberMock := "v1.0.135"
assert.False(t, isRuleKubescapeVersionCompatible(rule_invalid_from.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_invalid_until.Attributes, buildNumberMock))
// should use only rules that don't have "until"
buildNumberMock = ""
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.130"
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.132"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.133"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
// should only use rules that version is in range of use
buildNumberMock = "v1.0.135"
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_131.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_132.Attributes, buildNumberMock))
assert.False(t, isRuleKubescapeVersionCompatible(rule_v1_0_133.Attributes, buildNumberMock))
assert.True(t, isRuleKubescapeVersionCompatible(rule_v1_0_134.Attributes, buildNumberMock))
}
func TestCheckLatestVersion_Semver_Compare(t *testing.T) {
assert.Equal(t, -1, semver.Compare("v2.0.150", "v2.0.151"))
assert.Equal(t, 0, semver.Compare("v2.0.150", "v2.0.150"))
assert.Equal(t, 1, semver.Compare("v2.0.150", "v2.0.149"))
assert.Equal(t, -1, semver.Compare("v2.0.150", "v3.0.150"))
}
func TestCheckLatestVersion(t *testing.T) {
type args struct {
ctx context.Context
versionData *VersionCheckRequest
versionURL string
}
tests := []struct {
name string
args args
err error
}{
{
name: "Get latest version",
args: args{
ctx: context.Background(),
versionData: &VersionCheckRequest{},
versionURL: "https://us-central1-elated-pottery-310110.cloudfunctions.net/ksgf1v1",
},
err: nil,
},
{
name: "Failed to get latest version",
args: args{
ctx: context.Background(),
versionData: &VersionCheckRequest{},
versionURL: "https://example.com",
},
err: fmt.Errorf("failed to get latest version"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := &VersionCheckHandler{
versionURL: tt.args.versionURL,
}
err := v.CheckLatestVersion(tt.args.ctx, tt.args.versionData)
assert.Equal(t, tt.err, err)
})
}
}
func TestVersionCheckHandler_getLatestVersion(t *testing.T) {
type fields struct {
versionURL string
}
type args struct {
versionData *VersionCheckRequest
}
tests := []struct {
name string
fields fields
args args
want *VersionCheckResponse
wantErr bool
}{
{
name: "Get latest version",
fields: fields{
versionURL: "https://us-central1-elated-pottery-310110.cloudfunctions.net/ksgf1v1",
},
args: args{
versionData: &VersionCheckRequest{
Client: "kubescape",
},
},
want: &VersionCheckResponse{
Client: "kubescape",
ClientUpdate: "v3.0.0",
},
wantErr: false,
},
{
name: "Failed to get latest version",
fields: fields{
versionURL: "https://example.com",
},
args: args{
versionData: &VersionCheckRequest{},
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
v := &VersionCheckHandler{
versionURL: tt.fields.versionURL,
}
got, err := v.getLatestVersion(tt.args.versionData)
if (err != nil) != tt.wantErr {
t.Errorf("VersionCheckHandler.getLatestVersion() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("VersionCheckHandler.getLatestVersion() = %v, want %v", got, tt.want)
}
})
}
}
func TestGetTriggerSource(t *testing.T) {
// Running in github actions pipeline
os.Setenv("GITHUB_ACTIONS", "true")
source := getTriggerSource()
assert.Equal(t, "pipeline", source)
os.Args[0] = "ksserver"
source = getTriggerSource()
assert.Equal(t, "microservice", source)
}

View File

@@ -83,10 +83,7 @@ func (a *OperatorAdapter) httpPostOperatorScanRequest(body apis.Commands) (strin
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", fmt.Errorf("http-error: %d", resp.StatusCode)
}
return "success", nil
return httputils.HttpRespToString(resp)
}
func (a *OperatorAdapter) OperatorScan() (string, error) {

View File

@@ -8,7 +8,7 @@ import (
"sort"
"strings"
"github.com/kubescape/go-logger"
logger "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"

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/pkg/fixhandler"

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"github.com/anchore/grype/grype/presenter/models"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/cautils"
ksmetav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling"

View File

@@ -5,11 +5,10 @@ import (
"fmt"
"os"
"strings"
"time"
"github.com/anchore/grype/grype/presenter"
"github.com/anchore/grype/grype/presenter/models"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
@@ -18,13 +17,8 @@ import (
"github.com/kubescape/kubescape/v3/pkg/imagescan"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling"
copa "github.com/project-copacetic/copacetic/pkg/patch"
log "github.com/sirupsen/logrus"
copaGrype "github.com/anubhav06/copa-grype/grype"
"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"
)
func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
@@ -44,11 +38,6 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
if err != nil {
return nil, err
}
// If the scan results ID is empty, set it to "grype"
if scanResults.ID.Name == "" {
scanResults.ID.Name = "grype"
}
// Save the scan results to a file in json format
pres := presenter.GetPresenter("json", "", false, *scanResults)
@@ -57,27 +46,27 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
writer := printer.GetWriter(ctx, fileName)
if err = pres.Present(writer); err != nil {
if err := pres.Present(writer); err != nil {
return nil, err
}
logger.L().StopSuccess(fmt.Sprintf("Successfully scanned image: %s", patchInfo.Image))
// ===================== Patch the image using copacetic =====================
logger.L().Start("Patching image...")
patchedImageName := fmt.Sprintf("%s:%s", patchInfo.ImageName, patchInfo.PatchedImageTag)
sout, serr := os.Stdout, os.Stderr
if logger.L().GetLevel() != "debug" {
disableCopaLogger()
}
if err = copaPatch(ctx, patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
if err := copa.Patch(ctx, patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchInfo.PatchedImageTag, ""); err != nil {
return nil, err
}
// Restore the output streams
os.Stdout, os.Stderr = sout, serr
patchedImageName := fmt.Sprintf("%s:%s", patchInfo.ImageName, patchInfo.PatchedImageTag)
logger.L().StopSuccess(fmt.Sprintf("Patched image successfully. Loaded image: %s", patchedImageName))
// ===================== Re-scan the image =====================
@@ -108,6 +97,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
Image: patchedImageName,
},
}
resultsHandler.HandleResults(ctx)
return scanResultsPatched, resultsHandler.HandleResults(ctx)
}
@@ -117,110 +107,3 @@ func disableCopaLogger() {
null, _ := os.Open(os.DevNull)
log.SetOutput(null)
}
// copaPatch is a slightly modified copy of the Patch function from the original "project-copacetic/copacetic" repo
// https://github.com/project-copacetic/copacetic/blob/main/pkg/patch/patch.go
func copaPatch(ctx context.Context, timeout time.Duration, buildkitAddr, image, reportFile, patchedImageName, workingFolder string, ignoreError bool, bkOpts buildkit.Opts) error {
timeoutCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
ch := make(chan error)
go func() {
ch <- patchWithContext(timeoutCtx, buildkitAddr, image, reportFile, patchedImageName, workingFolder, ignoreError, bkOpts)
}()
select {
case err := <-ch:
return err
case <-timeoutCtx.Done():
// add a grace period for long running deferred cleanup functions to complete
<-time.After(1 * time.Second)
err := fmt.Errorf("patch exceeded timeout %v", timeout)
log.Error(err)
return err
}
}
func patchWithContext(ctx context.Context, buildkitAddr, image, reportFile, patchedImageName, workingFolder string, ignoreError bool, bkOpts buildkit.Opts) error {
// Ensure working folder exists for call to InstallUpdates
if workingFolder == "" {
var err error
workingFolder, err = os.MkdirTemp("", "copa-*")
if err != nil {
return err
}
defer os.RemoveAll(workingFolder)
if err := os.Chmod(workingFolder, 0o744); err != nil {
return err
}
} else {
if isNew, err := utils.EnsurePath(workingFolder, 0o744); err != nil {
log.Errorf("failed to create workingFolder %s", workingFolder)
return err
} else if isNew {
defer os.RemoveAll(workingFolder)
}
}
// Parse report for update packages
updates, err := tryParseScanReport(reportFile)
if err != nil {
return err
}
client, err := buildkit.NewClient(ctx, bkOpts)
if err != nil {
return err
}
defer client.Close()
// Configure buildctl/client for use by package manager
config, err := buildkit.InitializeBuildkitConfig(ctx, client, image, updates)
if err != nil {
return err
}
// Create package manager helper
pkgmgr, err := pkgmgr.GetPackageManager(updates.Metadata.OS.Type, config, workingFolder)
if err != nil {
return err
}
// Export the patched image state to Docker
patchedImageState, _, err := pkgmgr.InstallUpdates(ctx, updates, ignoreError)
if err != nil {
return err
}
if err = buildkit.SolveToDocker(ctx, config.Client, patchedImageState, config.ConfigData, patchedImageName); err != nil {
return err
}
return nil
}
// This function adds support to copa for patching Kubescape produced results
func tryParseScanReport(file string) (*unversioned.UpdateManifest, error) {
parser := copaGrype.GrypeParser{}
manifest, err := parser.Parse(file)
if err != nil {
return nil, err
}
// Convert from v1alpha1 to unversioned.UpdateManifest
var um unversioned.UpdateManifest
um.Metadata.OS.Type = manifest.Metadata.OS.Type
um.Metadata.OS.Version = manifest.Metadata.OS.Version
um.Metadata.Config.Arch = manifest.Metadata.Config.Arch
um.Updates = make([]unversioned.UpdatePackage, len(manifest.Updates))
for i, update := range manifest.Updates {
um.Updates[i].Name = update.Name
um.Updates[i].InstalledVersion = update.InstalledVersion
um.Updates[i].FixedVersion = update.FixedVersion
um.Updates[i].VulnerabilityID = update.VulnerabilityID
}
return &um, nil
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
@@ -23,7 +22,6 @@ import (
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"go.opentelemetry.io/otel"
"golang.org/x/exp/slices"
"k8s.io/client-go/kubernetes"
"github.com/kubescape/opa-utils/resources"
)
@@ -43,13 +41,10 @@ func getInterfaces(ctx context.Context, scanInfo *cautils.ScanInfo) componentInt
// ================== setup k8s interface object ======================================
var k8s *k8sinterface.KubernetesApi
var k8sClient kubernetes.Interface
if scanInfo.GetScanningContext() == cautils.ContextCluster {
k8s = getKubernetesApi()
if k8s == nil {
logger.L().Ctx(ctx).Fatal("failed connecting to Kubernetes cluster")
} else {
k8sClient = k8s.KubernetesClient
}
}
@@ -68,8 +63,8 @@ func getInterfaces(ctx context.Context, scanInfo *cautils.ScanInfo) componentInt
// ================== version testing ======================================
v := versioncheck.NewIVersionCheckHandler(ctx)
_ = v.CheckLatestVersion(ctx, versioncheck.NewVersionCheckRequest(scanInfo.AccountID, versioncheck.BuildNumber, policyIdentifierIdentities(scanInfo.PolicyIdentifier), "", string(scanInfo.GetScanningContext()), k8sClient))
v := cautils.NewIVersionCheckHandler(ctx)
v.CheckLatestVersion(ctx, cautils.NewVersionCheckRequest(cautils.BuildNumber, policyIdentifierIdentities(scanInfo.PolicyIdentifier), "", cautils.ScanningContextToScanningScope(scanInfo.GetScanningContext())))
// ================== setup host scanner object ======================================
ctxHostScanner, spanHostScanner := otel.Tracer("").Start(ctx, "setup host scanner")
@@ -128,7 +123,6 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
// ===================== Initialization =====================
scanInfo.Init(ctxInit) // initialize scan info
defer scanInfo.Cleanup()
interfaces := getInterfaces(ctxInit, scanInfo)
interfaces.report.SetTenantConfig(interfaces.tenantConfig)
@@ -169,7 +163,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
// ===================== resources =====================
ctxResources, spanResources := otel.Tracer("").Start(ctxInit, "resources")
err = resourcehandler.CollectResources(ctxResources, interfaces.resourceHandler, scanData, scanInfo)
err = resourcehandler.CollectResources(ctxResources, interfaces.resourceHandler, scanInfo.PolicyIdentifier, scanData, cautils.NewProgressHandler(""), scanInfo)
if err != nil {
spanInit.End()
return resultsHandling, err
@@ -182,7 +176,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
defer spanOpa.End()
deps := resources.NewRegoDependenciesData(k8sinterface.GetK8sConfig(), interfaces.tenantConfig.GetContextName())
reportResults := opaprocessor.NewOPAProcessor(scanData, deps, interfaces.tenantConfig.GetContextName(), scanInfo.ExcludedNamespaces, scanInfo.IncludeNamespaces)
reportResults := opaprocessor.NewOPAProcessor(scanData, deps, interfaces.tenantConfig.GetContextName())
if err = reportResults.ProcessRulesListener(ctxOpa, cautils.NewProgressHandler("")); err != nil {
// TODO - do something
return resultsHandling, fmt.Errorf("%w", err)
@@ -196,7 +190,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
} else if err := priotizationHandler.PrioritizeResources(scanData); err != nil {
return resultsHandling, fmt.Errorf("%w", err)
}
if isPrioritizationScanType(scanInfo.ScanType) {
if err == nil && isPrioritizationScanType(scanInfo.ScanType) {
scanData.SetTopWorkloads()
}
spanPrioritization.End()
@@ -216,7 +210,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
}
func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx context.Context, resultsHandling *resultshandling.ResultsHandler) {
var imagesToScan []string
imagesToScan := []string{}
if scanType == cautils.ScanTypeWorkload {
containers, err := workloadinterface.NewWorkloadObj(scanData.SingleResourceScan.GetObject()).GetContainers()
@@ -252,7 +246,7 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx
if err := scanSingleImage(ctx, img, svc, resultsHandling); err != nil {
logger.L().StopError("failed to scan", helpers.String("image", img), helpers.Error(err))
}
logger.L().StopSuccess("Done scanning", helpers.String("image", img))
logger.L().StopSuccess("Scan successful: ", helpers.String("image", img))
}
}

View File

@@ -1,18 +1,12 @@
package v1
import (
"time"
"github.com/project-copacetic/copacetic/pkg/buildkit"
)
import "time"
type PatchInfo struct {
Image string // image to be patched
PatchedImageTag string // can be empty, if empty then the image tag will be patched with the latest tag
BuildkitAddress string // buildkit address
Timeout time.Duration // timeout for patching an image
IgnoreError bool // ignore errors and continue patching
BuildKitOpts buildkit.Opts //build kit options
// Image registry credentials
Username string // username for registry login

View File

@@ -25,7 +25,7 @@ func GenerateContainerScanReportMock() ScanResultReport {
return ds
}
// GenerateContainerScanReportNoVulMock - generate a scan result
// GenerateContainerScanReportMock - generate a scan result
func GenerateContainerScanReportNoVulMock() ScanResultReport {
ds := ScanResultReport{
WLID: "wlid://cluster-k8s-geriatrix-k8s-demo3/namespace-whisky-app/deployment-whisky4all-shipping",

View File

@@ -15,7 +15,7 @@ import (
"github.com/armosec/armoapi-go/armotypes"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/opa-utils/objectsenvelopes"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"
"github.com/kubescape/opa-utils/reporthandling"

View File

@@ -8,7 +8,7 @@ import (
"testing"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/internal/testutils"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"

View File

@@ -14,6 +14,6 @@ metadata:
spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: true
image: nginx

View File

@@ -14,6 +14,6 @@ metadata:
spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: true
image: nginx

View File

@@ -16,6 +16,6 @@ spec:
containers:
# These are the first containers comments
- name: nginx_container
image: nginx
securityContext:
runAsRoot: true
image: nginx

View File

@@ -15,7 +15,7 @@ spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: true
image: nginx

View File

@@ -15,7 +15,7 @@ spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: false

View File

@@ -16,7 +16,7 @@ spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: true
image: nginx

View File

@@ -16,7 +16,7 @@ spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: false

View File

@@ -9,6 +9,6 @@ metadata:
spec:
containers:
- name: nginx_container
securityContext:
runAsRoot: false
image: nginx
securityContext:
runAsRoot: false

View File

@@ -9,4 +9,4 @@ metadata:
spec:
containers:
- name: nginx_container
image: nginx
image: nginx

View File

@@ -12,5 +12,4 @@ spec:
image: nginx
- name: container_with_security_issues
image: image_with_security_issues
restartPolicy: Always
image: image_with_security_issues

View File

@@ -10,5 +10,3 @@ spec:
containers:
- name: nginx_container
image: nginx
restartPolicy: Always

View File

@@ -8,7 +8,7 @@ metadata:
spec:
containers:
- name: nginx1
image: nginx
securityContext:
capabilities:
drop: ["NET_RAW", "SYS_ADM"]
image: nginx
drop: ["NET_RAW", "SYS_ADM"]

View File

@@ -8,7 +8,7 @@ metadata:
spec:
containers:
- name: nginx1
image: nginx
securityContext:
capabilities:
drop: ["NET_RAW"]
image: nginx
drop: ["NET_RAW"]

View File

@@ -9,9 +9,9 @@ metadata:
spec:
containers:
- name: nginx_container
image: nginx
securityContext:
runAsRoot: false
image: nginx
---
@@ -29,5 +29,4 @@ spec:
image: nginx
- name: container_with_security_issues
image: image_with_security_issues
restartPolicy: Always
image: image_with_security_issues

View File

@@ -25,5 +25,3 @@ spec:
containers:
- name: nginx_container
image: nginx
restartPolicy: Always

View File

@@ -9,6 +9,6 @@ metadata:
spec:
containers:
- name: nginx_container
securityContext:
runAsRoot: true
image: nginx
securityContext:
runAsRoot: true

View File

@@ -9,6 +9,6 @@ metadata:
spec:
containers:
- name: nginx_container
securityContext:
runAsRoot: false
image: nginx
securityContext:
runAsRoot: false

View File

@@ -10,9 +10,9 @@ metadata:
spec:
containers:
- name: nginx1
image: nginx
securityContext:
capabilities:
drop:
- "NET_RAW"
add: ["SYS_ADM"]
image: nginx
add: ["SYS_ADM"]

View File

@@ -10,9 +10,9 @@ metadata:
spec:
containers:
- name: nginx1
image: nginx
securityContext:
capabilities:
drop:
- "SYS_ADM"
add: ["NET_RAW"]
image: nginx
add: ["NET_RAW"]

View File

@@ -182,7 +182,7 @@ func addLinesToRemove(ctx context.Context, fixInfoMetadata *fixInfoMetadata) (in
newOriginalListTracker := updateTracker(fixInfoMetadata.originalList, fixInfoMetadata.originalListTracker)
*fixInfoMetadata.linesToRemove = append(*fixInfoMetadata.linesToRemove, linesToRemove{
startLine: currentDFSNode.node.Line,
endLine: getNodeLine(fixInfoMetadata.originalList, newOriginalListTracker-1), // newOriginalListTracker is the next node
endLine: getNodeLine(fixInfoMetadata.originalList, newOriginalListTracker),
})
return newOriginalListTracker, fixInfoMetadata.fixedListTracker

View File

@@ -12,7 +12,7 @@ import (
"os"
"strings"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/mikefarah/yq/v4/pkg/yqlib"
"gopkg.in/yaml.v3"
)

View File

@@ -8,7 +8,7 @@ import (
"sync"
"time"
"github.com/kubescape/go-logger"
logger "github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/k8sinterface"
"github.com/kubescape/k8s-interface/workloadinterface"
@@ -307,7 +307,7 @@ func (hsh *HostSensorHandler) updatePodInListAtomic(ctx context.Context, eventTy
}
}
// tearDownHostScanner manage the host-scanner deletion.
// tearDownNamespace manage the host-scanner deletion.
func (hsh *HostSensorHandler) tearDownHostScanner(namespace string) error {
client := hsh.k8sObj.KubernetesClient

Some files were not shown because too many files have changed in this diff Show More