From 931ba71b45faf19bde41ac016067290ce32ef206 Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Fri, 21 Aug 2026 01:03:09 -0700 Subject: [PATCH 1/5] Add ACR network diagnostics Log DNS resolution, TCP reachability, and the registry HTTP response before publishing PowerShell packages. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../publish-psresources-acr.yml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/.azure-pipelines/common-templates/publish-psresources-acr.yml b/.azure-pipelines/common-templates/publish-psresources-acr.yml index 4e1e25eebe7..831d2d6b698 100644 --- a/.azure-pipelines/common-templates/publish-psresources-acr.yml +++ b/.azure-pipelines/common-templates/publish-psresources-acr.yml @@ -10,6 +10,40 @@ parameters: type: string steps: + - task: PowerShell@2 + displayName: 'Diagnose ACR network access' + continueOnError: true + inputs: + targetType: Inline + pwsh: true + script: | + $ErrorActionPreference = 'Stop' + $registryHost = '${{ parameters.Registry }}' + $registryUri = "https://$registryHost/v2/" + + Write-Host "Resolving $registryHost." + $dnsRecords = Resolve-DnsName -Name $registryHost + $dnsOutput = $dnsRecords | + Select-Object Name, Type, IPAddress, NameHost | + Format-Table -AutoSize | + Out-String + Write-Host $dnsOutput + + Write-Host "Testing TCP connectivity to ${registryHost}:443." + $connection = Test-NetConnection -ComputerName $registryHost -Port 443 -InformationLevel Detailed + $connectionOutput = $connection | + Select-Object ComputerName, RemoteAddress, RemotePort, InterfaceAlias, SourceAddress, TcpTestSucceeded | + Format-List | + Out-String + Write-Host $connectionOutput + if (-not $connection.TcpTestSucceeded) { + throw "The build agent can't establish a TCP connection to ${registryHost}:443." + } + + Write-Host "Requesting $registryUri. An HTTP 401 response confirms that the ACR endpoint is reachable." + $response = Invoke-WebRequest -Uri $registryUri -Method Get -SkipHttpErrorCheck -TimeoutSec 30 + Write-Host "ACR endpoint returned HTTP $([int]$response.StatusCode) $($response.StatusDescription)." + - task: AzurePowerShell@5 displayName: 'Publish PowerShell packages to ACR' inputs: From 314810b84317fc503d6991356f9f80c189f7805a Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Fri, 21 Aug 2026 01:09:04 -0700 Subject: [PATCH 2/5] Allow manual ACR publication Add a default-off pipeline switch for testing ACR publication from manually queued feature-branch builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .azure-pipelines/ci-build.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index 95d09b92252..4a655053eac 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -14,6 +14,10 @@ parameters: - name: Sign type: boolean default: true +- name: ForceAcrPublish + displayName: Force ACR publication (manual runs only) + type: boolean + default: false - name: InternalFeed type: string default: '0985d294-5762-4bc2-a565-161ef349ca3e/PowerShell_V2_Build' @@ -144,7 +148,7 @@ extends: - stage: Deploy_to_ACR displayName: Deploy PowerShell packages to ACR dependsOn: stage - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'), ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.stage.outputs['MsGraphPsSdkCiBuild.DetectAcrChanges.ShouldPublishToAcr'], 'true')) + condition: and(succeeded(), or(and(eq(variables['Build.SourceBranch'], 'refs/heads/main'), ne(variables['Build.Reason'], 'PullRequest'), eq(dependencies.stage.outputs['MsGraphPsSdkCiBuild.DetectAcrChanges.ShouldPublishToAcr'], 'true')), and(eq(variables['Build.Reason'], 'Manual'), ${{ eq(parameters.ForceAcrPublish, true) }}))) jobs: - job: DeployPowerShellPackagesToAcr displayName: Deploy PowerShell packages to ACR From cf5a73ea337cb61670ca1edc6fe724e51ea08737 Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Mon, 24 Aug 2026 13:29:22 -0700 Subject: [PATCH 3/5] Allow ACR through network isolation Add the AzureContainerRegistry policy so the package publication job can connect directly to the registry while retaining enforced network isolation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .azure-pipelines/ci-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index 4a655053eac..bf8db5be151 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -60,7 +60,7 @@ extends: # non-allowlisted public egress is blocked. settings: networkIsolationMode: Enforce - networkIsolationPolicy: Good,GitHub,NuGet,PowershellGallery,CFSClean,CFSClean3 + networkIsolationPolicy: Good,GitHub,NuGet,PowershellGallery,AzureContainerRegistry,CFSClean,CFSClean3 sdl: binskim: enabled: false From a5ad291ab1d6ba8cbea8e38c753ea0bdfb01dd88 Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Tue, 25 Aug 2026 13:04:00 -0700 Subject: [PATCH 4/5] Verify published packages at ACR prefix Use the public/psresource repository path for idempotency and post-publication tag checks instead of unprefixed PSResource discovery. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../publish-psresources-acr.yml | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/.azure-pipelines/common-templates/publish-psresources-acr.yml b/.azure-pipelines/common-templates/publish-psresources-acr.yml index 831d2d6b698..fd83ff11132 100644 --- a/.azure-pipelines/common-templates/publish-psresources-acr.yml +++ b/.azure-pipelines/common-templates/publish-psresources-acr.yml @@ -116,27 +116,29 @@ steps: } }, Id + $prefix = 'public/psresource' foreach ($package in $packages) { - $existingPackage = Find-PSResource -Name $package.Id -Version $package.Version -Repository $repositoryName -ErrorAction SilentlyContinue - if ($null -ne $existingPackage) { + $acrRepository = "$prefix/$($package.Id.ToLowerInvariant())" + $existingTag = Get-AzContainerRegistryTag -RegistryName $repositoryName -RepositoryName $acrRepository -Name $package.Version -ErrorAction SilentlyContinue + if ($null -ne $existingTag) { Write-Host "$($package.Id) $($package.Version) already exists in $repositoryName; continuing the idempotent deployment." continue } Write-Host "Publishing $($package.Id) $($package.Version) to $repositoryName." - $prefix = "public/psresource" Publish-PSResource -NupkgPath $package.Path -Repository $repositoryName -ModulePrefix $prefix -ErrorAction Stop } foreach ($package in $packages) { - $foundPackage = $null - for ($attempt = 1; $attempt -le 6 -and $null -eq $foundPackage; $attempt++) { - $foundPackage = Find-PSResource -Name $package.Id -Version $package.Version -Repository $repositoryName -ErrorAction SilentlyContinue - if ($null -eq $foundPackage -and $attempt -lt 6) { + $acrRepository = "$prefix/$($package.Id.ToLowerInvariant())" + $publishedTag = $null + for ($attempt = 1; $attempt -le 6 -and $null -eq $publishedTag; $attempt++) { + $publishedTag = Get-AzContainerRegistryTag -RegistryName $repositoryName -RepositoryName $acrRepository -Name $package.Version -ErrorAction SilentlyContinue + if ($null -eq $publishedTag -and $attempt -lt 6) { Start-Sleep -Seconds 10 } } - if ($null -eq $foundPackage) { - throw "Published package '$($package.Id)' version '$($package.Version)' couldn't be found in ACR." + if ($null -eq $publishedTag) { + throw "Published package '$($package.Id)' version '$($package.Version)' couldn't be found at '$acrRepository' in ACR." } } From d9388d84d522b8136d585766215e1fec52768fea Mon Sep 17 00:00:00 2001 From: Microsoft Graph DevX Tooling Date: Tue, 25 Aug 2026 13:29:45 -0700 Subject: [PATCH 5/5] Remove temporary ACR diagnostics Drop the DNS, TCP, and HTTP preflight now that registry connectivity is confirmed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../publish-psresources-acr.yml | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/.azure-pipelines/common-templates/publish-psresources-acr.yml b/.azure-pipelines/common-templates/publish-psresources-acr.yml index fd83ff11132..7a53b0d478d 100644 --- a/.azure-pipelines/common-templates/publish-psresources-acr.yml +++ b/.azure-pipelines/common-templates/publish-psresources-acr.yml @@ -10,40 +10,6 @@ parameters: type: string steps: - - task: PowerShell@2 - displayName: 'Diagnose ACR network access' - continueOnError: true - inputs: - targetType: Inline - pwsh: true - script: | - $ErrorActionPreference = 'Stop' - $registryHost = '${{ parameters.Registry }}' - $registryUri = "https://$registryHost/v2/" - - Write-Host "Resolving $registryHost." - $dnsRecords = Resolve-DnsName -Name $registryHost - $dnsOutput = $dnsRecords | - Select-Object Name, Type, IPAddress, NameHost | - Format-Table -AutoSize | - Out-String - Write-Host $dnsOutput - - Write-Host "Testing TCP connectivity to ${registryHost}:443." - $connection = Test-NetConnection -ComputerName $registryHost -Port 443 -InformationLevel Detailed - $connectionOutput = $connection | - Select-Object ComputerName, RemoteAddress, RemotePort, InterfaceAlias, SourceAddress, TcpTestSucceeded | - Format-List | - Out-String - Write-Host $connectionOutput - if (-not $connection.TcpTestSucceeded) { - throw "The build agent can't establish a TCP connection to ${registryHost}:443." - } - - Write-Host "Requesting $registryUri. An HTTP 401 response confirms that the ACR endpoint is reachable." - $response = Invoke-WebRequest -Uri $registryUri -Method Get -SkipHttpErrorCheck -TimeoutSec 30 - Write-Host "ACR endpoint returned HTTP $([int]$response.StatusCode) $($response.StatusDescription)." - - task: AzurePowerShell@5 displayName: 'Publish PowerShell packages to ACR' inputs: