From 05abaaad2bb8747911f6b91e3a0becf0457a08c9 Mon Sep 17 00:00:00 2001
From: Aaron Powell <me@aaron-powell.com>
Date: Wed, 24 Jul 2024 16:13:55 +1000
Subject: [PATCH 1/3] Setting a default TLS version for Azure SQL to 1.3

Updated tests and added tests to validate user-specified override

Fixes #5042
---
 .../AzureSqlExtensions.cs                     |   1 +
 .../Azure/AzureBicepResourceTests.cs          | 190 ++++++++++++++++++
 2 files changed, 191 insertions(+)

diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
index 5f82b686e9..2799170fb4 100644
--- a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
+++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
@@ -28,6 +28,7 @@ internal static IResourceBuilder<SqlServerServerResource> PublishAsAzureSqlDatab
             sqlServer.AssignProperty(x => x.Administrators.Sid, construct.PrincipalIdParameter);
             sqlServer.AssignProperty(x => x.Administrators.Login, construct.PrincipalNameParameter);
             sqlServer.AssignProperty(x => x.Administrators.TenantId, "subscription().tenantId");
+            sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.3'");
 
             sqlServer.Properties.Tags["aspire-resource-name"] = construct.Resource.Name;
 
diff --git a/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs
index 43bdd94c14..32a849d21f 100644
--- a/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs
+++ b/tests/Aspire.Hosting.Tests/Azure/AzureBicepResourceTests.cs
@@ -1175,6 +1175,108 @@ param principalType string
               }
               properties: {
                 version: '12.0'
+                minimalTlsVersion: '1.3'
+                publicNetworkAccess: 'Enabled'
+                administrators: {
+                  administratorType: 'ActiveDirectory'
+                  principalType: principalType
+                  login: principalName
+                  sid: principalId
+                  tenantId: subscription().tenantId
+                  azureADOnlyAuthentication: true
+                }
+              }
+            }
+
+            resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
+              parent: sqlServer_lF9QWGqAt
+              name: 'AllowAllAzureIps'
+              properties: {
+                startIpAddress: '0.0.0.0'
+                endIpAddress: '0.0.0.0'
+              }
+            }
+
+            resource sqlFirewallRule_IgqbBC6Hr 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
+              parent: sqlServer_lF9QWGqAt
+              name: 'fw'
+              properties: {
+                startIpAddress: '0.0.0.0'
+                endIpAddress: '255.255.255.255'
+              }
+            }
+
+            resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = {
+              parent: sqlServer_lF9QWGqAt
+              name: 'dbName'
+              location: location
+              properties: {
+              }
+            }
+
+            output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName
+
+            """;
+        output.WriteLine(manifest.BicepText);
+        Assert.Equal(expectedBicep, manifest.BicepText);
+    }
+
+    [Fact]
+    public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties()
+    {
+        using var builder = TestDistributedApplicationBuilder.Create();
+
+        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) =>
+        {
+            azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
+            sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
+        });
+        sql.AddDatabase("db", "dbName");
+
+        var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource);
+
+        Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default));
+        Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression);
+
+        var expectedManifest = """
+            {
+              "type": "azure.bicep.v0",
+              "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022",
+              "path": "sql.module.bicep",
+              "params": {
+                "principalId": "",
+                "principalName": "",
+                "principalType": ""
+              }
+            }
+            """;
+        Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
+
+        var expectedBicep = """
+            targetScope = 'resourceGroup'
+
+            @description('')
+            param location string = resourceGroup().location
+
+            @description('')
+            param principalId string
+
+            @description('')
+            param principalName string
+
+            @description('')
+            param principalType string
+
+
+            resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = {
+              name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24))
+              location: location
+              tags: {
+                'aspire-resource-name': 'sql'
+              }
+              properties: {
+                version: '12.0'
+                minimalTlsVersion: '1.2'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'
@@ -1270,6 +1372,94 @@ param principalName string
               }
               properties: {
                 version: '12.0'
+                minimalTlsVersion: '1.3'
+                publicNetworkAccess: 'Enabled'
+                administrators: {
+                  administratorType: 'ActiveDirectory'
+                  login: principalName
+                  sid: principalId
+                  tenantId: subscription().tenantId
+                  azureADOnlyAuthentication: true
+                }
+              }
+            }
+
+            resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
+              parent: sqlServer_lF9QWGqAt
+              name: 'AllowAllAzureIps'
+              properties: {
+                startIpAddress: '0.0.0.0'
+                endIpAddress: '0.0.0.0'
+              }
+            }
+
+            resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = {
+              parent: sqlServer_lF9QWGqAt
+              name: 'dbName'
+              location: location
+              properties: {
+              }
+            }
+
+            output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName
+
+            """;
+        output.WriteLine(manifest.BicepText);
+        Assert.Equal(expectedBicep, manifest.BicepText);
+    }
+
+    [Fact]
+    public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties()
+    {
+        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
+
+        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, server, _) =>
+        {
+            azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
+            server.AssignProperty(p => p.MinimalTlsVersion, "'1.2'");
+        });
+        sql.AddDatabase("db", "dbName");
+
+        var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource);
+
+        Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default));
+        Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression);
+
+        var expectedManifest = """
+            {
+              "type": "azure.bicep.v0",
+              "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022",
+              "path": "sql.module.bicep",
+              "params": {
+                "principalId": "",
+                "principalName": ""
+              }
+            }
+            """;
+        Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
+
+        var expectedBicep = """
+            targetScope = 'resourceGroup'
+
+            @description('')
+            param location string = resourceGroup().location
+
+            @description('')
+            param principalId string
+
+            @description('')
+            param principalName string
+
+
+            resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = {
+              name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24))
+              location: location
+              tags: {
+                'aspire-resource-name': 'sql'
+              }
+              properties: {
+                version: '12.0'
+                minimalTlsVersion: '1.2'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'

From b67428b9016ab0c452939cbe8988b8db2e404f4d Mon Sep 17 00:00:00 2001
From: Aaron Powell <me@aaron-powell.com>
Date: Thu, 1 Aug 2024 12:21:20 +1000
Subject: [PATCH 2/3] Simplifying the tests

---
 .../AzureBicepResourceTests.cs                | 210 ++----------------
 1 file changed, 18 insertions(+), 192 deletions(-)

diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
index b372e64c1b..f8338775de 100644
--- a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
+++ b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
@@ -1121,115 +1121,21 @@ param principalType string
         Assert.Equal(expectedBicep, manifest.BicepText);
     }
 
