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 |
|
Python |
|
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_TOKENPaste your GitHub personal access token as the value
!!! tip “Creating a token”
If you don't have a token, create one at [github.com/settings/tokens](https://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"
}
}
!!! note “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 standardsAdd notifications: Send Slack or email alerts when scans fail
Generate reports: Use
ossiq-cli scan --presentation=htmlfor detailed HTML reportsScan 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.