Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input unset after negative rule evaluation #2142

Closed
gwkunze opened this issue Feb 25, 2020 · 1 comment · Fixed by #2148
Closed

Input unset after negative rule evaluation #2142

gwkunze opened this issue Feb 25, 2020 · 1 comment · Fixed by #2148
Assignees
Labels

Comments

@gwkunze
Copy link

gwkunze commented Feb 25, 2020

Expected Behavior

package test

test_foo {
  is_fruit with input as {
    "type": "apple",
    "real": true
  }
}

default is_fruit = false

is_fruit {
  input.type == "apple"
  not is_faking_apple with input as {"foo": "bar", "real": input.real}
  input.type == "apple"
}

is_faking_apple {
  input.real == false
  input.foo == "bar"
}

opa test . should be valid

Actual Behavior

The test fails, specifically, it seems input is not there anymore after the not is_faking_apple line. If you comment out the second input.type == "apple" statement, the test passes.

Steps to Reproduce the Problem

See above

Additional Info

Rewriting as follows makes it work:

package test

test_foo {
  is_fruit with input as {
    "type": "apple",
    "real": true
  }
}

default is_fruit = false

is_fruit {
  input.type == "apple"
  not_is_faking_apple with input as {"foo": "bar", "real": input.real}
  input.type == "apple"
}

not_is_faking_apple {
  not is_faking_apple
}

is_faking_apple {
  input.real == false
  input.foo == "bar"
}

but either that should not be necessary or possibly the original example should fail parsing.

@patrick-east patrick-east added the investigating Issues being actively investigated label Feb 25, 2020
@patrick-east patrick-east self-assigned this Feb 25, 2020
@patrick-east
Copy link
Contributor

Poking around at it this does appear to be an issue using with on negated expressions. Confirmed that it doesn't have anything specific to do with input either. A pretty minimal repro looks like:

package repro

foo {
  p with data.bar as {"a": 1}
}

p {
  not false with data.bar as {"a": 2}  # broken
  #true with data.bar as {"a": 2}      # works
  data.bar.a == 1
}

And just query for data.repro.foo

Haven't spent a ton of time looking for the fix yet, but at a guess when we are done evaluating the negated expression we aren't restoring the original with values. Quick look at evalWith shows that we should be pretty safetly restoring the with data back in the iterator function or on error...
https://github.com/open-policy-agent/opa/blob/master/topdown/eval.go#L403-L414

But in evalNot we don't use the iterator function (which does the restore) we do e.next(iter):
https://github.com/open-policy-agent/opa/blob/master/topdown/eval.go#L334-L336

I'll check and see if its as simple as just calling iter(e) instead of e.next(iter). Specific to the with case the iterator does the right thing, restoring state and then calling next(), not sure if that holds for all cases though.

@patrick-east patrick-east added bug and removed investigating Issues being actively investigated labels Feb 26, 2020
patrick-east added a commit to patrick-east/opa that referenced this issue Mar 3, 2020
In `evalNot` when it succeeds we were calling `e.next(..)` to continue
evaluation, but if the previous expression was from `evalWith` the
original state was not being restored. This caused the patched data
to persist for subsequent expression evaluation(s) until `iter()` was
used.

Similar treatment was required in `evalNotPartial` for the partial
evaluation case.

Fixes: open-policy-agent#2142
Signed-off-by: Patrick East <east.patrick@gmail.com>
patrick-east added a commit that referenced this issue Mar 4, 2020
In `evalNot` when it succeeds we were calling `e.next(..)` to continue
evaluation, but if the previous expression was from `evalWith` the
original state was not being restored. This caused the patched data
to persist for subsequent expression evaluation(s) until `iter()` was
used.

Similar treatment was required in `evalNotPartial` for the partial
evaluation case.

Fixes: #2142
Signed-off-by: Patrick East <east.patrick@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants