Return all keys in data

1.3k Views Asked by At

I'm new to OPA/Rego am having a hard time understanding what exactly is the issue here: https://play.openpolicyagent.org/p/h08NbfmF4j

I'd like to have teams associated with the * category, for which I'd expect the accessible[team] rule to return all existing categories. If the team has a specific category assigned, only that one should be returned.

The requirements are really trivial, but I can't figure out why I'm getting the `eval_conflict_error: object keys must be unique" error.

3

There are 3 best solutions below

1
On

Here's a modified version of your policy. The error resulted from the value that would have been generated for team c. In your policy, data.categories[_] expression would have iterated over the values in the categories map and caused a conflict with the result already set for key c in your cats rule. You'll need to return a collection for key c as shown in the modified policy.

0
On

The reason for the error is the second policy:

cats[team] = category {
  data.teams[team]
  data.teams[team].category == "*"
  category := data.categories[_]
}

The error comes from the last line. When you use '[_]' what is happening 'behind curtains' is that your policy is duplicated for each object that you iterate through. For example, in your case (according to your input), your policy is the same as writing the following:

cats[team] = category {
  data.teams[team]
  data.teams[team].category == "*"
  category := data.categories["x"]
}

cats[team] = category {
  data.teams[team]
  data.teams[team].category == "*"
  category := data.categories["y"]
}

cats[team] = category {
  data.teams[team]
  data.teams[team].category == "*"
  category := data.categories["z"]
}

So here is what happens: inside the "teams" object, the only object which matches your condition (category is '*') is the object which has a key of "c". Then, for each one of these rules you build an object where the key is "c" and the value is the current category. Meaning the result is the following:

"cats": {
    "c": {
            "foo": 1
        },
    "c": {
            "foo": 2
        },
    "c": {
            "bar": 3
        }
}

Now this causes an error, since you have the same key ('c') inside the 'cats' object more than once, with different values, and 'object keys must be unique'.

0
On

Although I could not really understand why the initial approach didn't work, I managed to get it working in this play.

From what I understand, the first cats rule can't be proved for c (thus no results), while the second cats rule could be proved for every existing category (and those should only be iterated once). I'd expect Rego to return every possible category value that proves the second rule to be true (i.e. all data.category keys). Finally the sets from the first and second rules would be joined together.

It seems this is exactly how it works, but maybe I got the initial syntax wrong?

If anyone can comment on why exactly the keys collided in the original code, I'd gladly add the details to this answer.