Skip to content

fix: fall back to device code when browser auth fails on macOS#290

Merged
gwharris7 merged 3 commits into
mainfrom
fix/macos-browser-auth-platform-fallback
Feb 25, 2026
Merged

fix: fall back to device code when browser auth fails on macOS#290
gwharris7 merged 3 commits into
mainfrom
fix/macos-browser-auth-platform-fallback

Conversation

@sellakumaran

@sellakumaran sellakumaran commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a365 setup failing on macOS 15.x with a PlatformNotSupportedException (message: "macOS 15.3.1") during authentication. MSAL throws this exception when the system browser is unavailable for interactive auth. Previously this bubbled up as an unhandled error; now the CLI automatically falls back to device code flow so the user can complete sign-in from any browser.

Changes

1. macOS browser auth fallback to device code (main fix)

  • MsalBrowserCredential.GetTokenAsync now catches PlatformNotSupportedException and wraps it as MsalAuthenticationFailedException so it is properly classified rather than escaping as an unexpected error
  • AuthenticateInteractivelyAsync detects the platform exception at the token acquisition site and automatically retries using device code flow
  • Extracts CreateDeviceCodeCredential helper to eliminate duplicated DeviceCodeCredential setup between the normal device code path and the new fallback path

2. Auth logging improvements

  • Changed LogError to LogWarning for PlatformNotSupportedException in MsalBrowserCredential — this is a recoverable condition, not an error
  • Moved device code info log messages to call sites so they only appear when device code is actually being used, not at credential construction time

3. Cross-platform install script

  • Adds install-cli.sh (bash) as the single implementation for building, packing, and installing the CLI tool locally
  • Replaces the Windows-only PowerShell implementation in install-cli.ps1 with a thin wrapper that locates Git Bash and delegates to install-cli.sh on all platforms
  • Eliminates ~100 lines of duplicated logic; any future changes to the install flow only need to be made in one place

Files Changed

File Change
src/.../Services/MsalBrowserCredential.cs Catch PlatformNotSupportedException, use LogWarning
src/.../Services/AuthenticationService.cs Device code fallback, extract CreateDeviceCodeCredential, fix log timing
scripts/cli/install-cli.sh New — cross-platform install implementation
scripts/cli/install-cli.ps1 Replaced with thin bash wrapper

Closes #291

sellakumaran and others added 3 commits February 24, 2026 18:24
MsalBrowserCredential.GetTokenAsync now catches PlatformNotSupportedException
(thrown by MSAL on macOS 15.x) and wraps it as MsalAuthenticationFailedException
so it is properly classified rather than appearing as an unexpected error.

AuthenticateInteractivelyAsync detects this platform exception at the token
acquisition site and automatically falls back to device code flow, allowing
a365 setup to complete on macOS without manual workarounds.

Extracts CreateDeviceCodeCredential helper to eliminate the duplicated
DeviceCodeCredential setup between the normal device code path and the fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Moved device code authentication info logs to calling sites so they're only shown when relevant. Changed platform-not-supported log level in MsalBrowserCredential from Error to Warning to better reflect recoverable conditions.
Replaced PowerShell install logic with a Bash script (install-cli.sh) that handles cleaning, building, packing, and installing the Agent 365 CLI from a local NuGet package. PowerShell now locates bash and invokes the script, unifying installation across platforms and simplifying maintenance.
Copilot AI review requested due to automatic review settings February 25, 2026 03:03
@sellakumaran sellakumaran requested review from a team as code owners February 25, 2026 03:03
@github-actions

Copy link
Copy Markdown

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

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 pull request fixes a critical authentication issue on macOS 15.x where PlatformNotSupportedException is thrown during browser-based authentication. The fix implements automatic fallback to device code flow when browser authentication is unavailable. Additionally, the PR consolidates install scripts to eliminate duplication by using a single bash implementation across all platforms.

Changes:

  • Implements automatic fallback from browser authentication to device code flow when PlatformNotSupportedException is encountered
  • Improves auth logging by using LogWarning instead of LogError for recoverable platform exceptions and moving device code messages to call sites
  • Consolidates install scripts: new install-cli.sh (bash) provides single cross-platform implementation; install-cli.ps1 becomes thin wrapper that locates Git Bash on Windows

Reviewed changes

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

