diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 7e5aff3a..35ac99a4 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -35,7 +35,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 7.x + dotnet-version: 8.x - name: Setup NuGet uses: nuget/setup-nuget@v1 diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 46beac7d..a70f6f62 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,7 +23,7 @@ variables: steps: - task: UseDotNet@2 inputs: - version: '7.x' + version: '8.x' - task: DotNetCoreCLI@2 displayName: 'Build' diff --git a/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj b/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj index e9eb124d..c8c548f2 100644 --- a/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj +++ b/src/Analyzer.BicepProcessor.UnitTests/Analyzer.BicepProcessor.UnitTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj b/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj index 61ea9dfb..57990e20 100644 --- a/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj +++ b/src/Analyzer.BicepProcessor/Analyzer.BicepProcessor.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.BicepProcessor Microsoft.Azure.Templates.Analyzer.BicepProcessor @@ -11,7 +11,7 @@ - + diff --git a/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs b/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs index 9bef1a70..677f9192 100644 --- a/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs +++ b/src/Analyzer.BicepProcessor/SourceMapFeatureProvider.cs @@ -68,9 +68,6 @@ public SourceMapFeatureProvider(IFeatureProvider features) /// public bool AssertsEnabled => features.AssertsEnabled; - /// - public bool CompileTimeImportsEnabled => features.CompileTimeImportsEnabled; - /// public bool MicrosoftGraphPreviewEnabled => features.MicrosoftGraphPreviewEnabled; @@ -82,5 +79,8 @@ public SourceMapFeatureProvider(IFeatureProvider features) /// public bool OptionalModuleNamesEnabled => features.OptionalModuleNamesEnabled; + + /// + public bool ResourceDerivedTypesEnabled => features.ResourceDerivedTypesEnabled; } } diff --git a/src/Analyzer.Cli.FunctionalTests/Analyzer.Cli.FunctionalTests.csproj b/src/Analyzer.Cli.FunctionalTests/Analyzer.Cli.FunctionalTests.csproj index 303a0f2b..f3705722 100644 --- a/src/Analyzer.Cli.FunctionalTests/Analyzer.Cli.FunctionalTests.csproj +++ b/src/Analyzer.Cli.FunctionalTests/Analyzer.Cli.FunctionalTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.Cli.FunctionalTests/CommandLineParserTests.cs b/src/Analyzer.Cli.FunctionalTests/CommandLineParserTests.cs index d79b0459..fd1928b0 100644 --- a/src/Analyzer.Cli.FunctionalTests/CommandLineParserTests.cs +++ b/src/Analyzer.Cli.FunctionalTests/CommandLineParserTests.cs @@ -209,7 +209,7 @@ public void AnalyzeDirectory_ExecutionWithErrorAndWarning_PrintsExpectedMessages expectedLogSummary += $"{Environment.NewLine}\tThe verbose mode (option -v or --verbose) can be used to obtain even more information about the execution."; } - var warningMessage = "An exception occurred when processing the template language expressions"; + var warningMessage = "The parsing of the template output named badOutput failed"; var errorMessage1 = $"An exception occurred while analyzing template {Path.Combine(directoryToAnalyze, "ReportsError.json")}"; var errorMessage2 = $"An exception occurred while analyzing template {Path.Combine(directoryToAnalyze, "ReportsError2.json")}"; @@ -263,8 +263,7 @@ public void AnalyzeDirectory_ExecutionWithErrorAndWarning_PrintsExpectedMessages { errorLog += $"{Environment.NewLine}Exception details:" + $"{Environment.NewLine}Microsoft.Azure.Templates.Analyzer.Core.TemplateAnalyzerException: Error while processing template."; - warningLog += $"{Environment.NewLine}Exception details:" + - $"{Environment.NewLine}Azure.Deployments.Templates.Exceptions.TemplateValidationException: The template parameter 'location' is not found."; + // output parse warning does not trigger exception, only log } var outputBeforeSummary = cliConsoleOutput[..indexOfLogSummary]; Assert.IsTrue(outputBeforeSummary.IndexOf(errorLog) > 0); diff --git a/src/Analyzer.Cli.FunctionalTests/Tests/ToTestSummaryLogger/ReportsWarning.json b/src/Analyzer.Cli.FunctionalTests/Tests/ToTestSummaryLogger/ReportsWarning.json index 0825034f..ae769bcf 100644 --- a/src/Analyzer.Cli.FunctionalTests/Tests/ToTestSummaryLogger/ReportsWarning.json +++ b/src/Analyzer.Cli.FunctionalTests/Tests/ToTestSummaryLogger/ReportsWarning.json @@ -6,9 +6,14 @@ "apiVersion": "2019-08-01", "type": "Microsoft.Web/sites", "name": "usesUndefinedParameter", - "location": "[parameters('location')]", "properties": { } } - ] + ], + "outputs": { + "badOutput": { + "type": "string", + "value": "[parameters('ImAComputer')]" + } + } } \ No newline at end of file diff --git a/src/Analyzer.Cli.FunctionalTests/Tests/TriggersOnlyNonSecurityRules.json b/src/Analyzer.Cli.FunctionalTests/Tests/TriggersOnlyNonSecurityRules.json index 73b80652..32e698d8 100644 --- a/src/Analyzer.Cli.FunctionalTests/Tests/TriggersOnlyNonSecurityRules.json +++ b/src/Analyzer.Cli.FunctionalTests/Tests/TriggersOnlyNonSecurityRules.json @@ -10,7 +10,16 @@ "name": "aWorkspace", "apiVersion": "2016-12-01", "location": "", - "properties": {} + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[format('{0}', resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', 'example'))]": {} + } + }, + "properties": { + "primaryUserAssignedIdentity": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', 'example')]", + "publicNetworkAccess": "Disabled" + } } ], "outputs": {} diff --git a/src/Analyzer.Cli.NuGet/Analyzer.Cli.nuspec b/src/Analyzer.Cli.NuGet/Analyzer.Cli.nuspec index f16d9165..354e78f6 100644 --- a/src/Analyzer.Cli.NuGet/Analyzer.Cli.nuspec +++ b/src/Analyzer.Cli.NuGet/Analyzer.Cli.nuspec @@ -12,7 +12,7 @@ - + diff --git a/src/Analyzer.Cli/Analyzer.Cli.csproj b/src/Analyzer.Cli/Analyzer.Cli.csproj index 2345bec0..748e7004 100644 --- a/src/Analyzer.Cli/Analyzer.Cli.csproj +++ b/src/Analyzer.Cli/Analyzer.Cli.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net8.0 TemplateAnalyzer A command line interface for Microsoft.Azure.Templates.Analyzer.Core - an ARM and Bicep template scanner for security misconfigurations and best practices diff --git a/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj b/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj index 4efb61af..39c1b382 100644 --- a/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj +++ b/src/Analyzer.Core.BuiltInRuleTests/Analyzer.Core.BuiltInRuleTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.Core.NuGet/Analyzer.Core.nuspec b/src/Analyzer.Core.NuGet/Analyzer.Core.nuspec index 65e160cd..bd5126fb 100644 --- a/src/Analyzer.Core.NuGet/Analyzer.Core.nuspec +++ b/src/Analyzer.Core.NuGet/Analyzer.Core.nuspec @@ -11,14 +11,14 @@ arm bicep azure template analyzer scanner deployment security - - - - - + + + + + - + diff --git a/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj b/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj index 2b5007a4..dbb78ebc 100644 --- a/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj +++ b/src/Analyzer.Core.UnitTests/Analyzer.Core.UnitTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.Core.UnitTests/TemplateAnalyzerTests.cs b/src/Analyzer.Core.UnitTests/TemplateAnalyzerTests.cs index 4804538c..db1d7a68 100644 --- a/src/Analyzer.Core.UnitTests/TemplateAnalyzerTests.cs +++ b/src/Analyzer.Core.UnitTests/TemplateAnalyzerTests.cs @@ -28,7 +28,7 @@ public static void AssemblyInitialize(TestContext context) [DataTestMethod] [DataRow(@"{ ""azureActiveDirectory"": { ""tenantId"": ""tenantId"" } }", "Microsoft.ServiceFabric/clusters", 1, 1, DisplayName = "1 matching resource with 1 passing evaluation")] [DataRow(@"{ ""azureActiveDirectory"": { ""someProperty"": ""propertyValue"" } }", "Microsoft.ServiceFabric/clusters", 1, 0, DisplayName = "1 matching resource with 1 failing evaluation")] - [DataRow(@"{ ""property1"": { ""someProperty"": ""propertyValue"" } }", "Microsoft.MachineLearningServices/workspaces", 0, 0, DisplayName = "0 matching resources with no results")] + [DataRow(@"{ ""property1"": { ""someProperty"": ""propertyValue"" } }", "Microsoft.MachineLearningServices/workspaces", 2, 0, DisplayName = "2 matching resources with no results")] [DataRow(@"{ ""azureActiveDirectory"": { ""tenantId"": ""tenantId"" } }", "Microsoft.ServiceFabric/clusters", 2, 1, @"{ ""azureActiveDirectory"": { ""someProperty"": ""propertyValue"" } }", DisplayName = "2 matching resources with 1 passing evaluation")] public void AnalyzeTemplate_ValidInputValues_ReturnCorrectEvaluations(string resource1Properties, string resourceType, int expectedEvaluationCount, int expectedEvaluationPassCount, string resource2Properties = null) { diff --git a/src/Analyzer.Core/Analyzer.Core.csproj b/src/Analyzer.Core/Analyzer.Core.csproj index 58497f4c..e6abcbce 100644 --- a/src/Analyzer.Core/Analyzer.Core.csproj +++ b/src/Analyzer.Core/Analyzer.Core.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer Microsoft.Azure.Templates.Analyzer.Core An ARM and Bicep template scanner for security misconfigurations and best practices diff --git a/src/Analyzer.Core/TemplateAnalyzer.cs b/src/Analyzer.Core/TemplateAnalyzer.cs index 1fbd85e9..7b0873ed 100644 --- a/src/Analyzer.Core/TemplateAnalyzer.cs +++ b/src/Analyzer.Core/TemplateAnalyzer.cs @@ -134,7 +134,7 @@ private IEnumerable AnalyzeAllIncludedTemplates(string populatedTem try { - templatejObject = armTemplateProcessor.ProcessTemplate(parameters, generateMissingParameters: parentContext.IsMainTemplate); + templatejObject = armTemplateProcessor.ProcessTemplate(parameters); } catch (Exception e) { diff --git a/src/Analyzer.Core/TemplateAnalyzerException.cs b/src/Analyzer.Core/TemplateAnalyzerException.cs index 26c42552..ecf153ec 100644 --- a/src/Analyzer.Core/TemplateAnalyzerException.cs +++ b/src/Analyzer.Core/TemplateAnalyzerException.cs @@ -37,10 +37,5 @@ public TemplateAnalyzerException(string message, Exception innerException) : base(message, innerException) { } - - protected TemplateAnalyzerException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj b/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj index 2911c513..bd68ebb9 100644 --- a/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj +++ b/src/Analyzer.JsonRuleEngine.FunctionalTests/Analyzer.JsonRuleEngine.FunctionalTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj b/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj index 75094e2e..1171508c 100644 --- a/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj +++ b/src/Analyzer.JsonRuleEngine.UnitTests/Analyzer.JsonRuleEngine.UnitTests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/src/Analyzer.JsonRuleEngine/Analyzer.JsonRuleEngine.csproj b/src/Analyzer.JsonRuleEngine/Analyzer.JsonRuleEngine.csproj index ef4bf4f8..7340fc68 100644 --- a/src/Analyzer.JsonRuleEngine/Analyzer.JsonRuleEngine.csproj +++ b/src/Analyzer.JsonRuleEngine/Analyzer.JsonRuleEngine.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.JsonRuleEngine Microsoft.Azure.Templates.Analyzer.RuleEngines.JsonEngine diff --git a/src/Analyzer.JsonRuleEngine/JsonRuleEngineException.cs b/src/Analyzer.JsonRuleEngine/JsonRuleEngineException.cs index eeb7619e..f51c1af2 100644 --- a/src/Analyzer.JsonRuleEngine/JsonRuleEngineException.cs +++ b/src/Analyzer.JsonRuleEngine/JsonRuleEngineException.cs @@ -37,10 +37,5 @@ public JsonRuleEngineException(string message, Exception innerException) : base(message, innerException) { } - - protected JsonRuleEngineException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } } } \ No newline at end of file diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj b/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj index 6aae6da5..e2f2df1f 100644 --- a/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/Analyzer.PowerShellRuleEngine.UnitTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs b/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs index c5482bfa..33b9311c 100644 --- a/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/PowerShellRuleEngineTests.cs @@ -16,6 +16,23 @@ namespace Microsoft.Azure.Templates.Analyzer.RuleEngines.PowerShellEngine.UnitTe [TestClass] public class PowerShellRuleEngineTests { + private const string EmptyBaseline = @" + [ + { + ""kind"": ""Baseline"", + ""metadata"": { + ""name"": ""RepeatedRulesBaseline"" + }, + ""apiVersion"": ""github.com/microsoft/PSRule/v1"", + ""spec"": { + ""rule"": { + ""exclude"": [ + ] + } + } + } + ]"; + private readonly string templatesFolder = @"templates"; private static PowerShellRuleEngine powerShellRuleEngineAllRules; private static PowerShellRuleEngine powerShellRuleEngineSecurityRules; @@ -29,8 +46,8 @@ public static void AssemblyInitialize(TestContext context) [DataTestMethod] // PSRule detects errors in two analysis stages: when looking at the whole file (through the file path), and when looking at each resource (pipeline.Process(resource)): - [DataRow("template_and_resource_level_results.json", true, 13, new int[] { 1, 1, 1, 1, 8, 14, 17, 1, 17, 17, 1, 17, 1 }, DisplayName = "Running all the rules against a template with errors reported in both analysis stages")] - [DataRow("template_and_resource_level_results.json", false, 4, new int[] { 17, 17, 17, 17 }, DisplayName = "Running only the security rules against a template with errors reported in both analysis stages")] + [DataRow("template_and_resource_level_results.json", true, 14, new int[] { 1, 1, 1, 1, 8, 11, 14, 17, 1, 17, 17, 1, 17, 1 }, DisplayName = "Running all the rules against a template with errors reported in both analysis stages")] + [DataRow("template_and_resource_level_results.json", false, 5, new int[] { 11, 17, 17, 17, 17 }, DisplayName = "Running only the security rules against a template with errors reported in both analysis stages")] // TODO add test case for error, warning (rule with severity level of warning?) and informational (also rule with that severity level?) public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string templateFileName, bool runsAllRules, int expectedErrorCount, dynamic expectedLineNumbers) { @@ -80,7 +97,7 @@ public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string temp Assert.AreEqual(expectedErrorCount, failedEvaluations.Count); // PSRule evaluations can change order depending on the OS: - foreach(var expectedLineNumber in expectedLineNumbers) + foreach (var expectedLineNumber in expectedLineNumbers) { var matchingEvaluation = failedEvaluations.Find(evaluation => evaluation.Result.SourceLocation.LineNumber == expectedLineNumber); failedEvaluations.Remove(matchingEvaluation); @@ -90,7 +107,7 @@ public void AnalyzeTemplate_ValidTemplate_ReturnsExpectedEvaluations(string temp [DataTestMethod] [DataRow(true, DisplayName = "Repeated rules are excluded when running all the rules")] - [DataRow(true, DisplayName = "Repeated rules are excluded when running only the security rules")] + [DataRow(false, DisplayName = "Repeated rules are excluded when running only the security rules")] public void AnalyzeTemplate_ValidTemplate_ExcludesRepeatedRules(bool runsAllRules) { var templateFilePath = Path.Combine(templatesFolder, "triggers_excluded_rules.json"); @@ -115,7 +132,7 @@ public void AnalyzeTemplate_ValidTemplate_ExcludesRepeatedRules(bool runsAllRule // The RepeatedRulesBaseline will only be used when all rules are run // Otherwise SecurityBaseline is used, those rules are not in the "include" array of the baseline so they won't be executed either - // Next we validate that when RepeatedRulesBaseline is an empty file then the test file does indeed trigger the excluded rule: + // Next we validate that when RepeatedRulesBaseline has no exclusions then the test file does indeed trigger the excluded rule: if (runsAllRules) { var baselineLocation = Path.Combine(Path.GetDirectoryName(AppContext.BaseDirectory), "baselines", "RepeatedRulesBaseline.Rule.json"); @@ -123,11 +140,10 @@ public void AnalyzeTemplate_ValidTemplate_ExcludesRepeatedRules(bool runsAllRule try { File.Move(baselineLocation, newBaselineLocation); - var emptyBaseline = File.Create(baselineLocation); - emptyBaseline.Close(); - + File.WriteAllText(baselineLocation, EmptyBaseline); + evaluations = powerShellRuleEngineAllRules.AnalyzeTemplate(templateContext); - + Assert.IsTrue(evaluations.Any(evaluation => evaluation.RuleId == "AZR-000081")); } finally @@ -138,6 +154,32 @@ public void AnalyzeTemplate_ValidTemplate_ExcludesRepeatedRules(bool runsAllRule } } + // Sanity checks for using hardcoded AZURE_RESOURCE_ALLOWED_LOCATIONS to match the placeholder region in the template processor + // locations used are different from the placeholder region westus2 + [TestMethod] + [DataRow("templateWithDefaultLocation.json", DisplayName = "Template with default location")] + [DataRow("templateWithHardcodedLocation.json", DisplayName = "Template with hardcoded location")] + public void AnalyzeTemplate_ValidTemplate_SpecifiedLocations(string templateFileName) + { + var templateFilePath = Path.Combine(templatesFolder, templateFileName); + + var template = File.ReadAllText(templateFilePath); + var armTemplateProcessor = new ArmTemplateProcessor(template); + var templatejObject = armTemplateProcessor.ProcessTemplate(); + + var templateContext = new TemplateContext + { + OriginalTemplate = JObject.Parse(template), + ExpandedTemplate = templatejObject, + ResourceMappings = armTemplateProcessor.ResourceMappings, + TemplateIdentifier = templateFilePath + }; + + var evaluations = powerShellRuleEngineSecurityRules.AnalyzeTemplate(templateContext); + + Assert.IsTrue(evaluations.All(evaluation => evaluation.Passed)); + } + [TestMethod] [ExpectedException(typeof(ArgumentException))] public void AnalyzeTemplate_NullTemplateContext_ThrowsException() diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithDefaultLocation.json b/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithDefaultLocation.json new file mode 100644 index 00000000..96111e9c --- /dev/null +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithDefaultLocation.json @@ -0,0 +1,50 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "type": "string", + "defaultValue": "southcentralus", + "metadata": { + "description": "Location for all resources." + } + }, + "managedIdentityName": { + "type": "string", + "metadata": { + "description": "Specifies managed identity name" + } + } + }, + "resources": [ + { + "apiVersion": "2019-08-01", + "type": "Microsoft.Web/sites", + "kind": "functionapp", + "name": "functionAppKind", + "location": "[parameters('location')]", + "properties": { + "httpsOnly": true, + "siteConfig": { + "detailedErrorLoggingEnabled": false, + "ftpsState": "Disabled", + "httpLoggingEnabled": false, + "minTlsVersion": "1.2", + "requestTracingEnabled": false + } + }, + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]": {} + } + } + }, + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('managedIdentityName')]", + "location": "[parameters('location')]" + } + ] +} \ No newline at end of file diff --git a/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithHardcodedLocation.json b/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithHardcodedLocation.json new file mode 100644 index 00000000..3c47374f --- /dev/null +++ b/src/Analyzer.PowerShellRuleEngine.UnitTests/templates/templateWithHardcodedLocation.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "managedIdentityName": { + "type": "string", + "metadata": { + "description": "Specifies managed identity name" + } + } + }, + "resources": [ + { + "apiVersion": "2019-08-01", + "type": "Microsoft.Web/sites", + "kind": "functionapp", + "name": "functionAppKind", + "location": "southcentralus", + "properties": { + "httpsOnly": true, + "siteConfig": { + "detailedErrorLoggingEnabled": false, + "ftpsState": "Disabled", + "httpLoggingEnabled": false, + "minTlsVersion": "1.2", + "requestTracingEnabled": false + } + }, + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('managedIdentityName'))]": {} + } + } + }, + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2018-11-30", + "name": "[parameters('managedIdentityName')]", + "location": "southcentralus" + } + ] +} \ No newline at end of file diff --git a/src/Analyzer.PowerShellRuleEngine/Analyzer.PowerShellRuleEngine.csproj b/src/Analyzer.PowerShellRuleEngine/Analyzer.PowerShellRuleEngine.csproj index 3c214f60..ea1cefc4 100644 --- a/src/Analyzer.PowerShellRuleEngine/Analyzer.PowerShellRuleEngine.csproj +++ b/src/Analyzer.PowerShellRuleEngine/Analyzer.PowerShellRuleEngine.csproj @@ -1,15 +1,15 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.PowerShellRuleEngine Microsoft.Azure.Templates.Analyzer.RuleEngines.PowerShellEngine - - - + + + diff --git a/src/Analyzer.PowerShellRuleEngine/PSRuleHostContext.cs b/src/Analyzer.PowerShellRuleEngine/PSRuleHostContext.cs index fcca5d34..42190383 100644 --- a/src/Analyzer.PowerShellRuleEngine/PSRuleHostContext.cs +++ b/src/Analyzer.PowerShellRuleEngine/PSRuleHostContext.cs @@ -41,6 +41,12 @@ public PSRuleHostContext(TemplateContext templateContext, ILogger logger = null) : new JsonSourceLocationResolver(templateContext); } + /// + public override ActionPreference GetPreferenceVariable(string variableName) + { + return string.Equals(variableName, "VerbosePreference", System.StringComparison.OrdinalIgnoreCase) ? ActionPreference.Continue : base.GetPreferenceVariable(variableName); + } + /// public override bool ShouldProcess(string target, string action) { @@ -68,6 +74,12 @@ public override void Information(InformationRecord informationRecord) } } + /// + public override void Verbose(string text) + { + logger?.LogDebug(text); + } + /// public override void Record(IResultRecord record) { diff --git a/src/Analyzer.PowerShellRuleEngine/PowerShellRuleEngine.cs b/src/Analyzer.PowerShellRuleEngine/PowerShellRuleEngine.cs index e352bede..cc62887f 100644 --- a/src/Analyzer.PowerShellRuleEngine/PowerShellRuleEngine.cs +++ b/src/Analyzer.PowerShellRuleEngine/PowerShellRuleEngine.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Microsoft.Azure.Templates.Analyzer.Types; using Microsoft.Azure.Templates.Analyzer.Utilities; using Microsoft.Extensions.Logging; @@ -91,6 +92,8 @@ public IEnumerable AnalyzeTemplate(TemplateContext templateContext) try { + var fileOptions = PSRuleOption.FromFileOrEmpty(); + hostContext = new PSRuleHostContext(templateContext, logger); var modules = new string[] { PSRuleModuleName }; var optionsForFileAnalysis = new PSRuleOption @@ -115,13 +118,16 @@ public IEnumerable AnalyzeTemplate(TemplateContext templateContext) }, Execution = new ExecutionOption { - NotProcessedWarning = false, - + UnprocessedObject = ExecutionActionPreference.Ignore, // PSRule internally creates a PowerShell initial state with InitialSessionState.CreateDefault(). // SessionState.Minimal causes PSRule to use CreateDefault2 instead of CreateDefault. - InitialSessionState = PSRule.Configuration.SessionState.Minimal + InitialSessionState = SessionState.Minimal } }; + + // placeholder value for location is westus2 + optionsForFileAnalysis.Configuration["AZURE_RESOURCE_ALLOWED_LOCATIONS"] = new[] { "westus2" }; + var resources = templateContext.ExpandedTemplate.InsensitiveToken("resources").Values(); var builder = CommandLineBuilder.Invoke(modules, optionsForFileAnalysis, hostContext); diff --git a/src/Analyzer.PowerShellRuleEngine/baselines/RepeatedRulesBaseline.Rule.json b/src/Analyzer.PowerShellRuleEngine/baselines/RepeatedRulesBaseline.Rule.json index 71be5f0e..6a1800a3 100644 --- a/src/Analyzer.PowerShellRuleEngine/baselines/RepeatedRulesBaseline.Rule.json +++ b/src/Analyzer.PowerShellRuleEngine/baselines/RepeatedRulesBaseline.Rule.json @@ -1,6 +1,6 @@ [ { - // Synopsis: Excludes the rules that are already in TemplateAnalyzer + "_comment": "Synopsis: Excludes the rules that are already in TemplateAnalyzer", "kind": "Baseline", "metadata": { "name": "RepeatedRulesBaseline" diff --git a/src/Analyzer.PowerShellRuleEngine/baselines/SecurityBaseline.Rule.json b/src/Analyzer.PowerShellRuleEngine/baselines/SecurityBaseline.Rule.json index 1e1a43db..87ccdde2 100644 --- a/src/Analyzer.PowerShellRuleEngine/baselines/SecurityBaseline.Rule.json +++ b/src/Analyzer.PowerShellRuleEngine/baselines/SecurityBaseline.Rule.json @@ -1,160 +1,196 @@ [ - { - // Synopsis: Includes all the rules from the Security pillar except the ones already in TemplateAnalyzer - "kind": "Baseline", - "metadata": { - "name": "SecurityBaseline" - }, - "apiVersion": "github.com/microsoft/PSRule/v1", - "spec": { - "rule": { - "include": [ - "PSRule.Rules.Azure\\Azure.ACR.ContainerScan", - "PSRule.Rules.Azure\\Azure.ACR.ImageHealth", - "PSRule.Rules.Azure\\Azure.AKS.AuditLogs", - "PSRule.Rules.Azure\\Azure.APIM.HTTPBackend", - "PSRule.Rules.Azure\\Azure.APIM.EncryptValues", - "PSRule.Rules.Azure\\Azure.APIM.ProductSubscription", - "PSRule.Rules.Azure\\Azure.APIM.ProductApproval", - "PSRule.Rules.Azure\\Azure.AppConfig.AuditLogs", - "PSRule.Rules.Azure\\Azure.AppGw.UseHTTPS", - "PSRule.Rules.Azure\\Azure.AppService.NETVersion", - "PSRule.Rules.Azure\\Azure.AppService.PHPVersion", - "PSRule.Rules.Azure\\Azure.Automation.WebHookExpiry", - "PSRule.Rules.Azure\\Azure.Automation.AuditLogs", - "PSRule.Rules.Azure\\Azure.CDN.MinTLS", - "PSRule.Rules.Azure\\Azure.Deployment.OutputSecretValue", - "PSRule.Rules.Azure\\Azure.Deployment.AdminUsername", - "PSRule.Rules.Azure\\Azure.Deployment.SecureValue", - "PSRule.Rules.Azure\\Azure.Deployment.OuterSecret", - "PSRule.Rules.Azure\\Azure.FrontDoor.MinTLS", - "PSRule.Rules.Azure\\Azure.FrontDoor.Logs", - "PSRule.Rules.Azure\\Azure.FrontDoor.UseWAF", - "PSRule.Rules.Azure\\Azure.KeyVault.AccessPolicy", - "PSRule.Rules.Azure\\Azure.KeyVault.Logs", - "PSRule.Rules.Azure\\Azure.KeyVault.AutoRotationPolicy", - "PSRule.Rules.Azure\\Azure.KeyVault.Firewall", - "PSRule.Rules.Azure\\Azure.LogicApp.LimitHTTPTrigger", - "PSRule.Rules.Azure\\Azure.MariaDB.DefenderCloud", - "PSRule.Rules.Azure\\Azure.MariaDB.UseSSL", - "PSRule.Rules.Azure\\Azure.MariaDB.MinTLS", - "PSRule.Rules.Azure\\Azure.MariaDB.AllowAzureAccess", - "PSRule.Rules.Azure\\Azure.MariaDB.FirewallRuleCount", - "PSRule.Rules.Azure\\Azure.MariaDB.FirewallIPRange", - "PSRule.Rules.Azure\\Azure.MySQL.FirewallRuleCount", - "PSRule.Rules.Azure\\Azure.MySQL.AllowAzureAccess", - "PSRule.Rules.Azure\\Azure.MySQL.FirewallIPRange", - "PSRule.Rules.Azure\\Azure.MySQL.DefenderCloud", - "PSRule.Rules.Azure\\Azure.NSG.AnyInboundSource", - "PSRule.Rules.Azure\\Azure.NSG.LateralTraversal", - "PSRule.Rules.Azure\\Azure.PostgreSQL.FirewallRuleCount", - "PSRule.Rules.Azure\\Azure.PostgreSQL.AllowAzureAccess", - "PSRule.Rules.Azure\\Azure.PostgreSQL.FirewallIPRange", - "PSRule.Rules.Azure\\Azure.PostgreSQL.DefenderCloud", - "PSRule.Rules.Azure\\Azure.Redis.FirewallRuleCount", - "PSRule.Rules.Azure\\Azure.Redis.FirewallIPRange", - "PSRule.Rules.Azure\\Azure.Resource.AllowedRegions", - "PSRule.Rules.Azure\\Azure.Search.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.ServiceBus.MinTLS", - "PSRule.Rules.Azure\\Azure.ServiceBus.AuditLogs", - "PSRule.Rules.Azure\\Azure.SQL.FirewallRuleCount", - "PSRule.Rules.Azure\\Azure.SQL.AllowAzureAccess", - "PSRule.Rules.Azure\\Azure.SQL.FirewallIPRange", - "PSRule.Rules.Azure\\Azure.SQL.DefenderCloud", - "PSRule.Rules.Azure\\Azure.SQL.Auditing", - "PSRule.Rules.Azure\\Azure.SQL.AAD", - "PSRule.Rules.Azure\\Azure.Storage.BlobAccessType", - "PSRule.Rules.Azure\\Azure.RBAC.UseGroups", - "PSRule.Rules.Azure\\Azure.RBAC.LimitOwner", - "PSRule.Rules.Azure\\Azure.RBAC.LimitMGDelegation", - "PSRule.Rules.Azure\\Azure.RBAC.CoAdministrator", - "PSRule.Rules.Azure\\Azure.RBAC.UseRGDelegation", - "PSRule.Rules.Azure\\Azure.RBAC.PIM", - "PSRule.Rules.Azure\\Azure.DefenderCloud.Contact", - "PSRule.Rules.Azure\\Azure.DefenderCloud.Provisioning", - "PSRule.Rules.Azure\\Azure.TrafficManager.Protocol", - "PSRule.Rules.Azure\\Azure.VM.PublicKey", - "PSRule.Rules.Azure\\Azure.VM.ADE", - "PSRule.Rules.Azure\\Azure.VM.ScriptExtensions", - "PSRule.Rules.Azure\\Azure.VMSS.PublicKey", - "PSRule.Rules.Azure\\Azure.VMSS.ScriptExtensions", - "PSRule.Rules.Azure\\Azure.VNET.UseNSGs", - "PSRule.Rules.Azure\\Azure.VNET.FirewallSubnet", - "PSRule.Rules.Azure\\Azure.ACR.AdminUser", - "PSRule.Rules.Azure\\Azure.ACR.ContentTrust", - "PSRule.Rules.Azure\\Azure.ADX.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.ADX.DiskEncryption", - "PSRule.Rules.Azure\\Azure.AKS.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.AKS.NetworkPolicy", - "PSRule.Rules.Azure\\Azure.AKS.AzurePolicyAddOn", - "PSRule.Rules.Azure\\Azure.AKS.ManagedAAD", - "PSRule.Rules.Azure\\Azure.AKS.AuthorizedIPs", - "PSRule.Rules.Azure\\Azure.AKS.AzureRBAC", - "PSRule.Rules.Azure\\Azure.AKS.SecretStore", - "PSRule.Rules.Azure\\Azure.AKS.SecretStoreRotation", - "PSRule.Rules.Azure\\Azure.AKS.HttpAppRouting", - "PSRule.Rules.Azure\\Azure.APIM.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.APIM.Protocols", - "PSRule.Rules.Azure\\Azure.APIM.Ciphers", - "PSRule.Rules.Azure\\Azure.AppConfig.DisableLocalAuth", - "PSRule.Rules.Azure\\Azure.AppGw.UseWAF", - "PSRule.Rules.Azure\\Azure.AppGw.SSLPolicy", - "PSRule.Rules.Azure\\Azure.AppGw.Prevention", - "PSRule.Rules.Azure\\Azure.AppGw.WAFEnabled", - "PSRule.Rules.Azure\\Azure.AppGw.OWASP", - "PSRule.Rules.Azure\\Azure.AppGw.WAFRules", - "PSRule.Rules.Azure\\Azure.AppGwWAF.Enabled", - "PSRule.Rules.Azure\\Azure.AppGwWAF.PreventionMode", - "PSRule.Rules.Azure\\Azure.AppGwWAF.Exclusions", - "PSRule.Rules.Azure\\Azure.AppGwWAF.RuleGroups", - "PSRule.Rules.Azure\\Azure.Automation.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.CDN.HTTP", - "PSRule.Rules.Azure\\Azure.Cognitive.PublicAccess", - "PSRule.Rules.Azure\\Azure.Cognitive.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.Cognitive.DisableLocalAuth", - "PSRule.Rules.Azure\\Azure.Cognitive.PrivateEndpoints", - "PSRule.Rules.Azure\\Azure.ContainerApp.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.ContainerApp.PublicAccess", - "PSRule.Rules.Azure\\Azure.Cosmos.DisableMetadataWrite", - "PSRule.Rules.Azure\\Azure.Defender.Containers", - "PSRule.Rules.Azure\\Azure.Defender.Servers", - "PSRule.Rules.Azure\\Azure.Defender.SQL", - "PSRule.Rules.Azure\\Azure.Defender.AppServices", - "PSRule.Rules.Azure\\Azure.Defender.Storage", - "PSRule.Rules.Azure\\Azure.Defender.SQLOnVM", - "PSRule.Rules.Azure\\Azure.Defender.KeyVault", - "PSRule.Rules.Azure\\Azure.Defender.Dns", - "PSRule.Rules.Azure\\Azure.Defender.Arm", - "PSRule.Rules.Azure\\Azure.EventGrid.TopicPublicAccess", - "PSRule.Rules.Azure\\Azure.EventGrid.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.EventGrid.DisableLocalAuth", - "PSRule.Rules.Azure\\Azure.EventHub.DisableLocalAuth", - "PSRule.Rules.Azure\\Azure.EventHub.MinTLS", - "PSRule.Rules.Azure\\Azure.Firewall.Mode", - "PSRule.Rules.Azure\\Azure.FrontDoor.WAF.Mode", - "PSRule.Rules.Azure\\Azure.FrontDoor.WAF.Enabled", - "PSRule.Rules.Azure\\Azure.FrontDoorWAF.Enabled", - "PSRule.Rules.Azure\\Azure.FrontDoorWAF.PreventionMode", - "PSRule.Rules.Azure\\Azure.FrontDoorWAF.Exclusions", - "PSRule.Rules.Azure\\Azure.FrontDoorWAF.RuleGroups", - "PSRule.Rules.Azure\\Azure.IoTHub.MinTLS", - "PSRule.Rules.Azure\\Azure.MySQL.UseSSL", - "PSRule.Rules.Azure\\Azure.MySQL.MinTLS", - "PSRule.Rules.Azure\\Azure.PostgreSQL.UseSSL", - "PSRule.Rules.Azure\\Azure.PostgreSQL.MinTLS", - "PSRule.Rules.Azure\\Azure.Redis.MinTLS", - "PSRule.Rules.Azure\\Azure.Redis.PublicNetworkAccess", - "PSRule.Rules.Azure\\Azure.RedisEnterprise.MinTLS", - "PSRule.Rules.Azure\\Azure.ServiceBus.DisableLocalAuth", - "PSRule.Rules.Azure\\Azure.SignalR.ManagedIdentity", - "PSRule.Rules.Azure\\Azure.SQL.MinTLS", - "PSRule.Rules.Azure\\Azure.Storage.Firewall", - "PSRule.Rules.Azure\\Azure.Storage.MinTLS", - "PSRule.Rules.Azure\\Azure.Storage.SecureTransfer", - "PSRule.Rules.Azure\\Azure.Storage.BlobPublicAccess", - "PSRule.Rules.Azure\\Azure.WebPubSub.ManagedIdentity" - ] - } + { + "_comment": "Synopsis: Includes all the rules from the Security pillar except the ones already in TemplateAnalyzer", + "kind": "Baseline", + "metadata": { + "name": "SecurityBaseline" + }, + "apiVersion": "github.com/microsoft/PSRule/v1", + "spec": { + "rule": { + "include": [ + "PSRule.Rules.Azure\\Azure.ACR.ContainerScan", + "PSRule.Rules.Azure\\Azure.ACR.ImageHealth", + "PSRule.Rules.Azure\\Azure.AKS.AuditLogs", + "PSRule.Rules.Azure\\Azure.APIM.HTTPBackend", + "PSRule.Rules.Azure\\Azure.APIM.EncryptValues", + "PSRule.Rules.Azure\\Azure.APIM.ProductSubscription", + "PSRule.Rules.Azure\\Azure.APIM.ProductApproval", + "PSRule.Rules.Azure\\Azure.APIM.CORSPolicy", + "PSRule.Rules.Azure\\Azure.APIM.PolicyBase", + "PSRule.Rules.Azure\\Azure.APIM.DefenderCloud", + "PSRule.Rules.Azure\\Azure.AppConfig.AuditLogs", + "PSRule.Rules.Azure\\Azure.AppGw.UseHTTPS", + "PSRule.Rules.Azure\\Azure.AppService.NETVersion", + "PSRule.Rules.Azure\\Azure.AppService.PHPVersion", + "PSRule.Rules.Azure\\Azure.Automation.WebHookExpiry", + "PSRule.Rules.Azure\\Azure.Automation.AuditLogs", + "PSRule.Rules.Azure\\Azure.CDN.MinTLS", + "PSRule.Rules.Azure\\Azure.ContainerApp.RestrictIngress", + "PSRule.Rules.Azure\\Azure.Cosmos.DefenderCloud", + "PSRule.Rules.Azure\\Azure.DefenderCloud.Contact", + "PSRule.Rules.Azure\\Azure.DefenderCloud.Provisioning", + "PSRule.Rules.Azure\\Azure.Deployment.OutputSecretValue", + "PSRule.Rules.Azure\\Azure.Deployment.AdminUsername", + "PSRule.Rules.Azure\\Azure.Deployment.SecureParameter", + "PSRule.Rules.Azure\\Azure.Deployment.SecureValue", + "PSRule.Rules.Azure\\Azure.Deployment.OuterSecret", + "PSRule.Rules.Azure\\Azure.FrontDoor.MinTLS", + "PSRule.Rules.Azure\\Azure.FrontDoor.Logs", + "PSRule.Rules.Azure\\Azure.FrontDoor.UseWAF", + "PSRule.Rules.Azure\\Azure.KeyVault.AccessPolicy", + "PSRule.Rules.Azure\\Azure.KeyVault.Logs", + "PSRule.Rules.Azure\\Azure.KeyVault.AutoRotationPolicy", + "PSRule.Rules.Azure\\Azure.KeyVault.Firewall", + "PSRule.Rules.Azure\\Azure.LogicApp.LimitHTTPTrigger", + "PSRule.Rules.Azure\\Azure.MariaDB.DefenderCloud", + "PSRule.Rules.Azure\\Azure.MariaDB.UseSSL", + "PSRule.Rules.Azure\\Azure.MariaDB.MinTLS", + "PSRule.Rules.Azure\\Azure.MariaDB.AllowAzureAccess", + "PSRule.Rules.Azure\\Azure.MariaDB.FirewallRuleCount", + "PSRule.Rules.Azure\\Azure.MariaDB.FirewallIPRange", + "PSRule.Rules.Azure\\Azure.MySQL.FirewallRuleCount", + "PSRule.Rules.Azure\\Azure.MySQL.AllowAzureAccess", + "PSRule.Rules.Azure\\Azure.MySQL.FirewallIPRange", + "PSRule.Rules.Azure\\Azure.MySQL.DefenderCloud", + "PSRule.Rules.Azure\\Azure.MySQL.AAD", + "PSRule.Rules.Azure\\Azure.MySQL.AADOnly", + "PSRule.Rules.Azure\\Azure.NSG.AnyInboundSource", + "PSRule.Rules.Azure\\Azure.NSG.LateralTraversal", + "PSRule.Rules.Azure\\Azure.PostgreSQL.FirewallRuleCount", + "PSRule.Rules.Azure\\Azure.PostgreSQL.AllowAzureAccess", + "PSRule.Rules.Azure\\Azure.PostgreSQL.FirewallIPRange", + "PSRule.Rules.Azure\\Azure.PostgreSQL.DefenderCloud", + "PSRule.Rules.Azure\\Azure.PostgreSQL.AAD", + "PSRule.Rules.Azure\\Azure.Redis.FirewallRuleCount", + "PSRule.Rules.Azure\\Azure.Redis.FirewallIPRange", + "PSRule.Rules.Azure\\Azure.Resource.AllowedRegions", + "PSRule.Rules.Azure\\Azure.Search.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.ServiceBus.MinTLS", + "PSRule.Rules.Azure\\Azure.ServiceBus.AuditLogs", + "PSRule.Rules.Azure\\Azure.SQL.FirewallRuleCount", + "PSRule.Rules.Azure\\Azure.SQL.AllowAzureAccess", + "PSRule.Rules.Azure\\Azure.SQL.FirewallIPRange", + "PSRule.Rules.Azure\\Azure.SQL.DefenderCloud", + "PSRule.Rules.Azure\\Azure.SQL.Auditing", + "PSRule.Rules.Azure\\Azure.SQL.AAD", + "PSRule.Rules.Azure\\Azure.SQL.AADOnly", + "PSRule.Rules.Azure\\Azure.SQLMI.AADOnly", + "PSRule.Rules.Azure\\Azure.SQLMI.AAD", + "PSRule.Rules.Azure\\Azure.Storage.BlobAccessType", + "PSRule.Rules.Azure\\Azure.Storage.DefenderCloud", + "PSRule.Rules.Azure\\Azure.RBAC.UseGroups", + "PSRule.Rules.Azure\\Azure.RBAC.LimitOwner", + "PSRule.Rules.Azure\\Azure.RBAC.LimitMGDelegation", + "PSRule.Rules.Azure\\Azure.RBAC.CoAdministrator", + "PSRule.Rules.Azure\\Azure.RBAC.UseRGDelegation", + "PSRule.Rules.Azure\\Azure.RBAC.PIM", + "PSRule.Rules.Azure\\Azure.DefenderCloud.Contact", + "PSRule.Rules.Azure\\Azure.DefenderCloud.Provisioning", + "PSRule.Rules.Azure\\Azure.TrafficManager.Protocol", + "PSRule.Rules.Azure\\Azure.VM.PublicKey", + "PSRule.Rules.Azure\\Azure.VM.ADE", + "PSRule.Rules.Azure\\Azure.VM.ScriptExtensions", + "PSRule.Rules.Azure\\Azure.VMSS.PublicKey", + "PSRule.Rules.Azure\\Azure.VMSS.ScriptExtensions", + "PSRule.Rules.Azure\\Azure.VNET.UseNSGs", + "PSRule.Rules.Azure\\Azure.VNET.FirewallSubnet", + "PSRule.Rules.Azure\\Azure.ACR.AdminUser", + "PSRule.Rules.Azure\\Azure.ACR.ContentTrust", + "PSRule.Rules.Azure\\Azure.ACR.Firewall", + "PSRule.Rules.Azure\\Azure.ADX.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.ADX.DiskEncryption", + "PSRule.Rules.Azure\\Azure.AKS.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.AKS.NetworkPolicy", + "PSRule.Rules.Azure\\Azure.AKS.AzurePolicyAddOn", + "PSRule.Rules.Azure\\Azure.AKS.ManagedAAD", + "PSRule.Rules.Azure\\Azure.AKS.AuthorizedIPs", + "PSRule.Rules.Azure\\Azure.AKS.LocalAccounts", + "PSRule.Rules.Azure\\Azure.AKS.AzureRBAC", + "PSRule.Rules.Azure\\Azure.AKS.SecretStore", + "PSRule.Rules.Azure\\Azure.AKS.SecretStoreRotation", + "PSRule.Rules.Azure\\Azure.AKS.HttpAppRouting", + "PSRule.Rules.Azure\\Azure.AKS.DefenderProfile", + "PSRule.Rules.Azure\\Azure.APIM.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.APIM.Protocols", + "PSRule.Rules.Azure\\Azure.APIM.Ciphers", + "PSRule.Rules.Azure\\Azure.AppConfig.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.AppGw.UseWAF", + "PSRule.Rules.Azure\\Azure.AppGw.SSLPolicy", + "PSRule.Rules.Azure\\Azure.AppGw.Prevention", + "PSRule.Rules.Azure\\Azure.AppGw.WAFEnabled", + "PSRule.Rules.Azure\\Azure.AppGw.OWASP", + "PSRule.Rules.Azure\\Azure.AppGw.WAFRules", + "PSRule.Rules.Azure\\Azure.AppGwWAF.Enabled", + "PSRule.Rules.Azure\\Azure.AppGwWAF.PreventionMode", + "PSRule.Rules.Azure\\Azure.AppGwWAF.Exclusions", + "PSRule.Rules.Azure\\Azure.AppGwWAF.RuleGroups", + "PSRule.Rules.Azure\\Azure.Automation.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.BV.Immutable", + "PSRule.Rules.Azure\\Azure.CDN.HTTP", + "PSRule.Rules.Azure\\Azure.Cognitive.PublicAccess", + "PSRule.Rules.Azure\\Azure.Cognitive.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.Cognitive.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.Cognitive.PrivateEndpoints", + "PSRule.Rules.Azure\\Azure.ContainerApp.Insecure", + "PSRule.Rules.Azure\\Azure.ContainerApp.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.ContainerApp.PublicAccess", + "PSRule.Rules.Azure\\Azure.ContainerApp.ExternalIngress", + "PSRule.Rules.Azure\\Azure.Cosmos.DisableMetadataWrite", + "PSRule.Rules.Azure\\Azure.Databricks.SecureConnectivity", + "PSRule.Rules.Azure\\Azure.Defender.Containers", + "PSRule.Rules.Azure\\Azure.Defender.Servers", + "PSRule.Rules.Azure\\Azure.Defender.SQL", + "PSRule.Rules.Azure\\Azure.Defender.AppServices", + "PSRule.Rules.Azure\\Azure.Defender.Storage", + "PSRule.Rules.Azure\\Azure.Defender.SQLOnVM", + "PSRule.Rules.Azure\\Azure.Defender.KeyVault", + "PSRule.Rules.Azure\\Azure.Defender.Dns", + "PSRule.Rules.Azure\\Azure.Defender.Arm", + "PSRule.Rules.Azure\\Azure.Defender.Cspm", + "PSRule.Rules.Azure\\Azure.Defender.Api", + "PSRule.Rules.Azure\\Azure.Defender.CosmosDb", + "PSRule.Rules.Azure\\Azure.Defender.OssRdb", + "PSRule.Rules.Azure\\Azure.EventGrid.TopicPublicAccess", + "PSRule.Rules.Azure\\Azure.EventGrid.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.EventGrid.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.EventHub.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.EventHub.MinTLS", + "PSRule.Rules.Azure\\Azure.Firewall.Mode", + "PSRule.Rules.Azure\\Azure.Firewall.PolicyMode", + "PSRule.Rules.Azure\\Azure.FrontDoor.WAF.Mode", + "PSRule.Rules.Azure\\Azure.FrontDoor.WAF.Enabled", + "PSRule.Rules.Azure\\Azure.FrontDoor.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.FrontDoorWAF.Enabled", + "PSRule.Rules.Azure\\Azure.FrontDoorWAF.PreventionMode", + "PSRule.Rules.Azure\\Azure.FrontDoorWAF.Exclusions", + "PSRule.Rules.Azure\\Azure.FrontDoorWAF.RuleGroups", + "PSRule.Rules.Azure\\Azure.IoTHub.MinTLS", + "PSRule.Rules.Azure\\Azure.KeyVault.RBAC", + "PSRule.Rules.Azure\\Azure.ML.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.ML.ComputeVnet", + "PSRule.Rules.Azure\\Azure.ML.PublicAccess", + "PSRule.Rules.Azure\\Azure.ML.UserManagedIdentity", + "PSRule.Rules.Azure\\Azure.MySQL.UseSSL", + "PSRule.Rules.Azure\\Azure.MySQL.MinTLS", + "PSRule.Rules.Azure\\Azure.PostgreSQL.UseSSL", + "PSRule.Rules.Azure\\Azure.PostgreSQL.MinTLS", + "PSRule.Rules.Azure\\Azure.PostgreSQL.AADOnly", + "PSRule.Rules.Azure\\Azure.Redis.MinTLS", + "PSRule.Rules.Azure\\Azure.Redis.PublicNetworkAccess", + "PSRule.Rules.Azure\\Azure.RedisEnterprise.MinTLS", + "PSRule.Rules.Azure\\Azure.RSV.Immutable", + "PSRule.Rules.Azure\\Azure.ServiceBus.DisableLocalAuth", + "PSRule.Rules.Azure\\Azure.SignalR.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.SQL.MinTLS", + "PSRule.Rules.Azure\\Azure.SQLMI.ManagedIdentity", + "PSRule.Rules.Azure\\Azure.Storage.Firewall", + "PSRule.Rules.Azure\\Azure.Storage.MinTLS", + "PSRule.Rules.Azure\\Azure.Storage.SecureTransfer", + "PSRule.Rules.Azure\\Azure.Storage.BlobPublicAccess", + "PSRule.Rules.Azure\\Azure.WebPubSub.ManagedIdentity" + ] + } + } } - } -] +] \ No newline at end of file diff --git a/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj b/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj index 7020bc7f..f6419ad8 100644 --- a/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj +++ b/src/Analyzer.Reports.UnitTests/Analyzer.Reports.UnitTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.Reports/Analyzer.Reports.csproj b/src/Analyzer.Reports/Analyzer.Reports.csproj index aa549817..5d8e5f0c 100644 --- a/src/Analyzer.Reports/Analyzer.Reports.csproj +++ b/src/Analyzer.Reports/Analyzer.Reports.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.Reports Microsoft.Azure.Templates.Analyzer.Reports diff --git a/src/Analyzer.TemplateProcessing.NuGet/Analyzer.TemplateProcessing.nuspec b/src/Analyzer.TemplateProcessing.NuGet/Analyzer.TemplateProcessing.nuspec index b4e0963c..489a54e7 100644 --- a/src/Analyzer.TemplateProcessing.NuGet/Analyzer.TemplateProcessing.nuspec +++ b/src/Analyzer.TemplateProcessing.NuGet/Analyzer.TemplateProcessing.nuspec @@ -12,11 +12,11 @@ arm bicep azure template analyzer scanner deployment security - - - - - + + + + + @@ -24,7 +24,7 @@ - + diff --git a/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj b/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj index 3ea60d9c..460889f0 100644 --- a/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj +++ b/src/Analyzer.TemplateProcessor.UnitTests/Analyzer.TemplateProcessor.UnitTests.csproj @@ -1,7 +1,7 @@ - net7.0 + net8.0 false diff --git a/src/Analyzer.TemplateProcessor.UnitTests/ArmTemplateProcessorTests.cs b/src/Analyzer.TemplateProcessor.UnitTests/ArmTemplateProcessorTests.cs index 8c09d55c..1d0d8586 100644 --- a/src/Analyzer.TemplateProcessor.UnitTests/ArmTemplateProcessorTests.cs +++ b/src/Analyzer.TemplateProcessor.UnitTests/ArmTemplateProcessorTests.cs @@ -452,7 +452,7 @@ public void ParseAndValidateTemplate_ValidTemplateWithTwoCopyLoops_ProcessResour }"; ArmTemplateProcessor armTemplateProcessor = new ArmTemplateProcessor(templateJson); - + Dictionary expectedMapping = new Dictionary { { "resources[0]", "resources[1]" }, { "resources[1]", "resources[0]" }, @@ -500,7 +500,7 @@ public void ParseAndValidateTemplate_ValidTemplateWithCopyIndex_ProcessResourceC }"; ArmTemplateProcessor armTemplateProcessor = new ArmTemplateProcessor(templateJson); - + Dictionary expectedMapping = new Dictionary { { "resources[0]", "resources[0]" }, { "resources[1]", "resources[0]" } @@ -577,7 +577,7 @@ public void ParseAndValidateTemplate_ValidTemplatesWithCopiesAndDependencies_Pro if (internalResources[resourceNumber].Length == 0) { Assert.AreEqual(null, template.Resources[resourceNumber].Resources); - } + } else { for (int internalResourceNumber = 0; internalResourceNumber < internalResources[resourceNumber].Length; internalResourceNumber++) @@ -606,7 +606,7 @@ public void CopyResourceDependants_ValidChildResourceDependsOnByNameAndResourceI ""parentResource"" ], ""properties"": { } - }"; + }"; string parentTemplateResource1Json = @"{ ""type"": ""Microsoft.Network/networkSecurityGroups"", ""apiVersion"": ""2019-02-01"", @@ -908,8 +908,8 @@ public void CopyResourceDependants_DependsOnIsChained_CopiesToCorrectResource() ""properties"": { } }"; - Dictionary expectedMapping = new Dictionary { - { "resources[0]", "resources[0]" }, + Dictionary expectedMapping = new Dictionary { + { "resources[0]", "resources[0]" }, { "resources[0].resources[0]", "resources[1]" }, { "resources[0].resources[0].resources[0]", "resources[2]" }, { "resources[1]", "resources[1]" }, @@ -1119,9 +1119,7 @@ public void ProcessTemplate_ValidTemplateUsingManagementGroupFunction_ProcessTem } [TestMethod] - [DataRow(false)] - [DataRow(true)] - public void ProcessTemplate_ValidTemplateWithPartialParameterList_ProcessTemplateFunction(bool generateMissingParameters) + public void ProcessTemplate_ValidTemplateWithPartialParameterList_ProcessTemplateFunction() { string parametersJson = @"{ ""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"", @@ -1157,21 +1155,15 @@ public void ProcessTemplate_ValidTemplateWithPartialParameterList_ProcessTemplat ] }"; + var armTemplateProcessor = new ArmTemplateProcessor(templateJson); + JToken template = armTemplateProcessor.ProcessTemplate(parametersJson, null); + + Assert.AreEqual(2, template["parameters"].Count()); + Assert.IsNotNull(template["parameters"]["trafficRoutingMethod"]); + Assert.AreEqual("Priority", template["parameters"]["trafficRoutingMethod"]["value"]); + Assert.IsNotNull(template["parameters"]["location"]); - if (generateMissingParameters) - { - JToken template = armTemplateProcessor.ProcessTemplate(parametersJson, null, generateMissingParameters); - Assert.AreEqual(2, template["parameters"].Count()); - Assert.IsNotNull(template["parameters"]["trafficRoutingMethod"]); - Assert.AreEqual("Priority", template["parameters"]["trafficRoutingMethod"]["value"]); - Assert.IsNotNull(template["parameters"]["location"]); - } - else - { - Assert.ThrowsException( - () => armTemplateProcessor.ProcessTemplate(parametersJson, null, generateMissingParameters)); - } } private string GenerateTemplateWithOutputs(string outputValue) diff --git a/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj b/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj index 1960caaa..6ed2dbc3 100644 --- a/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj +++ b/src/Analyzer.TemplateProcessor/Analyzer.TemplateProcessor.csproj @@ -1,16 +1,17 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.TemplateProcessor Microsoft.Azure.Templates.Analyzer.TemplateProcessor - - - + + + + diff --git a/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs b/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs index c219b73a..b6f0d218 100644 --- a/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs +++ b/src/Analyzer.TemplateProcessor/ArmTemplateProcessor.cs @@ -67,11 +67,10 @@ public JToken ProcessTemplate() /// Processes the ARM template with provided parameters and placeholder deployment metadata. /// /// The template parameters and their values JSON. Must follow this schema: https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json# - /// Use given parameters and generate placeholders for missing parameters /// The processed template as a JSON object. - public JToken ProcessTemplate(string parameters, bool generateMissingParameters = false) + public JToken ProcessTemplate(string parameters) { - return ProcessTemplate(parameters, null, generateMissingParameters); + return ProcessTemplate(parameters, null); } /// @@ -79,11 +78,10 @@ public JToken ProcessTemplate(string parameters, bool generateMissingParameters /// /// The template parameters and their values JSON. Must follow this schema: https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json# /// The deployment metadata JSON. - /// Use given parameters and generate placeholders for missing parameters /// The processed template as a JSON object. - public JToken ProcessTemplate(string parameters, string metadata, bool generateMissingParameters = false) + public JToken ProcessTemplate(string parameters, string metadata) { - string actualParams = string.IsNullOrEmpty(parameters) || generateMissingParameters + string actualParams = string.IsNullOrEmpty(parameters) ? PlaceholderInputGenerator.GeneratePlaceholderParameters(armTemplate, parameters) : parameters; @@ -103,18 +101,12 @@ public JToken ProcessTemplate(string parameters, string metadata, bool generateM /// The processed template as a Template object. internal Template ParseAndValidateTemplate(InsensitiveDictionary parameters, InsensitiveDictionary metadata) { - Dictionary copyNameMap = new Dictionary(); + Dictionary copyNameMap = []; Template template = TemplateEngine.ParseTemplate(armTemplate); TemplateEngine.ValidateTemplate(template, apiVersion, TemplateDeploymentScope.NotSpecified); - TemplateEngine.ParameterizeTemplate( - inputParameters: parameters, - template: template, - metadata: metadata, - diagnostics: null); - SetOriginalResourceNames(template); // If there are resources using copies, the original resource will @@ -135,7 +127,7 @@ internal Template ParseAndValidateTemplate(InsensitiveDictionary paramet try { - TemplateEngine.ProcessTemplateLanguageExpressions(managementGroupName, subscriptionId, resourceGroupName, template, apiVersion, null); + TemplateEngine.ProcessTemplateLanguageExpressions(managementGroupName, subscriptionId, resourceGroupName, template, apiVersion, parameters, metadata, null); } catch (Exception ex) { diff --git a/src/Analyzer.Types/Analyzer.Types.csproj b/src/Analyzer.Types/Analyzer.Types.csproj index a9a91367..f71313e3 100644 --- a/src/Analyzer.Types/Analyzer.Types.csproj +++ b/src/Analyzer.Types/Analyzer.Types.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.Types Microsoft.Azure.Templates.Analyzer.Types diff --git a/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj b/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj index 48f663ef..1acb367f 100644 --- a/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj +++ b/src/Analyzer.Utilities.UnitTests/Analyzer.Utilities.UnitTests.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 false diff --git a/src/Analyzer.Utilities/Analyzer.Utilities.csproj b/src/Analyzer.Utilities/Analyzer.Utilities.csproj index 13cf45ee..d46fee19 100644 --- a/src/Analyzer.Utilities/Analyzer.Utilities.csproj +++ b/src/Analyzer.Utilities/Analyzer.Utilities.csproj @@ -1,7 +1,7 @@  - net7.0 + net8.0 Microsoft.Azure.Templates.Analyzer.Utilities Microsoft.Azure.Templates.Analyzer.Utilities diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ed890c17..8241f298 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 0.6.0 + 0.7.0 Microsoft © Microsoft Corporation. All rights reserved.