From f31dbafe55a85ae41e02ae9f480f0f1123a29f10 Mon Sep 17 00:00:00 2001 From: "Gavin Barron (from Dev Box)" Date: Wed, 5 Aug 2026 11:32:52 -0700 Subject: [PATCH] Look up published version via CFS feed instead of api.nuget.org (CFSClean) The 'Validate updated version' gate in productionBuild.yml runs ValidateUpdatedNugetVersion.ps1, which Invoke-RestMethod's api.nuget.org directly (pwsh.exe -> api.nuget.org) - the sole CFSClean network-isolation violation on pipeline 197 (Dotnet Core Production). Parameterize the registrations base URL (default stays nuget.org for back-compat) and send SYSTEM_ACCESSTOKEN as a bearer token when set; point the pipeline step at the CFS feed's registrations2 endpoint (GraphDeveloperExperiences_Public, which upstreams nuget.org). Verified the feed returns the same latest version (4.0.1) so the gate is unchanged. Also broaden the graceful first-publish handling to HTTP 404 and fix the '&&' condition to '-and'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d3f8fec7-b00b-46be-ba39-7e1f3e7f7188 --- pipelines/productionBuild.yml | 6 ++++- scripts/ValidateUpdatedNugetVersion.ps1 | 29 ++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/pipelines/productionBuild.yml b/pipelines/productionBuild.yml index 21d7b702b..a014a1055 100644 --- a/pipelines/productionBuild.yml +++ b/pipelines/productionBuild.yml @@ -63,8 +63,12 @@ extends: inputs: targetType: filePath filePath: 'scripts\ValidateUpdatedNugetVersion.ps1' - arguments: '-packageName "$(PACKAGE_NAME)" -projectPath "$(PROJECT_PATH)"' + # Look up the latest published version via the CFS central feed (which upstreams + # nuget.org) instead of api.nuget.org, to satisfy 1ES network isolation (CFSClean). + arguments: '-packageName "$(PACKAGE_NAME)" -projectPath "$(PROJECT_PATH)" -registrationsBaseUrl "https://pkgs.dev.azure.com/microsoftgraph/0985d294-5762-4bc2-a565-161ef349ca3e/_packaging/GraphDeveloperExperiences_Public/nuget/v3/registrations2"' pwsh: true + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) enabled: true - powershell: | dotnet workload install android ios maccatalyst diff --git a/scripts/ValidateUpdatedNugetVersion.ps1 b/scripts/ValidateUpdatedNugetVersion.ps1 index 7226a06dd..c496ae7a6 100644 --- a/scripts/ValidateUpdatedNugetVersion.ps1 +++ b/scripts/ValidateUpdatedNugetVersion.ps1 @@ -16,6 +16,14 @@ .Parameter projectPath Specifies the path to the project file. + +.Parameter registrationsBaseUrl + Base URL of the NuGet v3 registrations resource used to look up the latest published + version. Defaults to the public nuget.org endpoint. In network-isolated pipelines (CFSClean) + pass the CFS/Azure Artifacts feed registrations endpoint (which upstreams nuget.org) so the + lookup does not egress to api.nuget.org. When the URL is an Azure Artifacts feed it requires + authentication; set the SYSTEM_ACCESSTOKEN environment variable and it will be sent as a + Bearer token. #> Param( @@ -23,7 +31,10 @@ Param( [string]$packageName, [parameter(Mandatory = $true)] - [string]$projectPath + [string]$projectPath, + + [parameter(Mandatory = $false)] + [string]$registrationsBaseUrl = "https://api.nuget.org/v3/registration5-gz-semver2" ) [xml]$xmlDoc = Get-Content $projectPath @@ -40,18 +51,26 @@ $currentProjectVersion = [System.Management.Automation.SemanticVersion]"$version # API is case-sensitive $packageName = $packageName.ToLower() -$url = "https://api.nuget.org/v3/registration5-gz-semver2/$packageName/index.json" +$url = "$($registrationsBaseUrl.TrimEnd('/'))/$packageName/index.json" + +# Azure Artifacts feed endpoints require authentication; send the pipeline access token when +# available. Public nuget.org ignores the header. +$headers = @{} +if ($env:SYSTEM_ACCESSTOKEN) { + $headers["Authorization"] = "Bearer $env:SYSTEM_ACCESSTOKEN" +} # Call the NuGet API for the package and get the current published version. Try { - $nugetIndex = Invoke-RestMethod -Uri $url -Method Get + $nugetIndex = Invoke-RestMethod -Uri $url -Method Get -Headers $headers } Catch { - if ($_.ErrorDetails.Message && $_.ErrorDetails.Message.Contains("The specified blob does not exist.")) { + $statusCode = $_.Exception.Response.StatusCode.value__ + if ($statusCode -eq 404 -or ($_.ErrorDetails.Message -and $_.ErrorDetails.Message.Contains("The specified blob does not exist."))) { Write-Host "No package exists. You will probably be publishing $packageName for the first time." Exit # exit gracefully } - + Write-Host $_ Exit 1 }