Skip to content

Commit ec29a13

Browse files
authored
Fix regression on secure inline object types and resource-derived string and object types (#18170)
Resolves #18161 ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/18170)
1 parent 61fbce4 commit ec29a13

File tree

4 files changed

+48
-21
lines changed

4 files changed

+48
-21
lines changed

src/Bicep.Core.IntegrationTests/ScenarioTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5776,8 +5776,8 @@ public void Test_Issue12908()
57765776

57775777
result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[]
57785778
{
5779-
("BCP439", DiagnosticLevel.Error, """The @secure() decorator can only be used on statements whose type clause is "string,", "object", or a literal type."""),
5780-
("BCP439", DiagnosticLevel.Error, """The @secure() decorator can only be used on statements whose type clause is "string,", "object", or a literal type."""),
5779+
("BCP308", DiagnosticLevel.Error, """The decorator "secure" may not be used on statements whose declared type is a reference to a user-defined type."""),
5780+
("BCP308", DiagnosticLevel.Error, """The decorator "secure" may not be used on statements whose declared type is a reference to a user-defined type."""),
57815781
});
57825782
}
57835783

src/Bicep.Core.IntegrationTests/UserDefinedTypeTests.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ param intParam constrainedInt
155155
("BCP308", DiagnosticLevel.Error, "The decorator \"maxValue\" may not be used on statements whose declared type is a reference to a user-defined type."),
156156
("BCP308", DiagnosticLevel.Error, "The decorator \"minLength\" may not be used on statements whose declared type is a reference to a user-defined type."),
157157
("BCP308", DiagnosticLevel.Error, "The decorator \"maxLength\" may not be used on statements whose declared type is a reference to a user-defined type."),
158-
("BCP439", DiagnosticLevel.Error, "The @secure() decorator can only be used on statements whose type clause is \"string,\", \"object\", or a literal type."),
158+
("BCP308", DiagnosticLevel.Error, "The decorator \"secure\" may not be used on statements whose declared type is a reference to a user-defined type."),
159159
("BCP308", DiagnosticLevel.Error, "The decorator \"allowed\" may not be used on statements whose declared type is a reference to a user-defined type."),
160160
("no-unused-params", DiagnosticLevel.Warning, "Parameter \"stringParam\" is declared but never used."),
161161
("BCP308", DiagnosticLevel.Error, "The decorator \"minValue\" may not be used on statements whose declared type is a reference to a user-defined type."),
@@ -1991,13 +1991,46 @@ public void Secure_decorator_is_blocked_on_any_and_resource_derived_types()
19911991
type untyped = any
19921992
19931993
@secure()
1994-
type rdt = resourceInput<'Microsoft.Resources/deployments@2022-09-01'>.name
1994+
type rdt = resourceInput<'Microsoft.Compute/virtualMachines/extensions@2019-12-01'>.properties.settings
19951995
""");
19961996

19971997
result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(
19981998
[
1999-
("BCP439", DiagnosticLevel.Error, "The @secure() decorator can only be used on statements whose type clause is \"string,\", \"object\", or a literal type."),
2000-
("BCP439", DiagnosticLevel.Error, "The @secure() decorator can only be used on statements whose type clause is \"string,\", \"object\", or a literal type."),
1999+
("BCP440", DiagnosticLevel.Error, "The @secure() decorator can only be used on statements whose type is a subtype of \"string\" or \"object\"."),
2000+
("BCP440", DiagnosticLevel.Error, "The @secure() decorator can only be used on statements whose type is a subtype of \"string\" or \"object\"."),
20012001
]);
20022002
}
2003+
2004+
[TestMethod]
2005+
public void Secure_decorator_is_permitted_on_inline_object_types()
2006+
{
2007+
var result = CompilationHelper.Compile("""
2008+
@secure()
2009+
param config {
2010+
*: string
2011+
}
2012+
2013+
@secure()
2014+
param foo 'bar' | 'baz' | 'quux'
2015+
""");
2016+
2017+
result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics();
2018+
}
2019+
2020+
[TestMethod]
2021+
public void Secure_decorator_on_resource_derived_type_should_use_secure_ARM_primitive_type()
2022+
{
2023+
var result = CompilationHelper.Compile("""
2024+
@secure()
2025+
type stringRdt = resourceInput<'Microsoft.Resources/tags@2022-09-01'>.properties.tags.*
2026+
2027+
@secure()
2028+
type objectRdt = resourceInput<'Microsoft.Resources/tags@2022-09-01'>.properties.tags
2029+
""");
2030+
2031+
result.Should().NotHaveAnyCompilationBlockingDiagnostics();
2032+
result.Template.Should().NotBeNull();
2033+
result.Template.Should().HaveValueAtPath("$.definitions.stringRdt.type", "securestring");
2034+
result.Template.Should().HaveValueAtPath("$.definitions.objectRdt.type", "secureObject");
2035+
}
20032036
}

src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,10 @@ public Diagnostic BaseIdentifierRedeclared() => CoreError(
20002000
public Diagnostic SecureDecoratorOnlyAllowedOnStringsAndObjects() => CoreError(
20012001
"BCP439",
20022002
"The @secure() decorator can only be used on statements whose type clause is \"string,\", \"object\", or a literal type.");
2003+
2004+
public Diagnostic SecureDecoratorTargetMustFitWithinStringOrObject() => CoreError(
2005+
"BCP440",
2006+
"The @secure() decorator can only be used on statements whose type is a subtype of \"string\" or \"object\".");
20032007
}
20042008

20052009
public static DiagnosticBuilderInternal ForPosition(TextSpan span)

src/Bicep.Core/Semantics/Namespaces/SystemNamespaceType.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,24 +1844,14 @@ static IEnumerable<Decorator> GetBicepTemplateDecorators(IFeatureProvider featur
18441844
return;
18451845
}
18461846

1847-
var targetTypeClause = UnwrapNullableSyntax(GetDeclaredTypeSyntaxOfParent(decoratorSyntax, binder));
1848-
if (IsLiteralSyntax(targetTypeClause, typeManager))
1847+
if (TypeHelper.TryGetArmPrimitiveType(targetType) is null)
18491848
{
1850-
// @secure() is allowed on literal string and object types
1851-
return;
1852-
}
1853-
1854-
if (targetTypeClause is not null &&
1855-
binder.GetSymbolInfo(targetTypeClause) is AmbientTypeSymbol ambientType &&
1856-
ambientType.DeclaringNamespace.ExtensionName.Equals(BuiltInName) &&
1857-
ambientType.Name is LanguageConstants.TypeNameString or LanguageConstants.ObjectType)
1858-
{
1859-
// @secure() is allowed if the target's type syntax is "string" or "object"
1860-
return;
1849+
// if we won't be emitting a "type" constraint in the compiled JSON, we can't make it a secure type
1850+
diagnosticWriter.Write(
1851+
DiagnosticBuilder.ForPosition(decoratorSyntax).SecureDecoratorTargetMustFitWithinStringOrObject());
18611852
}
18621853

1863-
diagnosticWriter.Write(
1864-
DiagnosticBuilder.ForPosition(decoratorSyntax).SecureDecoratorOnlyAllowedOnStringsAndObjects());
1854+
ValidateNotTargetingAlias(decoratorName, decoratorSyntax, targetType, typeManager, binder, parsingErrorLookup, diagnosticWriter);
18651855
})
18661856
.WithEvaluator((functionCall, decorated) =>
18671857
{

0 commit comments

Comments
 (0)