-    [Fact]
-    public async Task AsAzureSqlDatabaseViaRunMode()
+    [Theory]
+    [InlineData(true)]
+    [InlineData(false)]
+    public async Task AsAzureSqlDatabaseViaRunMode(bool overrideDefaultTlsVersion)
     {
         using var builder = TestDistributedApplicationBuilder.Create();
 
-        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, _, _) =>
+        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) =>
         {
             azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
-        });
-        sql.AddDatabase("db", "dbName");
-
-        var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource);
-
-        Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default));
-        Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression);
 
-        var expectedManifest = """
+            if (overrideDefaultTlsVersion)
             {
-              "type": "azure.bicep.v0",
-              "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022",
-              "path": "sql.module.bicep",
-              "params": {
-                "principalId": "",
-                "principalName": "",
-                "principalType": ""
-              }
-            }
-            """;
-        Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
-
-        var expectedBicep = """
-            targetScope = 'resourceGroup'
-
-            @description('')
-            param location string = resourceGroup().location
-
-            @description('')
-            param principalId string
-
-            @description('')
-            param principalName string
-
-            @description('')
-            param principalType string
-
-
-            resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = {
-              name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24))
-              location: location
-              tags: {
-                'aspire-resource-name': 'sql'
-              }
-              properties: {
-                version: '12.0'
-                minimalTlsVersion: '1.3'
-                publicNetworkAccess: 'Enabled'
-                administrators: {
-                  administratorType: 'ActiveDirectory'
-                  principalType: principalType
-                  login: principalName
-                  sid: principalId
-                  tenantId: subscription().tenantId
-                  azureADOnlyAuthentication: true
-                }
-              }
-            }
-
-            resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
-              parent: sqlServer_lF9QWGqAt
-              name: 'AllowAllAzureIps'
-              properties: {
-                startIpAddress: '0.0.0.0'
-                endIpAddress: '0.0.0.0'
-              }
-            }
-
-            resource sqlFirewallRule_IgqbBC6Hr 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
-              parent: sqlServer_lF9QWGqAt
-              name: 'fw'
-              properties: {
-                startIpAddress: '0.0.0.0'
-                endIpAddress: '255.255.255.255'
-              }
+                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
             }
-
-            resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = {
-              parent: sqlServer_lF9QWGqAt
-              name: 'dbName'
-              location: location
-              properties: {
-              }
-            }
-
-            output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName
-
-            """;
-        output.WriteLine(manifest.BicepText);
-        Assert.Equal(expectedBicep, manifest.BicepText);
-    }
-
-    [Fact]
-    public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties()
-    {
-        using var builder = TestDistributedApplicationBuilder.Create();
-
-        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) =>
-        {
-            azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
-            sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
         });
         sql.AddDatabase("db", "dbName");
 
