Skip to content

Dependency Scan

Dependency Scan #12

name: Dependency Scan
on:
schedule:
# Monthly: 1st of each month at 09:00 UTC
- cron: '0 9 1 * *'
workflow_dispatch:
inputs:
fail-on:
description: 'Fail on labels (comma-separated, empty = never fail)'
required: false
default: 'eol-confirmed'
extra-args:
description: 'Extra arguments passed to uzomuzo scan'
required: false
default: ''
create-issue:
description: 'Create a GitHub Issue with scan report'
required: false
default: true
type: boolean
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
outputs:
exit_code: ${{ steps.scan.outputs.exit_code }}
scan_output: ${{ steps.scan.outputs.scan_output }}
fail_on: ${{ steps.scan.outputs.fail_on }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
go-version-file: go.mod
- name: Build uzomuzo
run: go build -o uzomuzo ./cmd/uzomuzo
- name: Generate SBOM
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: 'fs'
format: 'cyclonedx'
output: 'sbom.json'
- name: Run scan
id: scan
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EXTRA_ARGS: ${{ github.event.inputs.extra-args || '' }}
FAIL_ON_INPUT: ${{ github.event.inputs.fail-on }}
EVENT_NAME: ${{ github.event_name }}
run: |
# For schedule runs, default to eol-confirmed.
# For workflow_dispatch, respect the input (empty = never fail).
if [ "$EVENT_NAME" = "schedule" ]; then
FAIL_ON="${FAIL_ON_INPUT:-eol-confirmed}"
else
FAIL_ON="$FAIL_ON_INPUT"
fi
ARGS=()
if [ -n "$FAIL_ON" ]; then
ARGS+=("--fail-on" "$FAIL_ON")
fi
if [ -n "$EXTRA_ARGS" ]; then
mapfile -t EXTRA_ARGS_ARRAY < <(python3 -c 'import os, shlex; [print(arg) for arg in shlex.split(os.environ["EXTRA_ARGS"])]')
ARGS+=("${EXTRA_ARGS_ARRAY[@]}")
fi
# Single scan run; detailed format includes summary table + detailed report
set +e
./uzomuzo scan --sbom sbom.json --format detailed "${ARGS[@]}" 2>&1 | tee scan-report.txt
EXIT_CODE=${PIPESTATUS[0]}
set -e
echo "exit_code=$EXIT_CODE" >> "$GITHUB_OUTPUT"
echo "fail_on=$FAIL_ON" >> "$GITHUB_OUTPUT"
# Extract summary table section (between markers) for issue body
{
echo 'scan_output<<SCAN_EOF'
sed -n '/^--- Summary Table ---$/,/^--- Detailed Report ---$/{ /^--- Detailed Report ---$/d; p; }' scan-report.txt
echo 'SCAN_EOF'
} >> "$GITHUB_OUTPUT"
exit $EXIT_CODE
- name: Upload scan report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dependency-scan-report
path: |
sbom.json
scan-report.txt
retention-days: 90
report:
needs: scan
if: always() && needs.scan.outputs.exit_code != '' && github.event.inputs.create-issue != 'false'
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Create monthly scan report issue
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SCAN_OUTPUT: ${{ needs.scan.outputs.scan_output }}
EXIT_CODE: ${{ needs.scan.outputs.exit_code }}
FAIL_ON_POLICY: ${{ needs.scan.outputs.fail_on }}
run: |
TITLE="Dependency scan report ($(date +%Y-%m-%d))"
# Deduplicate: skip if an open issue with the same title exists
EXISTING=$(gh issue list --repo "${{ github.repository }}" --state open --search "in:title $TITLE" --json title | jq --arg t "$TITLE" '[.[] | select(.title == $t)] | length')
if [ "$EXISTING" -gt 0 ]; then
echo "Open issue already exists, skipping creation"
exit 0
fi
if [ "$EXIT_CODE" != "0" ]; then
STATUS="Policy violations detected"
else
STATUS="No policy violations"
fi
BODY=$(cat <<EOF
## Dependency Scan Report
**Status**: $STATUS
**Workflow run**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
**Fail-on policy**: \`${FAIL_ON_POLICY:-(none)}\`
<details>
<summary>Scan output</summary>
\`\`\`
$SCAN_OUTPUT
\`\`\`
</details>
For detailed per-dependency analysis, download the \`dependency-scan-report\` artifact from the workflow run.
EOF
)
gh issue create --repo "${{ github.repository }}" --title "$TITLE" --body "$BODY" --label "dependencies"