Skip to content

Commit ea9e242

Browse files
Update dependencies from https://github.com/dotnet/arcade build 20260821.2
On relative base path root Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26257.101 -> To Version 11.0.0-beta.26421.2
1 parent 35f862b commit ea9e242

68 files changed

Lines changed: 2283 additions & 1923 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eng/Version.Details.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Dependencies>
33
<ToolsetDependencies>
4-
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="10.0.0-beta.26257.101">
5-
<Uri>https://github.com/dotnet/dotnet</Uri>
6-
<Sha>dc6e7082d768b79e69b16e8fd146a509dfa6130d</Sha>
4+
<Dependency Name="Microsoft.DotNet.Arcade.Sdk" Version="11.0.0-beta.26421.2">
5+
<Uri>https://github.com/dotnet/arcade</Uri>
6+
<Sha>51abc19095ae366ecb773826993966dc8a1063eb</Sha>
77
</Dependency>
88
</ToolsetDependencies>
99
</Dependencies>

eng/common/AGENTS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# `eng/common`
2+
3+
Files under `eng/common` come from [Arcade](https://github.com/dotnet/arcade).
4+
Edits in `eng/common` will be overwritten by automation unless the changes are made directly in the Arcade repository.
5+
For more information, see the [Arcade documentation](https://github.com/dotnet/arcade/tree/main/Documentation).

eng/common/Get-GitHubAppToken.ps1

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# Mints a short-lived GitHub App installation access token by signing a JWT
2+
# with a private key stored in Azure Key Vault (RSA, RS256). The signed JWT is
3+
# exchanged with the GitHub API for a token scoped to a single installation.
4+
#
5+
# Requirements:
6+
# - A GitHub App whose private key has been uploaded into Key Vault as an RSA
7+
# key (the PEM converted to a Key Vault *key*, NOT stored as a secret).
8+
# - The caller (the federated Azure service connection used to run this script)
9+
# must have the `Key Vault Crypto User` role (or at minimum the `Sign`
10+
# action) on that key.
11+
# - The App must be installed on the target organization/account
12+
# (`InstallationOwner`) with the permissions/repositories it needs.
13+
#
14+
# Installation tokens (ghs_*) are exempt from the enterprise classic-PAT
15+
# lifetime policy, which is why this replaces the long-lived PAT.
16+
17+
[CmdletBinding()]
18+
param(
19+
# Name of the Key Vault that holds the GitHub App's RSA signing key.
20+
[Parameter(Mandatory = $true)]
21+
[string] $KeyVaultName,
22+
23+
# Name of the RSA key inside the Key Vault (the App's private key).
24+
[Parameter(Mandatory = $true)]
25+
[string] $KeyName,
26+
27+
# The GitHub App's Client ID (the value to put in the `iss` JWT claim).
28+
[Parameter(Mandatory = $true)]
29+
[string] $AppClientId,
30+
31+
# Login of the organization or user account whose installation we should
32+
# mint the token for (e.g. `dotnet`, `microsoft`).
33+
[Parameter(Mandatory = $true)]
34+
[string] $InstallationOwner,
35+
36+
# Optional Azure DevOps pipeline variable name to set with the installation
37+
# token (marked as a secret). When not specified, the token is written to
38+
# stdout instead.
39+
[Parameter(Mandatory = $false)]
40+
[string] $OutputVariableName
41+
)
42+
43+
$ErrorActionPreference = 'Stop'
44+
$PSNativeCommandUseErrorActionPreference = $true
45+
46+
. $PSScriptRoot\pipeline-logging-functions.ps1
47+
48+
function ConvertTo-Base64Url([byte[]] $bytes) {
49+
return [Convert]::ToBase64String($bytes).TrimEnd('=').Replace('+', '-').Replace('/', '_')
50+
}
51+
52+
# Build JWT header and payload. Use [ordered] hashtables so JSON
53+
# serialization is deterministic.
54+
$jwtHeader = [ordered]@{
55+
alg = 'RS256'
56+
typ = 'JWT'
57+
}
58+
$now = [System.DateTimeOffset]::UtcNow
59+
$jwtPayload = [ordered]@{
60+
iat = $now.AddMinutes(-1).ToUnixTimeSeconds()
61+
exp = $now.AddMinutes(5).ToUnixTimeSeconds()
62+
iss = $AppClientId
63+
}
64+
65+
$headerEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtHeader | ConvertTo-Json -Compress)))
66+
$payloadEncoded = ConvertTo-Base64Url ([System.Text.Encoding]::UTF8.GetBytes(($jwtPayload | ConvertTo-Json -Compress)))
67+
$signingInput = "$headerEncoded.$payloadEncoded"
68+
69+
# Key Vault `sign` expects the *digest* (base64), not the raw bytes.
70+
$sha256 = [System.Security.Cryptography.SHA256]::Create()
71+
$digestBytes = $sha256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($signingInput))
72+
$digestBase64 = [Convert]::ToBase64String($digestBytes)
73+
74+
Write-Host "Signing JWT with key '$KeyName' in vault '$KeyVaultName'..."
75+
$previousNativeCommandErrorPreference = $PSNativeCommandUseErrorActionPreference
76+
try {
77+
# Azure CLI can emit non-fatal Python warnings to stderr even when signing succeeds.
78+
# Use the exit code to determine success for this invocation.
79+
$PSNativeCommandUseErrorActionPreference = $false
80+
$signatureBase64 = az keyvault key sign `
81+
--vault-name $KeyVaultName `
82+
--name $KeyName `
83+
--algorithm RS256 `
84+
--digest $digestBase64 `
85+
--query signature `
86+
--output tsv `
87+
--only-show-errors
88+
$signExitCode = $LASTEXITCODE
89+
}
90+
catch {
91+
Write-PipelineTelemetryError -Category 'Build' -Message "Failed to sign the JWT via Key Vault (key '$KeyName', vault '$KeyVaultName'): $_. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key."
92+
exit 1
93+
}
94+
finally {
95+
$PSNativeCommandUseErrorActionPreference = $previousNativeCommandErrorPreference
96+
}
97+
if ($signExitCode -ne 0 -or [string]::IsNullOrWhiteSpace($signatureBase64)) {
98+
Write-PipelineTelemetryError -Category 'Build' -Message "'az keyvault key sign' exited with code $signExitCode for key '$KeyName' in vault '$KeyVaultName'. Verify the service connection identity has the 'Key Vault Crypto User' role (Sign action) on the key."
99+
exit 1
100+
}
101+
$signatureUrl = $signatureBase64.Trim().TrimEnd('=').Replace('+', '-').Replace('/', '_')
102+
$jwt = "$signingInput.$signatureUrl"
103+
104+
$headers = @{
105+
Authorization = "Bearer $jwt"
106+
'X-GitHub-Api-Version' = '2022-11-28'
107+
Accept = 'application/vnd.github+json'
108+
'User-Agent' = 'dotnet-arcade-onelocbuild'
109+
}
110+
111+
Write-Host "Looking up installation for '$InstallationOwner'..."
112+
try {
113+
$installations = @()
114+
$page = 1
115+
do {
116+
# Assign the response before wrapping it in @(). PowerShell otherwise
117+
# preserves a top-level JSON array as one nested pipeline object.
118+
$pageResponse = Invoke-RestMethod `
119+
-Uri "https://api.github.com/app/installations?per_page=100&page=$page" `
120+
-Headers $headers `
121+
-Method Get
122+
$pageInstallations = @($pageResponse)
123+
$installations += $pageInstallations
124+
$page++
125+
} while ($pageInstallations.Count -eq 100)
126+
}
127+
catch {
128+
Write-PipelineTelemetryError -Category 'Build' -Message "Failed to list GitHub App installations: $_. The signed JWT may be invalid or the App's Client ID ('$AppClientId') may be incorrect."
129+
exit 1
130+
}
131+
$matchingInstallations = @($installations | Where-Object { $_.account.login -ieq $InstallationOwner })
132+
if ($matchingInstallations.Count -eq 0) {
133+
$found = ($installations | ForEach-Object { $_.account.login }) -join ', '
134+
Write-PipelineTelemetryError -Category 'Build' -Message "No installation found for '$InstallationOwner'. App is installed on: $found"
135+
exit 1
136+
}
137+
if ($matchingInstallations.Count -ne 1) {
138+
$matchingIds = ($matchingInstallations | ForEach-Object { $_.id }) -join ', '
139+
Write-PipelineTelemetryError -Category 'Build' -Message "Found multiple installations for '$InstallationOwner': $matchingIds"
140+
exit 1
141+
}
142+
$installation = $matchingInstallations[0]
143+
Write-Host "Using installation $($installation.id) for '$($installation.account.login)'."
144+
145+
try {
146+
$tokenResponse = Invoke-RestMethod `
147+
-Uri "https://api.github.com/app/installations/$($installation.id)/access_tokens" `
148+
-Headers $headers `
149+
-Method Post `
150+
-ContentType 'application/json'
151+
}
152+
catch {
153+
Write-PipelineTelemetryError -Category 'Build' -Message "Failed to mint an installation access token for '$InstallationOwner' (installation $($installation.id)): $_"
154+
exit 1
155+
}
156+
157+
Write-Host "Got installation token for '$InstallationOwner' (expires $($tokenResponse.expires_at))."
158+
if ($OutputVariableName) {
159+
Write-Host "Setting pipeline variable '$OutputVariableName'."
160+
Write-Host "##vso[task.setvariable variable=$OutputVariableName;issecret=true]$($tokenResponse.token)"
161+
}
162+
else {
163+
Write-Host $tokenResponse.token -ForegroundColor Green
164+
}

