Public/Test-CodeScanning.ps1
|
function Test-CodeScanning { [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter(Mandatory)] [ValidatePattern('^[a-zA-Z0-9._-]+$')] [string]$Owner, [Parameter(Mandatory)] [ValidatePattern('^[a-zA-Z0-9._-]+$')] [string]$Repo, [Parameter(Mandatory)] [string]$Token ) $target = "$Owner/$Repo" $results = [System.Collections.Generic.List[PSCustomObject]]::new() $resource = $target $staleThresholdDays = 30 try { $analyses = Invoke-GitHubApi ` -Endpoint "repos/$Owner/$Repo/code-scanning/analyses?per_page=10" ` -Token $Token } catch { $msg = $_.Exception.Message if ($msg -match '404' -or ($msg -match '403' -and $msg -match '(?i)disabled')) { $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Fail' ` -Severity 'Medium' ` -Resource $resource ` -Detail 'Code Scanning is not configured on this repository.' ` -Remediation 'Set up Code Scanning in Security → Code scanning. Use CodeQL or a third-party scanner via a GitHub Actions workflow.' ` -AttackMapping @('solarwinds-orion') ` -Target $target)) return $results.ToArray() } if ($msg -match '403') { $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Error' ` -Severity 'Medium' ` -Resource $resource ` -Detail 'Insufficient permissions to read Code Scanning analyses.' ` -Remediation 'Use a fine-grained token with Code scanning alerts:read permission, or a classic token with security_events scope.' ` -Target $target)) return $results.ToArray() } $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Error' ` -Severity 'Medium' ` -Resource $resource ` -Detail "Unexpected error reading Code Scanning analyses: $($_.Exception.Message)" ` -Remediation 'Re-run with a valid token and verify network access to api.github.com.' ` -Target $target)) return $results.ToArray() } if (-not $analyses -or ($analyses -is [System.Array] -and $analyses.Count -eq 0)) { $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Fail' ` -Severity 'Medium' ` -Resource $resource ` -Detail 'Code Scanning is configured but no analysis runs have been recorded.' ` -Remediation 'Trigger a code scanning workflow run. Verify the scanning workflow is not skipped or failing.' ` -AttackMapping @('solarwinds-orion') ` -Target $target)) return $results.ToArray() } # Check freshness of most recent analysis $latestAnalysis = if ($analyses -is [System.Array]) { $analyses[0] } else { $analyses } $analysisDate = [datetime]::Parse($latestAnalysis.created_at) $daysSince = ([datetime]::UtcNow - $analysisDate).TotalDays if ($daysSince -gt $staleThresholdDays) { $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Fail' ` -Severity 'Medium' ` -Resource $resource ` -Detail "Last Code Scanning analysis was $([math]::Floor($daysSince)) day(s) ago (threshold: $staleThresholdDays days). Scanning may not be running on recent commits." ` -Remediation 'Verify the code scanning workflow is scheduled or triggered on push/pull_request events. Check for workflow failures.' ` -AttackMapping @('solarwinds-orion') ` -Target $target)) return $results.ToArray() } $results.Add((Format-FylgyrResult ` -CheckName 'CodeScanning' ` -Status 'Pass' ` -Severity 'Info' ` -Resource $resource ` -Detail "Code Scanning is active. Last analysis: $($analysisDate.ToString('yyyy-MM-dd')) ($([math]::Floor($daysSince)) day(s) ago)." ` -Remediation 'No action needed.' ` -Target $target)) $results.ToArray() } |