Skip to content
Merged
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
28 changes: 28 additions & 0 deletions docs/ai-workflows/integration-test-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,34 @@ a365 setup blueprint
# Record: Blueprint ID (from a365.config.json)
```

#### Test 4.1a: Verify CustomClientAppId Configuration
```bash
# This test verifies the fix for issue #271 where CustomClientAppId was not being set,
# causing inheritable permissions operations to fail on macOS/Linux

# Prerequisite: Ensure config has clientAppId set
$config = Get-Content a365.config.json | ConvertFrom-Json
$config.clientAppId | Should -Not -BeNullOrEmpty

# Enable trace logging to capture Graph API authentication
$env:AGENT365_LOG_LEVEL = "Trace"

# Re-run blueprint setup with inheritable permissions
a365 setup blueprint --verbose 2>&1 | Tee-Object -Variable output

# Verify output contains correct client ID usage
# The trace logs should show Connect-MgGraph with the correct -ClientId parameter
$output | Select-String -Pattern "Connect-MgGraph.*-ClientId $($config.clientAppId)"

# Expected:
# - Trace logs show Connect-MgGraph command with correct -ClientId
# - No "Tenant not found" errors (would indicate clientAppId/tenantId were swapped)
# - Inheritable permissions operations succeed without falling back to SDK default app

# Record: CustomClientAppId configured correctly (Yes/No)
# Record: Connect-MgGraph used correct ClientId (Yes/No)
```

#### Test 4.2: Verify Blueprint in Entra ID
```bash
# Query blueprint scopes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ public static Command CreateCommand(

var setupConfig = await configService.LoadAsync(config.FullName);

// Configure GraphApiService with custom client app ID if available
// This ensures inheritable permissions operations use the validated custom app
if (!string.IsNullOrWhiteSpace(setupConfig.ClientAppId))
{
graphApiService.CustomClientAppId = setupConfig.ClientAppId;
}

// Handle --update-endpoint flag
if (!string.IsNullOrWhiteSpace(updateEndpoint))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1524,6 +1524,115 @@ await _mockBotConfigurator.Received(1).CreateEndpointWithAgentBlueprintAsync(

#endregion

#region CustomClientAppId Configuration Tests

[Fact]
public async Task SetHandler_WithClientAppId_ShouldConfigureGraphApiService()
{
// Arrange
var config = new Agent365Config
{
TenantId = "test-tenant",
ClientAppId = "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6",
AgentBlueprintDisplayName = "Test Blueprint"
};

_mockConfigService.LoadAsync(Arg.Any<string>(), Arg.Any<string>())
.Returns(Task.FromResult(config));

var command = BlueprintSubcommand.CreateCommand(
_mockLogger,
_mockConfigService,
_mockExecutor,
_mockAzureValidator,
_mockWebAppCreator,
_mockPlatformDetector,
_mockBotConfigurator,
_mockGraphApiService, _mockBlueprintService, _mockClientAppValidator, _mockBlueprintLookupService, _mockFederatedCredentialService);

var parser = new CommandLineBuilder(command).Build();
var testConsole = new TestConsole();

// Act
await parser.InvokeAsync("--dry-run", testConsole);

// Assert - Verify CustomClientAppId was set on GraphApiService
_mockGraphApiService.CustomClientAppId.Should().Be(config.ClientAppId,
"CustomClientAppId must be set to ensure inheritable permissions use the correct client app");
}

[Fact]
public async Task SetHandler_WithoutClientAppId_ShouldNotConfigureGraphApiService()
{
// Arrange
var config = new Agent365Config
{
TenantId = "test-tenant",
ClientAppId = "", // No client app ID
AgentBlueprintDisplayName = "Test Blueprint"
};

_mockConfigService.LoadAsync(Arg.Any<string>(), Arg.Any<string>())
.Returns(Task.FromResult(config));

var command = BlueprintSubcommand.CreateCommand(
_mockLogger,
_mockConfigService,
_mockExecutor,
_mockAzureValidator,
_mockWebAppCreator,
_mockPlatformDetector,
_mockBotConfigurator,
_mockGraphApiService, _mockBlueprintService, _mockClientAppValidator, _mockBlueprintLookupService, _mockFederatedCredentialService);

var parser = new CommandLineBuilder(command).Build();
var testConsole = new TestConsole();

// Act
await parser.InvokeAsync("--dry-run", testConsole);

// Assert - Verify CustomClientAppId was NOT set (remains null)
_mockGraphApiService.CustomClientAppId.Should().BeNullOrEmpty(
"CustomClientAppId should not be set when config does not have a ClientAppId");
}

[Fact]
public async Task SetHandler_WithWhitespaceClientAppId_ShouldNotConfigureGraphApiService()
{
// Arrange
var config = new Agent365Config
{
TenantId = "test-tenant",
ClientAppId = " ", // Whitespace only
AgentBlueprintDisplayName = "Test Blueprint"
};

_mockConfigService.LoadAsync(Arg.Any<string>(), Arg.Any<string>())
.Returns(Task.FromResult(config));

var command = BlueprintSubcommand.CreateCommand(
_mockLogger,
_mockConfigService,
_mockExecutor,
_mockAzureValidator,
_mockWebAppCreator,
_mockPlatformDetector,
_mockBotConfigurator,
_mockGraphApiService, _mockBlueprintService, _mockClientAppValidator, _mockBlueprintLookupService, _mockFederatedCredentialService);

var parser = new CommandLineBuilder(command).Build();
var testConsole = new TestConsole();

// Act
await parser.InvokeAsync("--dry-run", testConsole);

// Assert - Verify CustomClientAppId was NOT set
_mockGraphApiService.CustomClientAppId.Should().BeNullOrEmpty(
"CustomClientAppId should not be set when config has whitespace-only ClientAppId");
}

#endregion

#region Mutually Exclusive Options Tests

[Theory]
Expand Down
Loading