Skip to content

Commit 6b2b641

Browse files
author
Pallavi Sah
committed
Adding new test for admin password and admin usernames
1 parent 7bcf6f6 commit 6b2b641

File tree

6 files changed

+202
-0
lines changed

6 files changed

+202
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<#
2+
.Synopsis
3+
Ensures that all adminUsernames are expressions
4+
.Description
5+
Ensures that all properties within a template named adminUsername are expressions, not literal strings
6+
#>
7+
param(
8+
[Parameter(Mandatory = $true)]
9+
[PSObject]
10+
$TemplateObject
11+
)
12+
13+
# Find all references to an adminUserName
14+
# Filtering the complete $TemplateObject directly fails with "The script failed due to call depth overflow." errors
15+
16+
if ("resources" -in $TemplateObject.PSobject.Properties.Name) {
17+
$adminPasswordRefsResources = $TemplateObject.resources |
18+
Find-JsonContent -Key administratorLoginPassword -Value * -Like
19+
20+
foreach ($ref in $adminPasswordRefsResources) {
21+
# Walk over each one
22+
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
23+
$a = $ref.administratorLoginPassword
24+
if ($a -isnot [string]) {
25+
#check to see if this is a param value on a nested deployment - it will have a value property
26+
if ($a.value -is [string]) {
27+
$trimmedPassword = "$($a.value)".Trim()
28+
}
29+
else {
30+
continue # since we don't know what object shape we're testing at this point (could be a param declaration on a nested deployment)
31+
}
32+
}
33+
else {
34+
$trimmedPassword = "$($a)".Trim()
35+
}
36+
if ($trimmedPassword -notmatch '\[[^\]]+\]') {
37+
# If they aren't expressions
38+
Write-Error -TargetObject $ref -Message "AdministratorLoginPassword `"$trimmedPassword`" is not an expression" -ErrorId AdminPassword.Is.Literal # write an error
39+
continue # and move onto the next
40+
}
41+
}
42+
}
43+
44+
if ("variables" -in $TemplateObject.PSobject.Properties.Name) {
45+
$adminPasswordRefsVariables = $TemplateObject.variables |
46+
Find-JsonContent -Key administratorLoginPassword -Value * -Like
47+
48+
foreach ($ref in $adminPasswordRefsVariables) {
49+
# Walk over each one
50+
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
51+
if ($ref.administratorLoginPassword -isnot [string]) { continue }
52+
$trimmedPassword = "$($ref.administratorLoginPassword)".Trim()
53+
if ($trimmedPassword -notmatch '\[[^\]]+\]') {
54+
# If they aren't expressions
55+
Write-Error -TargetObject $ref -Message "AdminPassword `"$trimmedPassword`" is variable which is not an expression" -ErrorId AdminPassword.Var.Is.Literal # write an error
56+
continue # and move onto the next
57+
}
58+
}
59+
60+
# TODO - irregular doesn't handle null gracefully so we need to test for it
61+
if ($trimmedPassword -ne $null) {
62+
$UserNameHasVariable = $trimmedPassword | ?<ARM_Variable> -Extract
63+
# this will return the outer most function in the expression
64+
$userNameHasFunction = $trimmedPassword | ?<ARM_Template_Function> -Extract
65+
66+
# If we had a variable reference (not inside of another function) - then check it
67+
# TODO this will not flag things like concat so we should add a blacklist here to ensure it's still not a static or deterministic username
68+
if ($UserNameHasVariable -and $userNameHasFunction.FunctionName -eq 'variables') {
69+
$variableValue = $TemplateObject.variables.($UserNameHasVariable.VariableName)
70+
$variableValueExpression = $variableValue | ?<ARM_Template_Expression>
71+
if (-not $variableValueExpression) {
72+
Write-Error @"
73+
AdminPassword references variable '$($UserNameHasVariable.variableName)', which has a literal value.
74+
"@ -ErrorId AdminPassword.Is.Variable.Literal # write an error
75+
}
76+
}
77+
}
78+
}

