Search code examples
oparego

Determine why a rego test fails


new to Opa/rego. So, I have some rego test code

test_protected_allow {
    test_token := test.create_test_token({
            "audience": "https://whatever.companyname.com",
            "network": "internal",
            "acl": ["WHATEVER_READWRITE_POLICY_RULE"],
    })
    test_request := test.create_test_request({
        "path": "/s3",
        "method": "POST",
        "token": test_token
    })
    allow_protected == true with input as test_request 
}

And it's outputting "allow_protected": false

Is there a way to troubleshoot why this test evaluates to false? Maybe some kind of verbose mode that says "Hey this was rejected because your audience was wrong" or something like that.

Hoping there is a generic answer to this question that will make posting my application code unnecessary (though I can if I'm wrong).


Solution

  • While it can be a bit hard to interpret at times, you can use the --verbose/-v flag to get a trace printed for your failing tests. If you have a policy like this:

    package play
    
    import future.keywords
    
    allow {
         is_admin
    }
    
    is_admin {
         "admin" in input.user.roles
    }
    
    test_allow {
         allow with input as {"user": {"roles": ["developer"]}}
    }
    

    Running the test with the -v flag would provide an output like below:

    ❯ opa test --verbose .
    FAILURES
    --------------------------------------------------------------------------------
    data.play.test_allow: FAIL (288.292µs)
    
      query:1          Enter data.play.test_allow = _
      play.rego:13     | Enter data.play.test_allow
      play.rego:5      | | Enter data.play.allow
      play.rego:9      | | | Enter data.play.is_admin
      play.rego:10     | | | | Fail internal.member_2("admin", __local0__)
      play.rego:6      | | | Fail data.play.is_admin
      play.rego:14     | | Fail data.play.allow with input as {"user": {"roles": ["developer"]}}
      query:1          | Fail data.play.test_allow = _
    
    SUMMARY
    --------------------------------------------------------------------------------
    play.rego:
    data.play.test_allow: FAIL (288.292µs)
    --------------------------------------------------------------------------------
    FAIL: 1/1
    

    The first "fail" here is introduced in:

    play.rego:10     | | | | Fail internal.member_2("admin", __local0__)
    

    Where internal.member2 is the internal function name used for the in check, eventually leading to the rule evaluation failure:

    play.rego:6      | | | Fail data.play.is_admin
    

    While traces aren't super easy to read unless one is familiar with the internals of OPA evaluation, they can often help pointing one in the right direction.

    For more quick-n-dirty debugging, liberal use of the print function is often the fastest way to figure out where things stopped working.

    I wrote a little helper library to help work with test assertions some time back, perhaps you'll find it helpful too.