question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Bug due to Parentheses Simplification

See original GitHub issue

I have a very simple rule like this:

path /profile/{key1} {
  create() {
    isUser(key1);
  }

  update() {
    isUser(key1);
  }
}

Using these functions:

function isAuth() {
  (auth != null);
}

function isUser(user) {
  isAuth() && (user == auth.uid);
}

I’d expect the .write output of this to be something along the lines of:

(data.val() == null && (auth != null && $key1 == auth.uid))
||
(data.val() != null && newData.val() != null && (auth != null && $key1 == auth.uid))

Instead, what I get is (note the missing parentheses):

data.val() == null && (auth != null && $key1 == auth.uid)
||
data.val() != null && newData.val() != null && (auth != null && $key1 == auth.uid)

Which is not logically the same - not sure how to fix it since create and update are handled by Bolt itself.


Similarly, if I have a compound rule like this:

path /users/{key1} {
  read() {
    isUser(key1) || isAdmin();
  }
}

Relying on these functions:

function isAuth() {
  (auth != null);
}

function isUser(user) {
  isAuth() && (user == auth.uid);
}

function isAdmin() {
  isAuth() && (root.child('admins').child(auth.uid).val() != null);
}

The output I get on .read is the following:

auth != null && $key1 == auth.uid
||
auth != null && root.child('admins').child(auth.uid).val() != null

When I would expect it to be:

(auth != null && $key1 == auth.uid)
||
(auth != null && root.child('admins').child(auth.uid).val() != null)

Adding a redundant boolean check to the function calls:

path /users/{key1} {
  read() {
    (isUser(key1) == true) || (isAdmin() == true);
  }
}

Produces a logically valid output of:

(auth != null && $key1 == auth.uid) == true
||
(auth != null && root.child('access-control').child('admins').child(auth.uid).val() != null) == true

However, it’s kind of an obscure behavior.


Are these bugs known in Bolt? And if so, is there any way around them without patching the core?

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
spencerwilsoncommented, Jul 1, 2021

Oof, thank you! I had failed to find that last docs page you linked to.

Now that I’m looking at the relevant docs I understand the following to be the case:

  • Bolt doesn’t specify its operator precedence. (ref) Indeed, its language reference doesn’t even name && or || among its supported operators (though they appear in examples).
  • Realtime Database also doesn’t specify its operator precedence. (ref)
  • Strictly speaking, the above imply that operator precedence in both languages is undefined. In turn, there’s no sound way to decide in general whether a pair of parentheses is redundant or not.
  • => The only reliable way to write Bolt or Realtime Database rules is with parentheses around every sub-expression.

Either way, Bolt shouldn’t be eating parentheses as that dictates precedence over operator / logical precedence.

I had previously thought that maybe what you call eating parentheses may have been Bolt intelligently omitting parentheses that it knew would be redundant in Realtime Database’s security rule language. But now I know that can’t be the case.

I’m now fully on board with the changes you made in https://github.com/FirebaseExtended/bolt/pull/233. Not that my opinion matters 😆 Thank you for taking some time to explain!

0reactions
rockwotjcommented, Jul 2, 2021

For what it’s worth the RTDB is using JavaScript for it’s security rules language, and the AST parser respects the operator precedence rules according to: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence

Read more comments on GitHub >

github_iconTop Results From Across the Web

Simplifying Nested Parentheses - Purplemath
Getting bogged down in nested parentheses? This lesson demystifies the process, and demonstrates how to succeed!
Read more >
Problems With Parentheses | Reflections and Tangents
Sometimes parentheses are overused and other times they are missing, ... notice the error on the first try due to missing parentheses, ...
Read more >
How to Simplify Algebraic Expressions - Sciencing
Simplifying an expression is the first step to solving algebra problems. ... is always the same and starts with any parentheses in the...
Read more >
2.2: Simplifying Algebraic Expressions - Mathematics LibreTexts
Certainly, if the contents of the parentheses can be simplified, do that first. ... Subtracting 5−2 first leads to an incorrect result, ...
Read more >
Simplifying Boolean algebra expression with two brackets
Your Answer. Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question. Provide details and share your research ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found