OSV Security Vulnerability Scan #24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: OSV Security Vulnerability Scan | |
| on: | |
| schedule: | |
| - cron: "0 17 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| branches: | |
| description: "Allowlisted branch or branches to scan" | |
| type: choice | |
| default: all | |
| options: | |
| - all | |
| - main | |
| - v2.2.x | |
| - v2.3.x | |
| - v2.4.x | |
| permissions: | |
| actions: read | |
| contents: read | |
| packages: read | |
| security-events: write | |
| env: | |
| IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} | |
| OSV_SCANNER_IMAGE: ghcr.io/google/osv-scanner-action:v2.3.5 | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| determine_branches: | |
| name: Determine Branches | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| branches: ${{ steps.determine.outputs.branches }} | |
| steps: | |
| - name: Determine branch matrix | |
| id: determine | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| branches='["main","v2.2.x","v2.3.x","v2.4.x"]' | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| case "${{ inputs.branches }}" in | |
| all) | |
| ;; | |
| main) | |
| branches='["main"]' | |
| ;; | |
| v2.2.x) | |
| branches='["v2.2.x"]' | |
| ;; | |
| v2.3.x) | |
| branches='["v2.3.x"]' | |
| ;; | |
| v2.4.x) | |
| branches='["v2.4.x"]' | |
| ;; | |
| *) | |
| echo "::error::Unsupported branch selection: ${{ inputs.branches }}" | |
| exit 1 | |
| ;; | |
| esac | |
| fi | |
| { | |
| echo "branches=${branches}" | |
| } >> "$GITHUB_OUTPUT" | |
| # Source dependency scan (one analysis per branch, platform-independent). | |
| # Uploaded under category: osv-scanner-<branch> | |
| scan_source: | |
| needs: determine_branches | |
| name: Scan source (${{ matrix.branch }}) | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| branch: ${{ fromJson(needs.determine_branches.outputs.branches) }} | |
| steps: | |
| - name: Checkout branch | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| ref: ${{ matrix.branch }} | |
| - name: Collect upload metadata | |
| id: metadata | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| { | |
| echo "ref=refs/heads/${{ matrix.branch }}" | |
| echo "sha=$(git rev-parse HEAD)" | |
| echo "category=osv-scanner-$(echo '${{ matrix.branch }}' | tr '/.' '--')" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Run source scanner | |
| uses: google/osv-scanner-action/osv-scanner-action@c51854704019a247608d928f370c98740469d4b5 # v2.3.5 | |
| with: | |
| scan-args: |- | |
| --output=results.json | |
| --format=json | |
| --no-call-analysis=go | |
| --no-call-analysis=rust | |
| -r | |
| ./ | |
| continue-on-error: true | |
| - name: Convert source results to SARIF | |
| uses: google/osv-scanner-action/osv-reporter-action@c51854704019a247608d928f370c98740469d4b5 # v2.3.5 | |
| with: | |
| scan-args: |- | |
| --output=results.sarif | |
| --new=results.json | |
| --gh-annotations=false | |
| --fail-on-vuln=false | |
| - name: Upload source SARIF | |
| if: ${{ !cancelled() && hashFiles('results.sarif') != '' }} | |
| uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 | |
| with: | |
| sarif_file: results.sarif | |
| ref: ${{ steps.metadata.outputs.ref }} | |
| sha: ${{ steps.metadata.outputs.sha }} | |
| category: ${{ steps.metadata.outputs.category }} | |
| - name: Print Code Scanning URL | |
| if: ${{ !cancelled() && hashFiles('results.sarif') != '' }} | |
| shell: bash | |
| run: | | |
| echo "View the branch-specific OSV-Scanner results in Security -> Code scanning:" | |
| echo "GitHub defaults that page to the repository default branch, so use the branch filter in this link:" | |
| echo "${{ github.server_url }}/${{ github.repository }}/security/code-scanning?query=is%3Aopen+branch%3A${{ matrix.branch }}+tool%3Aosv-scanner" | |
| # Container image scan. One analysis per (branch, image, platform) so each | |
| # alert names the exact image it came from. | |
| # Uploaded under category: osv-scanner-<branch>-images-<image>-<platform> | |
| scan_image: | |
| needs: determine_branches | |
| name: Scan image (${{ matrix.branch }}, ${{ matrix.image }}, ${{ matrix.platform }}) | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| branch: ${{ fromJson(needs.determine_branches.outputs.branches) }} | |
| platform: | |
| - linux/amd64 | |
| - linux/arm64 | |
| image: | |
| - kgateway | |
| - sds | |
| - envoy-wrapper | |
| steps: | |
| - name: Checkout branch | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| persist-credentials: false | |
| ref: ${{ matrix.branch }} | |
| - name: Collect upload metadata | |
| id: metadata | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| { | |
| echo "ref=refs/heads/${{ matrix.branch }}" | |
| echo "sha=$(git rev-parse HEAD)" | |
| echo "image_category=osv-scanner-$(echo '${{ matrix.branch }}' | tr '/.' '--')-images-$(echo '${{ matrix.image }}' | tr '/.' '--')-$(echo '${{ matrix.platform }}' | tr '/.' '--')" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Resolve image scan target | |
| id: image-target | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| branch="${{ matrix.branch }}" | |
| case "${branch}" in | |
| main) | |
| image_version="$(make --no-print-directory print-ROLLING_MAIN_VERSION)" | |
| ;; | |
| v[0-9]*.[0-9]*.x) | |
| series="${branch%.x}" | |
| series_regex="${series//./\\.}" | |
| image_version="$( | |
| git ls-remote --tags --refs origin "${series}.*" \ | |
| | sed -E 's#.*refs/tags/##' \ | |
| | grep -E "^${series_regex}\\.[0-9]+$" \ | |
| | sort -V \ | |
| | tail -n 1 || true | |
| )" | |
| if [[ -z "${image_version}" ]]; then | |
| echo "::error::No stable patch release tag found for ${branch}" | |
| exit 1 | |
| fi | |
| ;; | |
| *) | |
| echo "::error::Unsupported branch for image scan: ${branch}" | |
| exit 1 | |
| ;; | |
| esac | |
| { | |
| echo "image_version=${image_version}" | |
| echo "image=${IMAGE_REGISTRY}/${{ matrix.image }}:${image_version}" | |
| } >> "$GITHUB_OUTPUT" | |
| echo "Resolved image for ${branch}: ${IMAGE_REGISTRY}/${{ matrix.image }}:${image_version}" | |
| - name: Log in to GHCR for image scans | |
| shell: bash | |
| env: | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: echo "${GITHUB_TOKEN}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin | |
| - name: Install skopeo | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install --no-install-recommends -y skopeo | |
| - name: Run image scanner | |
| shell: bash | |
| env: | |
| OSV_DOCKER_IMAGE: ${{ steps.image-target.outputs.image }} | |
| OSV_DOCKER_IMAGE_NAME: ${{ matrix.image }} | |
| OSV_DOCKER_PLATFORM: ${{ matrix.platform }} | |
| run: | | |
| set -euo pipefail | |
| archive_dir="${RUNNER_TEMP}/osv-image-archives" | |
| mkdir -p "${archive_dir}" | |
| scanner_status=0 | |
| reporter_status=0 | |
| image="${OSV_DOCKER_IMAGE}" | |
| safe_image="$(printf '%s' "${image}" | sed 's/[^A-Za-z0-9_.-]/-/g')" | |
| image_archive="${archive_dir}/${safe_image}.tar" | |
| result_json="image-result.json" | |
| result_sarif="image-result.sarif" | |
| image_platform="${OSV_DOCKER_PLATFORM}" | |
| image_os="${image_platform%%/*}" | |
| image_arch="${image_platform#*/}" | |
| image_arch="${image_arch%%/*}" | |
| rm -f "${image_archive}" | |
| skopeo copy \ | |
| --override-os "${image_os}" \ | |
| --override-arch "${image_arch}" \ | |
| "docker://${image}" \ | |
| "docker-archive:${image_archive}:${image}" | |
| echo "Running OSV-Scanner for Docker image: ${image}" | |
| if docker run \ | |
| --rm \ | |
| -v "${PWD}:/workspace" \ | |
| -v "${archive_dir}:/archives:ro" \ | |
| -w /workspace \ | |
| --entrypoint /root/osv-scanner \ | |
| "${OSV_SCANNER_IMAGE}" \ | |
| scan image \ | |
| --archive \ | |
| --config=/workspace/osv-scanner.toml \ | |
| --output-file="/workspace/${result_json}" \ | |
| --format=json \ | |
| --verbosity=warn \ | |
| "/archives/${safe_image}.tar"; then | |
| : | |
| else | |
| scanner_status=$? | |
| fi | |
| if [[ ! -f "${result_json}" ]]; then | |
| echo "::error::osv-scanner did not produce ${result_json}" | |
| exit 1 | |
| fi | |
| rm -f "${image_archive}" | |
| if docker run \ | |
| --rm \ | |
| -v "${PWD}:/workspace" \ | |
| -w /workspace \ | |
| --entrypoint /root/osv-reporter \ | |
| "${OSV_SCANNER_IMAGE}" \ | |
| --output-files="sarif:/workspace/${result_sarif}" \ | |
| --new="/workspace/${result_json}" \ | |
| --fail-on-vuln=false; then | |
| : | |
| else | |
| reporter_status=$? | |
| fi | |
| if [[ ! -f "${result_sarif}" ]]; then | |
| echo "::error::osv-reporter did not produce ${result_sarif}" | |
| exit 1 | |
| fi | |
| image_without_digest="${image%%@*}" | |
| if [[ "${image_without_digest}" == *:* ]]; then | |
| image_version="${image_without_digest##*:}" | |
| else | |
| image_version="untagged" | |
| fi | |
| safe_platform="$(printf '%s' "${OSV_DOCKER_PLATFORM}" | sed 's/[^A-Za-z0-9_.-]/-/g')" | |
| safe_image_version="$(printf '%s' "${image_version}" | sed 's/[^A-Za-z0-9_.-]/-/g')" | |
| safe_image_name="$(printf '%s' "${OSV_DOCKER_IMAGE_NAME}" | sed 's/[^A-Za-z0-9_.-]/-/g')" | |
| # Rewrite in-container file paths to a synthetic, image-qualified path so the | |
| # uploaded alert's location names the exact image: | |
| # container-images/<image>/<version>/<platform>/<path> | |
| # Also rename the SARIF tool driver to "osv-image-scanner" so it is | |
| # distinguishable from the source scan (osvtool keys image findings off this). | |
| jq \ | |
| --arg image "${image}" \ | |
| --arg image_name "${OSV_DOCKER_IMAGE_NAME}" \ | |
| --arg safe_image_name "${safe_image_name}" \ | |
| --arg image_version "${image_version}" \ | |
| --arg safe_image_version "${safe_image_version}" \ | |
| --arg platform "${OSV_DOCKER_PLATFORM}" \ | |
| --arg safe_platform "${safe_platform}" \ | |
| ' | |
| def rewrite_artifact_location: | |
| if ((.uri? // "") | startswith("file:///")) then | |
| . as $location | | |
| ($location.uri | sub("^file://"; "")) as $container_path | | |
| .uri = ("container-images/" + $safe_image_name + "/" + $safe_image_version + "/" + $safe_platform + "/" + ($container_path | sub("^/"; ""))) | | |
| .description = { | |
| text: ("Container image " + $image + " (" + $platform + "): " + $container_path) | |
| } | | |
| .properties = ((.properties // {}) + { | |
| containerImage: $image, | |
| containerImageName: $image_name, | |
| containerImageVersion: $image_version, | |
| containerPlatform: $platform, | |
| originalContainerPath: $container_path | |
| }) | | |
| del(.index) | |
| else | |
| . | |
| end; | |
| (.runs[]?.artifacts[]?.location) |= rewrite_artifact_location | | |
| (.runs[]?.results[]?.locations[]?.physicalLocation.artifactLocation) |= rewrite_artifact_location | | |
| (.runs[]?) |= ( | |
| .tool.driver.name = "osv-image-scanner" | | |
| .tool.driver.fullName = "OSV Image Scanner" | | |
| .tool.driver.informationUri = "https://google.github.io/osv-scanner/usage/scan-image/" | | |
| .tool.driver.properties = ((.tool.driver.properties // {}) + { | |
| sourceTool: "osv-scanner", | |
| scanTarget: "container-image", | |
| containerImage: $image, | |
| containerImageName: $image_name, | |
| containerImageVersion: $image_version, | |
| containerPlatform: $platform | |
| }) | |
| ) | |
| ' "${result_sarif}" > "${result_sarif}.tmp" | |
| mv "${result_sarif}.tmp" "${result_sarif}" | |
| if [[ "${scanner_status}" -ne 0 || "${reporter_status}" -ne 0 ]]; then | |
| echo "OSV image scan completed and wrote results despite non-zero scanner/reporter exit status." | |
| fi | |
| - name: Upload image SARIF | |
| if: ${{ !cancelled() && hashFiles('image-result.sarif') != '' }} | |
| uses: github/codeql-action/upload-sarif@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10 | |
| with: | |
| sarif_file: image-result.sarif | |
| ref: ${{ steps.metadata.outputs.ref }} | |
| sha: ${{ steps.metadata.outputs.sha }} | |
| category: ${{ steps.metadata.outputs.image_category }} |