@@ -1252,7 +1158,7 @@ public async Task AsAzureSqlDatabaseViaRunModeOverrideProperties()
             """;
         Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
 
-        var expectedBicep = """
+        var expectedBicep = $$"""
             targetScope = 'resourceGroup'
 
             @description('')
@@ -1276,7 +1182,7 @@ param principalType string
               }
               properties: {
                 version: '12.0'
-                minimalTlsVersion: '1.2'
+                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'
@@ -1322,101 +1228,21 @@ param principalType string
         Assert.Equal(expectedBicep, manifest.BicepText);
     }
 
-    [Fact]
-    public async Task AsAzureSqlDatabaseViaPublishMode()
+    [Theory]
+    [InlineData(true)]
+    [InlineData(false)]
+    public async Task AsAzureSqlDatabaseViaPublishMode(bool overrideDefaultTlsVersion)
     {
         using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
 
-        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, _, _) =>
+        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, sql, _) =>
         {
             azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
-        });
-        sql.AddDatabase("db", "dbName");
 
-        var manifest = await ManifestUtils.GetManifestWithBicep(sql.Resource);
-
-        Assert.Equal("Server=tcp:myserver,1433;Encrypt=True;Authentication=\"Active Directory Default\"", await sql.Resource.GetConnectionStringAsync(default));
-        Assert.Equal("Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\"Active Directory Default\"", sql.Resource.ConnectionStringExpression.ValueExpression);
-
-        var expectedManifest = """
+            if (overrideDefaultTlsVersion)
             {
-              "type": "azure.bicep.v0",
-              "connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022",
-              "path": "sql.module.bicep",
-              "params": {
-                "principalId": "",
-                "principalName": ""
-              }
+                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
             }
-            """;
-        Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
-
-        var expectedBicep = """
-            targetScope = 'resourceGroup'
-
-            @description('')
-            param location string = resourceGroup().location
-
-            @description('')
-            param principalId string
-
-            @description('')
-            param principalName string
-
-
-            resource sqlServer_lF9QWGqAt 'Microsoft.Sql/servers@2020-11-01-preview' = {
-              name: toLower(take('sql${uniqueString(resourceGroup().id)}', 24))
-              location: location
-              tags: {
-                'aspire-resource-name': 'sql'
-              }
-              properties: {
-                version: '12.0'
-                minimalTlsVersion: '1.3'
-                publicNetworkAccess: 'Enabled'
-                administrators: {
-                  administratorType: 'ActiveDirectory'
-                  login: principalName
-                  sid: principalId
-                  tenantId: subscription().tenantId
-                  azureADOnlyAuthentication: true
-                }
-              }
-            }
-
-            resource sqlFirewallRule_vcw7qNn72 'Microsoft.Sql/servers/firewallRules@2020-11-01-preview' = {
-              parent: sqlServer_lF9QWGqAt
-              name: 'AllowAllAzureIps'
-              properties: {
-                startIpAddress: '0.0.0.0'
-                endIpAddress: '0.0.0.0'
-              }
-            }
-
-            resource sqlDatabase_m3U42g9Y8 'Microsoft.Sql/servers/databases@2020-11-01-preview' = {
-              parent: sqlServer_lF9QWGqAt
-              name: 'dbName'
-              location: location
-              properties: {
-              }
-            }
-
-            output sqlServerFqdn string = sqlServer_lF9QWGqAt.properties.fullyQualifiedDomainName
-
-            """;
-        output.WriteLine(manifest.BicepText);
-        Assert.Equal(expectedBicep, manifest.BicepText);
-    }
-
-    [Fact]
-    public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties()
-    {
-        using var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);
-
-        var sql = builder.AddSqlServer("sql").AsAzureSqlDatabase((azureSqlBuilder, _, server, _) =>
-        {
-            azureSqlBuilder.Resource.Outputs["sqlServerFqdn"] = "myserver";
-            server.AssignProperty(p => p.MinimalTlsVersion, "'1.2'");
         });
         sql.AddDatabase("db", "dbName");
 
@@ -1438,7 +1264,7 @@ public async Task AsAzureSqlDatabaseViaPublishModeOverrideProperties()
             """;
         Assert.Equal(expectedManifest, manifest.ManifestNode.ToString());
 
