diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index 74a6b64fe6..d8d0260cd8 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -42,6 +42,8 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers - Bug fixes: - Fixed projection of default role authorization property `principalType` by @BernieWhite. [#3163](https://github.com/Azure/PSRule.Rules.Azure/issues/3163) + - Fixed user defined function not found when used as parameter default by @BernieWhite. + [#3169](https://github.com/Azure/PSRule.Rules.Azure/issues/3169) ## v1.40.0-B0063 (pre-release) diff --git a/src/PSRule.Rules.Azure/Data/Template/TemplateVisitor.cs b/src/PSRule.Rules.Azure/Data/Template/TemplateVisitor.cs index a33835d5e0..fd9f48413d 100644 --- a/src/PSRule.Rules.Azure/Data/Template/TemplateVisitor.cs +++ b/src/PSRule.Rules.Azure/Data/Template/TemplateVisitor.cs @@ -906,12 +906,12 @@ protected virtual void Template(TemplateContext context, string deploymentName, if (TryObjectProperty(template, PROPERTY_VARIABLES, out var variables)) FunctionVariables(context, variables); - if (TryObjectProperty(template, PROPERTY_PARAMETERS, out var parameters)) - Parameters(context, parameters); - if (TryArrayProperty(template, PROPERTY_FUNCTIONS, out var functions)) Functions(context, functions); + if (TryObjectProperty(template, PROPERTY_PARAMETERS, out var parameters)) + Parameters(context, parameters); + if (TryObjectProperty(template, PROPERTY_VARIABLES, out variables)) Variables(context, variables); diff --git a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/BicepUserDefinedFunctionTests.cs b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/BicepUserDefinedFunctionTests.cs index 76a82d7cc8..4f288f4bd5 100644 --- a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/BicepUserDefinedFunctionTests.cs +++ b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/BicepUserDefinedFunctionTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Linq; using Newtonsoft.Json.Linq; using PSRule.Rules.Azure.Data.Template; @@ -31,4 +32,18 @@ public void ProcessTemplate_WhenUserDefinedFunctionReferencesExportedVariables_S Assert.True(templateContext.RootDeployment.TryOutput("o5", out JObject o5)); Assert.Equal([3], o5["value"].Values()); } + + /// + /// Test case for https://github.com/Azure/PSRule.Rules.Azure/issues/3169 + /// + [Fact] + public void ProcessTemplate_WhenUserDefinedFunctionCalledAsParameterDefault_ShouldFindFunction() + { + var resources = ProcessTemplate(GetSourcePath("Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.json"), null, out var templateContext); + + Assert.NotNull(resources); + + var actual = resources.Where(r => r["type"].Value() == "Microsoft.Storage/storageAccounts").FirstOrDefault(); + Assert.Equal("sa5f3e65afb63bb1", actual["name"].Value()); + } } diff --git a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.bicep b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.bicep new file mode 100644 index 0000000000..bda27260fa --- /dev/null +++ b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.bicep @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Test case for https://github.com/Azure/PSRule.Rules.Azure/issues/3169 +// Based on work contributed by @modbase + +targetScope = 'resourceGroup' + +module storage 'Tests.Bicep.2.child.bicep' = { + name: 'storage' + params: {} +} diff --git a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.child.bicep b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.child.bicep new file mode 100644 index 0000000000..059ea38cba --- /dev/null +++ b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.child.bicep @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +targetScope = 'resourceGroup' + +param name string = customNamingFunction('sa', 1) + +import { customNamingFunction } from './Tests.Bicep.2.fn.bicep' + +resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = { + name: name + location: resourceGroup().location + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } +} diff --git a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.fn.bicep b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.fn.bicep new file mode 100644 index 0000000000..14c62b6a69 --- /dev/null +++ b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.fn.bicep @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +targetScope = 'resourceGroup' + +// A custom naming function. +@export() +func customNamingFunction(prefix string, instance int) string => + '${prefix}${uniqueString(resourceGroup().id)}${instance}' diff --git a/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.json b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.json new file mode 100644 index 0000000000..47518bb570 --- /dev/null +++ b/tests/PSRule.Rules.Azure.Tests/Bicep/UserDefinedFunctionTestCases/Tests.Bicep.2.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.31.34.60546", + "templateHash": "6735599436485338599" + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "storage", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": {}, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.31.34.60546", + "templateHash": "12715503820119808772" + } + }, + "functions": [ + { + "namespace": "__bicep", + "members": { + "customNamingFunction": { + "parameters": [ + { + "type": "string", + "name": "prefix" + }, + { + "type": "int", + "name": "instance" + } + ], + "output": { + "type": "string", + "value": "[format('{0}{1}{2}', parameters('prefix'), uniqueString(resourceGroup().id), parameters('instance'))]" + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "Tests.Bicep.2.fn.bicep" + } + } + } + } + } + ], + "parameters": { + "name": { + "type": "string", + "defaultValue": "[__bicep.customNamingFunction('sa', 1)]" + } + }, + "resources": { + "storage": { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-05-01", + "name": "[parameters('name')]", + "location": "[resourceGroup().location]", + "kind": "StorageV2", + "sku": { + "name": "Standard_LRS" + } + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/tests/PSRule.Rules.Azure.Tests/PSRule.Rules.Azure.Tests.csproj b/tests/PSRule.Rules.Azure.Tests/PSRule.Rules.Azure.Tests.csproj index 9720166653..5d9f485130 100644 --- a/tests/PSRule.Rules.Azure.Tests/PSRule.Rules.Azure.Tests.csproj +++ b/tests/PSRule.Rules.Azure.Tests/PSRule.Rules.Azure.Tests.csproj @@ -308,6 +308,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest