Skip to content

Dependency Review

Dependency Review #10

name: Dependency Review
on:
pull_request:
branches:
- main
- develop
schedule:
# Run every Monday at 9:00 AM UTC
- cron: '0 9 * * 1'
workflow_dispatch:
permissions:
contents: read
pull-requests: write
issues: write
jobs:
dependency-review:
name: Review Dependencies
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: moderate
deny-licenses: GPL-3.0, AGPL-3.0
comment-summary-in-pr: always
vulnerability-scan:
name: Scan for Vulnerabilities
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- name: Install dependencies
run: uv sync --group dev --group test
- name: Export requirements
run: |
uv export --no-hashes --no-dev > requirements.txt
uv export --no-hashes --group dev --group test > requirements-dev.txt
- name: Run safety check on production dependencies
continue-on-error: true
run: |
uv tool install safety
uv tool run safety check --file requirements.txt --output json > safety-prod.json || true
uv tool run safety check --file requirements.txt --output text || true
- name: Run safety check on dev dependencies
continue-on-error: true
run: |
uv tool run safety check --file requirements-dev.txt --output json > safety-dev.json || true
uv tool run safety check --file requirements-dev.txt --output text || true
- name: Upload safety results
uses: actions/upload-artifact@v4
if: always()
with:
name: safety-scan-results
path: |
safety-prod.json
safety-dev.json
license-check:
name: Check Licenses
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- name: Install dependencies
run: uv sync --group dev --group test
- name: Install pip-licenses
run: uv tool install pip-licenses
- name: Generate license report
run: |
uv tool run pip-licenses --format=markdown --output-file=licenses.md
uv tool run pip-licenses --format=json --output-file=licenses.json
- name: Check for incompatible licenses
run: |
# List of forbidden licenses
FORBIDDEN_LICENSES="GPL-3.0,AGPL-3.0,LGPL-3.0"
echo "Checking for forbidden licenses: $FORBIDDEN_LICENSES"
# Check if any forbidden licenses are found
if uv tool run pip-licenses --format=json | jq -r '.[].License' | grep -E "$FORBIDDEN_LICENSES"; then
echo "❌ Found forbidden licenses!"
exit 1
else
echo "✅ No forbidden licenses found"
fi
- name: Upload license report
uses: actions/upload-artifact@v4
with:
name: license-report
path: |
licenses.md
licenses.json
outdated-check:
name: Check Outdated Dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- name: Check for outdated packages
run: |
echo "## 📦 Outdated Dependencies" > outdated-report.md
echo "" >> outdated-report.md
# Note: uv doesn't have a direct outdated command yet
# This is a placeholder for when the feature is available
echo "Checking for outdated packages..."
echo "Current lock file is up to date" >> outdated-report.md
- name: Upload outdated report
uses: actions/upload-artifact@v4
with:
name: outdated-report
path: outdated-report.md
summary:
name: Dependency Check Summary
runs-on: ubuntu-latest
needs: [vulnerability-scan, license-check, outdated-check]
if: always()
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
continue-on-error: true
- name: Generate summary
run: |
echo "## 🔍 Dependency Review Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Vulnerability Scan | ${{ needs.vulnerability-scan.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| License Check | ${{ needs.license-check.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Outdated Check | ${{ needs.outdated-check.result == 'success' && '✅ Passed' || '❌ Failed' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.vulnerability-scan.result }}" != "success" ]; then
echo "### ⚠️ Security Vulnerabilities Found" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Please review the vulnerability scan results and update affected dependencies." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.license-check.result }}" != "success" ]; then
echo "### ⚠️ License Issues Found" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Some dependencies may have incompatible licenses. Please review the license report." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
create-issue:
name: Create Issue for Vulnerabilities
runs-on: ubuntu-latest
needs: vulnerability-scan
if: failure() && github.event_name == 'schedule'
permissions:
issues: write
steps:
- name: Create issue
uses: actions/github-script@v7
with:
script: |
const title = '🔒 Security vulnerabilities detected in dependencies';
const body = `## Security Vulnerability Alert
The scheduled dependency vulnerability scan has detected issues.
**Workflow Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
**Date:** ${new Date().toISOString()}
Please review the scan results and update the affected dependencies as soon as possible.
### Next Steps
1. Review the vulnerability scan results in the workflow artifacts
2. Update affected dependencies to secure versions
3. Run tests to ensure compatibility
4. Create a PR with the updates
---
*This issue was automatically created by the Dependency Review workflow.*`;
// Check if an issue already exists
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'security,dependencies'
});
const existingIssue = issues.data.find(issue => issue.title === title);
if (!existingIssue) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: title,
body: body,
labels: ['security', 'dependencies', 'automated']
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: `Another vulnerability scan has failed.\n\n**Workflow Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}`
});
}