firebase-tools icon indicating copy to clipboard operation
firebase-tools copied to clipboard

Firestore security rule emulator - get and getAfter throwing an exception on non existant doc

Open olivierkrener opened this issue 5 years ago • 21 comments

[REQUIRED] Environment info

**firebase-tools:**7.16.1

**Platform:**Windows

[REQUIRED] Test case

Just write a rule using a get or getAfter on a non existant doc. For instance: allow update: if get(/databases/$(database)/documents/doc/doesnot/exist) == null;

[REQUIRED] Steps to reproduce

See above

[REQUIRED] Expected behavior

As per the doc get and getAfter should return null. this is what the online simulator does.

[REQUIRED] Actual behavior

An exception is thrown Service call error. Function: [get], Argument: [path_value { ...}

olivierkrener avatar Mar 25 '20 21:03 olivierkrener

@olivierkrener thanks for reporting, @scottcrossen is looking into this.

samtstern avatar Mar 26 '20 12:03 samtstern

@olivierkrener Thanks for reporting it! The fix for this is actually quite simple, but there's a lot of organizational complexity surrounding it which will delay the release of the fix by around 1-2 months.

scottcrossen avatar Mar 26 '20 17:03 scottcrossen

Ok, thanks for the update, I am doing without for the time being

olivierkrener avatar Mar 27 '20 11:03 olivierkrener

Okay! That's great to hear. I'm sorry you're experiencing this. Because the emulator mirrors the production experience, you may also encounter this in production. One workaround is to write a global function like this:

rules_version='2';
// Overload firestore-provided function at global scope.
function get(path) {
  // You'll have to wait for the ternary operator to be released in the emulators
  return exists(path) ? get(path) : null;
}
service cloud.firestore {
  // Your code here.
}

It's not ideal because in production this may count as two data lookups instead of one, but it works. Also keep in mind that rules logic is 'short-circuiting' and that includes error handling. For example, `allow read: if get(/bad/path).boolean_field || true' would return true even though the first branch is an error.

Edit: It probably doesn't count as two rules lookups

scottcrossen avatar Mar 27 '20 18:03 scottcrossen

And that's why I raised an issue for the ternary operator ;)

olivierkrener avatar Mar 28 '20 08:03 olivierkrener

You say that

this will count as two data lookups instead of one

Can you elaborate? I thought that data lookup are counted by document reference. So doing 10x get(pathdoc) only counts as 1 data lookup in the end. I got this confirmed by one of your colleague on stackoverflow https://stackoverflow.com/questions/60676202/firestore-security-rules-how-are-reads-counted-for-exists-get-getafter

olivierkrener avatar Mar 28 '20 10:03 olivierkrener

Apparently this is no working in prod either, as you mention

olivierkrener avatar Mar 28 '20 11:03 olivierkrener

Confirmed, through i could not use ternary operator with the emulator.

bumpmann avatar Mar 28 '20 11:03 bumpmann

Can you elaborate?

Doug would know better than me about the billing and limitations that are customer facing. What he says is generally canon.

scottcrossen avatar Mar 28 '20 18:03 scottcrossen

Update: The first PR was merged on March 26th that will begin to fix this. It will take a few more months for it to be fully fixed because of deploy schedules.

scottcrossen avatar Mar 29 '20 00:03 scottcrossen

@scottcrossen can you close this issue when the fix is rolled out? Also is there an internal bug I could follow?

samtstern avatar Jun 02 '20 14:06 samtstern

@scottcrossen can you close this issue when the fix is rolled out? Also is there an internal bug I could follow?

In what release is this planned to be rolled out?

olivierkrener avatar Jun 03 '20 14:06 olivierkrener

Not sure if I'm supposed to link internal bugs here, but YOLO for posterity: b/152525307

@samtstern

Unfortunately I haven't followed up with the current assignee for a while. I'm sorry about that. I'll start annoying him to work on it. This is pretty egregious and needs to be fixed.

scottcrossen avatar Jun 03 '20 18:06 scottcrossen

clever way to bring down the max allowed get calls if i do say so myself

kaiserschmarrn0 avatar Dec 19 '20 20:12 kaiserschmarrn0

Any progress here?

wmadden avatar Apr 22 '21 11:04 wmadden

An issue with the current workaround with the ternary is that it consumes more expressions compared to a direct get call and Firestore has a 1000 limit on expressions.

SamyPesse avatar Jun 18 '21 21:06 SamyPesse

Is there any update on this issue? Using the workaround in frequent actions will cose double the amount of reads.

t4tapas avatar Aug 28 '21 14:08 t4tapas

How can a bug like this one be open for over two years? :'( BUMP

moekify avatar Mar 31 '22 15:03 moekify

...bump, still broken

Daspy11 avatar Jul 01 '22 10:07 Daspy11

this is still not working. also, the workaround gives me the following on the emulator output: i firestore: Change detected, updating rules... ⚠ firestore.rules:3:10 - ERROR Recursive call is not allowed. ⚠ firestore.rules:5:10 - WARNING Call to service function 'exists' occurs outside of defining scope. ✔ firestore: Rules updated.

I don't understand the error since the document exists as far as I can see.

VGerris avatar Oct 08 '22 19:10 VGerris

Thanks for reporting your experience VGerris, we're aware of this issue (exists in production too) but we have no expected fix timeline.

christhompsongoogle avatar Oct 10 '22 20:10 christhompsongoogle

Bump, this is still an issue. Any chance there's been progress on this?

finallyblueskies avatar Apr 22 '23 08:04 finallyblueskies

Just bumped into this. I'm trying to perform a transactional write, where two documents are created as a result and one of them is validated against another. Is there any other way to achieve this without bumping into this bug?

jellynoone avatar May 04 '23 18:05 jellynoone

Not with rules, you need to write server side logic because apparently Google doesn't care about fixing the bug.

On Thu, May 4, 2023, 20:47 jellynoone @.***> wrote:

Just bumped into this. I'm trying to perform a transactional write, where two documents are created as a result and one of them is validated against another. Is there any other way to achieve this without bumping into this bug?

— Reply to this email directly, view it on GitHub https://github.com/firebase/firebase-tools/issues/2067#issuecomment-1535244382, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAGB3CMT2CULOEJQRQDITLLXEP2SRANCNFSM4LTYGNAQ . You are receiving this because you commented.Message ID: @.***>

VGerris avatar May 04 '23 19:05 VGerris

Still an issue, please fix

Branchverse avatar Aug 12 '23 14:08 Branchverse

Any update on this issue?

LarsFlieger avatar Aug 12 '23 16:08 LarsFlieger

Started experiencing this on a very specific existsAfter call on only 2 of our 10+ dev environments. It throws an exception instead of returning as expected.

Anything we could do to debug this further? E.g. What could be affecting the affected envs, compared to the others?

sdirosa avatar Dec 06 '23 20:12 sdirosa