Skip to content

Commit 4f2e969

Browse files
authored
Fixed identification of list function false positive with resource Azure#2919 (Azure#2941)
1 parent 9d9bf2c commit 4f2e969

File tree

5 files changed

+69
-30
lines changed

5 files changed

+69
-30
lines changed

docs/CHANGELOG-v1.md

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ What's changed since pre-release v1.38.0-B0011:
4141
- Bug fixes:
4242
- Fixed failed to expand with direct outputs reference by @BernieWhite.
4343
[#2935](https://github.com/Azure/PSRule.Rules.Azure/issues/2935)
44+
- Fixed identification of `list*` function false positive with resource by @BernieWhite.
45+
[#2919](https://github.com/Azure/PSRule.Rules.Azure/issues/2919)
4446

4547
## v1.38.0-B0011 (pre-release)
4648

src/PSRule.Rules.Azure/Data/Template/TokenStreamValidator.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal static class TokenStreamValidator
1515
private const string FN_PARAMETERS = "parameters";
1616
private const string FN_VARIABLES = "variables";
1717
private const string FN_IF = "if";
18-
private const string FN_LISTKEYS = "listKeys";
18+
private const string FN_LIST = "list";
1919
private const string FN_REFERNECE = "reference";
2020

2121
/// <summary>
@@ -72,7 +72,7 @@ public static bool UsesListKeysFunction(TokenStream stream)
7272
continue;
7373
}
7474

75-
if (IsFunction(token, FN_LISTKEYS))
75+
if (IsFunctionWithPrefix(token, FN_LIST) && !IsFunction(token, FN_LIST))
7676
return true;
7777
}
7878
return false;
@@ -168,5 +168,11 @@ private static bool IsFunction(ExpressionToken token, string name)
168168
return token.Type == ExpressionTokenType.Element &&
169169
string.Equals(token.Content, name, StringComparison.OrdinalIgnoreCase);
170170
}
171+
172+
private static bool IsFunctionWithPrefix(ExpressionToken token, string prefix)
173+
{
174+
return token.Type == ExpressionTokenType.Element &&
175+
token.Content.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
176+
}
171177
}
172178
}

tests/PSRule.Rules.Azure.Tests/Tests.Bicep.9.goodStreamingJobs.bicep

+20-5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' = {
1111
name: 'aStorageAccount'
1212
}
1313

14+
resource search 'Microsoft.Search/searchServices@2022-09-01' existing = {
15+
name: 'aSearch'
16+
}
17+
1418
resource goodStreamingJobs 'Microsoft.StreamAnalytics/streamingjobs@2021-10-01-preview' = {
1519
name: 'goodStreamingJobs'
1620
properties: {
@@ -23,7 +27,7 @@ resource goodStreamingJobs 'Microsoft.StreamAnalytics/streamingjobs@2021-10-01-p
2327
type: 'Microsoft.Sql/Server/Database'
2428
properties: {
2529
password: secret
26-
}
30+
}
2731
}
2832
}
2933
}
@@ -35,7 +39,7 @@ resource goodStreamingJobs 'Microsoft.StreamAnalytics/streamingjobs@2021-10-01-p
3539
type: 'Microsoft.Sql/Server/Database'
3640
properties: {
3741
password: storage.listKeys().keys[0].value
38-
}
42+
}
3943
}
4044
}
4145
}
@@ -47,16 +51,27 @@ resource goodStreamingJobs 'Microsoft.StreamAnalytics/streamingjobs@2021-10-01-p
4751
type: 'Microsoft.Sql/Server/Database'
4852
properties: {
4953
password: secretFromKeyVault
50-
}
54+
}
55+
}
56+
}
57+
}
58+
{
59+
name: 'inputUsingSearchService'
60+
properties: {
61+
type: 'Reference'
62+
datasource: {
63+
type: 'Microsoft.Sql/Server/Database'
64+
properties: {
65+
password: search.listAdminKeys().primaryKey
66+
}
5167
}
5268
}
5369
}
5470
]
5571
outputs: [
5672
{
5773
name: 'outputWithoutPassword'
58-
properties: {
59-
}
74+
properties: {}
6075
}
6176
]
6277
}

tests/PSRule.Rules.Azure.Tests/Tests.Bicep.9.json