arm-ttk/testcases/deploymentTemplate/adminUsername-Should-Not-Be-A-Literal.test.ps1

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ if ("resources" -in $TemplateObject.PSobject.Properties.Name) {
1717
$adminUserNameRefsResources = $TemplateObject.resources |
1818
Find-JsonContent -Key adminUsername -Value * -Like
1919

20+
$adminLoginRefsResources = $TemplateObject.resources |
21+
Find-JsonContent -Key administratorLogin -Value * -Like
22+
2023
foreach ($ref in $adminUserNameRefsResources) {
2124
# Walk over each one
2225
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
@@ -39,12 +42,38 @@ if ("resources" -in $TemplateObject.PSobject.Properties.Name) {
3942
continue # and move onto the next
4043
}
4144
}
45+
46+
foreach ($ref in $adminLoginRefsResources) {
47+
# Walk over each one
48+
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
49+
$a = $ref.administratorLogin
50+
if ($a -isnot [string]) {
51+
#check to see if this is a param value on a nested deployment - it will have a value property
52+
if ($a.value -is [string]) {
53+
$trimmedUserName = "$($a.value)".Trim()
54+
}
55+
else {
56+
continue # since we don't know what object shape we're testing at this point (could be a param declaration on a nested deployment)
57+
}
58+
}
59+
else {
60+
$trimmedUserName = "$($a)".Trim()
61+
}
62+
if ($trimmedUserName -notmatch '\[[^\]]+\]') {
63+
# If they aren't expressions
64+
Write-Error -TargetObject $ref -Message "AdministratorLogin `"$trimmedUserName`" is not an expression" -ErrorId AdminUsername.Is.Literal # write an error
65+
continue # and move onto the next
66+
}
67+
}
4268
}
4369

4470
if ("variables" -in $TemplateObject.PSobject.Properties.Name) {
4571
$adminUserNameRefsVariables = $TemplateObject.variables |
4672
Find-JsonContent -Key adminUsername -Value * -Like
4773

74+
$administratorLoginRefsVariables = $TemplateObject.variables |
75+
Find-JsonContent -Key administratorLogin -Value * -Like
76+
4877
foreach ($ref in $adminUserNameRefsVariables) {
4978
# Walk over each one
5079
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
@@ -71,6 +100,37 @@ if ("variables" -in $TemplateObject.PSobject.Properties.Name) {
71100
if (-not $variableValueExpression) {
72101
Write-Error @"
73102
AdminUsername references variable '$($UserNameHasVariable.variableName)', which has a literal value.
103+
"@ -ErrorId AdminUserName.Is.Variable.Literal # write an error
104+
}
105+
}
106+
}
107+
108+
foreach ($ref in $administratorLoginRefsVariables) {
109+
# Walk over each one
110+
# if the property is not a string, then it's likely a param value for a nested deployment, and we should skip it.
111+
if ($ref.administratorLogin -isnot [string]) { continue }
112+
$trimmedUserName = "$($ref.administratorLogin)".Trim()
113+
if ($trimmedUserName -notmatch '\[[^\]]+\]') {
114+
# If they aren't expressions
115+
Write-Error -TargetObject $ref -Message "AdministratorLogin `"$trimmedUserName`" is variable which is not an expression" -ErrorId AdminUsername.Var.Is.Literal # write an error
116+
continue # and move onto the next
117+
}
118+
}
119+
120+
# TODO - irregular doesn't handle null gracefully so we need to test for it
121+
if ($trimmedUserName -ne $null) {
122+
$UserNameHasVariable = $trimmedUserName | ?<ARM_Variable> -Extract
123+
# this will return the outer most function in the expression
124+
$userNameHasFunction = $trimmedUserName | ?<ARM_Template_Function> -Extract
125+
126+
# If we had a variable reference (not inside of another function) - then check it
127+
# TODO this will not flag things like concat so we should add a blacklist here to ensure it's still not a static or deterministic username
128+
if ($UserNameHasVariable -and $userNameHasFunction.FunctionName -eq 'variables') {
129+
$variableValue = $TemplateObject.variables.($UserNameHasVariable.VariableName)
130+
$variableValueExpression = $variableValue | ?<ARM_Template_Expression>
131+
if (-not $variableValueExpression) {
132+
Write-Error @"
133+
AdministratorLogin references variable '$($UserNameHasVariable.variableName)', which has a literal value.
74134
"@ -ErrorId AdminUserName.Is.Variable.Literal # write an error
75135
}
76136
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"variables": {
5+
"administratorLogin": "fixedusername",
6+
"administratorLoginPassword": "fixedpassword"
7+
},
8+
"resources": [
9+
{
10+
"type": "Microsoft.DBforMySQL/flexibleServers",
11+
"apiVersion": "2021-05-01",
12+
"name": "name",
13+
"location": "location",
14+
"properties": {
15+
"administratorLogin": "[variables('administratorLogin')]",
16+
"administratorLoginPassword": "[variables('administratorLoginPassword')]"
17+
}
18+
}
19+
]
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"variables": {
5+
"deploymentName": "Deployment-1.0"
6+
},
7+
"resources": [
8+
{
9+
"properties": {
10+
"parameters": {
11+
"adminPassword": {
12+
"value": "[reference(resourceId('Microsoft.Resources/deployments', variables('deploymentName')), '2019-10-01').outputs.accountSettings.value.accountAdminName]"
13+
}
14+
}
15+
}
16+
}
17+
]
18+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
#requires -module arm-ttk
3+
. $PSScriptRoot\..\arm-ttk.test.functions.ps1
4+
Test-TTK $psScriptRoot
5+
return
6+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
3+
"contentVersion": "1.0.0.0",
4+
"variables": {
5+
"administratorLogin": "fixedusername",
6+
"administratorLoginPassword": "fixedpassword"
7+
},
8+
"resources": [
9+
{
10+
"type": "Microsoft.DBforMySQL/flexibleServers",
11+
"apiVersion": "2021-05-01",
12+
"name": "name",
13+
"location": "location",
14+
"properties": {
15+
"administratorLogin": "[variables('administratorLogin')]",
16+
"administratorLoginPassword": "[variables('administratorLoginPassword')]"
17+
}
18+
}
19+
]
20+
}

0 commit comments

Comments
 (0)