Skip to content

Latest commit

 

History

History
59 lines (49 loc) · 3.43 KB

README.md

File metadata and controls

59 lines (49 loc) · 3.43 KB

OPA Cookbook

General purpose info related to using Open Policy Agent (OPA), and related products such as conftest and Gatekeeper

Code fragments

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

Testing

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 an actual payload created by running the test case. If expected == 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