Skip to content

Commit 79e659a

Browse files
authored
Fixes for policy as rules export issues Azure#2724 Azure#2725 Azure#2726 (Azure#2740)
* Fixes for policy as rules export issues Azure#2724 Azure#2725 Azure#2726 * Additional fixes
1 parent a31acc0 commit 79e659a

8 files changed

+524
-20
lines changed

data/policy-ignore.json

+7
Original file line numberDiff line numberDiff line change
@@ -202,5 +202,12 @@
202202
],
203203
"reason": "Duplicate",
204204
"value": "Azure.Storage.MinTLS"
205+
},
206+
{
207+
"policyDefinitionIds": [
208+
"/providers/Microsoft.Authorization/policyDefinitions/fbb99e8e-e444-4da0-9ff1-75c92f5a85b2"
209+
],
210+
"reason": "NotApplicable",
211+
"value": "Checking for BYOK of a storage account used for logging activity is not enforcable by code (#2725)."
205212
}
206213
]

docs/CHANGELOG-v1.md

+9
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers
3232

3333
## Unreleased
3434

35+
What's changed since v1.34.0:
36+
37+
- Bug fixes:
38+
- Fixed policy as rules export issues by @BernieWhite.
39+
[#2724](https://github.com/Azure/PSRule.Rules.Azure/issues/2724)
40+
[#2725](https://github.com/Azure/PSRule.Rules.Azure/issues/2725)
41+
[#2726](https://github.com/Azure/PSRule.Rules.Azure/issues/2726)
42+
[#2727](https://github.com/Azure/PSRule.Rules.Azure/issues/2727)
43+
3544
## v1.34.0
3645

3746
What's changed since v1.33.2:

src/PSRule.Rules.Azure/Common/JsonExtensions.cs

+30-2
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,13 @@ internal static void ReplaceProperty(this JObject o, string propertyName, int va
271271
p.Value = new JValue(value);
272272
}
273273

274+
internal static void RemoveProperty(this JObject o, string propertyName)
275+
{
276+
var p = o.Property(propertyName, StringComparison.OrdinalIgnoreCase);
277+
if (p != null)
278+
p.Remove();
279+
}
280+
274281
/// <summary>
275282
/// Convert a string property to an integer.
276283
/// </summary>
@@ -481,11 +488,32 @@ internal static bool TryStringProperty(this JObject obj, string propertyName, ou
481488
internal static bool TryBoolProperty(this JObject o, string propertyName, out bool? value)
482489
{
483490
value = null;
484-
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var v) && v.Type == JTokenType.Boolean)
491+
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var token) && token.Type == JTokenType.Boolean)
485492
{
486-
value = v.Value<bool>();
493+
value = token.Value<bool>();
487494
return value != null;
488495
}
496+
else if (token != null && token.Type == JTokenType.String && bool.TryParse(token.Value<string>(), out var v))
497+
{
498+
value = v;
499+
return true;
500+
}
501+
return false;
502+
}
503+
504+
internal static bool TryIntegerProperty(this JObject o, string propertyName, out long? value)
505+
{
506+
value = null;
507+
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var token) && token.Type == JTokenType.Integer)
508+
{
509+
value = token.Value<long>();
510+
return value != null;
511+
}
512+
else if (token != null && token.Type == JTokenType.String && long.TryParse(token.Value<string>(), out var v))
513+
{
514+
value = v;
515+
return true;
516+
}
489517
return false;
490518
}
491519

src/PSRule.Rules.Azure/Data/Policy/PolicyAssignmentVisitor.cs