File Description
src/.../Services/MsalBrowserCredential.cs Catches PlatformNotSupportedException during token acquisition and wraps it as MsalAuthenticationFailedException; changes log level from error to warning for this recoverable condition
src/.../Services/AuthenticationService.cs Implements fallback logic to retry with device code flow when browser auth fails; extracts CreateDeviceCodeCredential helper to eliminate duplication; moves device code log messages to call sites
scripts/cli/install-cli.sh New cross-platform bash script that handles build, pack, and install workflow; eliminates ~100 lines of duplicated PowerShell logic
scripts/cli/install-cli.ps1 Replaced implementation with thin wrapper that locates Git Bash on Windows and delegates to install-cli.sh
Comments suppressed due to low confidence (2)

scripts/cli/install-cli.sh:1

  • According to the custom coding guidelines (Rule 2), all C# and script files should have proper Microsoft copyright headers. This new script file is missing the required copyright header. Please add the following at the top of the file (after the shebang line):

Copyright (c) Microsoft Corporation.

Licensed under the MIT License.

#!/usr/bin/env bash

src/Microsoft.Agents.A365.DevTools.Cli/Services/AuthenticationService.cs:250

  • The new fallback behavior from browser authentication to device code flow is a significant change to the authentication flow, but there are no tests covering this specific scenario. Consider adding a test that verifies the fallback occurs correctly when PlatformNotSupportedException is thrown. This would help ensure the fix continues to work as macOS and authentication libraries evolve.
            catch (MsalAuthenticationFailedException ex) when (useInteractiveBrowser && ex.InnerException is PlatformNotSupportedException)
            {
                _logger.LogWarning("Browser authentication is not supported on this platform, falling back to device code flow...");
                _logger.LogInformation("Using device code authentication...");
                _logger.LogInformation("Please sign in with your Microsoft account");
                var deviceCodeCredential = CreateDeviceCodeCredential(effectiveTenantId, effectiveClientId);
                tokenResult = await deviceCodeCredential.GetTokenAsync(tokenRequestContext, default);
            }

Comment thread scripts/cli/install-cli.ps1
@sellakumaran sellakumaran changed the title # fix: fall back to device code when browser auth fails on macOS fix: fall back to device code when browser auth fails on macOS Feb 25, 2026
@gwharris7 gwharris7 merged commit 1cfadfb into main Feb 25, 2026
12 checks passed
@gwharris7 gwharris7 deleted the fix/macos-browser-auth-platform-fallback branch February 25, 2026 17:06
sellakumaran added a commit that referenced this pull request Feb 25, 2026
- install-cli.ps1: replace $IsWindows with $env:OS -eq 'Windows_NT' for
  PowerShell 5.1 compatibility ($IsWindows is undefined/null in PS 5.1)
- install-cli.sh: add copyright header, set -u, show dotnet tool update output
- AuthenticationService: extract CreateBrowserCredential and CreateDeviceCodeCredential
  as protected virtual TokenCredential to enable test injection without changing the
  DI contract
- AuthenticationServiceTests: add ThrowingTokenCredential, StubTokenCredential,
  TestableAuthenticationService and 4 tests covering macOS PlatformNotSupportedException
  fallback behavior

Follows up on #290 (macOS browser auth platform fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sellakumaran added a commit that referenced this pull request Feb 27, 2026
#292)

* fix: PS 5.1 install compatibility and macOS auth testability follow-up

- install-cli.ps1: replace $IsWindows with $env:OS -eq 'Windows_NT' for
  PowerShell 5.1 compatibility ($IsWindows is undefined/null in PS 5.1)
- install-cli.sh: add copyright header, set -u, show dotnet tool update output
- AuthenticationService: extract CreateBrowserCredential and CreateDeviceCodeCredential
  as protected virtual TokenCredential to enable test injection without changing the
  DI contract
- AuthenticationServiceTests: add ThrowingTokenCredential, StubTokenCredential,
  TestableAuthenticationService and 4 tests covering macOS PlatformNotSupportedException
  fallback behavior

Follows up on #290 (macOS browser auth platform fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix parameter order for CreateDeviceCodeCredential method

Update CreateDeviceCodeCredential to use (clientId, tenantId) order in both implementation and tests. Update all call sites to match new signature. Add xUnit collection to authentication tests to prevent parallel execution and avoid shared resource conflicts.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
sellakumaran added a commit that referenced this pull request Feb 27, 2026
* fix: fall back to device code when browser auth fails on macOS

