Skip to content

Add universal dependency tracking workflow #3

Add universal dependency tracking workflow

Add universal dependency tracking workflow #3

name: Dependency Track SBOM Scan
on:
push:
branches:
- main
- master
pull_request:
branches:
- main
- master
schedule:
# Run daily at 9am UTC
- cron: '0 9 * * *'
workflow_dispatch: # Allow manual trigger
jobs:
dependency-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js (if needed)
if: hashFiles('**/package.json') != ''
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup Python (if needed)
if: hashFiles('**/requirements.txt', '**/pyproject.toml', '**/setup.py') != ''
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Setup Go (if needed)
if: hashFiles('**/go.mod') != ''
uses: actions/setup-go@v5
with:
go-version: 'stable'
- name: Setup Java (if needed)
if: hashFiles('**/pom.xml', '**/build.gradle', '**/build.gradle.kts') != ''
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies (all languages, including monorepos)
run: |
echo "🔍 Detecting and installing dependencies..."
# Install pnpm if any pnpm-lock.yaml exists (needed for mixed monorepos)
if find . -name "pnpm-lock.yaml" -not -path "*/node_modules/*" | grep -q .; then
echo "📦 Installing pnpm globally (detected pnpm projects)"
npm install -g pnpm
fi
# Node.js: Check root first for workspace-level install
if [ -f "pnpm-lock.yaml" ]; then
echo "📦 Detected pnpm workspace at root"
pnpm install --no-frozen-lockfile --ignore-scripts 2>/dev/null || echo "Note: pnpm install failed, continuing..."
elif [ -f "yarn.lock" ]; then
echo "📦 Detected yarn workspace at root"
yarn install --ignore-scripts 2>/dev/null || echo "Note: yarn install failed, continuing..."
elif [ -f "package-lock.json" ]; then
echo "📦 Found npm project at root"
npm ci 2>/dev/null || npm install 2>/dev/null || echo "Note: npm install failed, continuing..."
elif [ -f "package.json" ]; then
echo "📦 Found Node.js project at root (no lock file)"
npm install --package-lock-only 2>/dev/null || echo "Note: npm install failed, continuing..."
fi
# Find all subdirectories and install based on their lock files (for mixed monorepos)
find . -type d -not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "." | while read -r dir; do
if [ -f "$dir/pnpm-lock.yaml" ]; then
echo "📦 Found pnpm project in: $dir"
(cd "$dir" && pnpm install --no-frozen-lockfile --ignore-scripts 2>/dev/null || echo "Note: pnpm install failed in $dir")
elif [ -f "$dir/yarn.lock" ]; then
echo "📦 Found yarn project in: $dir"
(cd "$dir" && yarn install --ignore-scripts 2>/dev/null || echo "Note: yarn install failed in $dir")
elif [ -f "$dir/package-lock.json" ]; then
echo "📦 Found npm project in: $dir"
(cd "$dir" && (npm ci 2>/dev/null || npm install 2>/dev/null || echo "Note: npm install failed in $dir"))
elif [ -f "$dir/package.json" ]; then
echo "📦 Found Node.js project in: $dir (no lock file)"
(cd "$dir" && npm install --package-lock-only 2>/dev/null || echo "Note: npm install failed in $dir")
fi
done
# Python projects
find . -name "requirements.txt" -not -path "*/.git/*" -not -path "*/venv/*" | while read -r req; do
dir=$(dirname "$req")
echo "🐍 Found Python project in: $dir"
(cd "$dir" && pip install -r requirements.txt 2>/dev/null || echo "Note: pip install failed in $dir")
done
# Go projects
find . -name "go.mod" -not -path "*/.git/*" | while read -r gomod; do
dir=$(dirname "$gomod")
echo "🔷 Found Go project in: $dir"
(cd "$dir" && go mod download 2>/dev/null || echo "Note: go mod download failed in $dir")
done
# Java/Maven projects
find . -name "pom.xml" -not -path "*/.git/*" | while read -r pom; do
dir=$(dirname "$pom")
echo "☕ Found Maven project in: $dir"
(cd "$dir" && mvn dependency:resolve 2>/dev/null || echo "Note: mvn dependency:resolve failed in $dir")
done
# Java/Gradle projects
find . -name "build.gradle*" -not -path "*/.git/*" | while read -r gradle; do
dir=$(dirname "$gradle")
echo "☕ Found Gradle project in: $dir"
(cd "$dir" && (./gradlew dependencies 2>/dev/null || gradle dependencies 2>/dev/null || echo "Note: gradle dependencies failed in $dir"))
done
echo "✅ Dependency installation complete"
continue-on-error: true
- name: Install Trivy
run: |
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
- name: Generate SBOM with Trivy
run: |
echo "🔍 Scanning repository for dependencies and licenses..."
trivy fs --format cyclonedx --scanners license --license-full . -o bom-raw.json
echo "🧹 Cleaning SBOM (removing lock files and false positives)..."
cat bom-raw.json | jq '
.components |= map(select(
.name != "package-lock.json" and
.name != "yarn.lock" and
.name != "pnpm-lock.yaml" and
.name != "go.mod" and
.name != "go.sum" and
.name != "uv.lock" and
.name != "poetry.lock" and
.name != "Pipfile.lock" and
.name != "Cargo.lock" and
.name != "composer.lock" and
(.name | test(".*lock\\.json$") | not)
))
' > bom.json
echo ""
echo "📊 SBOM Statistics:"
cat bom.json | jq '{
totalComponents: (.components | length),
componentsWithLicenses: ([.components[] | select(.licenses)] | length)
}'
- name: Upload BOM to Dependency-Track
uses: DependencyTrack/gh-upload-sbom@v3
with:
serverhostname: '44.194.0.211'
port: '8091'
protocol: 'http'
apikey: ${{ secrets.DEPENDENCYTRACK_API_KEY }}
projectname: ${{ github.event.repository.name }}
projectversion: 'main'
bomfilename: 'bom.json'
autocreate: 'true'
- name: Archive SBOM artifact
uses: actions/upload-artifact@v4
if: always()
with:
name: sbom-cyclonedx
path: bom.json
retention-days: 90