Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

database.rules.json is not applied to the default RTDB instance in the emulator. #3124

Closed
aameen951 opened this issue Feb 10, 2021 · 8 comments · Fixed by #3146
Closed

database.rules.json is not applied to the default RTDB instance in the emulator. #3124

aameen951 opened this issue Feb 10, 2021 · 8 comments · Fixed by #3146
Assignees

Comments

@aameen951
Copy link

Hi there,

This #2979 pull request fixed one part of the problem mentioned in #2965 where the default instance in hosting is different from the default instance in firebase-admin and both of them now reference the same instance which is project-id-default-rtdb.

However, the rules in database.rule.json are still being applied to project-id instead of project-id-default-rtdb, and I don't know how to change that manually.

[REQUIRED] Environment info

firebase-tools: 9.3.0
Platform: Windows

[REQUIRED] Test case

functions/index.js

const admin = require("firebase-admin");

// After #2979, The following line will uses `http://localhost:9000?ns=project-id-default-rtdb`
admin.initializeApp();

admin.database().ref('test').set(1);

database.rules.json

{
  "rules": {
    "test":{
      ".read": true
    },
    ".read": false,
    ".write": false
  }
}

[REQUIRED] Steps to reproduce

  1. Run the command: curl localhost:9000/.settings/rules.json?ns=project-id-default-rtdb -H "Authorization: Bearer owner"
  2. The output is:
{
    "rules": {
        ".read": true,
        ".write": true
    }
}
  1. Run the command: curl localhost:9000/.settings/rules.json?ns=project-id -H "Authorization: Bearer owner"
  2. The output is:
{
  "rules": {
    "test":{
      ".read": true
    },
    ".read": false,
    ".write": false
  }
}

[REQUIRED] Expected behavior

Since project-id-default-rtdb is now the default instance, the database.rules.json should also be applied to project-id-default-rtdb instance instead of project-id instance.

[REQUIRED] Actual behavior

Now, database.rules.json is applied to project-id.

@StevenHallLtd
Copy link

This has been driving me crazy. Do you know of a workaround @aameen951? I tried using the instance flag on the CLI, and also setting a target in firebase.json, but to no avail. I'm not sure I'm setting it right as the docs aren't that explicit.

@samtstern samtstern self-assigned this Feb 18, 2021
@samtstern
Copy link
Contributor

Thanks @StevenHallLtd and @aameen951 for reporting, let me take a look at this.

@aameen951
Copy link
Author

aameen951 commented Feb 18, 2021

@StevenHallLtd At first, I didn't know it was happening. But when I start to use queries with filters it became an annoying problem.
I worked around it by programmatically setting the rules on the database from firebase functions.
In your functions/src/index.js do the following:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

import { promises as fs } from 'fs';
import * as path from 'path';

// This is the database instance
const db = admin.database();

// check if the firebase function is running inside the emulator.
const IS_INSIDE_EMULATOR = process.env.FUNCTIONS_EMULATOR === 'true';

if(IS_INSIDE_EMULATOR)
{
  // read the rules file.
  fs.readFile(path.join(__dirname, "../../../database.rules.json"), 'utf8').then((source) => {
    // manually set the rules on the database.
    db.setRules(source);
  });
}

The one downside to this workaround so far is that if you change the rules file it won't update automatically, you have to go to any file that belongs to functions and save it to make functions reload and cause the above code to run again.

@samtstern
Copy link
Contributor

Fixed in #3146 and will be included in the next release.

This was referenced Mar 9, 2021
This was referenced Mar 12, 2021
@phcoliveira
Copy link

I do not think this issue was fixed. I am using:

"firebase-tools": "13.14.0",
"firebase-admin": "12.1.0",
"firebase-functions": "5.0.1"

And I always end up having at least two databases.
Here is my file .firebaserc

{
  "projects": {
    "default": "noice-app-eu-staging",
    "dev": "demo-dev"
  }
}

And this is the command I used:

pnpm exec firebase emulators:start --only=database --project=dev --debug

@amks1
Copy link

amks1 commented Aug 12, 2024

@phcoliveira Did you get a solution? I noticed that my database.rules.json doesn't get applied to the emulated database.
I get

Index not defined, add ".indexOn"

when the index is clearly defined in my rules. It works perfectly on production Firebase realtime database.

@phcoliveira
Copy link

Hello @amks1. Yeah, I got a reasonable solution. I have two firebase configuration files. The default firebase.json for deploying to production, and firebase.local.json for local development. I could have only if I had understood the targets well enough. But I hadn't.
So here is my firebase.local.json file:

{
	"functions": [
	  {
		// ...
	  }
	],
	"emulators": {
	  "auth": {
		"port": 9099
	  },
	  "database": {
		"port": 9000
	  },
	  "hosting": {
		"port": 5174
	  },
	  "functions": {
		"port": 5001
	  },
	  "ui": {
		"enabled": true,
		"port": 4200
	  },
	  "singleProjectMode": true
	},
	"database": [
		{
			"instance": "demo-local",
			"rules": "apps/database/main/rules.json"
		}
	],
	"hosting": {
	  // ...
	}
  }

The key feature here is having the "database" entry as an array. You can have as many instances as you want. For example: demo-dev and demo-test.

Then, when you start the emulators, you can specify this other configuration file:

pnpm exec firebase:emulators start --config='firebase.local.json'

In my case, I end up having only one database, which is what I wanted.
Then, both my client app and Firebase functions use the same database URL:

// client
PUBLIC_FIREBASE_DATABASE_URL="http://localhost:9000/?ns=demo-local"
// function
FIREBASE_DATABASE_URL="http://localhost:9000/?ns=demo-local"

@amks1
Copy link

amks1 commented Aug 12, 2024

Thank you so much @phcoliveira, I finally got it working.
I only have a local firebase (I'm using the web interface to administrate my production) so I just changed the firebase.json to this:

{
  "emulators": {
    "firestore": {
      "port": 8080
    },
    "database": {
      "port": 9000
    },
    "storage": {
      "port": 9199
    },
    "ui": {
      "enabled": true
    },
    "singleProjectMode": true
  },
  "storage": {
    "rules": "storage.rules"
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "database": [{
    "instance": "my-development",
    "rules": "database.rules.json"
  }]
}

Then I just ran firebase emulators:start normally, and the rules were applied. What I was missing earlier was the instance field in the database entry. If this is omitted, it creates a second database for some reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants