name: Java - OWASP Dependency Check
on: workflow_call: inputs: runner: description: 'Runner type' required: false type: string default: 'ubuntu-latest' container_image: description: >- Run the job inside this image (e.g. ghcr.io/codehunters-io/ci-base-images:1.0.0). Empty = plain runner with actions/setup-java. The image already carries the JDK, so the per-run download is skipped and the version is pinned to the tag. Gradle still comes from ./gradlew, and setup-gradle still runs for its dependency cache. required: false type: string default: '' java_version: description: 'Java version (ignored when container_image is set)' required: false type: string default: '21' java_distribution: description: 'Java distribution' required: false type: string default: 'temurin' owasp_fail_on_cvss: description: 'CVSS score threshold to fail build (7 = HIGH+CRITICAL, 9 = CRITICAL only)' required: false type: number default: 7 build_tool: description: 'Build tool: gradle or maven' required: false type: string default: 'gradle'
secrets: NVD_API_KEY: required: false GH_PACKAGES_USERNAME: description: 'GitHub Packages username (for dependencies hosted on GitHub Packages)' required: false GH_PACKAGES_TOKEN: description: 'GitHub Packages read token' required: false
outputs: vulnerabilities: description: 'Total number of vulnerabilities found' value: ${{ jobs.owasp.outputs.vulns }} critical: description: 'Number of CRITICAL vulnerabilities' value: ${{ jobs.owasp.outputs.critical }} high: description: 'Number of HIGH vulnerabilities' value: ${{ jobs.owasp.outputs.high }}
# Least privilege for what this workflow actually does. Without it the# job inherits whatever the calling repository's default happens to be,# which on older repositories is write-all.permissions: contents: read packages: read
jobs: owasp: name: OWASP Dependency Check runs-on: ${{ inputs.runner }} # `container:` takes an object or nothing at all, and there is no way to # write "no container" as a string. fromJSON('null') is how you say it. container: ${{ inputs.container_image != '' && fromJSON(format('{{"image":"{0}"}}', inputs.container_image)) || fromJSON('null') }} timeout-minutes: 30
outputs: vulns: ${{ steps.owasp-check.outputs.vulnerabilities }} critical: ${{ steps.owasp-check.outputs.critical }} high: ${{ steps.owasp-check.outputs.high }}
steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Setup JDK ${{ inputs.java_version }} if: inputs.container_image == '' uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1 with: distribution: ${{ inputs.java_distribution }} java-version: ${{ inputs.java_version }}
- name: Report toolchain (container) if: inputs.container_image != '' run: | echo "Container: ${{ inputs.container_image }}" java -version
- name: Setup Gradle if: inputs.build_tool == 'gradle' uses: gradle/actions/setup-gradle@9c971963bec38e04b3d30dcc455b5382be2fdbfb # v6.3.0 with: cache-read-only: ${{ github.ref != 'refs/heads/main' && github.ref != 'refs/heads/master' }}
# ============================================ # RUN OWASP DEPENDENCY CHECK # ============================================ - name: Run OWASP Dependency Check (Gradle) id: owasp-check if: inputs.build_tool == 'gradle' env: NVD_API_KEY: ${{ secrets.NVD_API_KEY }} GH_PACKAGES_USERNAME: ${{ secrets.GH_PACKAGES_USERNAME }} GH_PACKAGES_TOKEN: ${{ secrets.GH_PACKAGES_TOKEN }} run: | echo "Running OWASP Dependency Check..."
OWASP_CMD="./gradlew dependencyCheckAnalyze --no-daemon --build-cache" if [ -n "$NVD_API_KEY" ]; then OWASP_CMD="$OWASP_CMD -DnvdApiKey=$NVD_API_KEY" fi
$OWASP_CMD || true
# Parse the report REPORT_FILE="build/reports/dependency-check-report.json" VULNS=0; CRITICAL=0; HIGH=0; MEDIUM=0; LOW=0
if [ -f "$REPORT_FILE" ]; then CRITICAL=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "CRITICAL")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") HIGH=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "HIGH")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") MEDIUM=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "MEDIUM")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") LOW=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "LOW")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") VULNS=$((CRITICAL + HIGH + MEDIUM + LOW)) fi
echo "vulnerabilities=$VULNS" >> $GITHUB_OUTPUT echo "critical=$CRITICAL" >> $GITHUB_OUTPUT echo "high=$HIGH" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_STEP_SUMMARY echo "### OWASP Dependency Check" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| CRITICAL | $CRITICAL |" >> $GITHUB_STEP_SUMMARY echo "| HIGH | $HIGH |" >> $GITHUB_STEP_SUMMARY echo "| MEDIUM | $MEDIUM |" >> $GITHUB_STEP_SUMMARY echo "| LOW | $LOW |" >> $GITHUB_STEP_SUMMARY echo "| **Total** | **$VULNS** |" >> $GITHUB_STEP_SUMMARY
- name: Run OWASP Dependency Check (Maven) id: owasp-check-maven if: inputs.build_tool == 'maven' env: NVD_API_KEY: ${{ secrets.NVD_API_KEY }} run: | echo "Running OWASP Dependency Check..."
MVN_CMD="mvn org.owasp:dependency-check-maven:check -B" if [ -n "$NVD_API_KEY" ]; then MVN_CMD="$MVN_CMD -DnvdApiKey=$NVD_API_KEY" fi
$MVN_CMD || true
REPORT_FILE=$(find . -path "*/dependency-check-report.json" | head -1) VULNS=0; CRITICAL=0; HIGH=0
if [ -n "$REPORT_FILE" ] && [ -f "$REPORT_FILE" ]; then CRITICAL=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "CRITICAL")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") HIGH=$(jq '[.dependencies[]?.vulnerabilities[]? | select(.severity == "HIGH")] | length' "$REPORT_FILE" 2>/dev/null || echo "0") VULNS=$((CRITICAL + HIGH)) fi
echo "vulnerabilities=$VULNS" >> $GITHUB_OUTPUT echo "critical=$CRITICAL" >> $GITHUB_OUTPUT echo "high=$HIGH" >> $GITHUB_OUTPUT
# ============================================ # CHECK THRESHOLDS # ============================================ - name: Check OWASP vulnerabilities run: | CRITICAL="${{ steps.owasp-check.outputs.critical || steps.owasp-check-maven.outputs.critical }}" HIGH="${{ steps.owasp-check.outputs.high || steps.owasp-check-maven.outputs.high }}" THRESHOLD="${{ inputs.owasp_fail_on_cvss }}"
CRITICAL="${CRITICAL:-0}" HIGH="${HIGH:-0}"
if [ "$CRITICAL" -gt 0 ]; then echo "::error::Found $CRITICAL CRITICAL vulnerabilities" exit 1 fi
if [ "$THRESHOLD" -le 7 ] && [ "$HIGH" -gt 0 ]; then echo "::error::Found $HIGH HIGH vulnerabilities" exit 1 fi
echo "No blocking vulnerabilities found"Java (Spring Boot)·Reusable workflow·on: workflow_call
Java Owasp
Java - OWASP Dependency Check
.github/workflows/java-owasp.yml