name: Dependency Pinning Scan
on:
workflow_call:
inputs:
threshold:
description: 'Compliance threshold percentage (0-100)'
required: false
type: number
default: 95
dependency-types:
description: 'Comma-separated list of dependency types to check'
required: false
type: string
default: 'github-actions'
soft-fail:
description: 'Whether to continue on compliance violations'
required: false
type: boolean
default: false
upload-sarif:
description: 'Whether to upload SARIF results to Security tab'
required: false
type: boolean
default: false
upload-artifact:
description: 'Whether to upload results as artifact'
required: false
type: boolean
default: true
outputs:
compliance-score:
description: 'Compliance score percentage'
value: ${{ jobs.scan.outputs.compliance-score }}
unpinned-count:
description: 'Number of unpinned dependencies found'
value: ${{ jobs.scan.outputs.unpinned-count }}
is-compliant:
description: 'Whether repository meets compliance threshold'
value: ${{ jobs.scan.outputs.is-compliant }}
permissions:
contents: read
jobs:
scan:
name: Validate SHA Pinning Compliance
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
outputs:
compliance-score: ${{ steps.pinning.outputs.compliance-score }}
unpinned-count: ${{ steps.pinning.outputs.unpinned-count }}
is-compliant: ${{ steps.pinning.outputs.is-compliant }}
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
with:
persist-credentials: false
- name: Run SHA Pinning Validation
id: pinning
shell: pwsh
run: |
Write-Host "Validating dependency SHA pinning compliance..."
# Ensure logs directory exists
New-Item -ItemType Directory -Force -Path logs | Out-Null
# Build parameter list for JSON output (always generate)
$params = @{
Path = '.'
Recursive = $true
Format = 'json'
OutputPath = 'logs/dependency-pinning-results.json'
}
# Enable failure on threshold violations unless soft-fail is requested
if ('${{ inputs.soft-fail }}' -ne 'true') {
$params['FailOnUnpinned'] = $true
}
# Pass dependency types filter to script
if ('${{ inputs.dependency-types }}') {
$params['IncludeTypes'] = '${{ inputs.dependency-types }}'
}
# Pass compliance threshold to script (script handles enforcement)
if ('${{ inputs.threshold }}') {
$params['Threshold'] = [int]'${{ inputs.threshold }}'
}
# Run validation script (JSON format)
& scripts/security/Test-DependencyPinning.ps1 @params
$jsonExitCode = $LASTEXITCODE
# Generate SARIF format if requested
if ('${{ inputs.upload-sarif }}' -eq 'true') {
Write-Host "Generating SARIF format for Security tab..."
$params['Format'] = 'sarif'
$params['OutputPath'] = 'logs/dependency-pinning-results.sarif'
& scripts/security/Test-DependencyPinning.ps1 @params
}
# Extract metrics from JSON report
if (Test-Path logs/dependency-pinning-results.json) {
$report = Get-Content logs/dependency-pinning-results.json | ConvertFrom-Json
$complianceScore = $report.ComplianceScore
$unpinnedCount = $report.UnpinnedDependencies
# Extract threshold from report metadata (script calculated compliance)
$threshold = $report.Metadata.ComplianceThreshold
$isCompliant = $complianceScore -ge $threshold
"compliance-score=$complianceScore" >> $env:GITHUB_OUTPUT
"unpinned-count=$unpinnedCount" >> $env:GITHUB_OUTPUT
"is-compliant=$($isCompliant.ToString().ToLower())" >> $env:GITHUB_OUTPUT
Write-Host "Compliance Score: $complianceScore%"
Write-Host "Unpinned Dependencies: $unpinnedCount"
Write-Host "Is Compliant (>=$threshold%): $isCompliant"
}
else {
Write-Error "Failed to generate dependency pinning report"
exit 1
}
- name: Upload SARIF to Security tab
if: inputs.upload-sarif && always()
uses: github/codeql-action/upload-sarif@ce729e4d353d580e6cacd6a8cf2921b72e5e310a # v3.27.0
with:
sarif_file: logs/dependency-pinning-results.sarif
category: dependency-pinning
continue-on-error: true
- name: Upload validation report
if: inputs.upload-artifact && always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v4.4.3
with:
name: dependency-pinning-results
path: logs/dependency-pinning-results.json
retention-days: 90
- name: Add job summary
if: always()
shell: pwsh
run: |
$complianceScore = '${{ steps.pinning.outputs.compliance-score }}'
$unpinnedCount = '${{ steps.pinning.outputs.unpinned-count }}'
$isCompliant = '${{ steps.pinning.outputs.is-compliant }}'
@"
## Dependency Pinning Scan Results
| Metric | Value |
|--------|-------|
| Compliance Score | $complianceScore% |
| Unpinned Dependencies | $unpinnedCount |
| Status | $(if ($isCompliant -eq 'true') { '✅ Compliant' } else { '⚠️ Non-Compliant' }) |
$(if ($unpinnedCount -ne '0') {
@"
### ⚠️ Action Required
**$unpinnedCount dependencies are not SHA-pinned.**
Review the warnings in the workflow log and pin dependencies to specific SHA commits.
"@
} else {
@"
### ✅ All Dependencies Pinned
All dependencies are properly SHA-pinned.
"@
})
"@ | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding UTF8microsoft/hve-core
Publicmirrored fromhttps://github.com/microsoft/hve-coreAvailable
.github/workflows/dependency-pinning-scan.yml
182lines · modepreview