+32-20
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
"metadata": {
55
"_generator": {
66
"name": "bicep",
7-
"version": "0.13.1.58284",
8-
"templateHash": "8685448171369407541"
7+
"version": "0.28.1.47646",
8+
"templateHash": "18275092912549928193"
99
}
1010
},
1111
"resources": [
1212
{
1313
"type": "Microsoft.Resources/deployments",
14-
"apiVersion": "2020-10-01",
14+
"apiVersion": "2022-09-01",
1515
"name": "secret_good",
1616
"properties": {
1717
"expressionEvaluationOptions": {
@@ -29,13 +29,13 @@
2929
"metadata": {
3030
"_generator": {
3131
"name": "bicep",
32-
"version": "0.13.1.58284",
33-
"templateHash": "3563517143203947158"
32+
"version": "0.28.1.47646",
33+
"templateHash": "1518984315103849805"
3434
}
3535
},
3636
"parameters": {
3737
"secret": {
38-
"type": "secureString"
38+
"type": "securestring"
3939
}
4040
},
4141
"resources": [
@@ -53,7 +53,7 @@
5353
},
5454
{
5555
"type": "Microsoft.Resources/deployments",
56-
"apiVersion": "2020-10-01",
56+
"apiVersion": "2022-09-01",
5757
"name": "secret_bad",
5858
"properties": {
5959
"expressionEvaluationOptions": {
@@ -71,8 +71,8 @@
7171
"metadata": {
7272
"_generator": {
7373
"name": "bicep",
74-
"version": "0.13.1.58284",
75-
"templateHash": "13907904796621207265"
74+
"version": "0.28.1.47646",
75+
"templateHash": "6215663120730168687"
7676
}
7777
},
7878
"parameters": {
@@ -95,7 +95,7 @@
9595
},
9696
{
9797
"type": "Microsoft.Resources/deployments",
98-
"apiVersion": "2020-10-01",
98+
"apiVersion": "2022-09-01",
9999
"name": "streaming_jobs_good",
100100
"properties": {
101101
"expressionEvaluationOptions": {
@@ -121,16 +121,16 @@
121121
"metadata": {
122122
"_generator": {
123123
"name": "bicep",
124-
"version": "0.13.1.58284",
125-
"templateHash": "1243191437263886583"
124+
"version": "0.28.1.47646",
125+
"templateHash": "3797411740136360330"
126126
}
127127
},
128128
"parameters": {
129129
"secret": {
130-
"type": "secureString"
130+
"type": "securestring"
131131
},
132132
"secretFromKeyVault": {
133-
"type": "secureString"
133+
"type": "securestring"
134134
}
135135
},
136136
"resources": [
@@ -180,6 +180,18 @@
180180
}
181181
}
182182
}
183+
},
184+
{
185+
"name": "inputUsingSearchService",
186+
"properties": {
187+
"type": "Reference",
188+
"datasource": {
189+
"type": "Microsoft.Sql/Server/Database",
190+
"properties": {
191+
"password": "[listAdminKeys(resourceId('Microsoft.Search/searchServices', 'aSearch'), '2022-09-01').primaryKey]"
192+
}
193+
}
194+
}
183195
}
184196
],
185197
"outputs": [
@@ -199,7 +211,7 @@
199211
},
200212
{
201213
"type": "Microsoft.Resources/deployments",
202-
"apiVersion": "2020-10-01",
214+
"apiVersion": "2022-09-01",
203215
"name": "streaming_jobs_bad",
204216
"properties": {
205217
"expressionEvaluationOptions": {
@@ -217,8 +229,8 @@
217229
"metadata": {
218230
"_generator": {
219231
"name": "bicep",
220-
"version": "0.13.1.58284",
221-
"templateHash": "14384591199981266606"
232+
"version": "0.28.1.47646",
233+
"templateHash": "4134825371520485157"
222234
}
223235
},
224236
"parameters": {
@@ -267,7 +279,7 @@
267279
},
268280
{
269281
"type": "Microsoft.Resources/deployments",
270-
"apiVersion": "2020-10-01",
282+
"apiVersion": "2022-09-01",
271283
"name": "reference_good",
272284
"properties": {
273285
"expressionEvaluationOptions": {
@@ -280,8 +292,8 @@
280292
"metadata": {
281293
"_generator": {
282294
"name": "bicep",
283-
"version": "0.13.1.58284",
284-
"templateHash": "9418583989023446705"
295+
"version": "0.28.1.47646",
296+
"templateHash": "6922313715624563061"
285297
}
286298
},
287299
"parameters": {

tests/PSRule.Rules.Azure.Tests/TokenStreamValidatorTests.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace PSRule.Rules.Azure
99
public sealed class TokenStreamValidatorTests
1010
{
1111
[Fact]
12-
public void HasInsecureToken()
12+
public void HasLiteralValue()
1313
{
1414
Assert.True(Helper.HasLiteralValue("password"));
1515
Assert.True(Helper.HasLiteralValue("123"));
@@ -33,8 +33,12 @@ public void GetParameterTokenValue()
3333
[Fact]
3434
public void UsesListKeysFunction()
3535
{
36-
Assert.True(Helper.UsesListKeysFunction("[listKeys(resourceId('Microsoft.Storage/storageAccounts', 'aStorageAccount'), '2021-09-01').keys[0].value]"));
37-
Assert.True(Helper.UsesListKeysFunction("[listKeys(resourceId('Microsoft.Storage/storageAccounts', 'aStorageAccount'), '2021-09-01')]"));
36+
Assert.True(Helper.UsesListKeysFunction("[listKeys(resourceId('Microsoft.Storage/storageAccounts', 'storage1'), '2021-09-01').keys[0].value]"));
37+
Assert.True(Helper.UsesListKeysFunction("[listKeys(resourceId('Microsoft.Storage/storageAccounts', 'storage1'), '2021-09-01')]"));
38+
Assert.True(Helper.UsesListKeysFunction("[listAdminKeys(resourceId('Microsoft.Search/searchServices', 'search1'), '2022-09-01').primaryKey]"));
39+
Assert.True(Helper.UsesListKeysFunction("[listQueryKeys(resourceId('Microsoft.Search/searchServices', 'search1'), '2021-09-01').value[0].key]"));
40+
Assert.False(Helper.UsesListKeysFunction("[list(resourceId('Microsoft.OperationalInsights/workspaces', 'workspace1'), '2023-09-01').value[0].properties.name]"));
41+
Assert.False(Helper.UsesListKeysFunction("[resourceId('Microsoft.Storage/storageAccounts', 'storage1')]"));
3842
}
3943

4044
[Fact]

0 commit comments

Comments
 (0)