fireward icon indicating copy to clipboard operation
fireward copied to clipboard

Compile errors

Open jmagaram opened this issue 2 years ago • 12 comments

Here is a very basic rules file. I ran your tool and it generates the rules file. When I deploy it, I see these errors. I'm not too worried about the unused variable warning, though it would be nice if that went away. But the invalid type warnings are concerning. I'm using firebase tools version 9.19.0

!  [W] 4:31 - Unused variable: prev.
!  [W] 23:35 - Unused variable: prev.
!  [W] 32:53 - Invalid type. Received one of [null]. Expected one of [list, map].
!  [W] 35:89 - Invalid type. Received one of [null]. Expected one of [list, map].
type Name = { first: string, last?: string }
type User = { name: Name | string }
type IceCream = { flavor: string, isFavorite: bool }

match /users/{id} is User {
  allow read: true;
  allow create, update: request.auth!=null; 
  allow delete: false;
}

match /icecream/{id} is IceCream {
  allow read: if request.time < timestamp.date(2021, 12, 1);
  allow write: if request.time < timestamp.date(2021, 12, 1);
}

There are no errors on the IceCream path. The errors have to do with User.

jmagaram avatar Oct 07 '21 19:10 jmagaram

I don't understand the underlying rules language. But I was able to get it to upload without errors as follows...

I changed resource==null ? null : resource.data to simply resource.data. Second I changed prev!=null ? prev : null to just prev. I don't know if this changed the behavior/intent of the rules but it made the compiler happy.

Are you still maintaining this repo?

jmagaram avatar Oct 07 '21 20:10 jmagaram

Thank you for reporting. I've experienced the same warnings, but they have not caused any problems in production. Nonetheless I should post this minimal case as an issue to the firebase repo.

bijoutrouvaille avatar Oct 07 '21 22:10 bijoutrouvaille

you mean this is a problem on their end? the docs say "resource" is non-null so resource==null ? null : resource.data might be incorrect. https://firebase.google.com/docs/reference/rules/rules.firestore#.resource

jmagaram avatar Oct 07 '21 23:10 jmagaram

doesn't work for me. can't read or delete any items in the icecream collection...

type Name = { first: string, last?: string }
type User = { name: Name }
type IceCream = { flavor: string, isFavorite: bool }

match /icecream/{id} is IceCream {
  allow read, write, delete: if request.time < timestamp.date(2021, 12, 1);
}

match /users/{id} is User {
  allow read: true;
  allow create, update: request.auth!=null; 
  allow delete: false;
}

This is the rules that were built...

match /icecream/{id} {
  function is______PathType(data, prev) {
    return is____IceCream(data, prev!=null ? prev : null);
  }
  allow read, write, delete: if is______PathType(request.resource.data, resource==null ? null : resource.data) && (request.time < timestamp.date(2021, 12, 1));
}