+129-15
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ internal abstract class PolicyAssignmentVisitor : ResourceManagerVisitor
7373
private const string PROPERTY_PATH = "path";
7474
private const string PROPERTY_CONVERT = "convert";
7575
private const string PROPERTY_NONCOMPLIANCEMESSAGES = "NonComplianceMessages";
76+
private const string PROPERTY_HASVALUE = "hasValue";
77+
private const string PROPERTY_EMPTY = "empty";
78+
private const string PROPERTY_LENGTH = "length";
79+
7680
private const string EFFECT_DISABLED = "Disabled";
7781
private const string EFFECT_AUDITIFNOTEXISTS = "AuditIfNotExists";
7882
private const string EFFECT_DEPLOYIFNOTEXISTS = "DeployIfNotExists";
@@ -90,6 +94,7 @@ internal abstract class PolicyAssignmentVisitor : ResourceManagerVisitor
9094
private const char SLASH = '/';
9195
private const char GROUP_OPEN = '(';
9296
private const char GROUP_CLOSE = ')';
97+
9398
private const string TYPE_SECURITYASSESSMENTS = "Microsoft.Security/assessments";
9499
private const string TYPE_GUESTCONFIGURATIONASSIGNMENTS = "Microsoft.GuestConfiguration/guestConfigurationAssignments";
95100
private const string TYPE_BACKUPPROTECTEDITEMS = "Microsoft.RecoveryServices/backupprotecteditems";
@@ -1020,7 +1025,7 @@ private static void VisitCondition(PolicyAssignmentContext context, PolicyDefini
10201025
private static void VisitCountExpression(PolicyAssignmentContext context, PolicyDefinition policyDefinition, JObject parent, JObject count)
10211026
{
10221027
// Remove from parent
1023-
parent.Remove(PROPERTY_COUNT);
1028+
parent.RemoveProperty(PROPERTY_COUNT);
10241029

10251030
if (count.TryGetProperty(PROPERTY_FIELD, out var field))
10261031
{
@@ -1203,7 +1208,7 @@ private static JObject VisitField(PolicyAssignmentContext context, PolicyDefinit
12031208
field = TemplateVisitor.ExpandString(context, field);
12041209
if (string.Equals(field, PROPERTY_TYPE, StringComparison.OrdinalIgnoreCase))
12051210
{
1206-
condition.Remove(PROPERTY_FIELD);
1211+
condition.RemoveProperty(PROPERTY_FIELD);
12071212
condition.Add(PROPERTY_TYPE, DOT);
12081213
AddTypes(context, policyDefinition, condition);
12091214
}
@@ -1257,32 +1262,32 @@ private static JObject VisitValueExpression(PolicyAssignmentContext context, JOb
12571262
tokens.ConsumeGroup() &&
12581263
tokens.ConsumePropertyName(PROPERTY_APIVERSION))
12591264
{
1260-
condition.Remove(PROPERTY_VALUE);
1265+
condition.RemoveProperty(PROPERTY_VALUE);
12611266
condition.Add(PROPERTY_FIELD, PROPERTY_APIVERSION);
12621267
if (condition.TryGetProperty(PROPERTY_LESS, out var value))
12631268
{
1264-
condition.Remove(PROPERTY_LESS);
1269+
condition.RemoveProperty(PROPERTY_LESS);
12651270
condition.Add(PROPERTY_APIVERSION, string.Concat(LESS_OPERATOR, value));
12661271
}
12671272
else if (condition.TryGetProperty(PROPERTY_LESSOREQUALS, out value))
12681273
{
1269-
condition.Remove(PROPERTY_LESSOREQUALS);
1274+
condition.RemoveProperty(PROPERTY_LESSOREQUALS);
12701275
condition.Add(PROPERTY_APIVERSION, string.Concat(LESSOREQUAL_OPERATOR, value));
12711276

12721277
}
12731278
else if (condition.TryGetProperty(PROPERTY_GREATER, out value))
12741279
{
1275-
condition.Remove(PROPERTY_GREATER);
1280+
condition.RemoveProperty(PROPERTY_GREATER);
12761281
condition.Add(PROPERTY_APIVERSION, string.Concat(GREATER_OPERATOR, value));
12771282
}
12781283
else if (condition.TryGetProperty(PROPERTY_GREATEROREQUALS, out value))
12791284
{
1280-
condition.Remove(PROPERTY_GREATEROREQUALS);
1285+
condition.RemoveProperty(PROPERTY_GREATEROREQUALS);
12811286
condition.Add(PROPERTY_APIVERSION, string.Concat(GREATEROREQUAL_OPERATOR, value));
12821287
}
12831288
else if (condition.TryGetProperty(PROPERTY_EQUALS, out value))
12841289
{
1285-
condition.Remove(PROPERTY_EQUALS);
1290+
condition.RemoveProperty(PROPERTY_EQUALS);
12861291
condition.Add(PROPERTY_APIVERSION, value);
12871292
}
12881293
}
@@ -1313,19 +1318,19 @@ private static JObject VisitFieldTokens(PolicyAssignmentContext context, JObject
13131318
// Handle [field('type')]
13141319
if (string.Equals(field, PROPERTY_TYPE, StringComparison.OrdinalIgnoreCase))
13151320
{
1316-
condition.Remove(PROPERTY_VALUE);
1321+
condition.RemoveProperty(PROPERTY_VALUE);
13171322
condition.Add(PROPERTY_TYPE, DOT);
13181323
}
13191324
else
13201325
{
1321-
condition.Remove(PROPERTY_VALUE);
1326+
condition.RemoveProperty(PROPERTY_VALUE);
13221327

13231328
field = context.TryPolicyAliasPath(field, out var aliasPath) ? TrimFieldName(context, aliasPath) : field;
13241329
condition.Add(PROPERTY_FIELD, field);
13251330
}
13261331
}
13271332

1328-
else if (tokens.ConsumeFunction("if") &&
1333+
else if (tokens.ConsumeFunction(PROPERTY_IF) &&
13291334
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
13301335
{
13311336
var orginal = condition;
@@ -1369,17 +1374,126 @@ private static JObject VisitFieldTokens(PolicyAssignmentContext context, JObject
13691374
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
13701375
}
13711376

1372-
else if (tokens.ConsumeFunction("empty") &&
1377+
else if (tokens.ConsumeFunction(PROPERTY_EMPTY) &&
13731378
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
13741379
{
13751380
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var emptyEquals))
13761381
{
1377-
condition.Remove(PROPERTY_EQUALS);
1378-
condition.Add("hasValue", !emptyEquals.Value);
1382+
condition.RemoveProperty(PROPERTY_EQUALS);
1383+
condition.Add(PROPERTY_HASVALUE, !emptyEquals.Value);
1384+
}
1385+
VisitFieldTokens(context, condition, tokens);
1386+
1387+
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
1388+
}
1389+
1390+
else if (tokens.ConsumeFunction(PROPERTY_LESS) &&
1391+
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
1392+
{
1393+
VisitFieldTokens(context, condition, tokens);
1394+
1395+
if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
1396+
{
1397+
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
1398+
{
1399+
condition.RemoveProperty(PROPERTY_EQUALS);
1400+
condition.Add(comparison.Value ? PROPERTY_LESS : PROPERTY_GREATEROREQUALS, comparisonInt.Value);
1401+
}
1402+
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
1403+
{
1404+
condition.RemoveProperty(PROPERTY_NOTEQUALS);
1405+
condition.Add(comparison.Value ? PROPERTY_GREATEROREQUALS : PROPERTY_LESS, comparisonInt.Value);
1406+
}
1407+
}
1408+
1409+
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
1410+
}
1411+
1412+
else if (tokens.ConsumeFunction(PROPERTY_LESSOREQUALS) &&
1413+
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
1414+
{
1415+
VisitFieldTokens(context, condition, tokens);
1416+
1417+
if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
1418+
{
1419+
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
1420+
{
1421+
condition.RemoveProperty(PROPERTY_EQUALS);
1422+
condition.Add(comparison.Value ? PROPERTY_LESSOREQUALS : PROPERTY_GREATER, comparisonInt.Value);
1423+
}
1424+
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
1425+
{
1426+
condition.RemoveProperty(PROPERTY_NOTEQUALS);
1427+
condition.Add(comparison.Value ? PROPERTY_GREATER : PROPERTY_LESSOREQUALS, comparisonInt.Value);
1428+
}
1429+
}
1430+
1431+
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
1432+
}
1433+
1434+
else if (tokens.ConsumeFunction(PROPERTY_GREATER) &&
1435+
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
1436+
{
1437+
VisitFieldTokens(context, condition, tokens);
1438+
1439+
if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
1440+
{
1441+
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
1442+
{
1443+
condition.RemoveProperty(PROPERTY_EQUALS);
1444+
condition.Add(comparison.Value ? PROPERTY_GREATER : PROPERTY_LESSOREQUALS, comparisonInt.Value);
1445+
}
1446+
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
1447+
{
1448+
condition.RemoveProperty(PROPERTY_NOTEQUALS);
1449+
condition.Add(comparison.Value ? PROPERTY_LESSOREQUALS : PROPERTY_GREATER, comparisonInt.Value);
1450+
}
1451+
}
1452+
1453+
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
1454+
}
1455+
1456+
else if (tokens.ConsumeFunction(PROPERTY_GREATEROREQUALS) &&
1457+
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
1458+
{
1459+
VisitFieldTokens(context, condition, tokens);
1460+
1461+
if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
1462+
{
1463+
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
1464+
{
1465+
condition.RemoveProperty(PROPERTY_EQUALS);
1466+
condition.Add(comparison.Value ? PROPERTY_GREATEROREQUALS : PROPERTY_LESS, comparisonInt.Value);
1467+
}
1468+
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
1469+
{
1470+
condition.RemoveProperty(PROPERTY_NOTEQUALS);
1471+
condition.Add(comparison.Value ? PROPERTY_LESS : PROPERTY_GREATEROREQUALS, comparisonInt.Value);
1472+
}
13791473
}
1474+
1475+
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
1476+
}
1477+
1478+
else if (tokens.ConsumeFunction(PROPERTY_LENGTH) &&
1479+
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
1480+
{
13801481
VisitFieldTokens(context, condition, tokens);
1482+
1483+
if (condition.TryIntegerProperty(PROPERTY_EQUALS, out var comparison))
1484+
{
1485+
condition.RemoveProperty(PROPERTY_EQUALS);
1486+
condition.Add(PROPERTY_COUNT, comparison.Value);
1487+
}
1488+
else if (condition.TryIntegerProperty(PROPERTY_NOTEQUALS, out comparison))
1489+
{
1490+
condition.RemoveProperty(PROPERTY_NOTEQUALS);
1491+
condition.Add(PROPERTY_NOTCOUNT, comparison.Value);
1492+
}
1493+
13811494
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
13821495
}
1496+
13831497
return condition;
13841498
}
13851499

@@ -1748,7 +1862,7 @@ private static void TrimPolicyRule(JObject policyRule)
17481862
effectBlock.TryObjectProperty(PROPERTY_DETAILS, out var details) &&
17491863
details.TryObjectProperty(PROPERTY_DEPLOYMENT, out _))
17501864
{
1751-
details.Remove(PROPERTY_DEPLOYMENT);
1865+
details.RemoveProperty(PROPERTY_DEPLOYMENT);
17521866
policyRule[PROPERTY_THEN][PROPERTY_DETAILS] = details;
17531867
}
17541868
}

tests/PSRule.Rules.Azure.Tests/PSRule.Rules.Azure.Tests.csproj

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
<None Update="Policy.assignment.5.json">
4545
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4646
</None>
47+
<None Update="Policy.assignment.6.json">
48+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
49+
</None>
50+
<None Update="Policy.assignment.7.json">
51+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
52+
</None>
4753
<None Update="Policy.assignment.json">
4854
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
4955
</None>

0 commit comments

Comments
 (0)