diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml new file mode 100644 index 00000000..9fe4d73f --- /dev/null +++ b/.github/workflows/scan.yaml @@ -0,0 +1,81 @@ +name: Scan for vulnerabilities + +on: + pull_request: + branches: [main] + types: [milestoned, opened, synchronize] + schedule: + - cron: '0 1 * * *' + workflow_dispatch: {} + +jobs: + # cannot scan registry1 and upstream at the same time because the sarif upload have a file limit of 20 files + scan-upstream: + runs-on: ubuntu-latest + name: Scan for vulnerabilities - Upstream + permissions: + contents: read + pull-requests: read + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Environment setup + uses: defenseunicorns/uds-common/.github/actions/setup@264ec430c4079129870820e70c4439f3f3d57cbc # v0.3.9 + with: + username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} + password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + + + - name: Scan the repository for vulnerabilities - Upstream + env: + FLAVOR: upstream + run: | + uds run grype:install + uds run scan:scan + + - name: Upload SARIF files - Upstream + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 + with: + sarif_file: ./sarif + + scan-registry1: + runs-on: ubuntu-latest + name: Scan for vulnerabilities - Registry1 + permissions: + contents: read + pull-requests: read + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Environment setup + uses: defenseunicorns/uds-common/.github/actions/setup@264ec430c4079129870820e70c4439f3f3d57cbc # v0.3.9 + with: + username: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} + password: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + + - name: Iron Bank Login + env: + REGISTRY_USERNAME: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.IRON_BANK_ROBOT_PASSWORD }} + run: echo "${{ env.REGISTRY_PASSWORD }}" | uds zarf tools registry login -u "${{ env.REGISTRY_USERNAME }}" --password-stdin registry1.dso.mil + shell: bash + + - name: Scan the repository for vulnerabilities - Registry1 + run: | + uds run grype:install + uds run scan:scan + env: + FLAVOR: registry1 + + - name: Upload SARIF files - Registry1 + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 + with: + sarif_file: ./sarif diff --git a/.gitignore b/.gitignore index 00998119..b198ee39 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ defense-unicorns-distro/preflight.sh .terraform tmp zarf-sbom +sbom/ +sarif/ .cache/ .idea/ diff --git a/tasks.yaml b/tasks.yaml index 854f1d9d..741495aa 100644 --- a/tasks.yaml +++ b/tasks.yaml @@ -7,6 +7,8 @@ includes: - pull: https://raw.githubusercontent.com/defenseunicorns/uds-common/v0.3.9/tasks/pull.yaml - deploy: https://raw.githubusercontent.com/defenseunicorns/uds-common/v0.3.9/tasks/deploy.yaml - setup: https://raw.githubusercontent.com/defenseunicorns/uds-common/v0.3.9/tasks/setup.yaml + - scan: ./tasks/scan.yaml + - grype: ./tasks/grype.yaml tasks: - name: default @@ -39,8 +41,8 @@ tasks: - task: dependencies:create - task: create:test-bundle -# CI will execute the following (via uds-common/.github/actions/test) so they need to be here with these names - +# CI will execute the following (via uds-common/.github/actions/test) so they need to be here with +# these names - name: test-package description: Test the GitLab package from the current branch actions: diff --git a/tasks/grype.yaml b/tasks/grype.yaml new file mode 100644 index 00000000..27b788ef --- /dev/null +++ b/tasks/grype.yaml @@ -0,0 +1,12 @@ +--- +tasks: + - name: install + description: Check if Grype is installed, if not install it + actions: + - cmd: | + if ! command -v grype &> /dev/null; then + echo "Grype could not be found, installing..." + curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin + else + echo "Grype is already installed." + fi diff --git a/tasks/scan.yaml b/tasks/scan.yaml new file mode 100644 index 00000000..2fc818f7 --- /dev/null +++ b/tasks/scan.yaml @@ -0,0 +1,29 @@ +--- +tasks: + - name: scan + description: Create a UDS package with specified flavor, extract the SBOM, and analyze for vulnerabilities + actions: + - cmd: | + bash -c ' + flavor="${FLAVOR}" + output_dir="sbom/$flavor" + mkdir -p "$output_dir" + uds zarf package create . --flavor="$flavor" --confirm --no-progress -o "$output_dir" + for file in "$output_dir"/*.zst; do + uds zarf package inspect "$file" --sbom-out "$output_dir" --no-progress + done + sarif_output_dir="./sarif" + mkdir -p "$sarif_output_dir" + find "sbom/$flavor" -type f -name "*.json" | while read -r json_file; do + sarif_file_name="${flavor}_$(basename "${json_file}").sarif" + echo "Processing $json_file" + echo "Outputting to $sarif_output_dir/$sarif_file_name" + grype sbom:"$json_file" -o sarif --file "$sarif_output_dir/$sarif_file_name" + echo "Grype analysis for $json_file exported to $sarif_output_dir/$sarif_file_name (errors ignored)" + # Extract the base name of the SBOM file without the .json extension + sbom_base_name=$(basename "$json_file" .json) + # Use yq to replace the path with the SBOM file name without the .json extension + yq eval "(.runs[].results[].locations[].physicalLocation.artifactLocation.uri) = \"$sbom_base_name\"" "$sarif_output_dir/$sarif_file_name" -i + echo "Updated SARIF file path to $sbom_base_name using yq for $sarif_file_name" + done + '