From a3ee8883d445d390a8bce76ddc38ddd502226daf Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 09:43:44 +0300 Subject: [PATCH 1/7] build: pin workspace Rust toolchain to 1.95.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- rust-toolchain.toml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000..4f974605d --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +# Keep workspace builds and diagnostics reproducible across users. +channel = "1.95.0" From eb9470b44b42caabbae289e3a4f26a76e48a4441 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 09:45:46 +0300 Subject: [PATCH 2/7] build: align workspace toolchain with RUST_LATEST Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- constants.env | 2 +- rust-toolchain.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/constants.env b/constants.env index bd4b66948..1aa672e9c 100644 --- a/constants.env +++ b/constants.env @@ -7,7 +7,7 @@ # used for testing, ensures the MSRV promise is kept; must match Cargo.toml [workspace.package].rust-version RUST_MSRV=1.93.1 -# used for static analysis & mutation testing +# used for static analysis & mutation testing; must match rust-toolchain.toml RUST_LATEST=1.96.1 # used for coverage and extended analysis; update on a regular basis RUST_NIGHTLY=nightly-2026-05-30 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 4f974605d..9955aaa92 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -# Keep workspace builds and diagnostics reproducible across users. -channel = "1.95.0" +# Must match RUST_LATEST in constants.env so local and CI diagnostics use the same compiler. +channel = "1.96.1" From 333368c8be98e8a7b613ca0ed243b2cfcb31fc31 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 10:02:05 +0300 Subject: [PATCH 3/7] fix: synchronize automated Rust toolchain updates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- README.md | 2 +- rust-toolchain.toml | 3 ++ scripts/update_rust_toolchain.ps1 | 47 +++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 215727e71..34970ddda 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,7 @@ We strive to deliver high-quality code and as such, we've put in place a number We pin the version of the tools we use in CI to ensure hermetic builds as much as possible. We routinely update the versions of everything to stay up to date using three scripts: -- `scripts/update_rust_toolchain.ps1` which updates the version of the Rust toolchain in the `constants.env` file. +- `scripts/update_rust_toolchain.ps1` which updates the Rust toolchain versions in `constants.env` and `rust-toolchain.toml`. - `scripts/update_tool_versions.ps1` which updates the version of tools in the `constants.env` file. - `scripts/update_action_versions.ps1` which updates the version of GitHub actions in the various files in `.github/workflows`. diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9955aaa92..79c3c5e56 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + [toolchain] # Must match RUST_LATEST in constants.env so local and CI diagnostics use the same compiler. channel = "1.96.1" diff --git a/scripts/update_rust_toolchain.ps1 b/scripts/update_rust_toolchain.ps1 index d87a7f045..7a3043be2 100644 --- a/scripts/update_rust_toolchain.ps1 +++ b/scripts/update_rust_toolchain.ps1 @@ -4,17 +4,20 @@ <# .SYNOPSIS - Updates Rust toolchain versions in constants.env. + Updates Rust toolchain versions in constants.env and rust-toolchain.toml. .DESCRIPTION This script automatically updates the Rust toolchain configuration to the latest versions: - - Queries the latest stable Rust version and updates RUST_LATEST in constants.env + - Queries the latest stable Rust version and updates RUST_LATEST in constants.env and rust-toolchain.toml - Calculates yesterday's nightly build date and updates RUST_NIGHTLY in constants.env - Fetches the latest cargo-check-external-types release to determine the tested nightly version for RUST_NIGHTLY_EXTERNAL_TYPES .PARAMETER ConstantsFile Path to the constants.env file. Defaults to ../constants.env relative to script location. +.PARAMETER ToolchainFile + Path to the rust-toolchain.toml file. Defaults to ../rust-toolchain.toml relative to script location. + .PARAMETER DryRun If specified, shows what would be updated without actually modifying the files. @@ -27,10 +30,12 @@ param( [string]$ConstantsFile = (Join-Path $PSScriptRoot ".." "constants.env"), + [string]$ToolchainFile = (Join-Path $PSScriptRoot ".." "rust-toolchain.toml"), [switch]$DryRun ) $ErrorActionPreference = "Stop" +$ToolchainChannelPattern = '(?m)^(channel[ \t]*=[ \t]*)"([^"]*)"' function Get-LatestStableRustVersion { <# @@ -146,6 +151,18 @@ function Update-ConstantsEnv { return $content } +function Update-RustToolchain { + param( + [string]$FilePath, + [string]$Version + ) + $content = Get-Content $FilePath -Raw + $content = Get-Content $FilePath -Raw + $replacement = '${1}"' + $Version + '"' + + return $content -replace $ToolchainChannelPattern, $replacement +} + # Main script execution Write-Host "Fetching latest Rust versions..." Write-Host "" @@ -156,6 +173,11 @@ if (-not (Test-Path $ConstantsFile)) { exit 1 } +if (-not (Test-Path $ToolchainFile)) { + Write-Host "Error: Rust toolchain file not found at '$ToolchainFile'" + exit 1 +} + # Get current versions $constantsContent = Get-Content $ConstantsFile @@ -163,6 +185,16 @@ $currentRustLatest = ($constantsContent | Select-String '^RUST_LATEST=(.+)$').Ma $currentRustNightly = ($constantsContent | Select-String '^RUST_NIGHTLY=(.+)$').Matches.Groups[1].Value $currentRustNightlyExternal = ($constantsContent | Select-String '^RUST_NIGHTLY_EXTERNAL_TYPES=(.+)$').Matches.Groups[1].Value +$toolchainContent = Get-Content $ToolchainFile -Raw +$toolchainMatch = [regex]::Match($toolchainContent, $ToolchainChannelPattern) + +if (-not $toolchainMatch.Success) { + Write-Host "Error: Rust toolchain channel not found in '$ToolchainFile'" + exit 1 +} + +$currentToolchain = $toolchainMatch.Groups[2].Value + # Fetch new versions $stableResult = Get-LatestStableRustVersion @@ -177,12 +209,14 @@ $externalTypesResult = Get-ExternalTypesTestedNightly Write-Host "Current versions:" Write-Host " RUST_LATEST : $currentRustLatest" +Write-Host " rust-toolchain.toml channel: $currentToolchain" Write-Host " RUST_NIGHTLY : $currentRustNightly" Write-Host " RUST_NIGHTLY_EXTERNAL_TYPES: $currentRustNightlyExternal" Write-Host "" Write-Host "New versions:" Write-Host " RUST_LATEST : $newStableVersion" +Write-Host " rust-toolchain.toml channel: $newStableVersion" Write-Host " RUST_NIGHTLY : $yesterdayNightly" if ($externalTypesResult.Success) { @@ -210,7 +244,9 @@ if ($externalTypesResult.Success -and $currentRustNightlyExternal -ne $externalT $constantsUpdates["RUST_NIGHTLY_EXTERNAL_TYPES"] = $externalTypesResult.Version } -if ($constantsUpdates.Count -eq 0) { +$toolchainNeedsUpdate = $currentToolchain -ne $newStableVersion + +if ($constantsUpdates.Count -eq 0 -and -not $toolchainNeedsUpdate) { exit 0 } @@ -223,3 +259,8 @@ if ($constantsUpdates.Count -gt 0) { $newConstantsContent = Update-ConstantsEnv -FilePath $ConstantsFile -Updates $constantsUpdates Set-Content -Path $ConstantsFile -Value $newConstantsContent -NoNewline } + +if ($toolchainNeedsUpdate) { + $newToolchainContent = Update-RustToolchain -FilePath $ToolchainFile -Version $newStableVersion + Set-Content -Path $ToolchainFile -Value $newToolchainContent -NoNewline +} From b7649afe71a1c1426d32f37e7b5c3d8ee4e3126f Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 10:07:27 +0300 Subject: [PATCH 4/7] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- scripts/update_rust_toolchain.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/update_rust_toolchain.ps1 b/scripts/update_rust_toolchain.ps1 index 7a3043be2..de731d0e3 100644 --- a/scripts/update_rust_toolchain.ps1 +++ b/scripts/update_rust_toolchain.ps1 @@ -157,7 +157,6 @@ function Update-RustToolchain { [string]$Version ) $content = Get-Content $FilePath -Raw - $content = Get-Content $FilePath -Raw $replacement = '${1}"' + $Version + '"' return $content -replace $ToolchainChannelPattern, $replacement From b19e5190f7cc5cd379762b6e95ee094367d4391b Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 13:03:20 +0300 Subject: [PATCH 5/7] fix: align public and internal Rust toolchains Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- README.md | 3 +- constants.env | 5 +- rust-toolchain.toml | 5 +- scripts/update_rust_toolchain.ps1 | 100 ++++++++++++++++++++++++------ 4 files changed, 89 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 34970ddda..3a7605b2e 100644 --- a/README.md +++ b/README.md @@ -242,7 +242,8 @@ We strive to deliver high-quality code and as such, we've put in place a number We pin the version of the tools we use in CI to ensure hermetic builds as much as possible. We routinely update the versions of everything to stay up to date using three scripts: -- `scripts/update_rust_toolchain.ps1` which updates the Rust toolchain versions in `constants.env` and `rust-toolchain.toml`. +- `scripts/update_rust_toolchain.ps1` which requires an internal `ox-sdk` checkout and updates the public + Rust toolchain versions after the internal release toolchain has been selected. - `scripts/update_tool_versions.ps1` which updates the version of tools in the `constants.env` file. - `scripts/update_action_versions.ps1` which updates the version of GitHub actions in the various files in `.github/workflows`. diff --git a/constants.env b/constants.env index 1aa672e9c..31c65ff49 100644 --- a/constants.env +++ b/constants.env @@ -7,8 +7,9 @@ # used for testing, ensures the MSRV promise is kept; must match Cargo.toml [workspace.package].rust-version RUST_MSRV=1.93.1 -# used for static analysis & mutation testing; must match rust-toolchain.toml -RUST_LATEST=1.96.1 +# used for static analysis & mutation testing; must match rust-toolchain.toml; its major/minor must match: +# https://o365exchange.visualstudio.com/O365%20Core/_git/ox-sdk?path=/.pipelines/variables/publish.yml +RUST_LATEST=1.95.0 # used for coverage and extended analysis; update on a regular basis RUST_NIGHTLY=nightly-2026-05-30 # used for external type exposure checks; update alongside updates to cargo-check-external-types diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 79c3c5e56..1b8b46e01 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,6 @@ # Licensed under the MIT License. [toolchain] -# Must match RUST_LATEST in constants.env so local and CI diagnostics use the same compiler. -channel = "1.96.1" +# Must match RUST_LATEST in constants.env. Its major/minor must match MSRUSTUP_TOOLCHAIN in: +# https://o365exchange.visualstudio.com/O365%20Core/_git/ox-sdk?path=/.pipelines/variables/publish.yml +channel = "1.95.0" diff --git a/scripts/update_rust_toolchain.ps1 b/scripts/update_rust_toolchain.ps1 index de731d0e3..06c326219 100644 --- a/scripts/update_rust_toolchain.ps1 +++ b/scripts/update_rust_toolchain.ps1 @@ -8,7 +8,7 @@ .DESCRIPTION This script automatically updates the Rust toolchain configuration to the latest versions: - - Queries the latest stable Rust version and updates RUST_LATEST in constants.env and rust-toolchain.toml + - Reads the internal stable Rust minor, then updates RUST_LATEST and rust-toolchain.toml to its latest upstream patch - Calculates yesterday's nightly build date and updates RUST_NIGHTLY in constants.env - Fetches the latest cargo-check-external-types release to determine the tested nightly version for RUST_NIGHTLY_EXTERNAL_TYPES @@ -18,19 +18,25 @@ .PARAMETER ToolchainFile Path to the rust-toolchain.toml file. Defaults to ../rust-toolchain.toml relative to script location. +.PARAMETER InternalToolchainFile + Path to ox-sdk's .pipelines/variables/publish.yml file. Update its MSRUSTUP_TOOLCHAIN values first; + this script then aligns the public toolchain files to the latest upstream patch in that Rust minor. + .PARAMETER DryRun If specified, shows what would be updated without actually modifying the files. .EXAMPLE - .\update_rust_toolchain.ps1 + .\update_rust_toolchain.ps1 -InternalToolchainFile ..\ox-sdk\.pipelines\variables\publish.yml .EXAMPLE - .\update_rust_toolchain.ps1 -DryRun + .\update_rust_toolchain.ps1 -InternalToolchainFile ..\ox-sdk\.pipelines\variables\publish.yml -DryRun #> param( [string]$ConstantsFile = (Join-Path $PSScriptRoot ".." "constants.env"), [string]$ToolchainFile = (Join-Path $PSScriptRoot ".." "rust-toolchain.toml"), + [Parameter(Mandatory = $true)] + [string]$InternalToolchainFile, [switch]$DryRun ) @@ -40,9 +46,13 @@ $ToolchainChannelPattern = '(?m)^(channel[ \t]*=[ \t]*)"([^"]*)"' function Get-LatestStableRustVersion { <# .SYNOPSIS - Retrieves the latest stable Rust version from the Rust GitHub releases. + Retrieves the latest stable Rust patch for a minor version from the Rust GitHub releases. #> - $apiUrl = "https://api.github.com/repos/rust-lang/rust/releases" + param( + [string]$MinorVersion + ) + + $apiUrl = "https://api.github.com/repos/rust-lang/rust/releases?per_page=100" try { $headers = @{ @@ -51,25 +61,20 @@ function Get-LatestStableRustVersion { } $response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -ErrorAction Stop + $versionPattern = "^$([regex]::Escape($MinorVersion))\.\d+$" - # Find the latest stable release (not a beta or nightly) + # The internal production feed controls the usable minor; select its latest upstream patch. $stableRelease = $response | Where-Object { - $_.tag_name -match '^\d+\.\d+\.\d+$' -and -not $_.prerelease + $_.tag_name -match $versionPattern -and -not $_.prerelease } | Select-Object -First 1 if ($null -eq $stableRelease) { - throw "No stable release found" + throw "No stable release found for Rust $MinorVersion" } - # Keep the full x.y.z version (e.g., "1.92.0") so the pinned Cargo bugfix patch is preserved - if ($stableRelease.tag_name -match '^\d+\.\d+\.\d+$') { - return @{ - Success = $true - Version = $stableRelease.tag_name - } - } - else { - throw "Could not parse version from tag: $($stableRelease.tag_name)" + return @{ + Success = $true + Version = $stableRelease.tag_name } } catch { @@ -156,12 +161,55 @@ function Update-RustToolchain { [string]$FilePath, [string]$Version ) + $content = Get-Content $FilePath -Raw $replacement = '${1}"' + $Version + '"' return $content -replace $ToolchainChannelPattern, $replacement } +function Get-InternalToolchainMinorVersion { + param( + [string]$FilePath + ) + + $content = Get-Content $FilePath -Raw + $definition = [regex]::Match( + $content, + '(?ms)^[ \t]*-[ \t]+name:[ \t]*MSRUSTUP_TOOLCHAIN[ \t]*\r?\n(?.*?)(?=^[ \t]*-[ \t]+name:|\z)' + ) + + if (-not $definition.Success) { + throw "MSRUSTUP_TOOLCHAIN definition not found in '$FilePath'" + } + + $values = [regex]::Matches($definition.Groups["body"].Value, '(?m)^[ \t]*value:[ \t]*(\S+)') + + if ($values.Count -eq 0) { + throw "MSRUSTUP_TOOLCHAIN has no values in '$FilePath'" + } + + $versions = @() + + foreach ($value in $values) { + $channel = $value.Groups[1].Value + + if ($channel -notmatch '^ms-prod-(\d+\.\d+)(?:@[a-z0-9_-]+)?$') { + throw "Unsupported MSRUSTUP_TOOLCHAIN channel '$channel' in '$FilePath'" + } + + $versions += $Matches[1] + } + + $uniqueVersions = @($versions | Sort-Object -Unique) + + if ($uniqueVersions.Count -ne 1) { + throw "MSRUSTUP_TOOLCHAIN entries in '$FilePath' select different Rust versions: $($uniqueVersions -join ', ')" + } + + return $uniqueVersions[0] +} + # Main script execution Write-Host "Fetching latest Rust versions..." Write-Host "" @@ -177,6 +225,11 @@ if (-not (Test-Path $ToolchainFile)) { exit 1 } +if (-not (Test-Path $InternalToolchainFile)) { + Write-Host "Error: Internal Rust toolchain file not found at '$InternalToolchainFile'" + exit 1 +} + # Get current versions $constantsContent = Get-Content $ConstantsFile @@ -194,11 +247,19 @@ if (-not $toolchainMatch.Success) { $currentToolchain = $toolchainMatch.Groups[2].Value +try { + $internalToolchainMinorVersion = Get-InternalToolchainMinorVersion -FilePath $InternalToolchainFile +} +catch { + Write-Host "Error reading internal Rust toolchain version: $($_.Exception.Message)" + exit 1 +} + # Fetch new versions -$stableResult = Get-LatestStableRustVersion +$stableResult = Get-LatestStableRustVersion -MinorVersion $internalToolchainMinorVersion if (-not $stableResult.Success) { - Write-Host "Error fetching latest stable Rust version: $($stableResult.Error)" + Write-Host "Error fetching the latest stable Rust $internalToolchainMinorVersion release: $($stableResult.Error)" exit 1 } @@ -207,6 +268,7 @@ $yesterdayNightly = Get-YesterdayNightlyVersion $externalTypesResult = Get-ExternalTypesTestedNightly Write-Host "Current versions:" +Write-Host " Internal Rust minor : $internalToolchainMinorVersion" Write-Host " RUST_LATEST : $currentRustLatest" Write-Host " rust-toolchain.toml channel: $currentToolchain" Write-Host " RUST_NIGHTLY : $currentRustNightly" From ae10ffb017adebbe7447fab8285c638c10f668b3 Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 13:15:37 +0300 Subject: [PATCH 6/7] fix: clarify Rust toolchain maintenance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- README.md | 1 + scripts/update_rust_toolchain.ps1 | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3a7605b2e..3ab183be4 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ the versions of everything to stay up to date using three scripts: - `scripts/update_rust_toolchain.ps1` which requires an internal `ox-sdk` checkout and updates the public Rust toolchain versions after the internal release toolchain has been selected. + Example: `.\scripts\update_rust_toolchain.ps1 -InternalToolchainFile ..\ox-sdk\.pipelines\variables\publish.yml`. - `scripts/update_tool_versions.ps1` which updates the version of tools in the `constants.env` file. - `scripts/update_action_versions.ps1` which updates the version of GitHub actions in the various files in `.github/workflows`. diff --git a/scripts/update_rust_toolchain.ps1 b/scripts/update_rust_toolchain.ps1 index 06c326219..7e475fe80 100644 --- a/scripts/update_rust_toolchain.ps1 +++ b/scripts/update_rust_toolchain.ps1 @@ -41,7 +41,7 @@ param( ) $ErrorActionPreference = "Stop" -$ToolchainChannelPattern = '(?m)^(channel[ \t]*=[ \t]*)"([^"]*)"' +$ToolchainChannelPattern = '(?m)^([ \t]*channel[ \t]*=[ \t]*)"([^"]*)"' function Get-LatestStableRustVersion { <# @@ -195,7 +195,12 @@ function Get-InternalToolchainMinorVersion { $channel = $value.Groups[1].Value if ($channel -notmatch '^ms-prod-(\d+\.\d+)(?:@[a-z0-9_-]+)?$') { - throw "Unsupported MSRUSTUP_TOOLCHAIN channel '$channel' in '$FilePath'" + throw ( + "MSRUSTUP_TOOLCHAIN channel '$channel' in '$FilePath' has an invalid format. " + + "Choose a production short name such as 'ms-prod-1.95' by running " + + "'msrustup toolchain available'; append a required backend such as '@llvm' " + + "only after the short name, for example 'ms-prod-1.95@llvm'." + ) } $versions += $Matches[1] From 3c3183ccc8de6eae92e21111b1b9c9e45104501d Mon Sep 17 00:00:00 2001 From: Sander Saares Date: Thu, 27 Aug 2026 13:22:29 +0300 Subject: [PATCH 7/7] fix: avoid implicit toolchain regex state Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c307c0c-048d-4dec-a6e7-bb28716a1f98 --- scripts/update_rust_toolchain.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/update_rust_toolchain.ps1 b/scripts/update_rust_toolchain.ps1 index 7e475fe80..678338a6c 100644 --- a/scripts/update_rust_toolchain.ps1 +++ b/scripts/update_rust_toolchain.ps1 @@ -193,8 +193,12 @@ function Get-InternalToolchainMinorVersion { foreach ($value in $values) { $channel = $value.Groups[1].Value + $channelMatch = [regex]::Match( + $channel, + '^(?[''"]?)ms-prod-(?\d+\.\d+)(?:@[a-z0-9_-]+)?\k$' + ) - if ($channel -notmatch '^ms-prod-(\d+\.\d+)(?:@[a-z0-9_-]+)?$') { + if (-not $channelMatch.Success) { throw ( "MSRUSTUP_TOOLCHAIN channel '$channel' in '$FilePath' has an invalid format. " + "Choose a production short name such as 'ms-prod-1.95' by running " + @@ -203,7 +207,7 @@ function Get-InternalToolchainMinorVersion { ) } - $versions += $Matches[1] + $versions += $channelMatch.Groups["minor"].Value } $uniqueVersions = @($versions | Sort-Object -Unique)