Skip to content

Commit

Permalink
Fixes for policy as rules export issues #2724 #2725 #2726 (#2740)
Browse files Browse the repository at this point in the history
* Fixes for policy as rules export issues #2724 #2725 #2726

* Additional fixes
  • Loading branch information
BernieWhite authored Mar 6, 2024
1 parent a31acc0 commit 79e659a
Show file tree
Hide file tree
Showing 8 changed files with 524 additions and 20 deletions.
7 changes: 7 additions & 0 deletions data/policy-ignore.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,5 +202,12 @@
],
"reason": "Duplicate",
"value": "Azure.Storage.MinTLS"
},
{
"policyDefinitionIds": [
"/providers/Microsoft.Authorization/policyDefinitions/fbb99e8e-e444-4da0-9ff1-75c92f5a85b2"
],
"reason": "NotApplicable",
"value": "Checking for BYOK of a storage account used for logging activity is not enforcable by code (#2725)."
}
]
9 changes: 9 additions & 0 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

## Unreleased

What's changed since v1.34.0:

- Bug fixes:
- Fixed policy as rules export issues by @BernieWhite.
[#2724](https://github.com/Azure/PSRule.Rules.Azure/issues/2724)
[#2725](https://github.com/Azure/PSRule.Rules.Azure/issues/2725)
[#2726](https://github.com/Azure/PSRule.Rules.Azure/issues/2726)
[#2727](https://github.com/Azure/PSRule.Rules.Azure/issues/2727)

## v1.34.0

What's changed since v1.33.2:
Expand Down
32 changes: 30 additions & 2 deletions src/PSRule.Rules.Azure/Common/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,13 @@ internal static void ReplaceProperty(this JObject o, string propertyName, int va
p.Value = new JValue(value);
}

internal static void RemoveProperty(this JObject o, string propertyName)
{
var p = o.Property(propertyName, StringComparison.OrdinalIgnoreCase);
if (p != null)
p.Remove();
}

/// <summary>
/// Convert a string property to an integer.
/// </summary>
Expand Down Expand Up @@ -481,11 +488,32 @@ internal static bool TryStringProperty(this JObject obj, string propertyName, ou
internal static bool TryBoolProperty(this JObject o, string propertyName, out bool? value)
{
value = null;
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var v) && v.Type == JTokenType.Boolean)
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var token) && token.Type == JTokenType.Boolean)
{
value = v.Value<bool>();
value = token.Value<bool>();
return value != null;
}
else if (token != null && token.Type == JTokenType.String && bool.TryParse(token.Value<string>(), out var v))
{
value = v;
return true;
}
return false;
}

internal static bool TryIntegerProperty(this JObject o, string propertyName, out long? value)
{
value = null;
if (o.TryGetValue(propertyName, StringComparison.OrdinalIgnoreCase, out var token) && token.Type == JTokenType.Integer)
{
value = token.Value<long>();
return value != null;
}
else if (token != null && token.Type == JTokenType.String && long.TryParse(token.Value<string>(), out var v))
{
value = v;
return true;
}
return false;
}

Expand Down
144 changes: 129 additions & 15 deletions src/PSRule.Rules.Azure/Data/Policy/PolicyAssignmentVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ internal abstract class PolicyAssignmentVisitor : ResourceManagerVisitor
private const string PROPERTY_PATH = "path";
private const string PROPERTY_CONVERT = "convert";
private const string PROPERTY_NONCOMPLIANCEMESSAGES = "NonComplianceMessages";
private const string PROPERTY_HASVALUE = "hasValue";
private const string PROPERTY_EMPTY = "empty";
private const string PROPERTY_LENGTH = "length";

private const string EFFECT_DISABLED = "Disabled";
private const string EFFECT_AUDITIFNOTEXISTS = "AuditIfNotExists";
private const string EFFECT_DEPLOYIFNOTEXISTS = "DeployIfNotExists";
Expand All @@ -90,6 +94,7 @@ internal abstract class PolicyAssignmentVisitor : ResourceManagerVisitor
private const char SLASH = '/';
private const char GROUP_OPEN = '(';
private const char GROUP_CLOSE = ')';

private const string TYPE_SECURITYASSESSMENTS = "Microsoft.Security/assessments";
private const string TYPE_GUESTCONFIGURATIONASSIGNMENTS = "Microsoft.GuestConfiguration/guestConfigurationAssignments";
private const string TYPE_BACKUPPROTECTEDITEMS = "Microsoft.RecoveryServices/backupprotecteditems";
Expand Down Expand Up @@ -1020,7 +1025,7 @@ private static void VisitCondition(PolicyAssignmentContext context, PolicyDefini
private static void VisitCountExpression(PolicyAssignmentContext context, PolicyDefinition policyDefinition, JObject parent, JObject count)
{
// Remove from parent
parent.Remove(PROPERTY_COUNT);
parent.RemoveProperty(PROPERTY_COUNT);

if (count.TryGetProperty(PROPERTY_FIELD, out var field))
{
Expand Down Expand Up @@ -1203,7 +1208,7 @@ private static JObject VisitField(PolicyAssignmentContext context, PolicyDefinit
field = TemplateVisitor.ExpandString(context, field);
if (string.Equals(field, PROPERTY_TYPE, StringComparison.OrdinalIgnoreCase))
{
condition.Remove(PROPERTY_FIELD);
condition.RemoveProperty(PROPERTY_FIELD);
condition.Add(PROPERTY_TYPE, DOT);
AddTypes(context, policyDefinition, condition);
}
Expand Down Expand Up @@ -1257,32 +1262,32 @@ private static JObject VisitValueExpression(PolicyAssignmentContext context, JOb
tokens.ConsumeGroup() &&
tokens.ConsumePropertyName(PROPERTY_APIVERSION))
{
condition.Remove(PROPERTY_VALUE);
condition.RemoveProperty(PROPERTY_VALUE);
condition.Add(PROPERTY_FIELD, PROPERTY_APIVERSION);
if (condition.TryGetProperty(PROPERTY_LESS, out var value))
{
condition.Remove(PROPERTY_LESS);
condition.RemoveProperty(PROPERTY_LESS);
condition.Add(PROPERTY_APIVERSION, string.Concat(LESS_OPERATOR, value));
}
else if (condition.TryGetProperty(PROPERTY_LESSOREQUALS, out value))
{
condition.Remove(PROPERTY_LESSOREQUALS);
condition.RemoveProperty(PROPERTY_LESSOREQUALS);
condition.Add(PROPERTY_APIVERSION, string.Concat(LESSOREQUAL_OPERATOR, value));

}
else if (condition.TryGetProperty(PROPERTY_GREATER, out value))
{
condition.Remove(PROPERTY_GREATER);
condition.RemoveProperty(PROPERTY_GREATER);
condition.Add(PROPERTY_APIVERSION, string.Concat(GREATER_OPERATOR, value));
}
else if (condition.TryGetProperty(PROPERTY_GREATEROREQUALS, out value))
{
condition.Remove(PROPERTY_GREATEROREQUALS);
condition.RemoveProperty(PROPERTY_GREATEROREQUALS);
condition.Add(PROPERTY_APIVERSION, string.Concat(GREATEROREQUAL_OPERATOR, value));
}
else if (condition.TryGetProperty(PROPERTY_EQUALS, out value))
{
condition.Remove(PROPERTY_EQUALS);
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(PROPERTY_APIVERSION, value);
}
}
Expand Down Expand Up @@ -1313,19 +1318,19 @@ private static JObject VisitFieldTokens(PolicyAssignmentContext context, JObject
// Handle [field('type')]
if (string.Equals(field, PROPERTY_TYPE, StringComparison.OrdinalIgnoreCase))
{
condition.Remove(PROPERTY_VALUE);
condition.RemoveProperty(PROPERTY_VALUE);
condition.Add(PROPERTY_TYPE, DOT);
}
else
{
condition.Remove(PROPERTY_VALUE);
condition.RemoveProperty(PROPERTY_VALUE);

field = context.TryPolicyAliasPath(field, out var aliasPath) ? TrimFieldName(context, aliasPath) : field;
condition.Add(PROPERTY_FIELD, field);
}
}

else if (tokens.ConsumeFunction("if") &&
else if (tokens.ConsumeFunction(PROPERTY_IF) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
var orginal = condition;
Expand Down Expand Up @@ -1369,17 +1374,126 @@ private static JObject VisitFieldTokens(PolicyAssignmentContext context, JObject
tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction("empty") &&
else if (tokens.ConsumeFunction(PROPERTY_EMPTY) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var emptyEquals))
{
condition.Remove(PROPERTY_EQUALS);
condition.Add("hasValue", !emptyEquals.Value);
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(PROPERTY_HASVALUE, !emptyEquals.Value);
}
VisitFieldTokens(context, condition, tokens);

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction(PROPERTY_LESS) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
VisitFieldTokens(context, condition, tokens);

if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
{
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
{
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(comparison.Value ? PROPERTY_LESS : PROPERTY_GREATEROREQUALS, comparisonInt.Value);
}
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
{
condition.RemoveProperty(PROPERTY_NOTEQUALS);
condition.Add(comparison.Value ? PROPERTY_GREATEROREQUALS : PROPERTY_LESS, comparisonInt.Value);
}
}

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction(PROPERTY_LESSOREQUALS) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
VisitFieldTokens(context, condition, tokens);

if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
{
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
{
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(comparison.Value ? PROPERTY_LESSOREQUALS : PROPERTY_GREATER, comparisonInt.Value);
}
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
{
condition.RemoveProperty(PROPERTY_NOTEQUALS);
condition.Add(comparison.Value ? PROPERTY_GREATER : PROPERTY_LESSOREQUALS, comparisonInt.Value);
}
}

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction(PROPERTY_GREATER) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
VisitFieldTokens(context, condition, tokens);

if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
{
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
{
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(comparison.Value ? PROPERTY_GREATER : PROPERTY_LESSOREQUALS, comparisonInt.Value);
}
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
{
condition.RemoveProperty(PROPERTY_NOTEQUALS);
condition.Add(comparison.Value ? PROPERTY_LESSOREQUALS : PROPERTY_GREATER, comparisonInt.Value);
}
}

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction(PROPERTY_GREATEROREQUALS) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
VisitFieldTokens(context, condition, tokens);

if (tokens.ConsumeInteger(out var comparisonInt) && comparisonInt.HasValue)
{
if (condition.TryBoolProperty(PROPERTY_EQUALS, out var comparison))
{
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(comparison.Value ? PROPERTY_GREATEROREQUALS : PROPERTY_LESS, comparisonInt.Value);
}
else if (condition.TryBoolProperty(PROPERTY_NOTEQUALS, out comparison))
{
condition.RemoveProperty(PROPERTY_NOTEQUALS);
condition.Add(comparison.Value ? PROPERTY_LESS : PROPERTY_GREATEROREQUALS, comparisonInt.Value);
}
}

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

else if (tokens.ConsumeFunction(PROPERTY_LENGTH) &&
tokens.TryTokenType(ExpressionTokenType.GroupStart, out _))
{
VisitFieldTokens(context, condition, tokens);

if (condition.TryIntegerProperty(PROPERTY_EQUALS, out var comparison))
{
condition.RemoveProperty(PROPERTY_EQUALS);
condition.Add(PROPERTY_COUNT, comparison.Value);
}
else if (condition.TryIntegerProperty(PROPERTY_NOTEQUALS, out comparison))
{
condition.RemoveProperty(PROPERTY_NOTEQUALS);
condition.Add(PROPERTY_NOTCOUNT, comparison.Value);
}

tokens.TryTokenType(ExpressionTokenType.GroupEnd, out _);
}

return condition;
}

Expand Down Expand Up @@ -1748,7 +1862,7 @@ private static void TrimPolicyRule(JObject policyRule)
effectBlock.TryObjectProperty(PROPERTY_DETAILS, out var details) &&
details.TryObjectProperty(PROPERTY_DEPLOYMENT, out _))
{
details.Remove(PROPERTY_DEPLOYMENT);
details.RemoveProperty(PROPERTY_DEPLOYMENT);
policyRule[PROPERTY_THEN][PROPERTY_DETAILS] = details;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
<None Update="Policy.assignment.5.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Policy.assignment.6.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Policy.assignment.7.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Policy.assignment.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
Loading

0 comments on commit 79e659a

Please sign in to comment.