mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-20 06:00:06 +08:00
* fix(ci): prepare Nix development shells in setup-nix Signed-off-by: Evan Lezar <elezar@nvidia.com> * fix(ci): retry Nix builds before executing apps once Signed-off-by: Evan Lezar <elezar@nvidia.com> --------- Signed-off-by: Evan Lezar <elezar@nvidia.com> Co-authored-by: Evan Lezar <elezar@nvidia.com>
230 lines
7.3 KiB
YAML
230 lines
7.3 KiB
YAML
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
name: Trivy Scan
|
|
|
|
# Manual or reusable scan of deployment configuration and supplied OCI
|
|
# artifacts. Findings are informational by default; scanner errors remain fatal.
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
candidate_ref:
|
|
description: Optional pre-release tag to scan instead of the triggering revision
|
|
default: ""
|
|
type: string
|
|
images:
|
|
description: Newline-separated image references to scan
|
|
type: string
|
|
default: ""
|
|
charts:
|
|
description: Newline-separated packaged Helm chart OCI references
|
|
type: string
|
|
default: ""
|
|
severity:
|
|
description: Severities that fail the workflow
|
|
type: string
|
|
default: HIGH,CRITICAL
|
|
ignore-unfixed:
|
|
description: Ignore image vulnerabilities with no upstream fix
|
|
type: boolean
|
|
default: true
|
|
fail-on-findings:
|
|
description: Fail the run on findings instead of warning
|
|
type: boolean
|
|
default: false
|
|
upload-sarif:
|
|
description: Upload results to GitHub Code Scanning
|
|
type: boolean
|
|
default: true
|
|
secrets:
|
|
CACHIX_AUTH_TOKEN:
|
|
description: Token used to write Nix build outputs to Cachix
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
images:
|
|
description: Newline-separated image references to scan
|
|
type: string
|
|
default: ""
|
|
charts:
|
|
description: Newline-separated packaged Helm chart OCI references to scan
|
|
type: string
|
|
default: ""
|
|
severity:
|
|
description: Severities that fail the workflow
|
|
type: string
|
|
default: HIGH,CRITICAL
|
|
ignore-unfixed:
|
|
description: Ignore image vulnerabilities with no upstream fix
|
|
type: boolean
|
|
default: true
|
|
fail-on-findings:
|
|
description: Fail the run on findings instead of warning
|
|
type: boolean
|
|
default: false
|
|
upload-sarif:
|
|
description: Upload results to GitHub Code Scanning
|
|
type: boolean
|
|
default: true
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
defaults:
|
|
run:
|
|
shell: nix develop --command bash -euo pipefail {0}
|
|
|
|
env:
|
|
TRIVY_SEVERITY: ${{ inputs.severity || 'HIGH,CRITICAL' }}
|
|
TRIVY_REPORT_DIR: reports/trivy
|
|
|
|
jobs:
|
|
scan:
|
|
name: ${{ inputs.fail-on-findings && 'OpenShell / Trivy' || 'OpenShell / Trivy (informational)' }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 60
|
|
outputs:
|
|
sarif-batches: ${{ steps.sarif.outputs.batches }}
|
|
artifact-id: ${{ steps.reports.outputs.artifact-id }}
|
|
permissions:
|
|
contents: read
|
|
packages: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
ref: ${{ inputs.candidate_ref && format('refs/tags/{0}', inputs.candidate_ref) || '' }}
|
|
persist-credentials: false
|
|
|
|
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ github.token }}
|
|
|
|
- name: Set up Nix
|
|
uses: ./.github/actions/setup-nix
|
|
with:
|
|
prepare-shell: "true"
|
|
cachix-auth-token: ${{ github.event_name != 'pull_request' && secrets.CACHIX_AUTH_TOKEN || '' }}
|
|
|
|
- name: Test scan reporting
|
|
run: tasks/scripts/trivy-scan-test.sh
|
|
|
|
- name: Scan configuration
|
|
id: config
|
|
env:
|
|
CHARTS: ${{ inputs.charts }}
|
|
run: |
|
|
args=()
|
|
while IFS= read -r ref; do
|
|
[ -n "$ref" ] || continue
|
|
args+=(--chart-ref "$ref")
|
|
done <<<"$CHARTS"
|
|
tasks/scripts/trivy-scan.sh config "${args[@]}"
|
|
|
|
- name: Scan images
|
|
id: images
|
|
if: ${{ !cancelled() }}
|
|
env:
|
|
IMAGES: ${{ inputs.images }}
|
|
TRIVY_IGNORE_UNFIXED: ${{ inputs.ignore-unfixed }}
|
|
run: |
|
|
refs=()
|
|
while IFS= read -r ref; do
|
|
[ -n "$ref" ] || continue
|
|
refs+=("$ref")
|
|
done <<<"$IMAGES"
|
|
if [ "${#refs[@]}" -gt 0 ]; then
|
|
tasks/scripts/trivy-scan.sh images "${refs[@]}"
|
|
fi
|
|
|
|
- name: Prepare consolidated SARIF uploads
|
|
id: sarif
|
|
if: >-
|
|
${{
|
|
!cancelled()
|
|
&& steps.config.conclusion == 'success'
|
|
&& steps.images.conclusion == 'success'
|
|
&& inputs.upload-sarif
|
|
}}
|
|
run: tasks/scripts/trivy-scan.sh prepare-sarif
|
|
|
|
- name: Upload reports
|
|
id: reports
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: trivy-${{ github.run_id }}
|
|
path: reports/trivy
|
|
if-no-files-found: ignore
|
|
retention-days: 14
|
|
|
|
- name: Report findings
|
|
if: >-
|
|
${{
|
|
!cancelled()
|
|
&& steps.config.conclusion == 'success'
|
|
&& steps.images.conclusion == 'success'
|
|
}}
|
|
env:
|
|
FAIL_ON_FINDINGS: ${{ inputs.fail-on-findings }}
|
|
run: |
|
|
set +e
|
|
tasks/scripts/trivy-scan.sh gate
|
|
status=$?
|
|
set -e
|
|
case "$status" in
|
|
0) echo "No findings at ${TRIVY_SEVERITY}." ;;
|
|
10)
|
|
if [ "$FAIL_ON_FINDINGS" = "true" ]; then
|
|
echo "::error::Trivy findings at ${TRIVY_SEVERITY}."
|
|
exit 1
|
|
fi
|
|
echo "::warning::Trivy findings at ${TRIVY_SEVERITY}; this check is informational."
|
|
;;
|
|
*) echo "::error::Trivy could not evaluate the reports (exit $status)."; exit "$status" ;;
|
|
esac
|
|
|
|
upload-sarif:
|
|
name: Publish Trivy SARIF (${{ matrix.batch }})
|
|
needs: scan
|
|
# Findings may fail the scan job after reports are prepared. Publish those
|
|
# complete results too, but never publish an incomplete/failed scan.
|
|
if: >-
|
|
${{
|
|
!cancelled()
|
|
&& inputs.upload-sarif
|
|
&& needs.scan.outputs.sarif-batches != ''
|
|
&& needs.scan.outputs.artifact-id != ''
|
|
}}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 10
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
batch: ${{ fromJSON(needs.scan.outputs.sarif-batches) }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
id: checkout
|
|
with:
|
|
ref: ${{ inputs.candidate_ref && format('refs/tags/{0}', inputs.candidate_ref) || '' }}
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
artifact-ids: ${{ needs.scan.outputs.artifact-id }}
|
|
merge-multiple: true
|
|
path: reports/trivy
|
|
|
|
# One configuration run, plus one run per image/platform or packaged
|
|
# chart. Each batch holds at most GitHub's limit of 20 SARIF runs.
|
|
- uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
|
|
with:
|
|
sarif_file: reports/trivy/code-scanning/uploads/${{ matrix.batch }}
|
|
ref: ${{ inputs.candidate_ref && format('refs/tags/{0}', inputs.candidate_ref) || '' }}
|
|
sha: ${{ inputs.candidate_ref && steps.checkout.outputs.commit || '' }}
|