MsalBrowserCredential.GetTokenAsync now catches PlatformNotSupportedException
(thrown by MSAL on macOS 15.x) and wraps it as MsalAuthenticationFailedException
so it is properly classified rather than appearing as an unexpected error.

AuthenticateInteractivelyAsync detects this platform exception at the token
acquisition site and automatically falls back to device code flow, allowing
a365 setup to complete on macOS without manual workarounds.

Extracts CreateDeviceCodeCredential helper to eliminate the duplicated
DeviceCodeCredential setup between the normal device code path and the fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve device code auth logging and error handling

Moved device code authentication info logs to calling sites so they're only shown when relevant. Changed platform-not-supported log level in MsalBrowserCredential from Error to Warning to better reflect recoverable conditions.

* Refactor CLI install: delegate to Bash script

Replaced PowerShell install logic with a Bash script (install-cli.sh) that handles cleaning, building, packing, and installing the Agent 365 CLI from a local NuGet package. PowerShell now locates bash and invokes the script, unifying installation across platforms and simplifying maintenance.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
pratapladhani pushed a commit to pratapladhani/Agent365-devTools that referenced this pull request Mar 4, 2026
…soft#290)

* fix: fall back to device code when browser auth fails on macOS

MsalBrowserCredential.GetTokenAsync now catches PlatformNotSupportedException
(thrown by MSAL on macOS 15.x) and wraps it as MsalAuthenticationFailedException
so it is properly classified rather than appearing as an unexpected error.

AuthenticateInteractivelyAsync detects this platform exception at the token
acquisition site and automatically falls back to device code flow, allowing
a365 setup to complete on macOS without manual workarounds.

Extracts CreateDeviceCodeCredential helper to eliminate the duplicated
DeviceCodeCredential setup between the normal device code path and the fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Improve device code auth logging and error handling

Moved device code authentication info logs to calling sites so they're only shown when relevant. Changed platform-not-supported log level in MsalBrowserCredential from Error to Warning to better reflect recoverable conditions.

* Refactor CLI install: delegate to Bash script

Replaced PowerShell install logic with a Bash script (install-cli.sh) that handles cleaning, building, packing, and installing the Agent 365 CLI from a local NuGet package. PowerShell now locates bash and invokes the script, unifying installation across platforms and simplifying maintenance.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
pratapladhani pushed a commit to pratapladhani/Agent365-devTools that referenced this pull request Mar 4, 2026
microsoft#292)

* fix: PS 5.1 install compatibility and macOS auth testability follow-up

- install-cli.ps1: replace $IsWindows with $env:OS -eq 'Windows_NT' for
  PowerShell 5.1 compatibility ($IsWindows is undefined/null in PS 5.1)
- install-cli.sh: add copyright header, set -u, show dotnet tool update output
- AuthenticationService: extract CreateBrowserCredential and CreateDeviceCodeCredential
  as protected virtual TokenCredential to enable test injection without changing the
  DI contract
- AuthenticationServiceTests: add ThrowingTokenCredential, StubTokenCredential,
  TestableAuthenticationService and 4 tests covering macOS PlatformNotSupportedException
  fallback behavior

Follows up on microsoft#290 (macOS browser auth platform fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix parameter order for CreateDeviceCodeCredential method

Update CreateDeviceCodeCredential to use (clientId, tenantId) order in both implementation and tests. Update all call sites to match new signature. Add xUnit collection to authentication tests to prevent parallel execution and avoid shared resource conflicts.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
sellakumaran added a commit that referenced this pull request Mar 4, 2026
…RL opening

- MsalBrowserCredential: catch PlatformNotSupportedException and fall back to
  device code flow instead of re-throwing, so macOS/Linux headless environments
  always get a working auth path
