Version Lag and CVE Quality Gate with GitHub Actions
In this tutorial, you will create a GitHub Actions workflow that automatically scans your project's dependencies with OSS IQ and blocks pull requests that introduce security vulnerabilities or severely outdated packages. By the end, you'll have a working quality gate that protects your main branch from risky dependency changes.
What you'll build:
A CI workflow that:
- Runs OSS IQ on every pull request
- Exports dependency metrics to JSON
- Fails the build if any CVEs are detected or if dependencies are too far behind
Prerequisites:
- A GitHub repository with a JavaScript (npm) or Python (uv/pip) project
- Basic familiarity with GitHub Actions
- A GitHub personal access token (for the OSS IQ API calls)
Time to complete: 15-20 minutes
Step 1: Prepare Your Repository
First, let's ensure your repository has the files OSS IQ needs to analyze.
OSS IQ auto-detects dependency files. Make sure your repository contains one of these:
| Ecosystem | Required Files |
|---|---|
| JavaScript | package.json and package-lock.json |
| Python | pyproject.toml and uv.lock (or requirements.txt) |
If you're starting fresh or want to follow along exactly, create a simple package.json:
{
"name": "quality-gate-demo",
"version": "1.0.0",
"dependencies": {
"lodash": "^4.17.21",
"express": "^4.18.2"
}
}
Run npm install to generate the lockfile.
Step 2: Add a GitHub Token as a Repository Secret
OSS IQ queries the GitHub API to gather repository health data for each dependency. Without authentication, GitHub limits requests to 60 per hour—not enough for most projects.
- Go to your repository on GitHub
- Navigate to Settings → Secrets and variables → Actions
- Click New repository secret
- Name it
OSSIQ_GITHUB_TOKEN - Paste your GitHub personal access token as the value
Creating a token
If you don't have a token, create one at github.com/settings/tokens. The token needs no special scopes—public repository access is sufficient.
Step 3: Create the Workflow File
Now let's create the GitHub Actions workflow that will run OSS IQ on every pull request.
Create the file .github/workflows/dependency-quality-gate.yml:
name: Dependency Quality Gate
on:
pull_request:
branches: [main]
jobs:
ossiq-scan:
name: OSS IQ Dependency Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install OSS IQ
run: pip install ossiq
- name: Run OSS IQ scan
env:
OSSIQ_GITHUB_TOKEN: ${{ github.token }}
run: |
ossiq-cli export \
--output-format=json \
--output=ossiq-report.json \
.
- name: Upload scan results
uses: actions/upload-artifact@v4
with:
name: ossiq-report
path: ossiq-report.json
- name: Check for critical issues
run: |
echo "Checking OSS IQ results..."
# Extract metrics from JSON report
TOTAL_CVES=$(jq '.summary.total_cves' ossiq-report.json)
PACKAGES_OUTDATED=$(jq '.summary.packages_outdated' ossiq-report.json)
TOTAL_PACKAGES=$(jq '.summary.total_packages' ossiq-report.json)
echo "📊 Scan Summary:"
echo " Total packages: $TOTAL_PACKAGES"
echo " Packages with CVEs: $TOTAL_CVES"
echo " Outdated packages: $PACKAGES_OUTDATED"
# Fail if any CVEs are found
if [ "$TOTAL_CVES" -gt 0 ]; then
echo ""
echo "❌ FAILED: Found $TOTAL_CVES CVE(s) in dependencies"
echo ""
echo "Packages with vulnerabilities:"
jq -r '(.production_packages + .development_packages) | .[] | select(.cve | length > 0) | " - \(.package_name)@\(.installed_version): \(.cve | length) CVE(s)"' ossiq-report.json
exit 1
fi
# Check for severely outdated packages (default: 365 days)
MAX_LAG_DAYS=${MAX_LAG_DAYS:-365}
SEVERELY_OUTDATED_COUNT=$(jq "(.production_packages + .development_packages) | map(select(.time_lag_days != null and .time_lag_days > $MAX_LAG_DAYS)) | length" ossiq-report.json)
if [ "$SEVERELY_OUTDATED_COUNT" -gt 0 ]; then
echo ""
echo "❌ FAILED: Found $SEVERELY_OUTDATED_COUNT package(s) more than $MAX_LAG_DAYS days behind latest"
echo ""
echo "Severely outdated packages:"
jq -r "(.production_packages + .development_packages) | .[] | select(.time_lag_days != null and .time_lag_days > $MAX_LAG_DAYS) | \" - \(.package_name): \(.time_lag_days) days behind\"" ossiq-report.json
exit 1
fi
echo ""
echo "✅ PASSED: No critical issues detected"
This workflow:
- Triggers on pull requests to the main branch
- Installs OSS IQ using pip
- Exports a JSON report containing all dependency metrics
- Uploads the report as a build artifact for later review
- Checks for CVEs and fails the build if any are found
- Blocks severely outdated packages that are more than a year old
Step 4: Test Your Quality Gate
Commit and push the workflow file:
git add .github/workflows/dependency-quality-gate.yml
git commit -m "Add OSS IQ dependency quality gate"
git push origin main
Now create a test pull request to see the workflow in action:
git checkout -b test-quality-gate
# Make any small change to trigger the workflow
echo "# Test" >> README.md
git add README.md
git commit -m "Test quality gate"
git push origin test-quality-gate
Open a pull request on GitHub. You should see the "Dependency Quality Gate" check running. If your dependencies have no CVEs and are not severely outdated, the check will pass with a green checkmark.
Step 5: See It Fail
Let's intentionally add a vulnerable or outdated dependency to verify the quality gate blocks it.
Testing CVEs
Update your package.json to include an old version of lodash with known vulnerabilities:
{
"name": "quality-gate-demo",
"version": "1.0.0",
"dependencies": {
"lodash": "4.17.4",
"express": "^4.18.2"
}
}
Why this version?
lodash@4.17.4 has several known CVEs including prototype pollution vulnerabilities.
This is a safe way to test your quality gate.
Run npm install to update the lockfile, then commit and push:
npm install
git add package.json package-lock.json
git commit -m "Downgrade lodash (testing quality gate)"
git push origin test-quality-gate
The workflow will now fail with output similar to:
📊 Scan Summary:
Total packages: 2
Packages with CVEs: 1
Outdated packages: 1
❌ FAILED: Found 3 CVE(s) in dependencies
Packages with vulnerabilities:
- lodash@4.17.4: 3 CVE(s)
The pull request will be blocked from merging until the vulnerability is resolved.
Testing Outdated Packages
Now, let's revert the vulnerable lodash and instead add a very old, but not insecure, package like moment@2.0.0 (released over a decade ago).
{
"name": "quality-gate-demo",
"version": "1.0.0",
"dependencies": {
"lodash": "^4.17.21",
"express": "^4.18.2",
"moment": "2.0.0"
}
}
Commit this change and push it. The workflow will fail again, but this time with a message about the package being outdated:
📊 Scan Summary:
Total packages: 3
Packages with CVEs: 0
Outdated packages: 1
❌ FAILED: Found 1 package(s) more than 365 days behind latest
Severely outdated packages:
- moment: 3500+ days behind
What You've Learned
Congratulations! You've successfully created a dependency quality gate that:
check Automatically scans dependencies on every pull request
check Exports structured metrics in JSON format
check Blocks PRs that introduce security vulnerabilities
check Blocks PRs with severely outdated packages
check Provides clear feedback about what needs to be fixed
Next Steps
Now that you have a basic quality gate working, you might want to:
- Adjust thresholds: Modify
MAX_LAG_DAYSor add checks forreleases_lagto match your team's standards - Add notifications: Send Slack or email alerts when scans fail
- Generate reports: Use
ossiq-cli scan --presentation=htmlfor detailed HTML reports - Scan on schedule: Add a
scheduletrigger to catch new CVEs in existing dependencies
For more details on OSS IQ's metrics and what they mean, see the Explanation documentation.