FirebaseExtended / bolt

Bolt Compiler (Firebase Security and Modeling)
Apache License 2.0
897 stars 107 forks source link

No way to have a type that both requires some fields and doesn't contain $other rule with .validate false #212

Open esprehn opened 7 years ago

esprehn commented 7 years ago

We have a bunch of rules of the form:

"_logs": {
  "$logKey": {
    ".validate": "newData.hasChildren(['type', 'timestamp', 'userLoggingId'])",
    "type": {
      ".validate": "newData.isString()"
    },
    "meta": {
      ".validate": "newData.isString() && newData.val().length <= 200"
    },
    "userLoggingId": {
      ".validate": "newData.isString()"
    },
    "timestamp": {
      ".validate": "newData.isNumber()"
    }
  }
}

I can't figure out how to express this. I both to require the type, timestamp and userLoggingId, while at the same time allow extra fields. While this might be considered bad practice this is how the app was written and old clients exist, so I can't change the code that generates the extra fields on the log, instead I need to figure out how to make bolt generate the right thing.

Doing /_logs is Log produces a $other rule with ".validate": "false", doing:

path /_logs {
  /type is String;
  /userLoggingId is String;
  /timestamp is Number;
}

doesn't give me a way to generate the hasChildren() rules.

levithomason commented 6 years ago

I have the same issue. I'm using a 3rd party library that wants to set .priority: ..., but it isn't allowed because Bolt generates $other: { .validate: false }.

I wanted to simply allow any additional fields, but it is not possible. I am also unable to add .priority as a property to my type. Bolt generates an odd array value for .priority keys.

The only solution is to avoid using any types for my path. I instead must write validate() rules for every key I want to be required.


@esprehn You might be able to work around this with a validate rule:

path /_logs {
  validate() {
    this.type != null &&
    this.userLoggingId != null &&
    this.timestamp != null
  }

  /type is String;
  /userLoggingId is String;
  /timestamp is Number;
}