added documetation

This commit is contained in:
Jurjen Ladenius
2025-11-03 08:12:01 +01:00
parent 8840b0e300
commit a226ca97ac
37 changed files with 8315 additions and 1481 deletions

View File

@@ -1,7 +1,102 @@
Write-Host "================================================================================================="
Write-Host "Creating Software Bill Of Materials."
Write-Host "================================================================================================="
<#
.SYNOPSIS
Generates a comprehensive Software Bill of Materials (SBOM) by consolidating Snyk dependency exports with enhanced package metadata.
.DESCRIPTION
This script processes multiple Snyk CSV dependency exports to create a unified Software Bill of Materials
with enriched package information. It combines vulnerability data from Snyk with additional metadata
from package repositories (NuGet) to provide comprehensive dependency insights.
Features:
• Multi-file CSV processing from Snyk dependency exports
• Enhanced NuGet package metadata enrichment (version history, deprecation status)
• Vulnerability aggregation across all projects and dependencies
• License information consolidation and analysis
• Deprecation detection for NuGet packages
• Comprehensive SBOM generation with timestamped output
• Support for npm, NuGet, and other package types
• Latest version tracking and publication date analysis
.PARAMETER None
This script does not accept parameters. Input files are processed from a predefined directory path.
.EXAMPLE
.\SBOM.ps1
Processes all Snyk CSV exports in c:\temp\snyk\ and generates a consolidated SBOM.
.EXAMPLE
# Prepare Snyk CSV exports first
# Export dependencies from Snyk UI or CLI to c:\temp\snyk\
.\SBOM.ps1
Creates enhanced SBOM with NuGet metadata enrichment.
.INPUTS
System.IO.FileInfo[]
Requires Snyk CSV dependency export files in c:\temp\snyk\ directory.
Expected CSV columns: id, name, version, type, issuesCritical, issuesHigh, issuesMedium,
issuesLow, dependenciesWithIssues, licenses, projects, license urls
.OUTPUTS
System.IO.FileInfo
Generates a timestamped CSV file containing enriched SBOM data with the following columns:
- FileName: Source CSV file name for traceability
- id: Package unique identifier from Snyk
- name: Package name
- version: Package version
- type: Package type (npm, nuget, maven, etc.)
- issuesCritical/High/Medium/Low: Vulnerability counts by severity
- dependenciesWithIssues: Count of vulnerable dependencies
- licenses: License information from Snyk
- projects: Projects using this dependency
- license_urls: URLs to license information
- latestVersion: Most recent available version (NuGet packages)
- latestVersionUrl: URL to latest version (NuGet packages)
- latestVersionPublishedDate: Publication date of latest version
- firstPublishedDate: Initial publication date of current version
- versionUrl: URL to current version information
- isDeprecated: Boolean indicating deprecation status
.NOTES
Requires PowerShell 5.1 or later
Requires PackageManagement module for NuGet package queries
Prerequisites:
- Snyk CSV dependency exports must be placed in c:\temp\snyk\ directory
- Network connectivity to nuget.org for package metadata enrichment
- PowerShell execution policy must allow script execution
Performance Considerations:
- Processing time depends on number of unique NuGet packages
- Each NuGet package requires API calls to nuget.org
- Large SBOM files may take several minutes to process
- Progress indicators show current processing status
Input File Requirements:
- Files must be CSV format with standard Snyk dependency export structure
- All CSV files in the source directory will be processed
- Files should contain complete dependency information from Snyk scans
.LINK
https://docs.snyk.io/products/snyk-open-source/dependency-management
https://docs.microsoft.com/en-us/nuget/api/overview
.COMPONENT
PackageManagement PowerShell Module, Snyk Dependency Exports
.ROLE
Software Composition Analysis, Security Governance, Compliance Reporting
.FUNCTIONALITY
SBOM generation, dependency analysis, vulnerability aggregation, package metadata enrichment
#>
Write-Host "========================================================================================================================================================================"
Write-Host "🔍 Software Bill of Materials (SBOM) Generator" -ForegroundColor Green
Write-Host "========================================================================================================================================================================"
Write-Host "📋 Processing Snyk dependency exports and enriching with package metadata..." -ForegroundColor Cyan
Write-Host ""
# Data structure class for enhanced SBOM entries
class CSVItem {
[string] $FileName = ""
[string] $id = ""
@@ -24,8 +119,36 @@ class CSVItem {
[string] $isDeprecated = ""
}
function PropagatePackage {
<#
.SYNOPSIS
Enriches package entries with additional metadata from package repositories.
.DESCRIPTION
This function queries package repositories (currently NuGet) to gather additional metadata
such as publication dates, latest versions, deprecation status, and repository URLs.
This enrichment provides comprehensive package lifecycle information for SBOM analysis.
.PARAMETER allItems
Array of CSVItem objects representing all packages in the SBOM.
.PARAMETER name
Name of the package to enrich with metadata.
.PARAMETER version
Version of the package to enrich.
.PARAMETER type
Package type (npm, nuget, maven, etc.). Only NuGet packages are currently enriched.
.PARAMETER progress
Progress indicator string showing current processing status.
.NOTES
Currently supports NuGet package enrichment only.
Makes API calls to NuGet.org which may impact performance for large SBOMs.
Handles deprecated packages by checking multiple metadata fields.
#>
function PropagatePackage {
param (
[CSVItem[]] $allItems,
[string] $name,
@@ -34,104 +157,253 @@ function PropagatePackage {
[string] $progress
)
# Find all SBOM entries matching this package
$foundItems = $allItems | Where-Object { ($_.name -eq $name) -and ($_.version -eq $version) -and ($_.type -eq $type)}
write-Host "[$progress] - Find $type package info for $name ($version) [$($foundItems.Length)]"
Write-Host " [$progress] 📦 Enriching $type package: $name ($version) - Found $($foundItems.Length) entries" -ForegroundColor Gray
# Currently only supports NuGet package enrichment
if ($type -ne "nuget") {
Write-Host " ⏭️ Skipping $type package (enrichment not supported)" -ForegroundColor DarkGray
return
}
$nuget = Find-Package $name -RequiredVersion $version -ProviderName Nuget
if ($null -eq $nuget) {
return
}
# Query NuGet repository for specific version metadata
try {
$lastNuget = Find-Package $name -ProviderName Nuget
$nuget = Find-Package $name -RequiredVersion $version -ProviderName Nuget -ErrorAction Stop
Write-Host " ✅ Found NuGet package metadata for $name $version" -ForegroundColor DarkGreen
}
catch {
Write-Host " ❌ Failed to find NuGet package: $name $version - $($_.Exception.Message)" -ForegroundColor DarkRed
return
}
# Query for latest version information
$lastNuget = $null
try {
$lastNuget = Find-Package $name -ProviderName Nuget -ErrorAction Stop
Write-Host " 📈 Latest version found: $($lastNuget.Version)" -ForegroundColor DarkGreen
}
catch {
Write-Host " ⚠️ Could not determine latest version for $name" -ForegroundColor DarkYellow
}
catch {}
# Enrich all matching SBOM entries with NuGet metadata
foreach ($propagateItem in $foundItems) {
# Set publication date for current version
$propagateItem.firstPublishedDate = $nuget.metadata["published"]
# Generate NuGet.org URL for current version
$propagateItem.versionUrl = "https://www.nuget.org/packages/$name/$version"
# Add latest version information if available
if ($null -ne $lastNuget) {
$propagateItem.latestVersion = $lastNuget.Version;
$propagateItem.latestVersion = $lastNuget.Version
$propagateItem.latestVersionPublishedDate = $lastNuget.metadata["published"]
$propagateItem.latestVersionUrl = "https://www.nuget.org/packages/$name/$($lastNuget.Version)"
}
$propagateItem.isDeprecated = ($null -eq $lastNuget) -or ($nuget.metadata["summary"] -like "*Deprecated*") -or ($nuget.metadata["title"] -like "*Deprecated*") -or ($nuget.metadata["tags"] -like "*Deprecated*")-or ($nuget.metadata["description"] -like "*Deprecated*")
# Determine deprecation status by checking multiple metadata fields
$isDeprecated = ($null -eq $lastNuget) -or
($nuget.metadata["summary"] -like "*Deprecated*") -or
($nuget.metadata["title"] -like "*Deprecated*") -or
($nuget.metadata["tags"] -like "*Deprecated*") -or
($nuget.metadata["description"] -like "*Deprecated*")
$propagateItem.isDeprecated = $isDeprecated
if ($isDeprecated) {
Write-Host " ⚠️ Package marked as deprecated: $name" -ForegroundColor Yellow
}
}
Write-Host " ✅ Successfully enriched $($foundItems.Length) SBOM entries" -ForegroundColor DarkGreen
return
}
# Generate timestamped output filename
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
$fileName = ".\$date snyk_npm_nuget_sbom.csv"
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host "Parsing CSV Files.."
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host "📁 Output file: $fileName" -ForegroundColor Gray
Write-Host ""
Write-Host "========================================================================================================================================================================"
Write-Host "📋 Phase 1: Processing Snyk CSV Dependencies" -ForegroundColor Cyan
Write-Host "========================================================================================================================================================================"
# Define source directory for Snyk CSV exports
$csvDependenciesExportPath = "c:\temp\snyk\*.csv"
$files = Get-ChildItem $csvDependenciesExportPath
# Locate all CSV files in the source directory
try {
$files = Get-ChildItem $csvDependenciesExportPath -ErrorAction Stop
Write-Host "✅ Found $($files.Count) Snyk CSV file(s) to process" -ForegroundColor Green
}
catch {
Write-Host "❌ No CSV files found in $csvDependenciesExportPath" -ForegroundColor Red
Write-Host " Please ensure Snyk dependency exports are placed in the directory" -ForegroundColor Yellow
exit 1
}
# Initialize SBOM collection
[CSVItem[]]$CSVItems = @()
$totalEntries = 0
# Process each CSV file
foreach($file in $files) {
Write-Host $file.FullName
Write-Host ""
Write-Host "📄 Processing file: $($file.Name)" -ForegroundColor Yellow
Write-Host " 📍 Path: $($file.FullName)" -ForegroundColor Gray
$csv = Import-Csv -Path $file.FullName
foreach ($csvLine in $csv) {
try {
$csv = Import-Csv -Path $file.FullName -ErrorAction Stop
Write-Host " 📊 Found $($csv.Count) dependency entries" -ForegroundColor White
# Process each dependency entry in the CSV file
$entryCount = 0
foreach ($csvLine in $csv) {
$entryCount++
$totalEntries++
# Create new SBOM entry
[CSVItem] $CSVItem = [CSVItem]::new()
$CSVItem.FileName = $file.Name
# Map Snyk CSV data to SBOM structure
$CSVItem.id = $csvLine.id
$CSVItem.name = $csvLine.name
$CSVItem.version = $csvLine.version
$CSVItem.type = $csvLine.type
# Vulnerability information
$CSVItem.issuesCritical = $csvLine.issuesCritical
$CSVItem.issuesHigh = $csvLine.issuesHigh
$CSVItem.issuesMedium = $csvLine.issuesMedium
$CSVItem.issuesLow = $csvLine.issuesLow
$CSVItem.dependenciesWithIssues = $csvLine.dependenciesWithIssues
# License and project information
$CSVItem.licenses = $csvLine.licenses
$CSVItem.projects = $csvLine.projects
$CSVItem.license_urls = $csvLine."license urls"
# Version and metadata (will be enriched later for NuGet packages)
$CSVItem.latestVersion = $csvLine.latestVersion
$CSVItem.latestVersionPublishedDate = $csvLine.latestVersionPublishedDate
$CSVItem.firstPublishedDate = $csvLine.firstPublishedDate
$CSVItem.isDeprecated = $csvLine.isDeprecated
$CSVItems += $CSVItem
}
Write-Host " ✅ Successfully processed $entryCount entries from $($file.Name)" -ForegroundColor Green
}
catch {
Write-Host " ❌ Error processing $($file.Name): $($_.Exception.Message)" -ForegroundColor Red
Write-Host " Skipping this file and continuing..." -ForegroundColor Yellow
continue
}
}
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host "Determine objects.."
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host ""
Write-Host "📊 CSV Processing Summary:" -ForegroundColor Cyan
Write-Host "=========================="
Write-Host "• Files Processed: $($files.Count)" -ForegroundColor White
Write-Host "• Total Dependencies: $totalEntries" -ForegroundColor White
Write-Host ""
$toDo = $CSVItems | Where-Object { $_.type -eq "nuget" } | Sort-Object -Property version| Sort-Object -Property name
$counter = 0
$length = $toDo.Length
foreach ($package in $toDo) {
$counter = $counter + 1
# Analyze package types
$packageTypes = $CSVItems | Group-Object type | Sort-Object Count -Descending
Write-Host "🔍 Package Type Distribution:" -ForegroundColor Cyan
foreach ($type in $packageTypes) {
Write-Host " $($type.Name): $($type.Count) packages" -ForegroundColor White
}
if ($package.latestVersion -eq "") {
PropagatePackage -allItems $CSVItems -name $package.name -type $package.type -version $package.version -progress ("{0:D4}/{1:D4}" -f $counter, $length)
Write-Host ""
Write-Host "========================================================================================================================================================================"
Write-Host "🔧 Phase 2: NuGet Package Metadata Enrichment" -ForegroundColor Cyan
Write-Host "========================================================================================================================================================================"
# Identify unique NuGet packages that need enrichment
$nugetPackages = $CSVItems | Where-Object { $_.type -eq "nuget" -and $_.latestVersion -eq "" } |
Sort-Object -Property name, version -Unique
$nugetCount = $nugetPackages.Count
if ($nugetCount -eq 0) {
Write-Host " No NuGet packages require enrichment (all already have metadata)" -ForegroundColor Blue
} else {
Write-Host "📦 Found $nugetCount unique NuGet packages requiring metadata enrichment" -ForegroundColor White
Write-Host "⏱️ This process may take several minutes depending on network connectivity..." -ForegroundColor Yellow
Write-Host ""
$counter = 0
foreach ($package in $nugetPackages) {
$counter++
$progressPercent = [math]::Round(($counter / $nugetCount) * 100, 1)
Write-Host "🔄 [$counter/$nugetCount - $progressPercent%] Processing NuGet package: $($package.name) v$($package.version)" -ForegroundColor Cyan
PropagatePackage -allItems $CSVItems -name $package.name -type $package.type -version $package.version -progress ("{0:D4}/{1:D4}" -f $counter, $nugetCount)
}
}
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host "Saving overview.."
Write-Host "-------------------------------------------------------------------------------------------------"
Write-Host ""
Write-Host "========================================================================================================================================================================"
Write-Host "💾 Phase 3: SBOM Export and Analysis" -ForegroundColor Cyan
Write-Host "========================================================================================================================================================================"
$CSVItems | Export-Csv -Path $fileName -NoTypeInformation
Write-Host "📄 Exporting enhanced SBOM to CSV..." -ForegroundColor White
Write-Host "Done."
try {
$CSVItems | Export-Csv -Path $fileName -NoTypeInformation -ErrorAction Stop
if (Test-Path $fileName) {
$fileSize = [math]::Round((Get-Item $fileName).Length / 1KB, 2)
Write-Host "✅ SBOM export completed successfully!" -ForegroundColor Green
Write-Host " 📁 File: $fileName" -ForegroundColor Gray
Write-Host " 📏 Size: $fileSize KB" -ForegroundColor Gray
Write-Host " 📊 Records: $($CSVItems.Count)" -ForegroundColor Gray
}
}
catch {
Write-Host "❌ Failed to export SBOM: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
Write-Host ""
Write-Host "📈 SBOM Analysis Summary:" -ForegroundColor Cyan
Write-Host "========================"
# Vulnerability summary
$criticalCount = ($CSVItems | Where-Object { [int]$_.issuesCritical -gt 0 }).Count
$highCount = ($CSVItems | Where-Object { [int]$_.issuesHigh -gt 0 }).Count
$mediumCount = ($CSVItems | Where-Object { [int]$_.issuesMedium -gt 0 }).Count
$lowCount = ($CSVItems | Where-Object { [int]$_.issuesLow -gt 0 }).Count
Write-Host "🚨 Vulnerability Summary:" -ForegroundColor Yellow
Write-Host " Critical Issues: $criticalCount packages" -ForegroundColor $(if($criticalCount -gt 0) {'Red'} else {'Green'})
Write-Host " High Issues: $highCount packages" -ForegroundColor $(if($highCount -gt 0) {'Red'} else {'Green'})
Write-Host " Medium Issues: $mediumCount packages" -ForegroundColor $(if($mediumCount -gt 0) {'Yellow'} else {'Green'})
Write-Host " Low Issues: $lowCount packages" -ForegroundColor $(if($lowCount -gt 0) {'Yellow'} else {'Green'})
# Deprecation summary
$deprecatedCount = ($CSVItems | Where-Object { $_.isDeprecated -eq $true -or $_.isDeprecated -eq "True" }).Count
Write-Host ""
Write-Host "⚠️ Deprecation Summary:" -ForegroundColor Yellow
Write-Host " Deprecated Packages: $deprecatedCount" -ForegroundColor $(if($deprecatedCount -gt 0) {'Yellow'} else {'Green'})
# License summary
$unlicensedCount = ($CSVItems | Where-Object { $_.licenses -eq "" -or $_.licenses -eq $null }).Count
Write-Host ""
Write-Host "📋 License Summary:" -ForegroundColor Cyan
Write-Host " Packages with License Info: $($CSVItems.Count - $unlicensedCount)" -ForegroundColor Green
Write-Host " Packages without License Info: $unlicensedCount" -ForegroundColor $(if($unlicensedCount -gt 0) {'Yellow'} else {'Green'})
Write-Host ""
Write-Host "========================================================================================================================================================================"
Write-Host "✅ Software Bill of Materials generation completed successfully!" -ForegroundColor Green
Write-Host "========================================================================================================================================================================"