Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adding getSecret helper to az namespace for bicepparam files #11236

Merged
merged 2 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
40 changes: 39 additions & 1 deletion src/Bicep.Core.IntegrationTests/Emit/ParamsFileWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,45 @@ param myParam string
")]
[DataRow(@"
using 'main.bicep'

param myParam = getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>')", @"
{
""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"",
""contentVersion"": ""1.0.0.0"",
""parameters"": {
""myParam"": {
""reference"": {
""keyVault"": {
""id"": ""/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>""
},
""secretName"": ""<secretName>""
}
}
}
}", @"
param myParam string
")]
[DataRow(@"
using 'main.bicep'
param myParam = getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>', '<secretVersion>')", @"
{
""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"",
""contentVersion"": ""1.0.0.0"",
""parameters"": {
""myParam"": {
""reference"": {
""keyVault"": {
""id"": ""/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>""
},
""secretName"": ""<secretName>"",
""secretVersion"": ""<secretVersion>""
}
}
}
}", @"
param myParam string
")]
[DataRow(@"
using 'main.bicep'
param myParam = 1", @"
{
""$schema"": ""https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#"",
Expand Down
50 changes: 39 additions & 11 deletions src/Bicep.Core.IntegrationTests/EvaluationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ are not
[TestMethod]
public void ResourceId_expressions_are_evaluated_successfully()
{
var bicepparamText = @"
var bicepparamText = @"
using 'main.bicep'

param parentName = 'myParent'
param childName = 'myChild'
";

var bicepTemplateText = @"
var bicepTemplateText = @"
param parentName string
param childName string

Expand Down Expand Up @@ -362,7 +362,7 @@ public void Join_function_evaluation_works()

[TestMethod]
public void indexof_contains_function_evaluation_works()
{
{
var bicepparamText = @"
using 'main.bicep'

Expand Down Expand Up @@ -437,7 +437,7 @@ param inputArray array

[TestMethod]
public void List_comprehension_function_evaluation_works()
{
{
var bicepparamText = @"
using 'main.bicep'

Expand Down Expand Up @@ -763,7 +763,7 @@ public void Issue8782()
/// </summary>
[TestMethod]
public void Issue8782_2()
{
{
var bicepparamText = @"
using 'main.bicep'

Expand Down Expand Up @@ -872,12 +872,12 @@ public void Issue8798()

[TestMethod]
public void Module_with_unknown_resourcetype_as_parameter_and_output_has_diagnostics()
{
{
var bicepparamText = @"
using 'main.bicep'

param useMod1 = true
";
";

var bicepTemplateText = @"
param useMod1 bool
Expand Down Expand Up @@ -917,12 +917,13 @@ param bar string

var result = CompilationHelper.Compile(("main.bicep", bicepTemplateText), ("module.bicep", bicepModuleText));

var evaluated = TemplateEvaluator.Evaluate(result.Template, parameters, config => config with {
var evaluated = TemplateEvaluator.Evaluate(result.Template, parameters, config => config with
{
OnReferenceFunc = (resourceId, apiVersion, fullBody) =>
{
var id = ResourceGroupLevelResourceId.Parse(resourceId);
var barVal = id.FormatName() == "test" ? "abc" : "def";
return JToken.Parse(@"{
var id = ResourceGroupLevelResourceId.Parse(resourceId);
var barVal = id.FormatName() == "test" ? "abc" : "def";
return JToken.Parse(@"{
""outputs"": {
""foo"": {
""value"": {
Expand Down Expand Up @@ -976,5 +977,32 @@ public void Safe_dereferences_are_evaluated_successfully()
evaluated.Should().HaveValueAtPath("$.outputs['properties'].value.doesntExistArrayAccess", JValue.CreateNull());
}
}

[TestMethod]
public void az_getsecret_functions_are_evaluated_successfully()
{
var bicepTemplateText = @"
param param1 object
output output1 object = param1
";

var bicepparamText = @"
using 'main.bicep'
param param1 = { reference: 'param1' }
";

var (parameters, _, _) = CompilationHelper.CompileParams(("parameters.bicepparam", bicepparamText), ("main.bicep", bicepTemplateText));

var (template, diagnostics, _) = CompilationHelper.Compile(bicepTemplateText);

using (new AssertionScope())
{
var evaluated = TemplateEvaluator.Evaluate(template, parameters);

diagnostics.Should().NotHaveAnyDiagnostics();

evaluated.Should().HaveValueAtPath("$.outputs['output1'].value.reference", $"param1");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ param myObj = {
environment: environment()
//@[15:26) [BCP057 (Error)] The name "environment" does not exist in the current context. (CodeDescription: none) |environment|
azNs: az
//@[08:10) [BCP057 (Error)] The name "az" does not exist in the current context. (CodeDescription: none) |az|
azNsFunc: az.providers('Microsoft.Compute')
//@[12:14) [BCP057 (Error)] The name "az" does not exist in the current context. (CodeDescription: none) |az|
//@[15:24) [BCP107 (Error)] The function "providers" does not exist in namespace "az". (CodeDescription: none) |providers|
}
13 changes: 9 additions & 4 deletions src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1426,7 +1426,7 @@ public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableA
"BCP243",
"Parentheses must contain exactly one expression.");

public ErrorDiagnostic LambdaExpectedArgCountMismatch(TypeSymbol lambdaType, int expectedArgCount, int actualArgCount) => new (
public ErrorDiagnostic LambdaExpectedArgCountMismatch(TypeSymbol lambdaType, int expectedArgCount, int actualArgCount) => new(
TextSpan,
"BCP244",
$"Expected lambda expression of type \"{lambdaType}\" with {expectedArgCount} arguments but received {actualArgCount} arguments.");
Expand Down Expand Up @@ -1920,17 +1920,22 @@ public ErrorDiagnostic RuntimeValueNotAllowedInFunctionDeclaration(string? acces
"BCP341",
$"This expression is being used inside a function declaration, which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}");
}

public ErrorDiagnostic UserDefinedTypesNotAllowedInFunctionDeclaration() => new(
TextSpan,
TextSpan,
"BCP342",
$"""User-defined types are not supported in user-defined function parameters or outputs.""");

public ErrorDiagnostic FuncDeclarationStatementsUnsupported() => new(
TextSpan,
"BCP343",
$@"Using a func declaration statement requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.UserDefinedFunctions)}"".");


public ErrorDiagnostic FunctionOnlyValidWithDirectAssignment(string functionName) => new(
TextSpan,
"BCP344",
$"Function \"{functionName}\" is not valid at this location. It can only be used when directly assigning to a parameter.");

public ErrorDiagnostic TestDeclarationMustReferenceBicepTest() => new(
TextSpan,
"BCP345",
Expand Down
25 changes: 18 additions & 7 deletions src/Bicep.Core/Emit/FunctionPlacementValidatorVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,26 @@ public override void VisitFunctionCallSyntax(FunctionCallSyntax syntax)

private void VerifyModuleSecureParameterFunctionPlacement(FunctionCallSyntaxBase syntax)
{
if (semanticModel.GetSymbolInfo(syntax) is FunctionSymbol functionSymbol && functionSymbol.FunctionFlags.HasFlag(FunctionFlags.ModuleSecureParameterOnly))
if (semanticModel.GetSymbolInfo(syntax) is FunctionSymbol functionSymbol)
{
// we can check placement only for funtions that were matched and has a proper placement flag
var (_, levelUpSymbol) = syntaxRecorder.Skip(1).SkipWhile(x => x.syntax is TernaryOperationSyntax).FirstOrDefault();
if (!(elementsRecorder.TryPeek(out var head) && head == VisitedElement.ModuleParams)
|| levelUpSymbol is not PropertySymbol propertySymbol
|| !propertySymbol.Type.ValidationFlags.HasFlag(TypeSymbolValidationFlags.IsSecure))
if (functionSymbol.FunctionFlags.HasFlag(FunctionFlags.ModuleSecureParameterOnly))
{
diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax).FunctionOnlyValidInModuleSecureParameterAssignment(functionSymbol.Name));
// we can check placement only for funtions that were matched and has a proper placement flag
var (_, levelUpSymbol) = syntaxRecorder.Skip(1).SkipWhile(x => x.syntax is TernaryOperationSyntax).FirstOrDefault();
if (!(elementsRecorder.TryPeek(out var head) && head == VisitedElement.ModuleParams)
|| levelUpSymbol is not PropertySymbol propertySymbol
|| !propertySymbol.Type.ValidationFlags.HasFlag(TypeSymbolValidationFlags.IsSecure))
{
diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax).FunctionOnlyValidInModuleSecureParameterAssignment(functionSymbol.Name));
}
}
if (functionSymbol.FunctionFlags.HasFlag(FunctionFlags.DirectAssignment))
{
var (_, levelUpSymbol) = syntaxRecorder.Skip(1).SkipWhile(x => x.syntax is TernaryOperationSyntax).FirstOrDefault();
if (levelUpSymbol is null)
{
diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax).FunctionOnlyValidWithDirectAssignment(functionSymbol.Name));
}
}
}
}
Expand Down
50 changes: 42 additions & 8 deletions src/Bicep.Core/Emit/ParametersJsonWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public ParametersJsonWriter(SemanticModel model)
}

public void Write(JsonTextWriter writer) => GenerateTemplate().WriteTo(writer);

public JToken GenerateTemplate()
{
using var stringWriter = new StringWriter();
Expand All @@ -36,16 +36,50 @@ public JToken GenerateTemplate()
jsonWriter.WritePropertyName("parameters");
jsonWriter.WriteStartObject();

foreach (var parameter in model.Root.ParameterAssignments)
foreach (var assignment in model.Root.ParameterAssignments)
{
jsonWriter.WritePropertyName(parameter.Name);
jsonWriter.WritePropertyName(assignment.Name);

var parameter = model.EmitLimitationInfo.ParameterAssignments[assignment];

var propertyName = parameter.Type switch
{
JTokenType.Object => (parameter?.First as JProperty)?.Name,
JTokenType.Array => (parameter as JArray).ToJson(),
_ => parameter.Value<string>()
};
var isReferenceProperty = propertyName == "reference";
var isObjectType = assignment.Type.TypeKind == TypeSystem.TypeKind.Object;

jsonWriter.WriteStartObject();
if (parameter?.Type == JTokenType.Object)
{
if (!isReferenceProperty || (isReferenceProperty && isObjectType))
{
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("value");
}
}
else
{
jsonWriter.WriteStartObject();
jsonWriter.WritePropertyName("value");
}

jsonWriter.WritePropertyName("value");
model.EmitLimitationInfo.ParameterAssignments[parameter].WriteTo(jsonWriter);
jsonWriter.WriteEndObject();
parameter?.WriteTo(jsonWriter);

if (parameter?.Type == JTokenType.Object)
{
if (!isReferenceProperty || (isReferenceProperty && isObjectType))
{
jsonWriter.WriteEndObject();
}
}
else
{
jsonWriter.WriteEndObject();
}
}

jsonWriter.WriteEndObject();

jsonWriter.WriteEndObject();
Expand All @@ -54,4 +88,4 @@ public JToken GenerateTemplate()

return content.FromJson<JToken>();
}
}
}
Loading