- InteractiveGraphAuthService: eagerly acquire token before constructing
  GraphServiceClient to surface auth failures at construction time rather than
  silently returning a broken client (Gap 2 from PR #290)
- InteractiveGraphAuthService: inject optional credentialFactory for testability
- AuthenticationService: replace Console.WriteLine with structured logger calls
  in device code callback
- Add BrowserHelper with cross-platform TryOpenUrl (Windows/macOS/Linux)
- Remove duplicated TryOpenBrowser methods from BlueprintSubcommand and
  A365CreateInstanceRunner; both now call BrowserHelper.TryOpenUrl directly
- Add 5 unit tests covering the eager-auth gap and credential caching behavior
sellakumaran added a commit that referenced this pull request Mar 6, 2026
…RL opening (#309)

* fix: device code fallback for macOS browser auth and cross-platform URL opening

- MsalBrowserCredential: catch PlatformNotSupportedException and fall back to
  device code flow instead of re-throwing, so macOS/Linux headless environments
  always get a working auth path
- InteractiveGraphAuthService: eagerly acquire token before constructing
  GraphServiceClient to surface auth failures at construction time rather than
  silently returning a broken client (Gap 2 from PR #290)
- InteractiveGraphAuthService: inject optional credentialFactory for testability
- AuthenticationService: replace Console.WriteLine with structured logger calls
  in device code callback
- Add BrowserHelper with cross-platform TryOpenUrl (Windows/macOS/Linux)
- Remove duplicated TryOpenBrowser methods from BlueprintSubcommand and
  A365CreateInstanceRunner; both now call BrowserHelper.TryOpenUrl directly
- Add 5 unit tests covering the eager-auth gap and credential caching behavior

* fix: address PR review comments and handle Linux xdg_open_failed error

- MsalBrowserCredential: also catch MsalClientException(linux_xdg_open_failed)
  for device code fallback on Linux/WSL (confirmed via WSL Ubuntu 24.04 repro);
  extract shared AcquireTokenWithDeviceCodeFallbackAsync to avoid duplication
- BrowserHelper: fall back to Console.Error when logger is null so the manual
  URL is never silently lost regardless of caller
- BlueprintSubcommand: log consent URL before TryOpenUrl and pass logger so
  users on headless platforms always see the URL to complete admin consent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: auto-fix public client flows, add requirements check to blueprint, clean AADSTS7000218 error

- ClientAppValidator: add EnsurePublicClientFlowsEnabledAsync (Step 7) that auto-detects and
  enables 'Allow public client flows' on the app registration via az rest GET/PATCH — required
  for MSAL device code fallback on macOS/Linux; non-fatal if PATCH fails
- BlueprintSubcommand: run config requirements checks (LocationCheck + ClientAppCheck) before
  blueprint logic, with --skip-requirements opt-out; matches AllSubcommand pattern
- MsalBrowserCredential: catch AADSTS7000218/invalid_client before general MsalException to
  emit clean actionable error message pointing to 'a365 setup requirements' instead of stack trace
- Tests: add EnsurePublicClientFlowsEnabledAsync tests (enabled/disabled/patch-fails) and
  CreateCommand_ShouldHaveSkipRequirementsOption test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: eliminate double auth on Linux, improve PS module error handling

- MsalBrowserCredential: add shared in-memory MSAL token cache for Linux
  so all MsalBrowserCredential instances within one CLI invocation share
  the same token cache, eliminating repeated device code prompts during
  multi-step operations (e.g. blueprint creation + client secret creation)

- BrowserHelper: remove exception object from LogWarning so xdg-open
  failures no longer emit a full stack trace in the output

- MicrosoftGraphTokenProvider: detect missing PowerShell module error and
  log actionable guidance to run 'a365 setup requirements'

- SetupHelpers: replace misleading "please sign in when prompted" message
  with one that mentions missing PS module as a common cause

- PowerShellModulesRequirementCheck: auto-install missing modules via
  Install-Module -Scope CurrentUser -Force -AllowClobber when detected;
  returns Success if auto-install succeeds, Failure with manual steps if not

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: add system requirement checks to all setup commands that use Graph PS auth

setup blueprint was running only config checks (Location + ClientApp),
missing PowerShellModulesRequirementCheck entirely. setup permissions
mcp/bot/custom and setup permissions copilotstudio had no requirement
checks at all. All four now gate on GetSystemRequirementChecks() before
executing Graph operations, so missing Microsoft.Graph.Authentication
is caught and auto-installed upfront rather than failing mid-run.

Closes partial work toward #106.

* Skip requirements on dry run; clarify browser fallback

Requirements checks are now skipped during dry runs to prevent unintended mutations. Updated `TryOpenUrl` documentation to clarify fallback behavior and logging when browser launch fails.

* fix: skip requirements on dry run, self-correct missing PS modules in Graph token acquisition

- Skip system requirement checks (including auto-install) when --dry-run is set in
  PermissionsSubcommand (mcp/bot/custom) and CopilotStudioSubcommand to preserve
  non-mutating dry-run semantics
- MicrosoftGraphTokenProvider now detects a missing/broken Microsoft.Graph module at
  runtime, auto-installs both required Graph modules, and retries token acquisition once
  before failing; error message clarifies auto-install was attempted if retry also fails
- PowerShellModulesRequirementCheck.ExecutePowerShellCommandAsync returns stderr instead
  of null on failure so auto-install debug logs are actionable

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: extract real JWT from Graph request headers; unify PS auth scopes to reduce login prompts

Microsoft.Graph.Authentication v2+ returns an opaque (non-JWT) token from
$ctx.AccessToken that is rejected when used as a Bearer token. Switch to
always extracting the token from the Authorization header of a live
Invoke-MgGraphRequest call, which always contains the real JWT.

Add AgentIdentityBlueprint.UpdateAuthProperties.All to RequiredPermissionGrantScopes
so all PowerShell-based Graph operations (OAuth2 grants, service principal
lookups, and inheritable permissions) use the same scope set. This ensures
Connect-MgGraph authenticates once and the access token is reused from the
in-process cache for all downstream calls, reducing device code prompts from
4 to 3 on first run (1 PS + 2 MSAL for different resources).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: extract last stdout line as JWT token; add clean error for missing config

- MicrosoftGraphTokenProvider: extract last non-empty stdout line as token.
  Connect-MgGraph in headless Linux/WSL falls back to device code and writes
  the 'To sign in...' prompt to stdout, contaminating the full StandardOutput
  string. Trimming the whole output returns a non-JWT string; taking only the
  last line (where $token is always written) fixes the JWT validation warning
  and the resulting SETUP_VALIDATION_FAILED for inheritable permissions.

- ConfigFileNotFoundException: new Agent365Exception subclass for missing
  a365.config.json. ConfigService.LoadAsync now throws this instead of a raw
  FileNotFoundException, so the global handler displays a clean actionable
  error ('run a365 config init') instead of a full stack trace.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: unify PS token cache key in RemoveStale and DeployCommand; update test

Both RemoveStaleCustomPermissionsAsync (PermissionsSubcommand) and DeployCommand
used a hardcoded 2-scope array missing DelegatedPermissionGrant.ReadWrite.All.
This produced a different sorted cache key than RequiredPermissionGrantScopes,
causing a second Connect-MgGraph device-code prompt during 'setup blueprint'
even though a token was already cached from the inheritable permissions step.

Switch both sites to AuthenticationConstants.RequiredPermissionGrantScopes so
all Graph token acquisitions share one cache entry per CLI invocation.

Update Agent365ConfigServiceTests to expect ConfigFileNotFoundException instead
of FileNotFoundException, matching the new exception type thrown by ConfigService.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: improve auth prompt UX and clarify custom permissions message

MicrosoftGraphTokenProvider: replace misleading "Device Code: False" log
with platform-specific guidance so users know what to expect:
- Windows: "A browser window will open for authentication..."
- Linux/macOS: "A device code prompt will appear below..."
This avoids confusion when Connect-MgGraph auto-switches to device code
in headless environments even though useDeviceCode=false was requested.

PermissionsSubcommand: change "No custom blueprint permissions configured"
to "No custom blueprint permissions specified in config. Skipping." to make
clear this is about config content, not a system state or error condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: retry blueprint SP lookup on Azure AD propagation delay

LookupServicePrincipalByAppIdAsync can return null for 10-30s after
blueprint creation due to Azure AD eventual consistency. Use the existing
RetryHelper (already used for inheritable permissions verification) to
retry up to 5 times with 5s base delay / exponential backoff before
throwing the 'service principal may not have propagated' error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: fix admin consent polling via MSAL token with Application.Read.All

Root cause: SP lookup and consent grant queries used az CLI token (scopes=null)
which lacks Application.Read.All and DelegatedPermissionGrant.ReadWrite.All.
Graph silently returned HTTP 200 with empty array, leaving blueprintSpId=null
and causing polling to time out after 180s even after consent was granted.

Changes:
- BlueprintSubcommand: pass RequiredPermissionGrantScopes to SP lookups and
  CheckConsentExistsAsync; resolve blueprintSpId once at start of consent flow;
  use new MSAL PollAdminConsentAsync when SP ID is available
- AdminConsentHelper: add MSAL PollAdminConsentAsync overload using GraphApiService;
  add scopes param to CheckConsentExistsAsync; add progress/timeout log messages
- BlueprintLookupService: add optional scopes param to GetServicePrincipalByAppIdAsync
- GraphApiService: add debug logging for failed GET; fix JsonDocument disposal
- CommandExecutor: add optional outputTransform to ExecuteWithStreamingAsync
- MicrosoftGraphTokenProvider: reformat PS device code output to MSAL box style
- AuthenticationService: reduce token cache log noise (LogInfo -> LogDebug)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: fall back to MSAL when PS Connect-MgGraph fails on any platform

When PowerShell Connect-MgGraph fails (NullRef in DeviceCodeCredential
on Linux, no TTY, module issues, or any other reason), fall back to
MsalBrowserCredential to acquire the Graph token. On Windows this uses
WAM; on Linux/macOS it uses device code with silent-first logic.

The token is stored in MicrosoftGraphTokenProvider's in-process cache
so subsequent calls (inheritable permissions, custom permissions) within
the same CLI invocation reuse it without re-prompting.

Also adds silent token acquisition attempt before device code in
MsalBrowserCredential.AcquireTokenWithDeviceCodeFallbackAsync to
reduce unnecessary device code prompts when a cached token exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address PR review comments - disposal, logging, exit handling, doc fixes

- ConfigFileNotFoundException: derive from FileNotFoundException so existing
  catch sites (CleanupCommand, DeployCommand, etc.) continue to work
- InteractiveGraphAuthService: remove unused Azure.Identity using; move
  credential factory resolution inside try/catch for consistent error wrapping
- BrowserHelper: include exception object in LogWarning for structured logging
- PowerShellModulesRequirementCheck: fix GenerateInstallationInstructions
  to produce valid PS syntax for multi-module Install-Module calls
- PermissionsSubcommand / CopilotStudioSubcommand: replace Environment.Exit(1)
  with ExceptionHandler.ExitWithCleanup(1) to flush output before exit
- MicrosoftGraphTokenProvider: dispose HttpResponseMessage after token extraction
- MsalBrowserCredential: use platform-neutral path notation in cache doc comment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address second round of PR review comments

- ConfigFileNotFoundException: add explicit using System.IO to avoid
  implicit global usings dependency
- SetupHelpers: remove unnecessary ! null-forgiving operator on awaited
  task (it only asserts the Task itself is non-null, not the result)
- BrowserHelper: use ArgumentList instead of Arguments for open/xdg-open
  to avoid argument parsing issues with special characters in URLs
- MsalBrowserCredential: filter cached MSAL account by tenant ID before
  silent auth to avoid authenticating as wrong identity when multiple
  accounts are cached; fall through to device code if no tenant match
- MicrosoftGraphTokenProvider: reuse IsPowerShellModuleMissingError in
  ProcessResult to eliminate duplicated string-matching logic

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add CHANGELOG, NuGet release notes, and review process updates

- CHANGELOG.md: Keep a Changelog format covering [Unreleased], 1.1.0, 1.0.0
- Directory.Build.props: PackageReleaseNotes points to CHANGELOG.md (fixes NuGet warning)
- src/DEVELOPER.md: update Release Process to describe workflow; add CHANGELOG to PR checklist
- .github/copilot-instructions.md: add CHANGELOG reminder to Code Review Mindset
- .claude/agents/pr-code-reviewer.md: add CHANGELOG check in Step 2
- .claude/agents/code-reviewer.md: add CHANGELOG check to Self-Verification
- .claude/agents/code-review-manager.md: add CHANGELOG to Project Context standards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address PR review comments - StringComparison, PSGallery, encoding, docs

- MsalBrowserCredential.cs: StringComparison.Ordinal on Contains calls; comment clarifying same-tenant account edge case
- InteractiveGraphAuthService.cs: StringComparison.Ordinal on all Contains calls in exception filters
- PowerShellModulesRequirementCheck.cs: pin Install-Module to -Repository PSGallery
- MicrosoftGraphTokenProvider.cs: pin both Install-Module calls to -Repository PSGallery
- GraphApiService.cs: fix U+FFFD encoding artifact in comment
- CommandExecutor.cs: document outputPrefix applies only to first line (outputTransform must not return multi-line)
- BlueprintLookupService.cs: comment that DisplayName is not populated in this lookup path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

a365 setup all fails on macOS 15.x with PlatformNotSupportedException during authentication

5 participants