Skip to content

Make Azure.Identity optional in AzureFoundry via injectable TokenCredential#9779

Merged
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/animated-waddle
Jul 9, 2026
Merged

Make Azure.Identity optional in AzureFoundry via injectable TokenCredential#9779
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/animated-waddle

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes #9712

Summary

Implements the TokenCredential-injection option from #9712 so that Microsoft.Testing.Extensions.AzureFoundry no longer carries a hard dependency on Azure.Identity (and its heavyweight MSAL graph). API-key users pull zero managed-identity assemblies; Entra ID / managed identity remains fully supported but is now opt-in — the consumer references Azure.Identity themselves and passes a credential.

This reworks the authentication added in #9707. It is not a revert: the managed-identity capability is preserved, only the Azure.Identity reference and the new DefaultAzureCredential() call move out of the package and into the caller (the idiomatic Azure SDK pattern that Azure.AI.OpenAI itself follows).

Changes

  • OpenAIChatClientProvider.cs — removed the static Lazy<DefaultAzureCredential> and using Azure.Identity. Added an optional injected TokenCredential (new constructor overload), an AuthenticationMode of None/ApiKey/TokenCredential, and GetAuthenticationMode(apiKey, credential). IsAvailable now also requires an API key or an injected credential; when neither is present CreateChatClientAsync throws a clear InvalidOperationException.
  • TestApplicationBuilderExtensions.cs — new AddAzureOpenAIChatClientProvider(this ITestApplicationBuilder, TokenCredential) overload (the parameterless API-key/auto-registered overload is kept).
  • .csproj + Directory.Packages.props — dropped Azure.Identity; added Azure.Core (1.44.1, already the transitive floor from Azure.AI.OpenAI) since TokenCredential now appears in the public API.
  • PublicAPI / InternalAPI — declared the new overload and reconciled the internal-API tracking files.
  • Resources — added the NoAuthenticationConfigured string.
  • PACKAGE.md — documented the opt-in Entra ID model.
  • Unit tests — updated/added coverage for API-key, injected-credential, no-auth-throws, precedence, and null-credential cases.

Behavioral change (needs sign-off)

This drops #9707's zero-config DefaultAzureCredential fallback: Entra users now reference Azure.Identity and pass a credential explicitly. This is exactly the dependency-footprint tradeoff #9712 asks to weigh before GA, surfaced here as a concrete diff for the team to review.

// API-key users: no Azure.Identity dependency at all
builder.AddAzureOpenAIChatClientProvider();

// Managed-identity users: reference Azure.Identity and pass the credential
builder.AddAzureOpenAIChatClientProvider(new DefaultAzureCredential());

Verification

  • AzureFoundry project builds clean (0 warnings / 0 errors) and unit tests pass (20/20) — verified prior to a local-worktree file-loss incident; the committed content is byte-identical to the verified changes.

