Skip to content

Support managed identity auth in AzureFoundry provider#9707

Merged
Evangelink merged 3 commits into
mainfrom
dev/amauryleve/azurefoundry-managed-identity-auth
Jul 8, 2026
Merged

Support managed identity auth in AzureFoundry provider#9707
Evangelink merged 3 commits into
mainfrom
dev/amauryleve/azurefoundry-managed-identity-auth

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes #8412

Summary

Microsoft.Testing.Extensions.AzureFoundry previously hard-required AZURE_OPENAI_API_KEY and always constructed AzureOpenAIClient with ApiKeyCredential, with no managed-identity / Entra path. This made the only built-in AI provider not secure-by-default for Azure-hosted scenarios.

Changes

  • IsAvailable now only requires AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_DEPLOYMENT_NAME; the API key is no longer mandatory.
  • CreateChatClientAsync prefers an explicit AZURE_OPENAI_API_KEY when present, otherwise falls back to DefaultAzureCredential (managed identity, workload identity, Azure CLI, Visual Studio, …).
  • Added the Azure.Identity package reference (version pinned in Directory.Packages.props).
  • Updated PACKAGE.md with a configuration table documenting both authentication modes.

Notes

  • No .resx/.xlf changes were needed — the existing EnvironmentVariableNotSet string is still used for the endpoint/deployment checks.
  • Built cleanly (netstandard2.0, net8.0, net9.0) with 0 warnings/0 errors.

The AzureFoundry chat client provider now authenticates with
DefaultAzureCredential (Entra ID / managed identity) when no
AZURE_OPENAI_API_KEY is set, keeping the provider secure-by-default
for Azure-hosted scenarios. The API key remains an explicit fallback,
and IsAvailable no longer requires an API key.

Fixes #8412

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 7, 2026 14:04

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

This PR makes the Microsoft.Testing.Extensions.AzureFoundry provider support Microsoft Entra ID / managed-identity authentication instead of hard-requiring AZURE_OPENAI_API_KEY, closing the secure-by-default gap described in issue #8412. The provider now reports itself available whenever the endpoint and deployment name are configured, and it authenticates via DefaultAzureCredential when no API key is supplied, keeping the explicit API-key path as an override.

Changes:

  • IsAvailable no longer requires AZURE_OPENAI_API_KEY (only endpoint + deployment name).
  • CreateChatClientAsync uses ApiKeyCredential when a key is present, otherwise falls back to DefaultAzureCredential.
  • Adds the Azure.Identity dependency (version pinned via CPM) and documents both auth modes in PACKAGE.md.
Show a summary per file
File Description
src/Platform/Microsoft.Testing.Extensions.AzureFoundry/OpenAIChatClientProvider.cs Drops the mandatory API-key check and selects DefaultAzureCredential vs ApiKeyCredential based on whether the key is set.
src/Platform/Microsoft.Testing.Extensions.AzureFoundry/PACKAGE.md Adds a configuration table and prose documenting the managed-identity and API-key authentication modes.
src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj References the new Azure.Identity package.
Directory.Packages.props Pins Azure.Identity version 1.14.2 under central package management.

Review details

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

Comment thread Directory.Packages.props Outdated

@github-actions github-actions Bot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

# Dimension Verdict
13 Test Completeness 🟡 1 MODERATE
20 Build Infrastructure & Dependencies 🟡 1 MODERATE
17 Documentation Accuracy ⚪ 1 NIT

✅ 19/22 dimensions clean (dimensions 10–12, 14, 18–19, 22 skipped as N/A).

  • Test Completeness — no unit tests cover the new DefaultAzureCredential branch (or any path of AzureOpenAIChatClientProvider)
  • Build Infrastructure — Azure.Identity adds a heavyweight transitive dependency graph; acceptable while alpha/non-shipping, but worth revisiting before GA
  • Documentation — consider noting local-dev latency from DefaultAzureCredential credential chain traversal

Overall: The implementation is clean, correct, and well-documented. The ternary conditional for credential selection is straightforward. The IsAvailable change correctly reflects the new optionality of the API key. No correctness, threading, security, or API compatibility concerns.

Comment thread src/Platform/Microsoft.Testing.Extensions.AzureFoundry/PACKAGE.md
Comment thread Directory.Packages.props Outdated
- Reuse a single DefaultAzureCredential instance (Lazy) so the token
  cache and credential-chain discovery are shared across calls instead
  of being rebuilt on every CreateChatClientAsync invocation.
