From 0990ddc642dd853ae629cddf3eb707e4d2d1f46b Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:43:50 -0700 Subject: [PATCH 1/3] Fix executable permissions for pwsh and createdump The tarball staging path used `Copy-Item`, which on *nix doesn't preserve the source file mode, so `pwsh` ended up 644 in the `.tar.gz`. The Debian, RPM, and macOS PKG paths explicitly `chmod` everything to 644 and then bump `pwsh` back to 755, which silently demoted `createdump` (the .NET helper that produces crash minidumps) along with it. Now we `chmod 755` both executables in all package staging paths, guarded by `Test-Path` since fxdependent builds don't bundle `createdump`. Also added regression tests which check the permissions of `pwsh` inside the Linux and macOS tarballs before we upload them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/linux-package-build.yml | 7 ++++++ .pipelines/templates/mac-package-build.yml | 4 ++++ tools/packaging/packaging.psm1 | 24 +++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index bb7ed723f42..e3f54ec4401 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -192,6 +192,13 @@ jobs: $pkgPath = Get-ChildItem -Path $(Pipeline.Workspace) -Filter $pkgFilter -Recurse -File | Select-Object -ExpandProperty FullName Write-Verbose -Verbose "pkgPath: $pkgPath" Copy-Item -Path $pkgPath -Destination '$(ob_outputDirectory)' -Force -Verbose + + if ($pkgPath -like '*.tar.gz') { + $entry = & tar -tzvf $pkgPath | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $pkgPath : $entry" + } + } displayName: 'Copy artifacts to output directory' env: __DOTNET_RUNTIME_FEED_KEY: $(RUNTIME_SOURCEFEED_KEY) diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 154cb6c0257..416ee9f40cb 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -162,6 +162,10 @@ jobs: foreach($t in $tarPkgPath) { $file = $t.FullName + $entry = & tar -tzvf $file | Where-Object { $_ -match '\spwsh$' } | Select-Object -First 1 + if ($entry -notmatch '^-..x') { + throw "pwsh is not executable in $file : $entry" + } Write-Verbose -verbose "Uploading $file to macos-pkgs" Write-Host "##vso[artifact.upload containerfolder=macos-pkgs;artifactname=macos-pkgs]$file" } diff --git a/tools/packaging/packaging.psm1 b/tools/packaging/packaging.psm1 index a551a483c8d..4c0c5421ead 100644 --- a/tools/packaging/packaging.psm1 +++ b/tools/packaging/packaging.psm1 @@ -776,6 +776,18 @@ function New-TarballPackage { $Staging = "$PSScriptRoot/staging" New-StagingFolder -StagingPath $Staging -PackageSourcePath $PackageSourcePath -R2RVerification $R2RVerification + # Ensure PowerShell executable has correct permissions in tarball + $pwshInStaging = Join-Path $Staging 'pwsh' + if (Test-Path -LiteralPath $pwshInStaging) { + Start-NativeExecution { chmod 755 $pwshInStaging } + } + + # Included .NET executable for producing crash dumps + $createdumpInStaging = Join-Path $Staging 'createdump' + if (Test-Path -LiteralPath $createdumpInStaging) { + Start-NativeExecution { chmod 755 $createdumpInStaging } + } + if (Get-Command -Name tar -CommandType Application -ErrorAction Ignore) { if ($Force -or $PSCmdlet.ShouldProcess("Create tarball package")) { $options = "-czf" @@ -1194,7 +1206,11 @@ function New-UnixPackage { find $Staging -type f | xargs chmod 644 chmod 644 $ManGzipInfo.GzipFile # refers to executable, does not vary by channel - chmod 755 "$Staging/pwsh" #only the executable file should be granted the execution permission + chmod 755 "$Staging/pwsh" # only the executable file should be granted the execution permission + # Included .NET executable for producing crash dumps + if (Test-Path "$Staging/createdump") { + chmod 755 "$Staging/createdump" + } } } @@ -1874,6 +1890,12 @@ $(if ($extendedDescription) { $extendedDescription + "`n" }) Start-NativeExecution { chmod 755 $pwshPath } } + # Included .NET executable for producing crash dumps + $createdumpPath = "$targetPath/createdump" + if (Test-Path $createdumpPath) { + Start-NativeExecution { chmod 755 $createdumpPath } + } + # Calculate md5sums for all files in data directory (excluding symlinks) $md5sumsFile = Join-Path $debianDir "md5sums" $md5Content = "" From 2237859aa8dfec30a7cfd2e48ec886b23db79946 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 24 Apr 2026 17:15:06 -0700 Subject: [PATCH 2/3] Move ESRP key codes into the `certificate_logical_to_actual` variable group MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `CP-…` key codes used for ESRP signing are now set from ADO via the `certificate_logical_to_actual` variable group. The templates reference the following variables instead of literal codes: - `$(authenticode_cert_id)` - `$(authenticode_test_cert_id)` - `$(nuget_cert_id)` - `$(apple_cert_id)` - `$(pgp_linux_cert_id)` - `$(pgp_release_cert_id)` `nupkg.yml`, `mac-package-build.yml`, and `linux-package-build.yml` pick up the new group import. `linux-package-build.yml` also now selects the PGP signing profile based on whether `jobName` starts with `mariner`, so `PowerShell-Packages-Stages.yml` no longer threads a `signingProfile` parameter in for the two Mariner jobs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .pipelines/templates/linux-package-build.yml | 14 +++++++++++--- .pipelines/templates/mac-package-build.yml | 6 ++++-- .pipelines/templates/mac.yml | 2 +- .pipelines/templates/nupkg.yml | 5 +++-- .pipelines/templates/shouldSign.yml | 6 +++--- .../stages/PowerShell-Packages-Stages.yml | 2 -- .pipelines/templates/windows-hosted-build.yml | 2 +- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index e3f54ec4401..cb940e8a2b4 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -3,7 +3,6 @@ parameters: signedeDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb' - signingProfile: 'CP-450779-pgpdetached' jobs: - job: ${{ parameters.jobName }} @@ -20,6 +19,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -34,8 +34,16 @@ jobs: value: $(Build.SourcesDirectory)/PowerShell/.config/tsaoptions.json - name: ob_sdl_credscan_suppressionsFile value: $(Build.SourcesDirectory)/PowerShell/.config/suppress.json - - name: SigningProfile - value: ${{ parameters.signingProfile }} + # PGP signing profile selection: Mariner (Azure Linux) packages ship through + # a different distribution channel and must be signed with the Mariner release + # key; all other Linux packages use the standard PowerShell Linux key. Both + # key codes come from the `certificate_logical_to_actual` variable group. + - ${{ if startsWith(parameters.jobName, 'mariner') }}: + - name: SigningProfile + value: $(pgp_release_cert_id) + - ${{ else }}: + - name: SigningProfile + value: $(pgp_linux_cert_id) steps: - checkout: self diff --git a/.pipelines/templates/mac-package-build.yml b/.pipelines/templates/mac-package-build.yml index 416ee9f40cb..89dab90aa04 100644 --- a/.pipelines/templates/mac-package-build.yml +++ b/.pipelines/templates/mac-package-build.yml @@ -22,6 +22,7 @@ jobs: - name: skipNugetSecurityAnalysis value: true - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -187,6 +188,7 @@ jobs: type: windows variables: + - group: certificate_logical_to_actual - name: ob_outputDirectory value: '$(Build.ArtifactStagingDirectory)/ONEBRANCH_ARTIFACT' - name: ob_sdl_binskim_enabled @@ -234,7 +236,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", @@ -253,7 +255,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppNotarize", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/mac.yml b/.pipelines/templates/mac.yml index b22149d5e46..cd492994617 100644 --- a/.pipelines/templates/mac.yml +++ b/.pipelines/templates/mac.yml @@ -168,7 +168,7 @@ jobs: inline_operation: | [ { - "KeyCode": "CP-401337-Apple", + "KeyCode": "$(apple_cert_id)", "OperationCode": "MacAppDeveloperSign", "ToolName": "sign", "ToolVersion": "1.0", diff --git a/.pipelines/templates/nupkg.yml b/.pipelines/templates/nupkg.yml index c296aadc242..043c0b1f75c 100644 --- a/.pipelines/templates/nupkg.yml +++ b/.pipelines/templates/nupkg.yml @@ -23,6 +23,7 @@ jobs: - group: mscodehub-feed-read-general - group: mscodehub-feed-read-akv - group: DotNetPrivateBuildAccess + - group: certificate_logical_to_actual steps: - checkout: self @@ -208,7 +209,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\nupkg' @@ -268,7 +269,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(Pipeline.Workspace)\globaltools' diff --git a/.pipelines/templates/shouldSign.yml b/.pipelines/templates/shouldSign.yml index 551297f3aaa..f3701acbc97 100644 --- a/.pipelines/templates/shouldSign.yml +++ b/.pipelines/templates/shouldSign.yml @@ -6,11 +6,11 @@ parameters: steps: - powershell: | $shouldSign = $true - $authenticodeCert = 'CP-230012' - $msixCert = 'CP-230012' + $authenticodeCert = '$(authenticode_cert_id)' + $msixCert = '$(authenticode_cert_id)' if($env:IS_DAILY -eq 'true') { - $authenticodeCert = 'CP-460906' + $authenticodeCert = '$(authenticode_test_cert_id)' } if($env:SKIP_SIGNING -eq 'Yes') { diff --git a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml index b1efb2a8097..b88a8ec94fc 100644 --- a/.pipelines/templates/stages/PowerShell-Packages-Stages.yml +++ b/.pipelines/templates/stages/PowerShell-Packages-Stages.yml @@ -93,7 +93,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_x64_mariner' packageType: rpm-fxdependent #mariner-x64 jobName: mariner_x64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: @@ -101,7 +100,6 @@ stages: signedDrop: 'drop_linux_sign_linux_fxd_arm64_mariner' packageType: rpm-fxdependent-arm64 #mariner-arm64 jobName: mariner_arm64 - signingProfile: 'CP-459159-pgpdetached' - template: /.pipelines/templates/linux-package-build.yml@self parameters: diff --git a/.pipelines/templates/windows-hosted-build.yml b/.pipelines/templates/windows-hosted-build.yml index a2933e90817..0f7c1f8fb2e 100644 --- a/.pipelines/templates/windows-hosted-build.yml +++ b/.pipelines/templates/windows-hosted-build.yml @@ -315,7 +315,7 @@ jobs: displayName: Sign nupkg files inputs: command: 'sign' - cp_code: 'CP-401405' + cp_code: '$(nuget_cert_id)' files_to_sign: '**\*.nupkg' search_root: '$(ob_outputDirectory)\globaltool' condition: and(succeeded(), eq(variables['Architecture'], 'fxdependent')) From 47e0c13eb84bea932bde01d123d59f6f063ed2d7 Mon Sep 17 00:00:00 2001 From: Andy Jordan <2226434+andyleejordan@users.noreply.github.com> Date: Fri, 1 May 2026 13:56:07 -0700 Subject: [PATCH 3/3] Correct typo in package parameters It's been this way for a couple years which means we've been passing...something else? --- .pipelines/templates/linux-package-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/linux-package-build.yml b/.pipelines/templates/linux-package-build.yml index cb940e8a2b4..a832268712c 100644 --- a/.pipelines/templates/linux-package-build.yml +++ b/.pipelines/templates/linux-package-build.yml @@ -1,6 +1,6 @@ parameters: unsignedDrop: 'drop_linux_build_linux_x64' - signedeDrop: 'drop_linux_sign_linux_x64' + signedDrop: 'drop_linux_sign_linux_x64' packageType: deb jobName: 'deb'