Skip to content

Re-land: Migrate AzDO feed publishing from PAT to Entra-based auth (#17113) - #17140

Merged
missymessa merged 20 commits into
dotnet:mainfrom
missymessa:relanding-feed-publish-entra
Jul 23, 2026
Merged

Re-land: Migrate AzDO feed publishing from PAT to Entra-based auth (#17113)#17140
missymessa merged 20 commits into
dotnet:mainfrom
missymessa:relanding-feed-publish-entra

Conversation

@missymessa

@missymessa missymessa commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

Re-lands #17113 (migrating AzDO feed publishing from the dn-bot-all-orgs-artifact-feeds-rw PAT to Entra/WIF auth), which was reverted in #17136 — but with a simpler auth flow based on review feedback.

Instead of pre-acquiring a token via a dedicated service connection, the Build Promotion publish step now publishes packages using the existing maestro-build-promotion identity that the step already runs under. The feed publisher acquires an Azure DevOps token on demand via DefaultIdentityTokenCredential, so there is no separately pre-acquired token that could expire mid-publish on a large build.

Related: dnceng WI 10145 — [Packaging] PAT Migration: dn-bot-all-orgs-artifact-feeds-rw.

Auth flow (what actually happens now)

  • The Publish packages, blobs and symbols task runs under azureSubscription: maestro-build-promotion with addSpnToEnvironment: true.
  • When no feed key is supplied, AzureDevOpsNugetFeedAssetPublisher / PublishArtifactsInManifestBase acquire an AzDO token via DefaultIdentityTokenCredential (supports AzurePipelinesCredential from AzureCLI@2, managed identity, and workload identity). Tokens are obtained as needed rather than pinned to one ~1h token.
  • NuGetAuthenticate@1 is retained for the ambient NuGet credential provider.

There is no GetFeedToken step and no AzureDevOpsFeedsKey pass-through anymore.

Out-of-repo infrastructure (already done)

The maestro-build-promotion identity (appId 6e870007-e236-4eb1-8734-8bf8cd54c748) was granted Contributor (push) on the shipping feeds:

  • dotnet-eng, dotnet-tools, dotnet-eng-internal, dotnet-tools-internal
  • general-testing (used by the promotion-validation test that runs in the official build's ValidateSdk stage)

The same service principal backs the maestro-build-promotion service connection in both dnceng and devdiv, so a single set of feed grants covers both orgs where the promotion pipeline runs.

What was removed vs. #17113

  • Removed the GetFeedToken AzureCLI@2 step and the AzureDevOpsFeedsKey argument in eng/publishing/v3/publish.yml.
  • Removed the dedicated dnceng-artifact-feeds-publish cross-org service connections and the pre-flight validation step (eng/validation/validate-feed-publish-connections.ps1 deleted; the corresponding step removed from eng/validate-promotion.yml).

Validation

  • Focused unit tests added for the JWT→Bearer / opaque-PAT→Basic auth-header selection in the feed publisher.
  • PR builds/unit tests green.
  • A pre-merge promotion test run was exercised by promoting an official build of this branch to the General Testing channel, which drives the publish pipeline from this branch and pushes to the general-testing feed using the maestro-build-promotion identity.
  • Note: PR validation reads YAML from main; the definitive proof is the post-merge promotion build — that should be monitored to confirm the publish step authenticates in both dnceng and devdiv.

…otnet#17113)

Reverts the revert (dotnet#17136). The original change was correct; it failed only because the WIF service connection infrastructure was not present in both orgs the Build Promotion Pipeline runs in. That infra (devdiv SC + FICs + pipeline authorizations) has now been created. Also adds a non-secret diagnostic + targeted error message to the GetFeedToken step to make SC/FIC misconfiguration obvious in build logs.
Copilot AI review requested due to automatic review settings July 17, 2026 14:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Re-lands the migration of Azure DevOps feed publishing from a long-lived PAT to Entra/WIF-based authentication, enabling either (1) a provided token (PAT or AAD) or (2) automatic token acquisition via DefaultIdentityTokenCredential when no feed key is supplied.

Changes:

  • Switch AzDO HTTP auth to use Bearer for AAD/JWT tokens while preserving Basic for PATs; add clearer failure messaging when Entra token acquisition fails.
  • Allow AzDO NuGet feeds to be configured without AzureDevOpsFeedsKey and rely on Entra fallback instead (with updated tests).
  • Update the publishing pipeline to acquire an AzDO access token via AzureCLI@2 using the dnceng-artifact-feeds-publish WIF service connection and use it for publishing.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishArtifactsInManifestBase.cs Adds Bearer-vs-Basic auth selection and Entra token acquisition fallback with improved error messaging.
src/Microsoft.DotNet.Build.Tasks.Feed/src/model/SetupTargetFeedConfigV3.cs Stops treating missing AzDO feed key as a hard error; logs info and keeps feed config.
src/Microsoft.DotNet.Build.Tasks.Feed/src/AzureDevOpsNugetFeedAssetPublisher.cs Implements token fallback via DefaultIdentityTokenCredential and Bearer-vs-Basic selection.
src/Microsoft.DotNet.Build.Tasks.Feed.Tests/SetupTargetFeedConfigV3Tests.cs Adds coverage ensuring missing AzDO feed key still produces feeds and does not log build errors.
src/Microsoft.DotNet.Arcade.Sdk/toolset/PublishArtifactsInManifest.proj Only includes FeedKey item when $(AzureDevOpsFeedsKey) is non-empty to enable fallback behavior.
eng/publishing/v3/publish.yml Replaces PAT-based publishing with WIF-acquired AzDO token + adds diagnostics around token acquisition.
Comments suppressed due to low confidence (1)

eng/publishing/v3/publish.yml:177

  • AzDoFeedToken is passed to MSBuild as /p:AzureDevOpsFeedsKey=..., which will typically end up in binlogs under artifacts/log/.... The publish-logs redaction step only redacts secrets explicitly listed (plus a static list) and currently only includes the Maestro token via CustomSensitiveDataList, so the Entra access token risks being uploaded in PostBuildLogs. Add the output token to CustomSensitiveDataList (or to eng/BinlogSecretsRedactionFile.txt) so the binlog redaction step reliably scrubs it.
          /p:AzureDevOpsFeedsKey='$(GetFeedToken.AzDoFeedToken)'
          /p:AkaMSClientId=$(akams-app-id)
          /p:AkaMSClientCertificate=$(Agent.TempDirectory)/akamsclientcert.pfx
          ${{ parameters.artifactsPublishingAdditionalParameters }} 
          /p:PDBArtifactsBasePath='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Promotion validation only exercised the dnceng promotion path, so the devdiv SC-missing failure that broke the Build Promotion Pipeline was never caught. Adds a pre-flight (eng/validation/validate-feed-publish-connections.ps1) that asserts the dnceng-artifact-feeds-publish service connection exists and is ready in BOTH dnceng and devdiv before the test promotion, and hardens GetFeedToken to fail fast if the minted token is not a JWT (which would silently fall back to PAT/Basic auth downstream).
Copilot AI review requested due to automatic review settings July 17, 2026 14:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Comment thread src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishArtifactsInManifestBase.cs Outdated
Comment thread src/Microsoft.DotNet.Build.Tasks.Feed/src/AzureDevOpsNugetFeedAssetPublisher.cs Outdated
Comment thread eng/publishing/v3/publish.yml Outdated
Comment thread eng/validation/validate-feed-publish-connections.ps1 Outdated
Use StringSplitOptions.RemoveEmptyEntries in the JWT-vs-PAT detection (both C# publishers and the publish.yml GetFeedToken assertion) so malformed tokens like '..' are not misclassified as JWTs. URL-encode the endpoint name in the feed-publish SC pre-flight query string.
Copilot AI review requested due to automatic review settings July 17, 2026 15:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Both publishers allocate the HttpClient before token acquisition and throw from the catch if it fails, so Dispose() never runs and the handler/sockets leak on repeated failures. Dispose the client in the catch before rethrowing.
Copilot AI review requested due to automatic review settings July 17, 2026 15:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

@missymessa
missymessa enabled auto-merge (squash) July 17, 2026 15:44
Copilot AI review requested due to automatic review settings July 20, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Comment thread eng/publishing/v3/publish.yml Outdated
Comment thread eng/publishing/v3/publish.yml Outdated
Copilot AI review requested due to automatic review settings July 22, 2026 16:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings July 22, 2026 17:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings July 22, 2026 17:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings July 22, 2026 17:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@missymessa

Copy link
Copy Markdown
Member Author

Kicked off a fresh official build on the current HEAD (98b91217a), which now includes the V4 Feeds() Entra-fallback fix (previous build 3029050 predated that fix and would still have hit No key found for {feed}):

Once it succeeds and registers a BAR build ID, I'll recreate the Maestro Build Promotion validation against it (channel 1647 / General Testing Internal, PublishingInfraVersion: 3), matching the earlier run. Will update this thread with the promotion result.

@missymessa

Copy link
Copy Markdown
Member Author

✅ Promotion validation passed — reproduced mmitche's earlier test end-to-end against the fixed branch.

  • Official build: 3029124 (20260722.7, commit 98b91217a) → BAR build 323981
  • Promotion (Maestro Build Promotion, def 750): 3029189https://dev.azure.com/dnceng/internal/_build/results?buildId=3029189
    • Same parameters as the previous run: PromoteToChannelIds: 1647 (General Testing Internal), PublishingInfraVersion: 3, PublishInstallersAndChecksums: True, validations off.

Result:

  • Publish packages, blobs and symbols task = succeeded — the exact task that failed in 3029006 with Value cannot be null. (Parameter 'source').
  • Overall status is "PartiallySucceeded" only because of 8 skipped auto-injected policy tasks (Guardian/Component Detection/secret downloads) — 71 succeeded, 0 failed.
  • darc add-build-to-channel confirmed build 323981 was successfully added to 'General Testing Internal'.

The Entra/WIF publish path (null-guard + V4 Feeds() Entra fallback) works end-to-end. @mmitche this should be good for your review now.

@missymessa

Copy link
Copy Markdown
Member Author

Clarification / correction on my previous comment about the "PartiallySucceeded" status:

The overall status is a rollup of two non-blocking things, neither introduced by this PR:

  1. 8 skipped auto-injected policy tasks (Guardian, Component Detection, secret downloads).
  2. Two continueOnError download errors (result succeededWithIssues, not build-failing):
    • Download V3 PDB Artifacts: Artifact PdbArtifacts was not found for build 3029124
    • Download V3 Merged Manifest: Artifact BlobArtifacts was not found for build 3029124

These same two errors appear in the earlier promotion run 3029006 (for the build it promoted, 3028944), so they are pre-existing — these arcade builds don't produce separate BlobArtifacts/PdbArtifacts containers (the publish log confirms No assets to publish to symbol server were found). The NuGet packages that exist were published, and darc confirmed BAR 323981 was added to the channel.

The material difference vs. 3029006: that run failed at Publish packages, blobs and symbols (the SetupTargetFeedConfigV4 null crash); this run succeeded at that task. So the Entra/WIF publish path is validated end-to-end; the artifact-download errors are an orthogonal, pre-existing quirk of promoting an arcade build.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

@missymessa
missymessa merged commit 9ab4b6b into dotnet:main Jul 23, 2026
9 of 10 checks passed
@ViktorHofer

Copy link
Copy Markdown
Member

Looks like that broke arcade publish: https://dev.azure.com/dnceng/internal/_build/results?buildId=3029933&view=results

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants