Skip to content

Commit

Permalink
Custom rules may skip related_resources (#210)
Browse files Browse the repository at this point in the history
Don't generate docs link for custom rules. Allow them to
provide their own, but if they don't it should be allowed
to be blank.

Fixes #207

Signed-off-by: Anders Eknert <anders@styra.com>
  • Loading branch information
anderseknert authored Jul 21, 2023
1 parent 9bdbe30 commit 6fdb963
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 9 deletions.
24 changes: 17 additions & 7 deletions bundle/regal/result.rego
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ fail(chain, details) := violation if {
some category, title
["custom", "regal", "rules", category, title] = link.path

# NOTE: consider allowing annotation to override any derived values?
annotation := object.union(link.annotations, {
"custom": {"category": category},
"title": title,
"related_resources": _related_resources(link.annotations, category, title),
})

violation := _fail_annotated(annotation, details)
violation := _fail_annotated_custom(annotation, details)
}

_related_resources(annotations, _, _) := annotations.related_resources
Expand All @@ -56,7 +54,7 @@ _related_resources(annotations, category, title) := rr if {
}

_fail_annotated(metadata, details) := violation if {
is_object(metadata) # from rego.metadata.rule()
is_object(metadata)
with_location := object.union(metadata, details)
category := with_location.custom.category
with_category := object.union(with_location, {
Expand All @@ -67,12 +65,24 @@ _fail_annotated(metadata, details) := violation if {
without_custom_and_scope := object.remove(with_category, ["custom", "scope"])
related_resources := resource_urls(without_custom_and_scope.related_resources, category)

violation := object.union(
object.remove(without_custom_and_scope, ["related_resources"]),
{"related_resources": related_resources},
violation := json.patch(
without_custom_and_scope,
[{"op": "replace", "path": "/related_resources", "value": related_resources}],
)
}

_fail_annotated_custom(metadata, details) := violation if {
is_object(metadata)
with_location := object.union(metadata, details)
category := with_location.custom.category
with_category := object.union(with_location, {
"category": category,
"level": config.rule_level(config.for_rule(with_location)),
})

violation := object.remove(with_category, ["custom", "scope"])
}

fail(metadata, details) := _fail_annotated(metadata, details)

resource_urls(related_resources, category) := [r |
Expand Down
81 changes: 81 additions & 0 deletions bundle/regal/result_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package regal.result_test

import data.regal.result

test_no_related_resources_in_result_fail_on_custom_rule_unless_provided {
chain := [
{"path": ["custom", "regal", "rules", "categoy", "name", "report"]},
{
"annotations": {
"scope": "package",
"description": "This is a test",
},
"path": ["custom", "regal", "rules", "categoy", "name"],
},
]

violation := result.fail(chain, {})

violation == {
"category": "categoy",
"description": "This is a test",
"level": "error",
"title": "name",
}
}

test_related_resources_in_result_fail_on_custom_rule_when_provided {
chain := [
{"path": ["custom", "regal", "rules", "categoy", "name", "report"]},
{
"annotations": {
"scope": "package",
"description": "This is a test",
"related_resources": [{
"description": "documentation",
"ref": "https://example.com",
}],
},
"path": ["custom", "regal", "rules", "categoy", "name"],
},
]

violation := result.fail(chain, {})

violation == {
"category": "categoy",
"description": "This is a test",
"level": "error",
"related_resources": [{
"description": "documentation",
"ref": "https://example.com",
}],
"title": "name",
}
}

test_related_resources_generated_by_result_fail_for_builtin_rule {
chain := [
{"path": ["regal", "rules", "categoy", "name", "report"]},
{
"annotations": {
"scope": "package",
"description": "This is a test",
},
"path": ["regal", "rules", "categoy", "name"],
},
]

violation := result.fail(chain, {})

violation == {
"category": "categoy",
"description": "This is a test",
"level": "error",
"related_resources": [{
"description": "documentation",
"ref": "https://github.com/StyraInc/regal/blob/main/docs/rules/categoy/name.md",
}],
"title": "name",
}
}
4 changes: 2 additions & 2 deletions internal/test/rego_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ func TestRunRegoUnitTests(t *testing.T) {

compiler := compile.NewCompilerWithRegalBuiltins().
WithSchemas(compile.SchemaSet(schema)).
WithUseTypeCheckAnnotations(true)
WithUseTypeCheckAnnotations(true).
WithEnablePrintStatements(true)

runner := tester.NewRunner().
SetCompiler(compiler).
SetStore(store).
CapturePrintOutput(true).
SetRuntime(ast.NewTerm(ast.NewObject())).
SetBundles(bundle).
// TODO: Not needed?
Expand Down

0 comments on commit 6fdb963

Please sign in to comment.