tasks/analysis.tasks.ps1
$covenantVersion = "0.12.0" $CovenantIncludeSpdxReport = $true $CovenantIncludeCycloneDxReport = $true $CovenantMetadata = @{ git_repo = $(if (Get-Command "gh" -ErrorAction SilentlyContinue) { try { $ghRepo = & gh repo view --json nameWithOwner $ghRepo | ConvertFrom-Json | Select-Object -expandproperty nameWithOwner } catch { "" } }) git_branch = $(if (Get-Command "git" -ErrorAction SilentlyContinue) {git branch --show-current }) git_sha = $(if (Get-Command "git" -ErrorAction SilentlyContinue) { & git rev-parse HEAD }) } # Defaults for publishing-related variables $PublishCovenantOutputToStorage = $false $AnalysisOutputStorageAccountName = "" $AnalysisOutputContainerName = "" $AnalysisOutputBlobPath = "" task InstallCovenantTool { Install-DotNetTool -Name covenant -Version $covenantVersion } # Synopsis: Setup SBOM metadata for Covenant command-line task PrepareCovenantMetadata { $script:covenantMetadataArgs = @() foreach ($key in $CovenantMetadata.Keys) { # NOTE: No space after the '-m' switch otherwise the metadata key has a leading space in the report $script:covenantMetadataArgs += "-m$key=$($CovenantMetadata[$key])" } } task RunCovenantTool -If { $SolutionToBuild } Version, InstallCovenantTool, PrepareCovenantMetadata,{ $baseOutputName = [IO.Path]::GetFileNameWithoutExtension($SolutionToBuild) # Ensure we have a fully-qualified path, as this will be needed when uploading on build server $script:covenantJsonOutputFile = Join-Path $here ("/{0}.sbom.json" -f $baseOutputName) $script:covenantSpdxOutputFile = Join-Path $here ("/{0}.sbom.spdx.json" -f $baseOutputName) $script:covenantCycloneDxOutputFile = Join-Path $here ("/{0}.sbom.cyclonedx.xml" -f $baseOutputName) $script:covenantHtmlReportFile = Join-Path $here ("/{0}.sbom.html" -f $baseOutputName) Write-Verbose "covenantHtmlReportFile: $covenantHtmlReportFile" # Generate SBOM exec { & dotnet-covenant ` generate ` $SolutionToBuild ` -v $script:GitVersion.SemVer ` --output $covenantJsonOutputFile ` $covenantMetadataArgs } # Generate HTML report exec { & dotnet-covenant ` report ` $covenantJsonOutputFile ` --output $covenantHtmlReportFile } } # Synopsis: Generate SPDX-formatted report task GenerateCovenantSpdxReport -If { $SolutionToBuild -and $CovenantIncludeSpdxReport } RunCovenantTool,{ exec { & dotnet-covenant ` convert ` spdx ` $covenantJsonOutputFile ` --output $covenantSpdxOutputFile } Write-Verbose "covenantSpdxOutputFile: $covenantSpdxOutputFile" } # Synopsis: Generate CycloneDX-formatted report task GenerateCovenantCycloneDxReport -If { $SolutionToBuild -and $CovenantIncludeCycloneDxReport } RunCovenantTool,{ exec { & dotnet-covenant ` convert ` cyclonedx ` $covenantJsonOutputFile ` --output $covenantCycloneDxOutputFile } Write-Verbose "covenantCycloneDxOutputFile: $covenantCycloneDxOutputFile" } task PublishCovenantBuildArtefacts -If { $IsAzureDevops } { Write-Host "##vso[task.setvariable variable=SbomHtmlReportPath;isoutput=true]$covenantHtmlReportFile" Write-Host "##vso[artifact.upload artifactname=SBOM]$covenantHtmlReportFile" Write-Host "##vso[artifact.upload artifactname=SBOM]$covenantJsonOutputFile" if ($CovenantIncludeSpdxReport) { Write-Host "##vso[artifact.upload artifactname=SBOM]$covenantSpdxOutputFile" } if ($CovenantIncludeCycloneDxReport) { Write-Host "##vso[artifact.upload artifactname=SBOM]$covenantCycloneDxOutputFile" } } task PublishCovenantOutputToStorage -If { $SolutionToBuild -and $PublishCovenantOutputToStorage } { if ( (Test-Path $covenantJsonOutputFile) -and ` $AnalysisOutputStorageAccountName -and ` $AnalysisOutputContainerName -and ` $AnalysisOutputBlobPath) { $covenantJsonOutputFilename = (Split-Path -Leaf $covenantJsonOutputFile) $filename = "{0}-{1}.json" -f [IO.Path]::GetFileNameWithoutExtension($covenantJsonOutputFilename), ([DateTime]::Now).ToString('yyyyMMddHHmmssfff') Write-Information @" Publishing storage account: Source File: $covenantJsonOutputFile Account: $AnalysisOutputStorageAccountName Blob Path: "$AnalysisOutputContainerName/$AnalysisOutputBlobPath/$filename" "@ $uri = "https://{0}.blob.core.windows.net/{1}/{2}/{3}" -f $AnalysisOutputStorageAccountName, $AnalysisOutputContainerName, $AnalysisOutputBlobPath, $filename $authUri = & az storage blob generate-sas ` --auth-mode login ` --as-user ` --https-only ` --account-name $AnalysisOutputStorageAccountName ` --blob-url $uri ` --permissions c ` --start (Get-Date).ToUniversalTime().ToString("yyyy-M-d'T'H:m'Z'") ` --expiry (Get-Date).AddMinutes(10).ToUniversalTime().ToString("yyyy-M-d'T'H:m'Z'") ` --full-uri ` -o tsv $headers = @{ "x-ms-date" = [System.DateTime]::UtcNow.ToString("R") "x-ms-blob-type" = "BlockBlob" } Invoke-RestMethod -Headers $headers ` -Uri $authUri ` -Method PUT ` -InFile $covenantJsonOutputFile ` -Verbose:$false | Out-Null Write-Information "Covenant JSON output published to storage account" } else { Write-Information "Publishing of Covenant output skipped, due to absent configuration" } } task RunCovenant RunCovenantTool, GenerateCovenantSpdxReport, GenerateCovenantCycloneDxReport, PublishCovenantBuildArtefacts, PublishCovenantOutputToStorage |