microsoft/hve-core

Public

mirrored fromhttps://github.com/microsoft/hve-coreAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2b4d1232f1fef5f2c858ccec23582bfed93db47f

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.github/workflows/dependency-pinning-scan.yml

208lines · modecode

1name: Dependency Pinning Scan
2
3on:
4 workflow_call:
5 inputs:
6 threshold:
7 description: 'Compliance threshold percentage (0-100)'
8 required: false
9 type: number
10 default: 95
11 dependency-types:
12 description: 'Comma-separated list of dependency types to check'
13 required: false
14 type: string
15 default: 'github-actions'
16 soft-fail:
17 description: 'Whether to continue on compliance violations'
18 required: false
19 type: boolean
20 default: false
21 upload-sarif:
22 description: 'Whether to upload SARIF results to Security tab'
23 required: false
24 type: boolean
25 default: false
26 upload-artifact:
27 description: 'Whether to upload results as artifact'
28 required: false
29 type: boolean
30 default: true
31 outputs:
32 compliance-score:
33 description: 'Compliance score percentage'
34 value: ${{ jobs.scan.outputs.compliance-score }}
35 unpinned-count:
36 description: 'Number of unpinned dependencies found'
37 value: ${{ jobs.scan.outputs.unpinned-count }}
38 is-compliant:
39 description: 'Whether repository meets compliance threshold'
40 value: ${{ jobs.scan.outputs.is-compliant }}
41
42permissions:
43 contents: read
44
45jobs:
46 scan:
47 name: Validate SHA Pinning Compliance
48 runs-on: ubuntu-latest
49 permissions:
50 contents: read
51 security-events: write
52 outputs:
53 compliance-score: ${{ steps.pinning.outputs.compliance-score }}
54 unpinned-count: ${{ steps.pinning.outputs.unpinned-count }}
55 is-compliant: ${{ steps.pinning.outputs.is-compliant }}
56 steps:
57 - name: Checkout code
58 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4.2.2
59 with:
60 persist-credentials: false
61
62 - name: Run SHA Pinning Validation
63 id: pinning
64 shell: pwsh
65 run: |
66 Write-Host "Validating dependency SHA pinning compliance..."
67
68 # Ensure logs directory exists
69 New-Item -ItemType Directory -Force -Path logs | Out-Null
70
71 # Build parameter list for JSON output (always generate)
72 $params = @{
73 Path = '.'
74 Recursive = $true
75 Format = 'json'
76 OutputPath = 'logs/dependency-pinning-results.json'
77 }
78
79 # Enable failure on threshold violations unless soft-fail is requested
80 if ('${{ inputs.soft-fail }}' -ne 'true') {
81 $params['FailOnUnpinned'] = $true
82 }
83
84 # Pass dependency types filter to script
85 if ('${{ inputs.dependency-types }}') {
86 $params['IncludeTypes'] = '${{ inputs.dependency-types }}'
87 }
88
89 # Pass compliance threshold to script (script handles enforcement)
90 if ('${{ inputs.threshold }}') {
91 $params['Threshold'] = [int]'${{ inputs.threshold }}'
92 }
93
94 # Run validation script (JSON format)
95 & scripts/security/Test-DependencyPinning.ps1 @params
96 $jsonExitCode = $LASTEXITCODE
97
98 # Generate SARIF format if requested
99 if ('${{ inputs.upload-sarif }}' -eq 'true') {
100 Write-Host "Generating SARIF format for Security tab..."
101 $params['Format'] = 'sarif'
102 $params['OutputPath'] = 'logs/dependency-pinning-results.sarif'
103
104 & scripts/security/Test-DependencyPinning.ps1 @params
105 }
106
107 # Extract metrics from JSON report
108 if (Test-Path logs/dependency-pinning-results.json) {
109 $report = Get-Content logs/dependency-pinning-results.json | ConvertFrom-Json
110 $complianceScore = $report.ComplianceScore
111 $unpinnedCount = $report.UnpinnedDependencies
112
113 # Extract threshold from report metadata (script calculated compliance)
114 $threshold = $report.Metadata.ComplianceThreshold
115 $isCompliant = $complianceScore -ge $threshold
116
117 "compliance-score=$complianceScore" >> $env:GITHUB_OUTPUT
118 "unpinned-count=$unpinnedCount" >> $env:GITHUB_OUTPUT
119 "is-compliant=$($isCompliant.ToString().ToLower())" >> $env:GITHUB_OUTPUT
120
121 Write-Host "Compliance Score: $complianceScore%"
122 Write-Host "Unpinned Dependencies: $unpinnedCount"
123 Write-Host "Is Compliant (>=$threshold%): $isCompliant"
124
125 # Fire GitHub Actions warnings for each violation
126 if ($unpinnedCount -gt 0) {
127 # Escape function to prevent workflow command injection
128 function ConvertTo-GHAEscaped($Value, [switch]$ForProperty) {
129 if ([string]::IsNullOrEmpty($Value)) { return $Value }
130 $escaped = $Value -replace '%', '%25'
131 $escaped = $escaped -replace "`r", '%0D'
132 $escaped = $escaped -replace "`n", '%0A'
133 $escaped = $escaped -replace '::', '%3A%3A'
134 if ($ForProperty) {
135 $escaped = $escaped -replace ':', '%3A'
136 $escaped = $escaped -replace ',', '%2C'
137 }
138 return $escaped
139 }
140
141 foreach ($violation in $report.Violations) {
142 $escapedFile = ConvertTo-GHAEscaped $violation.File -ForProperty
143 $escapedName = ConvertTo-GHAEscaped $violation.Name
144 $escapedVersion = ConvertTo-GHAEscaped $violation.Version
145 $escapedType = ConvertTo-GHAEscaped $violation.Type
146 $escapedSeverity = ConvertTo-GHAEscaped $violation.Severity
147 Write-Output "::warning file=$escapedFile,line=$($violation.Line)::Unpinned $escapedType dependency: $escapedName@$escapedVersion (Severity: $escapedSeverity)"
148 }
149 }
150 }
151 else {
152 Write-Error "Failed to generate dependency pinning report"
153 exit 1
154 }
155
156 - name: Upload SARIF to Security tab
157 if: inputs.upload-sarif && always()
158 uses: github/codeql-action/upload-sarif@ce729e4d353d580e6cacd6a8cf2921b72e5e310a # v3.27.0
159 with:
160 sarif_file: logs/dependency-pinning-results.sarif
161 category: dependency-pinning
162 continue-on-error: true
163
164 - name: Upload validation report
165 if: inputs.upload-artifact && always()
166 uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v4.4.3
167 with:
168 name: dependency-pinning-results
169 path: logs/dependency-pinning-results.json
170 retention-days: 90
171
172 - name: Add job summary
173 if: always()
174 shell: pwsh
175 run: |
176 $complianceScore = '${{ steps.pinning.outputs.compliance-score }}'
177 $unpinnedCount = '${{ steps.pinning.outputs.unpinned-count }}'
178 $isCompliant = '${{ steps.pinning.outputs.is-compliant }}'
179
180 @"
181 ## Dependency Pinning Scan Results
182
183 | Metric | Value |
184 |--------|-------|
185 | Compliance Score | $complianceScore% |
186 | Unpinned Dependencies | $unpinnedCount |
187 | Status | $(if ($isCompliant -eq 'true') { '✅ Compliant' } else { '⚠️ Non-Compliant' }) |
188
189 $(if ($unpinnedCount -ne '0') {
190 @"
191
192 ### ⚠️ Action Required
193
194 **$unpinnedCount dependencies are not SHA-pinned.**
195
196 Review the warnings in the workflow log and pin dependencies to specific SHA commits.
197
198 "@
199 } else {
200 @"
201
202 ### ✅ All Dependencies Pinned
203
204 All dependencies are properly SHA-pinned.
205
206 "@
207 })
208 "@ | Out-File -FilePath $env:GITHUB_STEP_SUMMARY -Encoding UTF8
209