eng/common/SetupNugetSources.ps1

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# This script adds internal feeds required to build commits that depend on internal package sources. For instance,
2-
# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly,
3-
# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present.
4-
# In addition, this script also enables disabled internal Maestro (darc-int*) feeds.
2+
# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. In addition also enables
3+
# disabled internal Maestro (darc-int*) feeds.
54
#
65
# Optionally, this script also adds a credential entry for each of the internal feeds if supplied.
76
#
@@ -12,9 +11,13 @@
1211
# condition: eq(variables['Agent.OS'], 'Windows_NT')
1312
# inputs:
1413
# filePath: $(System.DefaultWorkingDirectory)/eng/common/SetupNugetSources.ps1
15-
# arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config -Password $Env:Token
14+
# arguments: -ConfigFile $(System.DefaultWorkingDirectory)/NuGet.config
1615
# env:
17-
# Token: $(dn-bot-dnceng-artifact-feeds-rw)
16+
# Token: $(InternalFeedToken)
17+
#
18+
# Note: This logic is abstracted into enable-internal-sources.yml, which uses
19+
# NuGetAuthenticate or a WIF-backed service connection. Prefer that template
20+
# over calling this script directly.
1821
#
1922
# Note that the NuGetAuthenticate task should be called after SetupNugetSources.
2023
# This ensures that:
@@ -26,24 +29,31 @@
2629
[CmdletBinding()]
2730
param (
2831
[Parameter(Mandatory = $true)][string]$ConfigFile,
29-
$Password
32+
# Keep the legacy name as an alias while callers migrate secrets to the Token environment variable.
33+
[Alias("Password")]$Credential
3034
)
3135

