diff --git a/.azure-pipelines/hidi-release.yml b/.azure-pipelines/hidi-release.yml index 67fde2b0..c3ff5510 100644 --- a/.azure-pipelines/hidi-release.yml +++ b/.azure-pipelines/hidi-release.yml @@ -265,20 +265,61 @@ extends: if ([version]($version -split '-')[0] -le [version]'2.12.2') { throw "Do not republish the migration baseline or an older hidi version." } Write-Host "##vso[task.setvariable variable=HidiReleaseVersion]$version" displayName: Read independent hidi version + - 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)/HidiDockerContext' 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 \ - --file "$(Pipeline.Workspace)/HidiDockerContext/Dockerfile" \ - --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiReleaseVersion)" \ - --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:latest" \ - --push "$(Pipeline.Workspace)/HidiDockerContext" + $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" ` + --file "$(Pipeline.Workspace)/HidiDockerContext/Dockerfile" ` + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:$(HidiReleaseVersion)" ` + --tag "msgraphprodregistry.azurecr.io/public/openapi/hidi:latest" ` + --push "$(Pipeline.Workspace)/HidiDockerContext" + 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 2ec9d0a9..8b7936b0 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 15e267fd..b8703368 100644 --- a/src/Microsoft.OpenApi.Hidi/readme.md +++ b/src/Microsoft.OpenApi.Hidi/readme.md @@ -86,6 +86,21 @@ private keys are excluded. The container release job consumes this artifact as a 1ES input without checking out the repository. NuGet and Windows release artifacts continue to use the separate `Hidi` artifact. +The container release job retains the 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. + +The official container job authenticates 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 gated official pipeline retains the consumer image `mcr.microsoft.com/openapi/hidi`, backed by `msgraphprodregistry.azurecr.io/public/openapi/hidi`. Stable images use `latest`