firebase-tools: resource.data is missing data when evaluating firestore rules in emulator

[REQUIRED] Environment info

firebase-tools: 10.6.0

Platform: macOS

[REQUIRED] Test case

The following function in security rule function will return true even when the document in question definitely contains the userId field

function doesntExistOrMissingUserId(){
      return resource == null || !resource.data.keys().hasAll(['userId']);
}

[REQUIRED] Steps to reproduce

Add the above function to a read rule. Issue a query from a client for a doc that contains a userId field. The rule will pass when it should be rejected.

[REQUIRED] Expected behavior

The rule should be rejected

[REQUIRED] Actual behavior

The rule evaluates to true

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 3
  • Comments: 15 (7 by maintainers)

Most upvoted comments

Actual data in collection:

{
        inviterId: TEAM_OWNER_ID,
        teamId: TEAM_A_ID,
        inviteeId: USER_NOT_IN_MY_TEAM_ID,
 }

Test case:

    it('Inviter can read their invitations to a team', async () => {
      const db = getFirestore( { uid: 'TEAM_OWNER_ID' });
      const testDoc = db.collection('TEAM_INVITATIONS_COLLECTION').where('inviterId', '==', 'TEAM_OWNER_ID');
      await firebase.assertSucceeds(await testDoc.get());
    });

Rules:

match /team_invitations/{invitationId} {
  allow read: if debug(resource.data.inviteeId) == request.auth.uid;
}

Error: Property inviteeId is undefined on object. for ‘list’ @ L40

Output of debug is correct. It prints ‘USER_NOT_IN_MY_TEAM_ID’.

So it fails every time when we check other field than mentioned in query. The correct behavior would be that resource.data has all fields that are visible in “Data” tab in emulator UI.

I suspect that other issue is the same thing basically.

The workaround mentioned there is:

if your security rule checks for admin == uid you need to include .where(“admin”, “==”, uid) even though all your documents may have admin == uid

Or more generally, include everything your rule checks for in a where clause.

Yes this is my experience too. It means you might need ‘dummy’ clauses, but this is good enough workaround to unblock me I think. I will post back if I find a situation where this doesn’t work.

All this kind of makes me think: unless it is a super simple security rule, then use a function as the gatekeeper rather than rules.