General purpose info related to using Open Policy Agent (OPA), and related products such as conftest and Gatekeeper
Category | Description | Sample use case | Sample code |
---|---|---|---|
Code Fragment | You have a value for a key, and you need to check whether that value is acceptable by matching it against a set of acceptable keys | You have a label for a cloud service (e.g. owner ) and you need to ensure that the value of the owner label is one of a pre-defined set of values |
https://play.openpolicyagent.org/p/4MD3veVSyL |
Code Fragment | You need to confirm that all values in a set or array meet some specific criteria | Data sovereignty - You have a cloud service that can be deployed in multiple locations, and you need to ensure that every deployment is in a pre-defined set of locations | https://play.openpolicyagent.org/p/IHvEfAYVjE |
As of 22/12/22, there is no generally accepted testing framework available for OPA. This approach to writing tests seems to work fairly well:
test_a_thing {
# Note that the value of 'expected' is surrounded by *two* sets of {}. That's to convert the JSON object into a set, which is what our denys return
# Two options in defining 'expected':
# - expected := set() if you expect the payload to pass (i.e. not produce any denys)
# - expected := {{deny payload}} if you expect the payload to fail (i.e. produce 1 or more denys)
expected := {{
"msg": "Cloud Interconnect does not enforce IPSEC encryption",
"details": concat(" ", [policy, bpdata.gcp_controls[policy]]),
}}
# Print the expected value. This is handy for debugging
trace(sprintf("expect: %v", [expected]))
# Execute the test case with a suitable test payload, and capture the output as `actual`
actual := deny with input.asset as {
"asset_type": "compute.googleapis.com/InterconnectAttachment",
"resource": {"data": {"encryption": 0}},
}
# Print the actual value, and whether actual matches expected
trace(sprintf("actual: %v", [actual]))
trace(sprintf("match?: %v", [expected == actual]))
# Uncomment this line if you want to force the test case to fail for any reason - this can be very useful for debugging, as it will cause all of the `trace(sprintf(...)` lines to execute and print data
#false
# Pass the test case only if the expected payload = the actual payload
expected == actual
}
Key points:
- the approach taken is common to automated testing in general: first we define an
expected
payload, then check it against anactual
payload created by running the test case. Ifexpected == actual
then the test case passes; otherwise it fails trace(sprintf...))
commands are sprinkled through the test case, and will be triggered if the test case failes. Feel free to add other traces, and also to uncomment the#false
line which will automatically cause the test case to fail and trigger any trace commands