- Add unit tests for the auth-selection logic (IsAvailable, ModelName,
  API-key vs Entra path, missing-variable failures) in
  Microsoft.Testing.Extensions.UnitTests, with env-var snapshot/restore
  and DoNotParallelize; grant InternalsVisibleTo to the test assembly.
- Document AZURE_CLIENT_ID (user-assigned managed identity) and the
  deferred authentication-failure behavior in PACKAGE.md.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

- Bump Azure.Identity 1.14.2 -> 1.21.0. The 1.14.x line is deprecated
  (depends on a deprecated MSAL); 1.21.0 is the current supported
  release. Verified clean restore/build across all TFMs (no NU1605,
  no audit warnings) and compatible with Azure.AI.OpenAI 2.1.0.
- Extract an internal AuthenticationMode + GetAuthenticationMode seam so
  the API-key-vs-DefaultAzureCredential selection is deterministically
  unit-tested (upgrades the two 'only IsNotNull' tests and adds three
  dedicated selection tests).
- Document DefaultAzureCredential local-dev credential-chain latency in
  PACKAGE.md.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

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: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Low

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #9707

14 new tests graded across 1 file. 12 earn A for clean AAA structure, proper env-var isolation via [DoNotParallelize] + [TestInitialize]/[TestCleanup] snapshot/restore, and precise assertions (equality, boolean state, or exact exception type + message). 2 earn B for mixing two distinct behavioral checks in one test body — extracting the GetAuthenticationMode assertions into their own tests would sharpen those two.

GradeTestNotes
B (80–89) new AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WithApiKey_
UsesApiKeyPathAndReturnsClient
Mixes a GetAuthenticationMode equality check with IsNotNull on the client — consider separate focused tests per concern.
B (80–89) new AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WithoutApiKey_
UsesEntraPathAndReturnsClient
Dual-behavior pattern; GetAuthenticationMode(null) is already covered by a dedicated test — consider removing it from this body.
A (90–100) new AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WhenDeploymentMissing_
Throws
Exact exception type + message content verifies the deployment-missing error path. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
CreateChatClientAsync_
WhenEndpointMissing_
Throws
Exact exception type + message content verifies the endpoint-missing error path. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithApiKey_
ReturnsApiKey
Terse expression-bodied; precise equality confirms non-empty key routes to ApiKey mode. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithEmptyApiKey_
ReturnsDefaultAzureCredential
Edge case covered; empty string triggers managed identity auth identically to null. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
GetAuthenticationMode_
WithoutApiKey_
ReturnsDefaultAzureCredential
Terse; null maps to DefaultAzureCredential. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
HasToolsCapability_
ReturnsTrue
State assertion on the public contract; constant property — test guards against accidental future changes. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
IsAvailable_
WhenApiKeyAlsoSet_
ReturnsTrue
Confirms availability is unchanged when an API key is also provided. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
IsAvailable_
WhenDeploymentMissing_
ReturnsFalse
Negative test; missing deployment variable prevents availability. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
IsAvailable_
WhenEndpointAndDeploymentSetWithoutApiKey_
ReturnsTrue
Positive test for the new no-API-key availability condition. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
IsAvailable_
WhenEndpointMissing_
ReturnsFalse
Negative test; missing endpoint variable prevents availability. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
ModelName_
ReturnsDeploymentName
Clean equality assertion; deployment variable value is surfaced correctly. No issues found.
A (90–100) new AzureFoundryChatClientProviderTests.
ModelName_
WhenDeploymentMissing_
ReturnsUnknown
Equality assertion covers the "unknown" fallback when no deployment is configured. No issues found.

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. · 118.1 AIC · ⌖ 10.5 AIC · ⊞ 9.5K · [◷]( · )

@Evangelink
Evangelink enabled auto-merge (squash) July 8, 2026 07:34
@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jul 8, 2026
@Evangelink
Evangelink merged commit d04f011 into main Jul 8, 2026
63 checks passed
@Evangelink
Evangelink deleted the dev/amauryleve/azurefoundry-managed-identity-auth branch July 8, 2026 08:03
github-actions Bot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
  and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
  for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
  as of MSTest 4.3

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Evangelink pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
  and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
  for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
  as of MSTest 4.3

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

[MTP Diagnostic Analysis] AzureFoundry hard-requires API keys and has no managed-identity auth path

3 participants