1+ // Licensed to the .NET Foundation under one or more agreements.
2+ // The .NET Foundation licenses this file to you under the MIT license.
3+
4+ using Aspire . Hosting . ApplicationModel ;
5+ using Aspire . Hosting . Utils ;
6+ using Microsoft . Extensions . DependencyInjection ;
7+ using Xunit ;
8+
9+ namespace Aspire . Hosting . Azure . Tests ;
10+
11+ public class AzureKeyVaultTests ( ITestOutputHelper output )
12+ {
13+ [ Fact ]
14+ public async Task AddKeyVaultViaRunMode ( )
15+ {
16+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
17+
18+ var mykv = builder . AddAzureKeyVault ( "mykv" ) ;
19+
20+ var manifest = await AzureManifestUtils . GetManifestWithBicep ( mykv . Resource ) ;
21+
22+ var expectedManifest = """
23+ {
24+ "type": "azure.bicep.v0",
25+ "connectionString": "{mykv.outputs.vaultUri}",
26+ "path": "mykv.module.bicep"
27+ }
28+ """ ;
29+ Assert . Equal ( expectedManifest , manifest . ManifestNode . ToString ( ) ) ;
30+
31+ var expectedBicep = """
32+ @description('The location for the resource(s) to be deployed.')
33+ param location string = resourceGroup().location
34+
35+ resource mykv 'Microsoft.KeyVault/vaults@2023-07-01' = {
36+ name: take('mykv-${uniqueString(resourceGroup().id)}', 24)
37+ location: location
38+ properties: {
39+ tenantId: tenant().tenantId
40+ sku: {
41+ family: 'A'
42+ name: 'standard'
43+ }
44+ enableRbacAuthorization: true
45+ }
46+ tags: {
47+ 'aspire-resource-name': 'mykv'
48+ }
49+ }
50+
51+ output vaultUri string = mykv.properties.vaultUri
52+
53+ output name string = mykv.name
54+ """ ;
55+ output . WriteLine ( manifest . BicepText ) ;
56+ Assert . Equal ( expectedBicep , manifest . BicepText ) ;
57+ }
58+
59+ [ Fact ]
60+ public async Task AddKeyVaultViaPublishMode ( )
61+ {
62+ using var builder = TestDistributedApplicationBuilder . Create ( DistributedApplicationOperation . Publish ) ;
63+
64+ var mykv = builder . AddAzureKeyVault ( "mykv" ) ;
65+
66+ using var app = builder . Build ( ) ;
67+ var model = app . Services . GetRequiredService < DistributedApplicationModel > ( ) ;
68+ var manifest = await AzureManifestUtils . GetManifestWithBicep ( model , mykv . Resource ) ;
69+
70+ var expectedManifest = """
71+ {
72+ "type": "azure.bicep.v0",
73+ "connectionString": "{mykv.outputs.vaultUri}",
74+ "path": "mykv.module.bicep"
75+ }
76+ """ ;
77+ Assert . Equal ( expectedManifest , manifest . ManifestNode . ToString ( ) ) ;
78+
79+ var expectedBicep = """
80+ @description('The location for the resource(s) to be deployed.')
81+ param location string = resourceGroup().location
82+
83+ resource mykv 'Microsoft.KeyVault/vaults@2023-07-01' = {
84+ name: take('mykv-${uniqueString(resourceGroup().id)}', 24)
85+ location: location
86+ properties: {
87+ tenantId: tenant().tenantId
88+ sku: {
89+ family: 'A'
90+ name: 'standard'
91+ }
92+ enableRbacAuthorization: true
93+ }
94+ tags: {
95+ 'aspire-resource-name': 'mykv'
96+ }
97+ }
98+
99+ output vaultUri string = mykv.properties.vaultUri
100+
101+ output name string = mykv.name
102+ """ ;
103+ output . WriteLine ( manifest . BicepText ) ;
104+ Assert . Equal ( expectedBicep , manifest . BicepText ) ;
105+
106+ var kvRoles = Assert . Single ( model . Resources . OfType < AzureProvisioningResource > ( ) . Where ( r => r . Name == $ "mykv-roles") ) ;
107+ var kvRolesManifest = await AzureManifestUtils . GetManifestWithBicep ( kvRoles , skipPreparer : true ) ;
108+ expectedBicep = """
109+ @description('The location for the resource(s) to be deployed.')
110+ param location string = resourceGroup().location
111+
112+ param mykv_outputs_name string
113+
114+ param principalType string
115+
116+ param principalId string
117+
118+ resource mykv 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
119+ name: mykv_outputs_name
120+ }
121+
122+ resource mykv_KeyVaultSecretsUser 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
123+ name: guid(mykv.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6'))
124+ properties: {
125+ principalId: principalId
126+ roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
127+ principalType: principalType
128+ }
129+ scope: mykv
130+ }
131+ """ ;
132+ output . WriteLine ( kvRolesManifest . BicepText ) ;
133+ Assert . Equal ( expectedBicep , kvRolesManifest . BicepText ) ;
134+ }
135+
136+ [ Fact ]
137+ public async Task WithEnvironment_AddsKeyVaultSecretReference ( )
138+ {
139+ // Arrange: Create a test application builder.
140+ using var builder = TestDistributedApplicationBuilder . Create ( ) ;
141+
142+ // Add a key vault resource.
143+ var kv = builder . AddAzureKeyVault ( "myKeyVault" ) ;
144+
145+ kv . Resource . SecretResolver = ( s , ct ) =>
146+ {
147+ return Task . FromResult < string ? > ( "my secret value" ) ;
148+ } ;
149+
150+ // Get a secret reference from the key vault resource.
151+ var secretReference = kv . Resource . GetSecret ( "mySecret" ) ;
152+
153+ // Add a container resource that supports environment variables.
154+ var containerBuilder = builder . AddContainer ( "myContainer" , "nginx" )
155+ . WithEnvironment ( "MY_SECRET" , secretReference ) ;
156+
157+ var runEnv = await containerBuilder . Resource . GetEnvironmentVariableValuesAsync ( DistributedApplicationOperation . Run ) ;
158+ var publishEnv = await containerBuilder . Resource . GetEnvironmentVariableValuesAsync ( DistributedApplicationOperation . Publish ) ;
159+
160+ var runKvp = Assert . Single ( runEnv ) ;
161+ var pubishKvp = Assert . Single ( publishEnv ) ;
162+
163+ Assert . Equal ( "MY_SECRET" , runKvp . Key ) ;
164+ Assert . Same ( "my secret value" , runKvp . Value ) ;
165+
166+ Assert . Equal ( "MY_SECRET" , pubishKvp . Key ) ;
167+ Assert . Equal ( "{myKeyVault.secrets.mySecret}" , pubishKvp . Value ) ;
168+ }
169+ }
0 commit comments