If I delete the whole is______PathType(request.resource. condition then I can delete items. (edited - posted wrong rules file before)

jmagaram avatar Oct 07 '21 23:10 jmagaram

Most likely you can't delete items because you have read, write and delete directives on the same line. That's an anti-pattern and will in most cases generate errors.

bijoutrouvaille avatar Oct 08 '21 02:10 bijoutrouvaille

you mean this is a problem on their end? the docs say "resource" is non-null so resource==null ? null : resource.data might be incorrect. https://firebase.google.com/docs/reference/rules/rules.firestore#.resource

The syntax shouldn't cause any errors. In any case, these warnings don't give any useful information.

bijoutrouvaille avatar Oct 08 '21 02:10 bijoutrouvaille

I hope you'll take a closer look at this. I changed the rules so just read and write are on the line. Without trying to delete anything, I see an error in the browser dev tools when trying to read from the ice cream table, which has a few documents in it. The error is Uncaught Error in snapshot listener: FirebaseError: Missing or insufficient permissions. Then I simply take out the is______PathType(request.resource.data... clause using the Firestore console and my app works. So something in that clause is probably not working. Here are the details.

The original rules...

type Name = { first: string, last?: string }
type User = { name: Name }
type IceCream = { flavor: string, isFavorite: bool }

match /icecream/{id} is IceCream {
  allow read, write: if request.time < timestamp.date(2021, 12, 1);
}

match /users/{id} is User {
  allow read: true;
  allow create, update: request.auth!=null; 
  allow delete: false;
}

The generated rules...

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    function is____Name(data, prev) {
      return data.keys().hasAll(['first'])
      && data.size() >= 1 && data.size() <= 2
      && data.keys().hasOnly(['first', 'last'])
      && data['first'] is string
      && (
        !data.keys().hasAny(['last'])
        || data['last'] is string
      );
    }
    function is____User(data, prev) {
      return data.keys().hasAll(['name'])
      && data.size() >= 1 && data.size() <= 1
      && data.keys().hasOnly(['name'])
      && is____Name(data['name'], prev!=null && 'name' in prev ? prev['name'] : null);
    }
    function is____IceCream(data, prev) {
      return data.keys().hasAll(['flavor', 'isFavorite'])
      && data.size() >= 2 && data.size() <= 2
      && data.keys().hasOnly(['flavor', 'isFavorite'])
      && data['flavor'] is string
      && data['isFavorite'] is bool;
    }
    match /icecream/{id} {
      function is______PathType(data, prev) {
        return is____IceCream(data, prev!=null ? prev : null);
      }
      allow read, write: if is______PathType(request.resource.data, resource==null ? null : resource.data) && (request.time < timestamp.date(2021, 12, 1));
    }
    match /users/{id} {
      function is______PathType(data, prev) {
        return is____User(data, prev!=null ? prev : null);
      }
      allow read: if true;
      allow create, update: if is______PathType(request.resource.data, resource==null ? null : resource.data) && (request.auth != null);
      allow delete: if false;
    }
  }
}

In the console I changed the ice cream section to this, and it works...

    match /icecream/{id} {
      function is______PathType(data, prev) {
        return is____IceCream(data, prev!=null ? prev : null);
      }
      allow read, write: if (request.time < timestamp.date(2021, 12, 1));
    }

jmagaram avatar Oct 08 '21 04:10 jmagaram

I am investigating further. Writing seems to work. Maybe my error on the reading?

jmagaram avatar Oct 08 '21 04:10 jmagaram

Ok making progress...these rules seem to work. Separating just read and write wasn't good enough. I didn't realize you need to separate create, update, and delete. Hmmm...is this my error? I thought you could combine rules, and definitely use write without breaking it up into separate categories.

match /icecream/{id} is IceCream {
  allow read: if request.time < timestamp.date(2021, 12, 1);
  allow create: if request.time < timestamp.date(2021, 12, 1);
  allow update: if request.time < timestamp.date(2021, 12, 1);
  allow delete: if request.time < timestamp.date(2021, 12, 1);
}

jmagaram avatar Oct 08 '21 04:10 jmagaram

You technically can. However, Fireward does not do any extra magic to rewrite your conditions depending on their kind. So if you have them all combined, the type check (isPathType) will be performed on reads and deletes, which will fail.

Usually creates and updates can be combined without problems, because what matters here is the incoming data, but you should do so consciously, knowing that it is a source of possible errors.

In the future Fireward may add some checks, this being a common issue, but we have to be careful, because we are very limited on the size of the rules file as well as the number of operations per execution, so we have to watch our bloat.

bijoutrouvaille avatar Oct 08 '21 05:10 bijoutrouvaille

Ok you can close this. Maybe Fireward should give a warning if delete and reads are combined, or do something different. It sure looks like my original rule - you can do anything prior to December - should work.

jmagaram avatar Oct 08 '21 05:10 jmagaram

I seem to recall to have added the warning to the beta version, now that you mention it. I'm planning to release it as 2.0 asap.

bijoutrouvaille avatar Oct 08 '21 05:10 bijoutrouvaille