3236
$ErrorActionPreference = "Stop"
3337
Set-StrictMode -Version 2.0
3438
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
39+
$feedCredential = if ($env:Token) { $env:Token } else { $Credential }
40+
41+
# This script only consumes helper functions from tools.ps1 to configure NuGet feeds.
42+
# Skip importing configure-toolset.ps1 so that repo-specific toolset setup (e.g. acquiring
43+
# a bootstrap SDK) is not triggered as a side effect of feed configuration.
44+
$disableConfigureToolsetImport = $true
3545

3646
. $PSScriptRoot\tools.ps1
3747

3848
# Adds or enables the package source with the given name
39-
function AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) {
40-
if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName)) {
41-
AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $userName -pwd $Password
49+
function AddOrEnablePackageSource($sources, $disabledPackageSources, $SourceName, $SourceEndPoint, $creds, $Username, $credential) {
50+
if ($disabledPackageSources -eq $null -or -not (EnableInternalPackageSource -DisabledPackageSources $disabledPackageSources -Creds $creds -PackageSourceName $SourceName -Credential $credential)) {
51+
AddPackageSource -Sources $sources -SourceName $SourceName -SourceEndPoint $SourceEndPoint -Creds $creds -Username $Username -credential $credential
4252
}
4353
}
4454

4555
# Add source entry to PackageSources
46-
function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) {
56+
function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $credential) {
4757
$packageSource = $sources.SelectSingleNode("add[@key='$SourceName']")
4858

4959
if ($packageSource -eq $null)
@@ -59,13 +69,13 @@ function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Usern
5969
Write-Host "Package source $SourceName already present and enabled."
6070
}
6171