-        var expectedBicep = """
+        var expectedBicep = $$"""
             targetScope = 'resourceGroup'
 
             @description('')
@@ -1459,7 +1285,7 @@ param principalName string
               }
               properties: {
                 version: '12.0'
-                minimalTlsVersion: '1.2'
+                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'

From 6d0c51697489e5e02c1c68677175b6cffc3e56a3 Mon Sep 17 00:00:00 2001
From: Eric Erhardt <eric.erhardt@microsoft.com>
Date: Wed, 21 Aug 2024 19:08:31 -0500
Subject: [PATCH 3/3] Set the default TLS to 1.2

---
 src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs        | 2 +-
 .../Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
index 2799170fb4..9f999dec54 100644
--- a/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
+++ b/src/Aspire.Hosting.Azure.Sql/AzureSqlExtensions.cs
@@ -28,7 +28,7 @@ internal static IResourceBuilder<SqlServerServerResource> PublishAsAzureSqlDatab
             sqlServer.AssignProperty(x => x.Administrators.Sid, construct.PrincipalIdParameter);
             sqlServer.AssignProperty(x => x.Administrators.Login, construct.PrincipalNameParameter);
             sqlServer.AssignProperty(x => x.Administrators.TenantId, "subscription().tenantId");
-            sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.3'");
+            sqlServer.AssignProperty(x => x.MinimalTlsVersion, "'1.2'");
 
             sqlServer.Properties.Tags["aspire-resource-name"] = construct.Resource.Name;
 
diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
index f8338775de..854af99be2 100644
--- a/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
+++ b/tests/Aspire.Hosting.Azure.Tests/AzureBicepResourceTests.cs
@@ -1134,7 +1134,7 @@ public async Task AsAzureSqlDatabaseViaRunMode(bool overrideDefaultTlsVersion)
 
             if (overrideDefaultTlsVersion)
             {
-                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
+                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.3'");
             }
         });
         sql.AddDatabase("db", "dbName");
@@ -1182,7 +1182,7 @@ param principalType string
               }
               properties: {
                 version: '12.0'
-                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}'
+                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.3" : "1.2")}}'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'
@@ -1241,7 +1241,7 @@ public async Task AsAzureSqlDatabaseViaPublishMode(bool overrideDefaultTlsVersio
 
             if (overrideDefaultTlsVersion)
             {
-                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.2'");
+                sql.AssignProperty(s => s.MinimalTlsVersion, "'1.3'");
             }
         });
         sql.AddDatabase("db", "dbName");
@@ -1285,7 +1285,7 @@ param principalName string
               }
               properties: {
                 version: '12.0'
-                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.2" : "1.3")}}'
+                minimalTlsVersion: '{{(overrideDefaultTlsVersion ? "1.3" : "1.2")}}'
                 publicNetworkAccess: 'Enabled'
                 administrators: {
                   administratorType: 'ActiveDirectory'