diff --git a/.azure-pipelines/hidi-release.yml b/.azure-pipelines/hidi-release.yml
index 0d16e78c..010b3784 100644
--- a/.azure-pipelines/hidi-release.yml
+++ b/.azure-pipelines/hidi-release.yml
@@ -286,22 +286,63 @@ extends:
Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$version"
displayName: Read independent hidi version
workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context'
+ - task: NuGetAuthenticate@1
+ displayName: Authenticate Docker restore to Azure Artifacts
- task: AzureCLI@2
displayName: Publish multi-platform hidi image
+ env:
+ FEED_ACCESS_TOKEN: $(System.AccessToken)
inputs:
azureSubscription: ACR Images Push Service Connection
- scriptType: bash
+ scriptType: pscore
scriptLocation: inlineScript
workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context'
inlineScript: |
- set -euo pipefail
- az acr login --name msgraphprodregistry
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker buildx create --use
- docker buildx build --platform linux/amd64,linux/arm64/v8 \
- --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiReleaseVersion)" \
- --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:latest" \
- --push .
+ $ErrorActionPreference = 'Stop'
+ $nugetConfigPath = Join-Path '$(Agent.TempDirectory)' ("hidi-docker-{0}.nuget.config" -f [Guid]::NewGuid().ToString('N'))
+ try {
+ if ([string]::IsNullOrWhiteSpace($env:FEED_ACCESS_TOKEN)) {
+ throw "No Azure Artifacts access token available for the Docker build."
+ }
+ New-Item -ItemType File -Path $nugetConfigPath | Out-Null
+ [IO.File]::SetUnixFileMode($nugetConfigPath, ([IO.UnixFileMode]::UserRead -bor [IO.UnixFileMode]::UserWrite))
+ $feedAccessToken = [System.Security.SecurityElement]::Escape($env:FEED_ACCESS_TOKEN)
+ @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "@ | Set-Content -LiteralPath $nugetConfigPath -Encoding UTF8
+ $env:FEED_ACCESS_TOKEN = $null
+ az acr login --name msgraphprodregistry
+ if ($LASTEXITCODE -ne 0) { throw "ACR login failed with exit code $LASTEXITCODE." }
+ docker run --privileged --rm tonistiigi/binfmt --install all
+ if ($LASTEXITCODE -ne 0) { throw "Docker platform setup failed with exit code $LASTEXITCODE." }
+ docker buildx create --use
+ if ($LASTEXITCODE -ne 0) { throw "Docker BuildX setup failed with exit code $LASTEXITCODE." }
+ docker buildx build --platform linux/amd64,linux/arm64/v8 `
+ --secret "id=nuget_config,src=$nugetConfigPath" `
+ --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiReleaseVersion)" `
+ --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:latest" `
+ --push .
+ if ($LASTEXITCODE -ne 0) { throw "Docker build/push failed with exit code $LASTEXITCODE." }
+ }
+ finally {
+ $env:FEED_ACCESS_TOKEN = $null
+ if (Test-Path -LiteralPath $nugetConfigPath) {
+ Remove-Item -LiteralPath $nugetConfigPath -Force
+ }
+ }
- stage: preview
dependsOn: build
condition: and(succeeded(), eq(variables.hidiPublishingEnabled, 'true'), eq(variables.hidiPreviewPublishingEnabled, 'true'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
@@ -328,19 +369,60 @@ extends:
Write-Host "##vso[task.setvariable variable=HidiPreviewVersion]$previewVersion"
displayName: Compute independent hidi preview tag
workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context'
+ - task: NuGetAuthenticate@1
+ displayName: Authenticate Docker restore to Azure Artifacts
- task: AzureCLI@2
displayName: Publish multi-platform hidi preview image
+ env:
+ FEED_ACCESS_TOKEN: $(System.AccessToken)
inputs:
azureSubscription: ACR Images Push Service Connection
- scriptType: bash
+ scriptType: pscore
scriptLocation: inlineScript
workingDirectory: '$(Pipeline.Workspace)/hidi-docker-context'
inlineScript: |
- set -euo pipefail
- az acr login --name msgraphprodregistry
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker buildx create --use
- docker buildx build --platform linux/amd64,linux/arm64/v8 \
- --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiPreviewVersion)" \
- --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:nightly" \
- --push .
+ $ErrorActionPreference = 'Stop'
+ $nugetConfigPath = Join-Path '$(Agent.TempDirectory)' ("hidi-docker-{0}.nuget.config" -f [Guid]::NewGuid().ToString('N'))
+ try {
+ if ([string]::IsNullOrWhiteSpace($env:FEED_ACCESS_TOKEN)) {
+ throw "No Azure Artifacts access token available for the Docker build."
+ }
+ New-Item -ItemType File -Path $nugetConfigPath | Out-Null
+ [IO.File]::SetUnixFileMode($nugetConfigPath, ([IO.UnixFileMode]::UserRead -bor [IO.UnixFileMode]::UserWrite))
+ $feedAccessToken = [System.Security.SecurityElement]::Escape($env:FEED_ACCESS_TOKEN)
+ @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "@ | Set-Content -LiteralPath $nugetConfigPath -Encoding UTF8
+ $env:FEED_ACCESS_TOKEN = $null
+ az acr login --name msgraphprodregistry
+ if ($LASTEXITCODE -ne 0) { throw "ACR login failed with exit code $LASTEXITCODE." }
+ docker run --privileged --rm tonistiigi/binfmt --install all
+ if ($LASTEXITCODE -ne 0) { throw "Docker platform setup failed with exit code $LASTEXITCODE." }
+ docker buildx create --use
+ if ($LASTEXITCODE -ne 0) { throw "Docker BuildX setup failed with exit code $LASTEXITCODE." }
+ docker buildx build --platform linux/amd64,linux/arm64/v8 `
+ --secret "id=nuget_config,src=$nugetConfigPath" `
+ --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiPreviewVersion)" `
+ --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:nightly" `
+ --push .
+ if ($LASTEXITCODE -ne 0) { throw "Docker build/push failed with exit code $LASTEXITCODE." }
+ }
+ finally {
+ $env:FEED_ACCESS_TOKEN = $null
+ if (Test-Path -LiteralPath $nugetConfigPath) {
+ Remove-Item -LiteralPath $nugetConfigPath -Force
+ }
+ }
diff --git a/Dockerfile b/Dockerfile
index 0ec43beb..4a66f598 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,7 +10,9 @@ COPY ./tool/Microsoft.OpenApi.OData.public.snk ./hidi/tool/Microsoft.OpenApi.ODa
COPY ./tool/Microsoft.OpenApi.Hidi.public.snk ./hidi/tool/Microsoft.OpenApi.Hidi.public.snk
COPY ./README.md ./hidi/README.md
WORKDIR /app/hidi
-RUN dotnet publish ./src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj -c Release -o /app/publish -p:GeneratePackageOnBuild=false -p:HidiPublicSignBuild=true
+# Official CI supplies the central feed config as a secret; local builds use default NuGet sources.
+RUN --mount=type=secret,id=nuget_config,target=/app/hidi/NuGet.Config \
+ dotnet publish ./src/Microsoft.OpenApi.Hidi/Microsoft.OpenApi.Hidi.csproj -c Release -o /app/publish -p:GeneratePackageOnBuild=false -p:HidiPublicSignBuild=true
FROM mcr.microsoft.com/dotnet/runtime:8.0-jammy-chiseled AS runtime
WORKDIR /app
diff --git a/src/Microsoft.OpenApi.Hidi/readme.md b/src/Microsoft.OpenApi.Hidi/readme.md
index da02c05e..4862f258 100644
--- a/src/Microsoft.OpenApi.Hidi/readme.md
+++ b/src/Microsoft.OpenApi.Hidi/readme.md
@@ -109,6 +109,17 @@ Container jobs retain the source publisher's existing `docker-images-deploy`
environment and its approvals/checks. The destination pipeline must be authorized
for that protected environment before official publishing can be enabled.
+Official container jobs authenticate to the approved
+`GraphDeveloperExperiences_Public` central feed using the existing Azure DevOps
+job identity. A credential-bearing NuGet config is created with owner-only
+permissions in the agent temp directory, passed as the BuildKit `nuget_config`
+secret, and removed in `finally`, including on build failure. It is never staged
+in `HidiDockerContext`, published as an artifact, or copied into an image layer.
+The destination pipeline identity must already be authorized to read the feed;
+this handoff does not grant permissions or bypass service-connection approvals.
+The Dockerfile secret mount is optional, so local and GitHub Actions builds
+without a secret continue to use their default NuGet sources.
+
The migration baseline 3.10.2 is already published. Destination Hidi NuGet,
GitHub release, stable Docker and preview Docker publishing are disabled until
source cutover. The first destination stable release must advance the Hidi