62-
AddCredential -Creds $creds -Source $SourceName -Username $Username -pwd $pwd
72+
AddCredential -Creds $creds -Source $SourceName -Username $Username -credential $credential
6373
}
6474

6575
# Add a credential node for the specified source
66-
function AddCredential($creds, $source, $username, $pwd) {
76+
function AddCredential($creds, $source, $username, $credential) {
6777
# If no cred supplied, don't do anything.
68-
if (!$pwd) {
78+
if (!$credential) {
6979
return;
7080
}
7181

@@ -100,27 +110,27 @@ function AddCredential($creds, $source, $username, $pwd) {
100110
$sourceElement.AppendChild($passwordElement) | Out-Null
101111
}
102112

103-
$passwordElement.SetAttribute("value", $pwd)
113+
$passwordElement.SetAttribute("value", $credential)
104114
}
105115

106116
# Enable all darc-int package sources.
107-
function EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds) {
117+
function EnableMaestroInternalPackageSources($DisabledPackageSources, $Creds, $Credential) {
108118
$maestroInternalSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]")
109119
ForEach ($DisabledPackageSource in $maestroInternalSources) {
110-
EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key
120+
EnableInternalPackageSource -DisabledPackageSources $DisabledPackageSources -Creds $Creds -PackageSourceName $DisabledPackageSource.key -Credential $Credential
111121
}
112122
}
113123

114124
# Enables an internal package source by name, if found. Returns true if the package source was found and enabled, false otherwise.
115-
function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName) {
125+
function EnableInternalPackageSource($DisabledPackageSources, $Creds, $PackageSourceName, $Credential) {
116126
$DisabledPackageSource = $DisabledPackageSources.SelectSingleNode("add[@key='$PackageSourceName']")
117127
if ($DisabledPackageSource) {
118128
Write-Host "Enabling internal source '$($DisabledPackageSource.key)'."
119129

120130
# Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries
121131
$DisabledPackageSources.RemoveChild($DisabledPackageSource)
122132

123-
AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -pwd $Password
133+
AddCredential -Creds $creds -Source $DisabledPackageSource.Key -Username $userName -credential $credential
124134
return $true
125135
}
126136
return $false
@@ -145,7 +155,7 @@ if ($sources -eq $null) {
145155

146156
$creds = $null
147157
$feedSuffix = "v3/index.json"
148-
if ($Password) {
158+
if ($feedCredential) {
149159
$feedSuffix = "v2"
150160
# Looks for a <PackageSourceCredentials> node. Create it if none is found.
151161
$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials")
@@ -161,29 +171,17 @@ $userName = "dn-bot"
161171
$disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources")
162172
if ($disabledSources -ne $null) {
163173
Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node"
164-
EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds
174+
EnableMaestroInternalPackageSources -DisabledPackageSources $disabledSources -Creds $creds -Credential $feedCredential
165175
}
166-
$dotnetVersions = @('5','6','7','8','9','10')
176+
$dotnetVersions = @('5','6','7','8','9','10','11')
167177

168178
foreach ($dotnetVersion in $dotnetVersions) {
169179
$feedPrefix = "dotnet" + $dotnetVersion;
170180
$dotnetSource = $sources.SelectSingleNode("add[@key='$feedPrefix']")
171181
if ($dotnetSource -ne $null) {
172-
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
173-
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
182+
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -credential $feedCredential
183+
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/$feedSuffix" -Creds $creds -Username $userName -credential $feedCredential
174184
}
175185
}
176186

177-
# Check for dotnet-eng and add dotnet-eng-internal if present
178-
$dotnetEngSource = $sources.SelectSingleNode("add[@key='dotnet-eng']")
179-
if ($dotnetEngSource -ne $null) {
180-
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-eng-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
181-
}
182-
183-
# Check for dotnet-tools and add dotnet-tools-internal if present
184-
$dotnetToolsSource = $sources.SelectSingleNode("add[@key='dotnet-tools']")
185-
if ($dotnetToolsSource -ne $null) {
186-
AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-tools-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
187-
}
188-
189187
$doc.Save($filename)

0 commit comments

Comments
 (0)