From a64cdd733bfa58fbf96ea5edb35f689bd2acb53f Mon Sep 17 00:00:00 2001 From: Shlomo Heigh Date: Tue, 21 May 2024 14:25:04 -0400 Subject: [PATCH] Add support for tests namespace and multiple vex docs --- .github/workflows/self-test.yml | 3 ++- README.md | 10 +++++++- action.yml | 12 ++++++++-- generate.sh | 41 +++++++++++++++++++++++++++------ install.sh | 2 +- self-test/test.sh | 6 ++--- 6 files changed, 59 insertions(+), 15 deletions(-) diff --git a/.github/workflows/self-test.yml b/.github/workflows/self-test.yml index 87a1ec8..953fff0 100644 --- a/.github/workflows/self-test.yml +++ b/.github/workflows/self-test.yml @@ -27,5 +27,6 @@ jobs: uses: ./ with: helm-chart-path: "charts/examples/charts/hello-world" - ready-condition: "kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=hello-world --timeout=300s" + namespace: "self-test" + ready-condition: "kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=hello-world --timeout=300s -n self-test" test-command: "self-test/test.sh" diff --git a/README.md b/README.md index 1225bef..9a9ff04 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ artifact. - `helm-chart-path`: (Required) The path to the Helm chart that you want to test. +- `namespace`: (Optional) The namespace that the Helm chart should be deployed + to. If omitted, the namespace will be set to `tests`. - `ready-condition`: (Optional) A condition that the action should wait for before collecting VEX information. - `test-command`: (Optional) The command that should be run to test the @@ -26,7 +28,8 @@ To use this action in your workflow, include it in your workflow file with the r - uses: slashben/generate-vex-action@v1 with: helm-chart-path: './path/to/your/chart' # Ex. './charts/hello-world' - ready-condition: 'your-condition' # Ex. `kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=hello-world --timeout=300s` + namespace: 'tests' # This is the default value + ready-condition: 'your-condition' # Ex. `kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=hello-world --timeout=300s -n tests` test-command: 'your-test-command' # Ex. `./ci/test_integration.sh` ``` @@ -35,3 +38,8 @@ Replace `your-org/generate-vex-with-kubescape@v1` with the actual repository and ## Example To see an example of this Action in use, check out the [self test](./.github/workflows/self-test.yml) workflow in this repository. + +## Roadmap + +- Use https://github.com/helm/kind-action +- Add signing of VEX documents diff --git a/action.yml b/action.yml index 1dcc643..56769d5 100644 --- a/action.yml +++ b/action.yml @@ -4,6 +4,10 @@ inputs: helm-chart-path: description: "Path to Helm chart to test" required: true + namespace: + description: "Namespace to deploy the Helm chart into" + default: "tests" + required: false ready-condition: description: "Condition to wait for before collecting VEX info" required: false @@ -22,22 +26,26 @@ runs: env: HELM_CHART_PATH: ${{ inputs.helm-chart-path }} READY_CONDITION: ${{ inputs.ready-condition }} + TESTS_NAMESPACE: ${{ inputs.namespace }} run: $GITHUB_ACTION_PATH/install.sh shell: bash - name: "Run tests" env: TEST_COMMAND: ${{ inputs.test-command }} + TESTS_NAMESPACE: ${{ inputs.namespace }} run: $GITHUB_ACTION_PATH/test.sh shell: bash - name: "Generate VEX" run: $GITHUB_ACTION_PATH/generate.sh + env: + TESTS_NAMESPACE: ${{ inputs.namespace }} shell: bash - name: Upload VEX document if: always() uses: actions/upload-artifact@v4 with: - name: VEX document - path: vex.json + name: VEX documents + path: out/*.json diff --git a/generate.sh b/generate.sh index 724cbff..042a97c 100755 --- a/generate.sh +++ b/generate.sh @@ -20,12 +20,39 @@ while [[ -z $(kubectl -n kubescape get openvulnerabilityexchangecontainers.spdx. done echo "Saving VEX results..." -kubectl -n kubescape get openvulnerabilityexchangecontainer \ - "$(kubectl -n kubescape get openvulnerabilityexchangecontainer -o jsonpath='{.items[0].metadata.name}')" \ - -o jsonpath='{.spec}' > vex.json +mkdir -p out -echo "Affected:" -jq "." vex.json | grep -c "\"affected\"" +# List available VEX documents +vex_docs=$(kubectl get openvulnerabilityexchangecontainer -n kubescape -o jsonpath='{.items[*].metadata.name}') -echo "Not affected:" -jq "." vex.json | grep -c "\"not_affected\"" +# Iterate over the VEX documents and save them +for doc in $vex_docs; do + # Get the full VEX document object + vex_object=$(kubectl -n kubescape get openvulnerabilityexchangecontainer "$doc" -o json) + + # Check the labels to see if this VEX is for a workload in the TESTS_NAMESPACE + + workload_ns=$(jq -r ".metadata.labels[\"kubescape.io/workload-namespace\"]" <<< "$vex_object") + if [[ $workload_ns != "$TESTS_NAMESPACE" ]]; then + echo "Skipping VEX document $doc as it is not for the TESTS_NAMESPACE" + continue + fi + + # Get the image name + image=$(jq -r ".metadata.labels[\"kubescape.io/image-id\"]" <<< "$vex_object") + + # # Save the VEX document (the .spec portion) to a file + jq ".spec" <<< "$vex_object" > out/"$image".json + + echo "Affected:" + jq "." out/"$image".json | grep -c "\"affected\"" + + echo "Not affected:" + jq "." out/"$image".json | grep -c "\"not_affected\"" +done + +# Check if there are any VEX documents saved +if [[ -z $(ls out) ]]; then + echo "No VEX documents saved. Exiting..." + exit 1 +fi diff --git a/install.sh b/install.sh index 75ae09e..d3c7e0c 100755 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -x -helm install "$HELM_CHART_PATH" --wait --timeout 300s --generate-name +helm install "$HELM_CHART_PATH" --wait --timeout 300s --generate-name -n "$TESTS_NAMESPACE" --create-namespace if [[ -n "$READY_CONDITION" ]]; then $READY_CONDITION diff --git a/self-test/test.sh b/self-test/test.sh index 338d065..dfef241 100755 --- a/self-test/test.sh +++ b/self-test/test.sh @@ -2,10 +2,10 @@ set -x # Get the pod name and container port of the test application -POD_NAME=$(kubectl get pods -l "app.kubernetes.io/name=hello-world" -o jsonpath="{.items[0].metadata.name}") -CONTAINER_PORT=$(kubectl get pod "$POD_NAME" -o jsonpath="{.spec.containers[0].ports[0].containerPort}") +POD_NAME=$(kubectl -n self-test get pods -l "app.kubernetes.io/name=hello-world" -o jsonpath="{.items[0].metadata.name}") +CONTAINER_PORT=$(kubectl -n self-test get pod "$POD_NAME" -o jsonpath="{.spec.containers[0].ports[0].containerPort}") # Expose the test app on localhost -kubectl port-forward "$POD_NAME" 8080:"$CONTAINER_PORT" & +kubectl -n self-test port-forward "$POD_NAME" 8080:"$CONTAINER_PORT" & sleep 5 # Test the application by sending a request to it a number of times for _ in {1..10}; do