feat: dependency scan & update #2
Workflow file for this run
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: Dependency Security Scan | |
| # Runs on pushes/PRs so a bad upgrade is caught immediately, and on a schedule | |
| # because a dependency can become vulnerable without this repo changing at all. | |
| on: | |
| push: | |
| branches: | |
| - master | |
| - staging | |
| pull_request: | |
| branches: | |
| - master | |
| - staging | |
| schedule: | |
| # Mondays 06:00 UTC | |
| - cron: '0 6 * * 1' | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| osv-scan: | |
| name: OSV scan (all modules) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| # Needed to post the scan result as a comment on the pull request. | |
| pull-requests: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| # NOTE: JDK 17, not the JDK 8 used by gradle.yml. settings.gradle only | |
| # includes :app-javafx on Java 11+, so a JDK 8 run would silently skip | |
| # that module's dependencies -- exactly the blind spot that let a known | |
| # org.json CVE sit in the demo modules after sdk-java had been fixed. | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'corretto' | |
| - name: Set up Gradle | |
| uses: gradle/actions/setup-gradle@v4 | |
| - name: Resolve dependencies for every module | |
| run: | | |
| set -o pipefail | |
| ./gradlew -q --init-script .github/scripts/dependency-report.init.gradle \ | |
| printResolvedDependencies | tee resolved-dependencies.txt | |
| count=$(grep -c '^COORD' resolved-dependencies.txt || true) | |
| echo "Resolved $count coordinate lines." | |
| if [ "$count" -eq 0 ]; then | |
| echo "::error::Gradle produced no dependency coordinates" | |
| exit 1 | |
| fi | |
| - name: Check resolved dependencies against OSV | |
| id: osv | |
| run: python3 .github/scripts/osv_scan.py < resolved-dependencies.txt | |
| # The job summary written above only shows on the workflow run page. This | |
| # is what actually puts the result on the pull request. It updates one | |
| # sticky comment instead of adding a new one on every push. | |
| - name: Comment scan result on the pull request | |
| if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const marker = '<!-- countly-dependency-security-scan -->'; | |
| const outcome = '${{ steps.osv.outcome }}'; | |
| // The report body already carries its own heading. | |
| const status = outcome === 'success' | |
| ? '**Result: passed**' | |
| : '**Result: FAILED — a dependency has a known vulnerability**'; | |
| let report = ''; | |
| try { | |
| report = fs.readFileSync('osv-report.md', 'utf8'); | |
| } catch (e) { | |
| report = `The scan step did not produce a report (outcome: ${outcome}). See the workflow logs.`; | |
| } | |
| const body = [ | |
| marker, | |
| report, | |
| status, | |
| '', | |
| `[Full run log](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`, | |
| ].join('\n'); | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find(c => c.body && c.body.includes(marker)); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body, | |
| }); | |
| } | |
| - name: Upload dependency list | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: resolved-dependencies | |
| path: | | |
| resolved-dependencies.txt | |
| osv-report.md | |
| dependency-submission: | |
| name: Submit dependency graph | |
| # Deliberately NOT run on pull_request: on that event the ref is | |
| # refs/pull/N/merge, which is not a branch, and the dependency submission | |
| # API expects a real branch. Snapshots are what power Dependabot alerts, | |
| # so they are submitted from the long-lived branches (and on the weekly | |
| # cron, so a newly published advisory is matched against a fresh graph). | |
| # Use workflow_dispatch to submit one on demand from another branch. | |
| if: github.event_name != 'pull_request' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-java@v4 | |
| with: | |
| java-version: '17' | |
| distribution: 'corretto' | |
| - name: Submit resolved dependency graph to GitHub | |
| uses: gradle/actions/dependency-submission@v4 | |
| dependency-review: | |
| name: Review dependency changes | |
| # SCOPE: on a Gradle project with no lockfile this reviews the GitHub | |
| # Actions used by the workflows, their licenses and any denied packages -- | |
| # it does NOT see the Gradle dependencies, because that needs a submitted | |
| # snapshot for both the base and the head of the PR. The osv-scan job is | |
| # the check that actually covers the Gradle dependencies on every PR. | |
| # (Do not add `needs: dependency-submission` -- that job is skipped on | |
| # pull_request, and a skipped dependency would skip this job too.) | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fail the PR on newly introduced vulnerable dependencies | |
| uses: actions/dependency-review-action@v4 | |
| with: | |
| fail-on-severity: low | |
| comment-summary-in-pr: on-failure |