firebase / firebase/firebase-tools

Closed access rules for Storage not work in emulators

Open
#7,946 6 comments 2 reactions 1 assignee Claimed by @aalej View on GitHub
api: storage emulators: storage reproducible type: bug
Dominant language
TypeScript
Stars
4.5k
Forks
1.3k
Avg merge
1d 12h
Merged PRs (30d)
84

Description

### [REQUIRED] Environment info

**firebase-tools:** 13.25.0

**Platform:** macOS Sequioa 15.1

### [REQUIRED] Test case

`storage.rules` minimal file with [closed access](https://firebase.google.com/docs/rules/insecure-rules#closed_access):

```
rules_version = '2';

service firebase.storage {
match /b/{bucket}/o {
// Firebase Admin SDK only
match /{file=**} {
allow read, write: if false;
}
}
}
```

`firebase.json` with the following `emulators` settings (and other settings required for your project):

```json
{
"emulators": {
"singleProjectMode": true,
"ui": {
"enabled": true,
"port": 3010
},
"auth": {
"port": 3011,
"host": "localhost"
},
"firestore": {
"port": 3012,
"host": "localhost"
},
"database": {
"port": 3013,
"host": "localhost"
},
"storage": {
"port": 3014,
"host": "localhost"
},
"functions": {
"port": 3015,
"host": "localhost"
},
"eventarc": {
"port": 3016,
"host": "localhost"
},
"pubsub": {
"port": 3017,
"host": "localhost"
},
"hosting": {
"port": 3018,
"host": "localhost"
}
}
}
```

### [REQUIRED] Steps to reproduce

1. If necessary, build TypeScript Cloud Functions.
2. Start emulators with `firebase emulators:start`.
3. Upload a file to Storage emulator from Emulators UI.
4. Get this file with `firebase-admin/storage` in a Cloud Function.
5. Error `ApiError: Permission denied. No READ permission`.

### [REQUIRED] Expected behavior

Same behaviours of closed access rules between the Cloud Storage service and the Storage emulator.

### [REQUIRED] Actual behavior

Closed access rules work for Cloud Storage service in a Cloud Function with `firebase-admin/storage`, but not on the Storage emulator.

Logs:

```json
{
"user":{
"severity":"ERROR",
"message":"[getFile] Storage error ApiError: Permission denied. No READ permission.\n at new ApiError (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:114:15)\n at Util.parseHttpRespBody (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:253:38)\n at Util.handleResp (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:193:30)\n at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:583:22\n at onResponse (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/retry-request@7.0.2_encoding@0.1.13/node_modules/retry-request/index.js:259:7)\n at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/teeny-request@9.0.0_encoding@0.1.13/node_modules/teeny-request/build/src/index.js:217:17\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {\n code: 403,\n errors: undefined,\n response: PassThrough {\n _readableState: ReadableState {\n objectMode: false,\n highWaterMark: 16384,\n buffer: BufferList { head: null, tail: null, length: 0 },\n length: 0,\n pipes: [],\n flowing: true,\n ended: true,\n endEmitted: true,\n reading: false,\n constructed: true,\n sync: false,\n needReadable: false,\n emittedReadable: false,\n readableListening: false,\n resumeScheduled: false,\n errorEmitted: false,\n emitClose: true,\n autoDestroy: true,\n destroyed: true,\n errored: null,\n closed: true,\n closeEmitted: true,\n defaultEncoding: 'utf8',\n awaitDrainWriters: null,\n multiAwaitDrain: false,\n readingMore: false,\n dataEmitted: true,\n decoder: null,\n encoding: null,\n [Symbol(kPaused)]: false\n },\n _events: [Object: null prototype] {\n prefinish: [Function: prefinish],\n error: [Array],\n data: [Function (anonymous)],\n end: [Function (anonymous)]\n },\n _eventsCount: 4,\n _maxListeners: undefined,\n _writableState: WritableState {\n objectMode: false,\n highWaterMark: 16384,\n finalCalled: true,\n needDrain: false,\n ending: true,\n ended: true,\n finished: true,\n destroyed: true,\n decodeStrings: true,\n defaultEncoding: 'utf8',\n length: 0,\n writing: false,\n corked: 0,\n sync: false,\n bufferProcessing: false,\n onwrite: [Function: bound onwrite],\n writecb: null,\n writelen: 0,\n afterWriteTickInfo: null,\n buffered: [],\n bufferedIndex: 0,\n allBuffers: true,\n allNoop: true,\n pendingcb: 0,\n constructed: true,\n prefinished: true,\n errorEmitted: false,\n emitClose: true,\n autoDestroy: true,\n errored: null,\n closed: true,\n closeEmitted: true,\n [Symbol(kOnFinished)]: []\n },\n allowHalfOpen: true,\n statusCode: 403,\n statusMessage: 'Forbidden',\n request: {\n agent: [Agent],\n headers: [Object],\n href: 'http://127.0.0.1:3014/v0/b/live-display-staging.appspot.com/o/authorized-emails.json'\n },\n body: { error: [Object] },\n headers: {\n 'access-control-expose-headers': 'content-type,x-firebase-storage-version,X-Goog-Upload-Size-Received,x-goog-upload-url,x-goog-upload-command,x-gupload-uploadid,x-goog-upload-header-content-length,x-goog-upload-header-content-type,x-goog-upload-protocol,x-goog-upload-status,x-goog-upload-chunk-granularity,x-goog-upload-control-url',\n connection: 'keep-alive',\n 'content-length': '73',\n 'content-type': 'application/json; charset=utf-8',\n date: 'Wed, 13 Nov 2024 22:02:00 GMT',\n etag: 'W/\"49-rW1o0iNt7zW3rgr9/wz7M3rApug\"',\n 'keep-alive': 'timeout=5',\n vary: 'Origin',\n 'x-powered-by': 'Express'\n },\n toJSON: [Function: toJSON],\n [Symbol(kCapture)]: false,\n [Symbol(kCallback)]: null\n }\n}"
},
"metadata":{
"emulator":{
"name":"functions"
},
"function":{
"name":"europe-west3-checkEmailAuthorized"
},
"extension":{

},
"message":"\u001b[90m> \u001b[39m {\"severity\":\"ERROR\",\"message\":\"[getFile] Storage error ApiError: Permission denied. No READ permission.\\n at new ApiError (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:114:15)\\n at Util.parseHttpRespBody (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:253:38)\\n at Util.handleResp (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:193:30)\\n at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/@google-cloud+storage@7.14.0_encoding@0.1.13/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js:583:22\\n at onResponse (/Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/retry-request@7.0.2_encoding@0.1.13/node_modules/retry-request/index.js:259:7)\\n at /Volumes/Drive/bgd/Documents/live-display/node_modules/.pnpm/teeny-request@9.0.0_encoding@0.1.13/node_modules/teeny-request/build/src/index.js:217:17\\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {\\n code: 403,\\n errors: undefined,\\n response: PassThrough {\\n _readableState: ReadableState {\\n objectMode: false,\\n highWaterMark: 16384,\\n buffer: BufferList { head: null, tail: null, length: 0 },\\n length: 0,\\n pipes: [],\\n flowing: true,\\n ended: true,\\n endEmitted: true,\\n reading: false,\\n constructed: true,\\n sync: false,\\n needReadable: false,\\n emittedReadable: false,\\n readableListening: false,\\n resumeScheduled: false,\\n errorEmitted: false,\\n emitClose: true,\\n autoDestroy: true,\\n destroyed: true,\\n errored: null,\\n closed: true,\\n closeEmitted: true,\\n defaultEncoding: 'utf8',\\n awaitDrainWriters: null,\\n multiAwaitDrain: false,\\n readingMore: false,\\n dataEmitted: true,\\n decoder: null,\\n encoding: null,\\n [Symbol(kPaused)]: false\\n },\\n _events: [Object: null prototype] {\\n prefinish: [Function: prefinish],\\n error: [Array],\\n data: [Function (anonymous)],\\n end: [Function (anonymous)]\\n },\\n _eventsCount: 4,\\n _maxListeners: undefined,\\n _writableState: WritableState {\\n objectMode: false,\\n highWaterMark: 16384,\\n finalCalled: true,\\n needDrain: false,\\n ending: true,\\n ended: true,\\n finished: true,\\n destroyed: true,\\n decodeStrings: true,\\n defaultEncoding: 'utf8',\\n length: 0,\\n writing: false,\\n corked: 0,\\n sync: false,\\n bufferProcessing: false,\\n onwrite: [Function: bound onwrite],\\n writecb: null,\\n writelen: 0,\\n afterWriteTickInfo: null,\\n buffered: [],\\n bufferedIndex: 0,\\n allBuffers: true,\\n allNoop: true,\\n pendingcb: 0,\\n constructed: true,\\n prefinished: true,\\n errorEmitted: false,\\n emitClose: true,\\n autoDestroy: true,\\n errored: null,\\n closed: true,\\n closeEmitted: true,\\n [Symbol(kOnFinished)]: []\\n },\\n allowHalfOpen: true,\\n statusCode: 403,\\n statusMessage: 'Forbidden',\\n request: {\\n agent: [Agent],\\n headers: [Object],\\n href: 'http://127.0.0.1:3014/v0/b/live-display-staging.appspot.com/o/authorized-emails.json'\\n },\\n body: { error: [Object] },\\n headers: {\\n 'access-control-expose-headers': 'content-type,x-firebase-storage-version,X-Goog-Upload-Size-Received,x-goog-upload-url,x-goog-upload-command,x-gupload-uploadid,x-goog-upload-header-content-length,x-goog-upload-header-content-type,x-goog-upload-protocol,x-goog-upload-status,x-goog-upload-chunk-granularity,x-goog-upload-control-url',\\n connection: 'keep-alive',\\n 'content-length': '73',\\n 'content-type': 'application/json; charset=utf-8',\\n date: 'Wed, 13 Nov 2024 22:02:00 GMT',\\n etag: 'W/\\\"49-rW1o0iNt7zW3rgr9/wz7M3rApug\\\"',\\n 'keep-alive': 'timeout=5',\\n vary: 'Origin',\\n 'x-powered-by': 'Express'\\n },\\n toJSON: [Function: toJSON],\\n [Symbol(kCapture)]: false,\\n [Symbol(kCallback)]: null\\n }\\n}\"}"
}
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.