Notes

  • xlf not modified: the package is IsShipping=false, and Arcade's Localization.targets only wires XliffTasks for shipping assemblies, so UpdateXlf is unavailable and CI does not validate xlf for this project. Per the repo rule against hand-editing xlf, the .xlf files are left untouched; the loc pipeline will regenerate them when the package flips to shipping.
  • Also worth confirming at GA (per Revisit Azure.Identity dependency in Microsoft.Testing.Extensions.AzureFoundry before GA #9712): whether the pinned Azure SDK versions are still current/supported.

…ential

Removes the hard Azure.Identity/MSAL dependency from the core
Microsoft.Testing.Extensions.AzureFoundry package. API-key users no longer
pull the managed-identity graph; Entra ID / managed identity is now opt-in by
referencing Azure.Identity and passing a TokenCredential to
AddAzureOpenAIChatClientProvider.

Fixes #9712

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 12:34
@Evangelink
Evangelink enabled auto-merge (squash) July 9, 2026 12:39
@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jul 9, 2026

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

Note

Copilot was unable to run its full agentic suite in this review.

This PR reworks the Azure OpenAI chat client provider so that it authenticates with an API key by default and only uses Entra ID / managed identity when a TokenCredential is explicitly supplied. This removes the hard dependency on Azure.Identity (and its MSAL graph) from the package, replacing it with a lighter Azure.Core reference and an injectable credential.

Changes:

  • Replaced the implicit DefaultAzureCredential fallback with an optional, injectable TokenCredential, adding a None authentication mode when neither an API key nor a credential is available.
  • Added a new AddAzureOpenAIChatClientProvider(ITestApplicationBuilder, TokenCredential) overload and a new NoAuthenticationConfigured error resource.
  • Swapped the Azure.Identity package reference for Azure.Core, and updated public/internal API baselines, docs, and tests accordingly.
Show a summary per file
File Description
OpenAIChatClientProvider.cs Core change: injectable credential, None auth mode, API-key-first selection logic, and throw when no auth is configured.
TestApplicationBuilderExtensions.cs Adds a credential-accepting overload and updates XML docs.
Resources/ExtensionResources.resx Adds the NoAuthenticationConfigured error message.
PublicAPI/PublicAPI.Unshipped.txt Declares the new public overload.
PACKAGE.md Documents API-key-by-default and opt-in TokenCredential authentication.
Microsoft.Testing.Extensions.AzureFoundry.csproj Replaces Azure.Identity with Azure.Core.
InternalAPI/InternalAPI.Unshipped.txt Adds new enum members and constructor.
InternalAPI/InternalAPI.Shipped.txt Removes old enum members and updates GetAuthenticationMode signature.
Directory.Packages.props Replaces the Azure.Identity package version with Azure.Core.
AzureFoundryChatClientProviderTests.cs Updates and adds tests for the new authentication behavior.

Review details

  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Medium

@Evangelink
Evangelink disabled auto-merge July 9, 2026 17:08
@Evangelink
Evangelink enabled auto-merge (squash) July 9, 2026 17:08
Copilot AI review requested due to automatic review settings July 9, 2026 17:08
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9779

14 changed test methods graded across 1 file (AzureFoundryChatClientProviderTests): 12 A and 2 B. The two B-grade tests each fold mode-selection and client-construction assertions into a single body — splitting each into two focused tests would sharpen intent and make failure messages more precise. All other tests are clean with well-scoped, precise assertions.

GradeTestNotes
B (80–89) mod AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WithApiKey_
UsesApiKeyPathAndReturnsClient
Verifies mode selection and client construction together — consider splitting into two focused single-behavior tests.
B (80–89) mod AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WithCredentialAndNoApiKey_
UsesCredentialPathAndReturnsClient
Verifies credential mode and client construction in one body — consider splitting for cleaner single-behavior isolation.
A (90–100) new AzureFoundryChatClientProviderTests.
Constructor_
WithNullCredential_
Throws
Concise null-arg guard using ThrowsExactly — no issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WithoutApiKeyOrCredential_
Throws
Clean exception test; verifies exact type and message content — no issues found.
A (90–100) mod AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithApiKey_
ReturnsApiKey
Updated to two-parameter signature; equality assertion is complete for this pure function — no issues.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithApiKeyAndCredential_
ReturnsApiKey
Tests key-over-credential precedence with precise equality — no issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithCredentialAndNoApiKey_
ReturnsTokenCredential
No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithEmptyApiKeyAndCredential_
ReturnsTokenCredential
Empty-string key treated same as null when a credential is present — edge case covered correctly.
A (90–100) mod AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithEmptyApiKeyAndNoCredential_
ReturnsNone
Tests empty-string key without credential returns None — edge case properly asserted.
A (90–100) mod AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithoutApiKeyOrCredential_
ReturnsNone
Renamed to reflect new None mode; equality assertion is precise — no issues.
A (90–100) mod AzureFoundryChatClientProviderTests.
IsAvailable_
WhenDeploymentMissing_
ReturnsFalse
Setup now includes API key to reflect new auth requirements — no issues.
A (90–100) new AzureFoundryChatClientProviderTests.
IsAvailable_
WhenEndpointAndDeploymentSetWithCredential_
ReturnsTrue
New test covers credential injection path; boolean state assertion is clear — no issues.
A (90–100) mod AzureFoundryChatClientProviderTests.
IsAvailable_
WhenEndpointAndDeploymentSetWithoutApiKeyOrCredential_
ReturnsFalse
Renamed + inverted to correctly test no-auth unavailability — no issues found.
A (90–100) mod AzureFoundryChatClientProviderTests.
IsAvailable_
WhenEndpointMissing_
ReturnsFalse
Setup now includes API key to reflect new auth requirements — no issues.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · 84.2 AIC · ⌖ 10 AIC · ⊞ 9.5K · [◷]( · )

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.

Review details

  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Medium

@Evangelink
Evangelink disabled auto-merge July 9, 2026 18:58
@Evangelink
Evangelink enabled auto-merge (squash) July 9, 2026 18:58
@Evangelink
Evangelink disabled auto-merge July 9, 2026 19:04
@Evangelink
Evangelink enabled auto-merge (squash) July 9, 2026 19:04
@Evangelink
Evangelink merged commit fbbbfb9 into main Jul 9, 2026
54 checks passed
@Evangelink
Evangelink deleted the dev/amauryleve/animated-waddle branch July 9, 2026 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-review Awaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revisit Azure.Identity dependency in Microsoft.Testing.Extensions.AzureFoundry before GA

3 participants