Skip to content

Commit e138b17

Browse files
authored
Linter rule should exclude all metadata (#17667)
## Description Fixes #10308 ## Checklist - [X] I have read and adhere to the [contribution guide](https://github.com/Azure/bicep/blob/main/CONTRIBUTING.md). ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/17667)
1 parent 664f8a6 commit e138b17

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

src/Bicep.Core.UnitTests/Diagnostics/LinterRuleTests/NoHardcodedEnvironmentUrlsRuleTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,5 +201,35 @@ public void ExcludedHostsMatchingTest(string testString, bool isMatch)
201201
}
202202
});
203203
}
204+
205+
[DataRow(0, @"
206+
@description('Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.')
207+
param keyVaultUri string
208+
")]
209+
[DataRow(0, @"
210+
@sys.description('Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.')
211+
param keyVaultUri string
212+
")]
213+
[DataRow(0, @"
214+
@metadata({
215+
description: 'Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.'
216+
})
217+
param keyVaultUri string
218+
")]
219+
[DataRow(0, @"
220+
@metadata({
221+
description: 'Required. The full uri for the encrypt key from key vault. Example: https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>.',
222+
otherProperty: 'some other value'
223+
})
224+
param keyVaultUri string
225+
")]
226+
[DataRow(1, @"
227+
param keyVaultUri string = 'https://<keyvaultname>.vault.azure.net/keys/<keyname>/<version>'
228+
")]
229+
[DataTestMethod]
230+
public void ShouldSkipDescriptionAndMetadataDecorators(int diagnosticCount, string text)
231+
{
232+
AssertLinterRuleDiagnostics(NoHardcodedEnvironmentUrlsRule.Code, text, diagnosticCount, new Options(OnCompileErrors.Ignore));
233+
}
204234
}
205235
}

src/Bicep.Core/Analyzers/Linter/Rules/NoHardcodedEnvironmentUrlsRule.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
using System.Collections.Immutable;
55
using Bicep.Core.Diagnostics;
66
using Bicep.Core.Semantics;
7+
using Bicep.Core.Semantics.Namespaces;
78
using Bicep.Core.SourceGraph;
89
using Bicep.Core.Syntax;
910
using Bicep.Core.Text;
11+
using Bicep.Core.TypeSystem;
12+
using Bicep.Core.TypeSystem.Types;
1013

1114
namespace Bicep.Core.Analyzers.Linter.Rules
1215
{
@@ -41,7 +44,7 @@ public override IEnumerable<IDiagnostic> AnalyzeInternal(SemanticModel model, Di
4144

4245
if (disallowedHosts.Any())
4346
{
44-
var visitor = new Visitor(disallowedHosts, disallowedHosts.Min(h => h.Length), excludedHosts);
47+
var visitor = new Visitor(disallowedHosts, disallowedHosts.Min(h => h.Length), excludedHosts, model);
4548
visitor.Visit(model.SourceFile.ProgramSyntax);
4649

4750
return visitor.DisallowedHostSpans.Select(entry => CreateDiagnosticForSpan(diagnosticLevel, entry.Key, entry.Value));
@@ -102,12 +105,14 @@ private sealed class Visitor : AstVisitor
102105
private readonly ImmutableArray<string> disallowedHosts;
103106
private readonly int minHostLen;
104107
private readonly ImmutableArray<string> excludedHosts;
108+
private readonly SemanticModel model;
105109

106-
public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, ImmutableArray<string> excludedHosts)
110+
public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, ImmutableArray<string> excludedHosts, SemanticModel model)
107111
{
108112
this.disallowedHosts = disallowedHosts;
109113
this.minHostLen = minHostLen;
110114
this.excludedHosts = excludedHosts;
115+
this.model = model;
111116
}
112117

113118
public static IEnumerable<(TextSpan RelativeSpan, string Value)> RemoveOverlapping(IEnumerable<(TextSpan RelativeSpan, string Value)> matches)
@@ -126,8 +131,24 @@ public Visitor(ImmutableArray<string> disallowedHosts, int minHostLen, Immutable
126131
}
127132
}
128133

134+
public override void VisitDecoratorSyntax(DecoratorSyntax syntax)
135+
{
136+
// Skip @description and @metadata decorators entirely
137+
if (model.GetSymbolInfo(syntax.Expression) is FunctionSymbol functionSymbol &&
138+
functionSymbol.DeclaringObject is NamespaceType namespaceType &&
139+
LanguageConstants.IdentifierComparer.Equals(namespaceType.ExtensionName, SystemNamespaceType.BuiltInName) &&
140+
(LanguageConstants.IdentifierComparer.Equals(functionSymbol.Name, LanguageConstants.MetadataDescriptionPropertyName) ||
141+
LanguageConstants.IdentifierComparer.Equals(functionSymbol.Name, LanguageConstants.ParameterMetadataPropertyName)))
142+
{
143+
return;
144+
}
145+
146+
base.VisitDecoratorSyntax(syntax);
147+
}
148+
129149
public override void VisitStringSyntax(StringSyntax syntax)
130150
{
151+
131152
// shortcut check by testing length of full span
132153
if (syntax.Span.Length > minHostLen)
133154
{
@@ -181,6 +202,12 @@ public override void VisitModuleDeclarationSyntax(ModuleDeclarationSyntax syntax
181202
this.VisitNodes(syntax.LeadingNodes);
182203
this.Visit(syntax.Value);
183204
}
205+
206+
public override void VisitMetadataDeclarationSyntax(MetadataDeclarationSyntax syntax)
207+
{
208+
// Skip metadata declarations entirely - URLs in metadata should be allowed
209+
return;
210+
}
184211
}
185212
}
186213
}

0 commit comments

Comments
 (0)