From 6b858667ff3a622485d08269985979652ed7bb11 Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 16:53:14 -0700 Subject: [PATCH 1/2] fix(hidi): preserve signed assembly in v2 tool packages Replace the tool publish assembly input with the ESRP staging DLL and verify its packaged hash and Microsoft Authenticode signature before NuGet signing. Cover fail-closed validation through the existing measured Pester workflow. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ca73667e-f3d5-4518-b76d-1bf49dc7da23 --- .azure-pipelines/hidi-release.yml | 5 +- .github/workflows/sonarcloud.yml | 72 ++++++++------- README.md | 8 +- scripts/verify-hidi-package-assembly.ps1 | 59 ++++++++++++ .../Microsoft.OpenApi.Hidi.csproj | 21 +++++ src/Microsoft.OpenApi.Hidi/readme.md | 15 ++++ .../verify-hidi-package-assembly.Tests.ps1 | 90 +++++++++++++++++++ 7 files changed, 231 insertions(+), 39 deletions(-) create mode 100644 scripts/verify-hidi-package-assembly.ps1 create mode 100644 test/Microsoft.OpenApi.Hidi.Tests/verify-hidi-package-assembly.Tests.ps1 diff --git a/.azure-pipelines/hidi-release.yml b/.azure-pipelines/hidi-release.yml index 0087ca80..c84fefd3 100644 --- a/.azure-pipelines/hidi-release.yml +++ b/.azure-pipelines/hidi-release.yml @@ -165,11 +165,12 @@ extends: MaxRetryAttempts: '5' PendingAnalysisWaitTimeoutMinutes: '5' - pwsh: | - Copy-Item artifacts\hidi\signing\Microsoft.OpenApi.Hidi.dll src\Microsoft.OpenApi.Hidi\bin\$(buildConfiguration)\net8.0\Microsoft.OpenApi.Hidi.dll + $ErrorActionPreference = 'Stop' Copy-Item artifacts\hidi\signing\Microsoft.OpenApi.Hidi.exe artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe New-Item -ItemType Directory -Force '$(Build.ArtifactStagingDirectory)\hidi' | Out-Null - dotnet pack src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg -o '$(Build.ArtifactStagingDirectory)\hidi' + dotnet pack src\Microsoft.OpenApi.Hidi\Microsoft.OpenApi.Hidi.csproj -c $(buildConfiguration) --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg "/p:HidiSignedAssemblyPath=$(Build.SourcesDirectory)\artifacts\hidi\signing\Microsoft.OpenApi.Hidi.dll" -o '$(Build.ArtifactStagingDirectory)\hidi' if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + & .\scripts\verify-hidi-package-assembly.ps1 -PackagePath '$(Build.ArtifactStagingDirectory)\hidi\Microsoft.OpenApi.Hidi.$(HidiVersion).nupkg' -SignedAssemblyPath '$(Build.SourcesDirectory)\artifacts\hidi\signing\Microsoft.OpenApi.Hidi.dll' Compress-Archive -Path artifacts\hidi\win-x64\* -DestinationPath '$(Build.ArtifactStagingDirectory)\hidi\hidi-win-x64-$(HidiVersion).zip' Copy-Item artifacts\hidi\win-x64\Microsoft.OpenApi.Hidi.exe '$(Build.ArtifactStagingDirectory)\hidi\Microsoft.OpenApi.Hidi.exe' displayName: Pack signed hidi binaries diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index d717f338..3681312c 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -60,59 +60,65 @@ jobs: - name: Install PowerShell test dependency shell: pwsh run: Install-Module Pester -RequiredVersion 5.7.1 -Scope CurrentUser -Force - - name: Test Hidi NuGet helper with measured coverage + - name: Test Hidi NuGet helpers with measured coverage shell: pwsh run: | $ErrorActionPreference = 'Stop' Import-Module Pester -RequiredVersion 5.7.1 -ErrorAction Stop - $helperPath = 'scripts/check-nuget-package-published.ps1' - $helper = (Resolve-Path $helperPath).Path + $helperPaths = @('scripts/check-nuget-package-published.ps1', 'scripts/verify-hidi-package-assembly.ps1') + $helpers = @($helperPaths | ForEach-Object { (Resolve-Path $_).Path }) $outputRoot = Join-Path $PWD 'artifacts\hidi\powershell-coverage' New-Item -ItemType Directory -Force -Path $outputRoot | Out-Null $configuration = New-PesterConfiguration - $configuration.Run.Path = 'test\Microsoft.OpenApi.Hidi.Tests\check-nuget-package-published.Tests.ps1' + $configuration.Run.Path = @('test\Microsoft.OpenApi.Hidi.Tests\check-nuget-package-published.Tests.ps1', 'test\Microsoft.OpenApi.Hidi.Tests\verify-hidi-package-assembly.Tests.ps1') $configuration.Run.PassThru = $true $configuration.CodeCoverage.Enabled = $true - $configuration.CodeCoverage.Path = $helper + $configuration.CodeCoverage.Path = $helpers $configuration.CodeCoverage.OutputFormat = 'JaCoCo' $configuration.CodeCoverage.OutputPath = Join-Path $outputRoot 'pester-coverage.xml' $configuration.CodeCoverage.CoveragePercentTarget = 80 $result = Invoke-Pester -Configuration $configuration - if ($result.FailedCount -gt 0 -or $result.PassedCount -lt 24) { - throw "Hidi NuGet helper tests failed or did not execute all 24 cases." + if ($result.FailedCount -gt 0 -or $result.PassedCount -lt 45) { + throw "Hidi NuGet helper tests failed or did not execute all 45 cases." } $report = [xml](Get-Content $configuration.CodeCoverage.OutputPath.Value -Raw) $sourceFiles = @($report.SelectNodes('//sourcefile')) - if ($sourceFiles.Count -ne 1 -or $sourceFiles[0].name -ne [IO.Path]::GetFileName($helper)) { - throw 'Expected measured coverage of only the Hidi NuGet helper.' - } - $lines = @($sourceFiles[0].SelectNodes('line')) - $sourceLineCount = @(Get-Content $helper).Count - $lineNumbers = @($lines | ForEach-Object { [int]$_.nr }) - if ($lines.Count -eq 0 -or @($lineNumbers | Select-Object -Unique).Count -ne $lines.Count -or - @($lines | Where-Object { - [int]$_.nr -le 0 -or [int]$_.nr -gt $sourceLineCount -or - -not $_.HasAttribute('ci') -or -not $_.HasAttribute('mi') -or - [int]$_.ci -lt 0 -or [int]$_.mi -lt 0 -or ([int]$_.ci + [int]$_.mi) -le 0 - }).Count -gt 0) { - throw 'Missing or invalid measured helper coverage lines.' - } - $covered = @($lines | Where-Object { [int]$_.ci -gt 0 }).Count - if ($covered / $lines.Count -lt 0.8) { - throw "Insufficient measured Hidi helper coverage: $covered/$($lines.Count) lines." + if ($sourceFiles.Count -ne $helpers.Count) { + throw 'Expected measured coverage of both Hidi NuGet helpers.' } $coverage = [xml]'' - $file = $coverage.CreateElement('file') - $file.SetAttribute('path', $helperPath) - [void]$coverage.DocumentElement.AppendChild($file) - foreach ($line in $lines) { - $entry = $coverage.CreateElement('lineToCover') - $entry.SetAttribute('lineNumber', $line.nr) - $entry.SetAttribute('covered', ([int]$line.ci -gt 0).ToString().ToLowerInvariant()) - [void]$file.AppendChild($entry) + foreach ($helperPath in $helperPaths) { + $helper = (Resolve-Path $helperPath).Path + $source = @($sourceFiles | Where-Object { $_.name -eq [IO.Path]::GetFileName($helper) }) + if ($source.Count -ne 1) { throw "Missing or ambiguous measured coverage for $helperPath." } + $lines = @($source[0].SelectNodes('line')) + $sourceLineCount = @(Get-Content $helper).Count + $lineNumbers = @($lines | ForEach-Object { [int]$_.nr }) + if ($lines.Count -eq 0 -or @($lineNumbers | Select-Object -Unique).Count -ne $lines.Count -or + @($lines | Where-Object { + [int]$_.nr -le 0 -or [int]$_.nr -gt $sourceLineCount -or + -not $_.HasAttribute('ci') -or -not $_.HasAttribute('mi') -or + [int]$_.ci -lt 0 -or [int]$_.mi -lt 0 -or ([int]$_.ci + [int]$_.mi) -le 0 + }).Count -gt 0) { + throw "Missing or invalid measured helper coverage lines for $helperPath." + } + $covered = @($lines | Where-Object { [int]$_.ci -gt 0 }).Count + if ($covered / $lines.Count -lt 0.8) { + throw "Insufficient measured Hidi helper coverage for ${helperPath}: $covered/$($lines.Count) lines." + } + $file = $coverage.CreateElement('file') + $file.SetAttribute('path', $helperPath) + [void]$coverage.DocumentElement.AppendChild($file) + foreach ($line in $lines) { + $entry = $coverage.CreateElement('lineToCover') + $entry.SetAttribute('lineNumber', $line.nr) + $entry.SetAttribute('covered', ([int]$line.ci -gt 0).ToString().ToLowerInvariant()) + [void]$file.AppendChild($entry) + } + Write-Host "Measured Hidi NuGet helper coverage for ${helperPath}: $covered/$($lines.Count) lines." } $coverage.Save((Join-Path $outputRoot 'sonar-coverage.xml')) - Write-Host "Measured Hidi NuGet helper coverage: $covered/$($lines.Count) lines; Sonar generic report generated." + Write-Host "Sonar generic report generated from measured coverage." - name: Build and analyze env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any diff --git a/README.md b/README.md index a73ea9b1..c8fd6df7 100644 --- a/README.md +++ b/README.md @@ -116,12 +116,12 @@ feed responses fail closed. Releases must use an exact `hidi-v2.` tag matching the project version and be newer than the `2.12.2` migration baseline. This pipeline implementation does not enable publishing or authorize resources. -The SonarCloud workflow runs the private-feed helper tests with Pester 5.7.1 and -converts measured JaCoCo line hits to Sonar generic coverage, alongside the -existing C# OpenCover reports. The Pester script resides inside the Hidi test +The SonarCloud workflow runs the private-feed and signed-payload helper tests +with Pester 5.7.1 and converts measured JaCoCo line hits to Sonar generic coverage, +alongside existing C# OpenCover reports. The Pester scripts reside inside the Hidi test project directory so Sonar assigns it to test sources; a linked sibling file does not establish that ownership. Run the helper tests locally with -`Import-Module Pester -RequiredVersion 5.7.1; Invoke-Pester .\test\Microsoft.OpenApi.Hidi.Tests\check-nuget-package-published.Tests.ps1`. +`Import-Module Pester -RequiredVersion 5.7.1; Invoke-Pester .\test\Microsoft.OpenApi.Hidi.Tests\*.Tests.ps1`. --- diff --git a/scripts/verify-hidi-package-assembly.ps1 b/scripts/verify-hidi-package-assembly.ps1 new file mode 100644 index 00000000..53365fe7 --- /dev/null +++ b/scripts/verify-hidi-package-assembly.ps1 @@ -0,0 +1,59 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +<# +.SYNOPSIS +Verifies the Hidi tool package contains the exact Microsoft-signed staging DLL. +.DESCRIPTION +Run after tool packing and before NuGet signing. A signed NuGet container does +not prove that its assembly payload retained the ESRP signature. +#> +[CmdletBinding()] +param( + [Parameter(Mandatory = $true)] + [string]$PackagePath, + [Parameter(Mandatory = $true)] + [string]$SignedAssemblyPath +) + +$ErrorActionPreference = 'Stop' + +foreach ($path in @($PackagePath, $SignedAssemblyPath)) { + if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { + throw "Missing Hidi signing verification input: $path" + } +} + +$temporaryDirectory = Join-Path ([IO.Path]::GetTempPath()) ([guid]::NewGuid().ToString()) +New-Item -ItemType Directory -Path $temporaryDirectory | Out-Null +$packagedAssembly = Join-Path $temporaryDirectory 'Microsoft.OpenApi.Hidi.dll' +$archive = $null +try { + $archive = [IO.Compression.ZipFile]::OpenRead((Resolve-Path -LiteralPath $PackagePath).Path) + $assemblies = @($archive.Entries | Where-Object { $_.Name -ieq 'Microsoft.OpenApi.Hidi.dll' }) + if ($assemblies.Count -ne 1 -or $assemblies[0].FullName -cne 'tools/net8.0/any/Microsoft.OpenApi.Hidi.dll') { + throw 'Expected exactly one Hidi DLL at tools/net8.0/any/Microsoft.OpenApi.Hidi.dll.' + } + [IO.Compression.ZipFileExtensions]::ExtractToFile($assemblies[0], $packagedAssembly) + + $stagingHash = (Get-FileHash -LiteralPath $SignedAssemblyPath -Algorithm SHA256).Hash + $packageHash = (Get-FileHash -LiteralPath $packagedAssembly -Algorithm SHA256).Hash + if ($packageHash -cne $stagingHash) { + throw "Packaged Hidi DLL differs from the signed staging DLL: $packageHash != $stagingHash" + } + foreach ($assembly in @($SignedAssemblyPath, $packagedAssembly)) { + $signature = Get-AuthenticodeSignature -LiteralPath $assembly + if ($signature.Status -ne 'Valid' -or + $signature.SignerCertificate.Subject -notmatch '(^|,\s*)O=Microsoft Corporation(,|$)') { + throw "Hidi DLL must have a valid Microsoft Corporation Authenticode signature: $assembly ($($signature.Status))" + } + } + Write-Host "Verified packaged Hidi DLL: valid Microsoft Authenticode signature; signed staging SHA256=$stagingHash" +} +finally { + if ($null -ne $archive) { $archive.Dispose() } + if (Test-Path -LiteralPath $packagedAssembly) { + Remove-Item -LiteralPath $packagedAssembly -Force + } + Remove-Item -LiteralPath $temporaryDirectory -Force +} diff --git a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj index b1cf4efa..ad64f08b 100644 --- a/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj +++ b/src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj @@ -68,4 +68,25 @@ + + + + + <_HidiAssemblyToReplace Include="@(ResolvedFileToPublish)" + Condition="'%(ResolvedFileToPublish.RelativePath)' == '$(TargetFileName)'"/> + + + + + + $(TargetFileName) + Always + + + + diff --git a/src/Microsoft.OpenApi.Hidi/readme.md b/src/Microsoft.OpenApi.Hidi/readme.md index a922a5ee..56282a8b 100644 --- a/src/Microsoft.OpenApi.Hidi/readme.md +++ b/src/Microsoft.OpenApi.Hidi/readme.md @@ -72,6 +72,21 @@ Local/CI builds use the public-only strong-name identity. Official release artifacts are signed in Azure Pipelines; private signing keys do not belong in this repository. The migration baseline 2.12.2 is already published. Destination NuGet, executable, and Docker publishing are disabled until source cutover. +Official tool packing passes `HidiSignedAssemblyPath` to replace the Hidi DLL +in the SDK's `ResolvedFileToPublish` items after `ComputeFilesToPublish`. +`PackAsTool` publishes the intermediate assembly from `obj`, so replacing only +the DLL in `bin` does not preserve its Authenticode signature. The opt-in target +uses the exact ESRP staging DLL without recompiling it; ordinary local packing +and Windows single-file publishing retain their default inputs. +Before NuGet signing, `scripts/verify-hidi-package-assembly.ps1` requires exactly +one DLL at `tools/net8.0/any/Microsoft.OpenApi.Hidi.dll`, verifies its SHA256 +matches the staging DLL, and requires valid Microsoft Corporation Authenticode +signatures on both. Missing, mismatched, unsigned, or unverifiable payloads fail +the build. A signed NuGet container alone is not assembly-signature evidence. +Local byte-provenance checks and mocked signature unit tests cannot establish +Microsoft ESRP signing readiness; that requires a publish-disabled official run +after the normally approved merge. + The standard Release Please config tracks Hidi as its own component, with a separate manifest version, project version, changelog, and `hidi-v2.*` tags. The first destination package release must advance beyond the baseline and use diff --git a/test/Microsoft.OpenApi.Hidi.Tests/verify-hidi-package-assembly.Tests.ps1 b/test/Microsoft.OpenApi.Hidi.Tests/verify-hidi-package-assembly.Tests.ps1 new file mode 100644 index 00000000..4dd2a0e7 --- /dev/null +++ b/test/Microsoft.OpenApi.Hidi.Tests/verify-hidi-package-assembly.Tests.ps1 @@ -0,0 +1,90 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +BeforeDiscovery { + $cases = @( + @{ Name = 'matching signed DLL before NuGet signing' } + @{ Name = 'different payload bytes'; Payload = 'unsigned-build'; ExpectedError = '*differs from the signed staging DLL*' } + @{ Name = 'missing tool DLL'; Entries = @(); ExpectedError = '*exactly one Hidi DLL*' } + @{ Name = 'wrong tool location'; Entries = @('lib/net8.0/Microsoft.OpenApi.Hidi.dll'); ExpectedError = '*exactly one Hidi DLL*' } + @{ Name = 'duplicate tool DLL'; Entries = @('tools/net8.0/any/Microsoft.OpenApi.Hidi.dll', 'tools/net8.0/any/Microsoft.OpenApi.Hidi.dll'); ExpectedError = '*exactly one Hidi DLL*' } + @{ Name = 'extra tool DLL elsewhere'; Entries = @('tools/net8.0/any/Microsoft.OpenApi.Hidi.dll', 'lib/net8.0/Microsoft.OpenApi.Hidi.dll'); ExpectedError = '*exactly one Hidi DLL*' } + @{ Name = 'wrong entry casing'; Entries = @('tools/net8.0/any/microsoft.openapi.hidi.dll'); ExpectedError = '*exactly one Hidi DLL*' } + @{ Name = 'unsigned package payload'; PackageStatus = 'NotSigned'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'damaged package signature'; PackageStatus = 'HashMismatch'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'unverifiable package signature'; PackageStatus = 'UnknownError'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'unsigned staging DLL'; StagingStatus = 'NotSigned'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'damaged staging signature'; StagingStatus = 'HashMismatch'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'non-Microsoft payload signer'; PackageSubject = 'CN=Example, O=Example'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'non-Microsoft staging signer'; StagingSubject = 'CN=Example, O=Example'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'misleading Microsoft signer name'; PackageSubject = 'CN=Microsoft Corporation, O=Example'; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'missing payload certificate'; MissingPackageCertificate = $true; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'missing staging certificate'; MissingStagingCertificate = $true; ExpectedError = '*valid Microsoft Corporation Authenticode signature*' } + @{ Name = 'missing package'; MissingPackage = $true; ExpectedError = '*Missing Hidi signing verification input*' } + @{ Name = 'missing staging DLL'; MissingStaging = $true; ExpectedError = '*Missing Hidi signing verification input*' } + @{ Name = 'invalid package archive'; InvalidArchive = $true; ExpectedError = '*' } + @{ Name = 'signature verification error'; SignatureError = $true; ExpectedError = '*Signature verification unavailable*' } + ) +} + +Describe 'Hidi package signed-assembly provenance' { + BeforeAll { + $helper = Join-Path $PSScriptRoot '..\..\scripts\verify-hidi-package-assembly.ps1' + } + + It '' -ForEach $cases { + $testCase = $_ + $directory = Join-Path $TestDrive ([guid]::NewGuid().ToString()) + New-Item -ItemType Directory -Path $directory | Out-Null + $package = Join-Path $directory 'Microsoft.OpenApi.Hidi.2.13.0.nupkg' + $staging = Join-Path $directory 'Microsoft.OpenApi.Hidi.dll' + if (-not $MissingStaging) { [IO.File]::WriteAllText($staging, 'signed-staging') } + if (-not $MissingPackage) { + if ($InvalidArchive) { + [IO.File]::WriteAllText($package, 'not-a-zip') + } + else { + $archive = [IO.Compression.ZipFile]::Open($package, 'Create') + try { + $entryNames = if ($testCase.ContainsKey('Entries')) { $Entries } else { @('tools/net8.0/any/Microsoft.OpenApi.Hidi.dll') } + foreach ($name in $entryNames) { + $writer = [IO.StreamWriter]::new($archive.CreateEntry($name).Open()) + try { $writer.Write($(if ($Payload) { $Payload } else { 'signed-staging' })) } + finally { $writer.Dispose() } + } + } + finally { $archive.Dispose() } + } + } + $inspectedPaths = [Collections.Generic.List[string]]::new() + Mock Get-AuthenticodeSignature { + param($LiteralPath) + $inspectedPaths.Add($LiteralPath) + if ($SignatureError) { throw 'Signature verification unavailable' } + $isStaging = $LiteralPath -eq $staging + $status = if ($isStaging -and $StagingStatus) { $StagingStatus } + elseif (-not $isStaging -and $PackageStatus) { $PackageStatus } + else { 'Valid' } + $subject = if ($isStaging -and $StagingSubject) { $StagingSubject } + elseif (-not $isStaging -and $PackageSubject) { $PackageSubject } + else { 'CN=Microsoft Corporation, O=Microsoft Corporation, C=US' } + $certificate = if (($isStaging -and $MissingStagingCertificate) -or + (-not $isStaging -and $MissingPackageCertificate)) { $null } + else { [pscustomobject]@{ Subject = $subject } } + [pscustomobject]@{ Status = $status; SignerCertificate = $certificate } + } + + if ($ExpectedError) { + { & $helper -PackagePath $package -SignedAssemblyPath $staging } | Should -Throw $ExpectedError + } + else { + $output = & $helper -PackagePath $package -SignedAssemblyPath $staging 6>&1 + $output | Should -Match "signed staging SHA256=$((Get-FileHash -LiteralPath $staging).Hash)" + Should -Invoke Get-AuthenticodeSignature -Times 2 -Exactly + } + foreach ($path in $inspectedPaths | Where-Object { $_ -ne $staging }) { + Test-Path -LiteralPath $path | Should -BeFalse + Test-Path -LiteralPath (Split-Path $path -Parent) | Should -BeFalse + } + } +} From 65e1d1f2f2cb622023f5345cbadfbff17fb65b3e Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Fri, 9 Oct 2026 16:57:52 -0700 Subject: [PATCH 2/2] fix(ci): authenticate repository metadata lookup Use the workflow-provided GitHub token only for the existing Data gatherer repository GET to avoid anonymous API rate limiting. Preserve request count, metadata output, workflow conditions and permissions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: ca73667e-f3d5-4518-b76d-1bf49dc7da23 --- .github/workflows/ci-cd.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index afa7c5c2..3fc94750 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -26,10 +26,12 @@ jobs: - name: Data gatherer id: data_gatherer shell: pwsh + env: + GITHUB_TOKEN: ${{ github.token }} run: | # Get default branch $repo = 'microsoft/OpenAPI.NET.OData' - $defaultBranch = Invoke-RestMethod -Method GET -Uri https://api.github.com/repos/$repo | Select-Object -ExpandProperty default_branch + $defaultBranch = Invoke-RestMethod -Method GET -Uri https://api.github.com/repos/$repo -Headers @{ Authorization = "Bearer $env:GITHUB_TOKEN" } | Select-Object -ExpandProperty default_branch Write-Output "default_branch=$(echo $defaultBranch) >> $GITHUB_OUTPUT" - name: Conditionals handler