Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions core/Azure.Mcp.Core/src/Helpers/CommandHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ public static bool HasSubscriptionAvailable(CommandResult commandResult)
var subscriptionValue = parseResult.GetValueOrDefault<string>(OptionDefinitions.Common.Subscription.Name);

var envSubscription = EnvironmentHelpers.GetAzureSubscriptionId();
return (string.IsNullOrEmpty(subscriptionValue) || IsPlaceholder(subscriptionValue)) && !string.IsNullOrEmpty(envSubscription)
return string.IsNullOrEmpty(subscriptionValue) && !string.IsNullOrEmpty(envSubscription)
? envSubscription
: subscriptionValue;
}

private static bool IsPlaceholder(string value) => value.Contains("subscription") || value.Contains("default");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,23 @@ public async Task<SubscriptionResource> GetSubscription(string subscription, str
{
ValidateRequiredParameters((nameof(subscription), subscription));

// Get the subscription ID first, whether the input is a name or ID
var subscriptionId = await GetSubscriptionId(subscription, tenant, retryPolicy, cancellationToken);
string subscriptionId;
try
{
// Get the subscription ID first, whether the input is a name or ID
subscriptionId = await GetSubscriptionId(subscription, tenant, retryPolicy, cancellationToken);
}
catch
{
// If the subscription lookup failed, try environment variable as fallback
var envSubscription = Core.Helpers.EnvironmentHelpers.GetAzureSubscriptionId();
if (string.IsNullOrEmpty(envSubscription))
{
throw; // Re-throw the original exception if no environment variable is available
}

subscriptionId = await GetSubscriptionId(envSubscription, tenant, retryPolicy, cancellationToken);
}
Comment on lines +50 to +66
Copy link
Contributor

@alzimmermsft alzimmermsft Nov 24, 2025

Choose a reason for hiding this comment

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

By the time we reach this point, didn't we already go through the logic in CommandHelper which checks for --subscription being passed, and if it wasn't falling back to the environment variable AZURE_SUBSCRIPTION_ID? So, wouldn't this be more confusing as if I pass --subscription invalid but have AZURE_SUBSCRIPTION_ID=valid I now have a complicated to understand flow with my --subscription input being ignored and --subscription valid was used.


// Use subscription ID for cache key
var cacheKey = string.IsNullOrEmpty(tenant)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Azure.Mcp.Core.Helpers;
using Azure.Mcp.Core.Options;
using Azure.Mcp.Core.Services.Azure.Subscription;
using Azure.Mcp.Core.Services.Azure.Tenant;
using Azure.Mcp.Core.Services.Caching;
using NSubstitute;
using Xunit;

namespace Azure.Mcp.Core.UnitTests.Services.Azure.Subscription;

public class SubscriptionServiceTests : IDisposable
{
private const string TestSubscriptionId = "12345678-1234-1234-1234-123456789012";
private const string TestSubscriptionName = "Test Subscription";
private const string EnvVarSubscriptionId = "87654321-4321-4321-4321-210987654321";

private readonly ICacheService _cacheService;
private readonly ITenantService _tenantService;
private readonly SubscriptionService _subscriptionService;
private readonly string? _originalEnvValue;

public SubscriptionServiceTests()
{
// Save original environment variable
_originalEnvValue = Environment.GetEnvironmentVariable("AZURE_SUBSCRIPTION_ID");

_cacheService = Substitute.For<ICacheService>();
_tenantService = Substitute.For<ITenantService>();
_subscriptionService = new SubscriptionService(_cacheService, _tenantService);

// Setup default cache behavior to return null (cache miss)
_cacheService.GetAsync<object>(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<TimeSpan>())
.Returns((object?)null);
}

public void Dispose()
{
// Restore original environment variable
if (_originalEnvValue != null)
{
Environment.SetEnvironmentVariable("AZURE_SUBSCRIPTION_ID", _originalEnvValue);
}
else
{
Environment.SetEnvironmentVariable("AZURE_SUBSCRIPTION_ID", null);
}
}

[Fact]
public void IsSubscriptionId_ValidGuid_ReturnsTrue()
{
// Act
var result = _subscriptionService.IsSubscriptionId(TestSubscriptionId);

// Assert
Assert.True(result);
}

[Fact]
public void IsSubscriptionId_InvalidGuid_ReturnsFalse()
{
// Act
var result = _subscriptionService.IsSubscriptionId("not-a-guid");

// Assert
Assert.False(result);
}

[Fact]
public void IsSubscriptionId_SubscriptionName_ReturnsFalse()
{
// Act
var result = _subscriptionService.IsSubscriptionId(TestSubscriptionName);

// Assert
Assert.False(result);
}

[Fact]
public void EnvironmentVariableFallback_IsAvailable()
{
// Arrange
Environment.SetEnvironmentVariable("AZURE_SUBSCRIPTION_ID", EnvVarSubscriptionId);

// Act
var envSubscription = EnvironmentHelpers.GetAzureSubscriptionId();

// Assert
Assert.Equal(EnvVarSubscriptionId, envSubscription);
}

[Fact]
public void EnvironmentVariableFallback_WhenNotSet_ReturnsNull()
{
// Arrange
Environment.SetEnvironmentVariable("AZURE_SUBSCRIPTION_ID", null);

// Act
var envSubscription = EnvironmentHelpers.GetAzureSubscriptionId();

// Assert
Assert.Null(envSubscription);
}

[Theory]
[InlineData("12345678-1234-1234-1234-123456789012", true)]
[InlineData("00000000-0000-0000-0000-000000000000", true)]
[InlineData("subscription", false)]
[InlineData("default", false)]
[InlineData("My Subscription Name", false)]
[InlineData("test-subscription", false)]
public void IsSubscriptionId_VariousInputs_ReturnsExpected(string input, bool expected)
{
// Act
var result = _subscriptionService.IsSubscriptionId(input);

// Assert
Assert.Equal(expected, result);
}
}

Loading