Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GitHub Action #2

Merged
merged 4 commits into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 0 additions & 58 deletions .github/workflows/generate-vex.yaml

This file was deleted.

31 changes: 31 additions & 0 deletions .github/workflows/self-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Self test
on:
push:
branches:
- main
pull_request:
paths-ignore:
- '**/*.md'
types: [labeled, synchronize, ready_for_review, opened, reopened]

jobs:
generate_vex:
runs-on: ubuntu-latest
name: Test VEX Generation
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Checkout nginx helm chart
uses: actions/checkout@v4
with:
repository: helm/examples
path: charts/examples
ref: main

- name: Test VEX Generation
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"
test-command: "self-test/test.sh"
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,37 @@
# generate-vex-action
# Generate VEX with Kubescape GitHub Action

This GitHub Action is designed to generate a VEX (Vulnerability Exploitability
eXchange) document using Kubescape. It does this by deploying a Helm chart to a
KinD cluster and running a test command, which should run your suite of tests
and thereby generate usage information for Kubescape. The Action will then
produce a VEX document based on the information collected and save it as an
artifact.

## Inputs

- `helm-chart-path`: (Required) The path to the Helm chart that you want to
test.
- `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
deployment. This should be a command that runs your suite of tests. If
omitted, no tests will be run and the VEX document will likely be unreliable
as there will be no real usage information.

## Usage

To use this action in your workflow, include it in your workflow file with the required inputs:

```yaml
- 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`
test-command: 'your-test-command' # Ex. `./ci/test_integration.sh`
```

Replace `your-org/generate-vex-with-kubescape@v1` with the actual repository and version of the action. Replace the values of `helm-chart-path`, `ready-condition`, and `test-command` with your actual values.

## Example

To see an example of this Action in use, check out the [self test](./.github/workflows/self-test.yml) workflow in this repository.
43 changes: 43 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: "Generate VEX with Kubescape"
description: "Generate VEX with Kubescape"
inputs:
helm-chart-path:
description: "Path to Helm chart to test"
required: true
ready-condition:
description: "Condition to wait for before collecting VEX info"
required: false
test-command:
description: "Command to run to test the deployment"
required: false

runs:
using: "composite"
steps:
- name: "Setup"
run: $GITHUB_ACTION_PATH/setup.sh
shell: bash

- name: "Install Helm Chart"
env:
HELM_CHART_PATH: ${{ inputs.helm-chart-path }}
READY_CONDITION: ${{ inputs.ready-condition }}
run: $GITHUB_ACTION_PATH/install.sh
shell: bash

- name: "Run tests"
env:
TEST_COMMAND: ${{ inputs.test-command }}
run: $GITHUB_ACTION_PATH/test.sh
shell: bash

- name: "Generate VEX"
run: $GITHUB_ACTION_PATH/generate.sh
shell: bash

- name: Upload VEX document
if: always()
uses: actions/upload-artifact@v4
with:
name: VEX document
path: vex.json
31 changes: 31 additions & 0 deletions generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -x

timeout=300
start_time=$SECONDS
while [[ -z $(kubectl -n kubescape get openvulnerabilityexchangecontainers.spdx.softwarecomposition.kubescape.io) ]]; do
echo "Waiting for VEX generation..."
sleep 10
if [[ $((SECONDS - start_time)) -gt $timeout ]]; then
echo "Timeout reached. Exiting..."

# Loop through all pods in the kubescape namespace and print the logs
for pod in $(kubectl -n kubescape get pods -o jsonpath='{.items[*].metadata.name}'); do
echo "Logs for $pod:"
kubectl -n kubescape logs "$pod"
done

break
fi
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

echo "Affected:"
jq "." vex.json | grep -c "\"affected\""

echo "Not affected:"
jq "." vex.json | grep -c "\"not_affected\""
8 changes: 8 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -x

helm install "$HELM_CHART_PATH" --wait --timeout 300s --generate-name

if [[ -n "$READY_CONDITION" ]]; then
$READY_CONDITION
fi
17 changes: 17 additions & 0 deletions self-test/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
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}")
# Expose the test app on localhost
kubectl 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
# Prints just the status code
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080
echo
done
# Stop the port-forwarding
kill %1
29 changes: 29 additions & 0 deletions setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -x

# Install kind and kubectl
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-$(uname)-amd64
chmod +x ./kind
./kind create cluster
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kubectl
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
# Install helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
sudo ./get_helm.sh
# Install Kubescape
helm repo add kubescape https://kubescape.github.io/helm-charts/
helm repo update
helm upgrade --install kubescape kubescape/kubescape-operator -n kubescape --create-namespace \
--set clusterName="$(kubectl config current-context)" \
--set capabilities.vexGeneration=enable \
--set nodeAgent.config.learningPeriod=1m \
--set nodeAgent.config.updatePeriod=1m \
--set logger.level=debug \
--wait
# Wait for the pod to be ready
sleep 5
kubectl -n kubescape wait --for=condition=ready pod -l app.kubernetes.io/name=node-agent --timeout=300s
kubectl -n kubescape wait --for=condition=ready pod -l app.kubernetes.io/name=storage --timeout=300s
echo "Kubescape is ready"
6 changes: 6 additions & 0 deletions test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -x

if [[ -n "$TEST_COMMAND" ]]; then
$TEST_COMMAND
fi