Skip to content

Commit ea3fce5

Browse files
committed
fix: get default bucket from FIREBASE_CONFIG env if available
1 parent d65f464 commit ea3fce5

File tree

4 files changed

+99
-4
lines changed

4 files changed

+99
-4
lines changed

src/firebase_functions/options.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,18 @@ def _endpoint(
331331
**kwargs,
332332
) -> _manifest.ManifestEndpoint:
333333
assert kwargs["event_type"] is not None
334-
# TODO get bucket from admin sdk if no bucket set
334+
bucket = self.bucket
335+
if bucket is None:
336+
firebase_config = _util.firebase_config()
337+
if firebase_config is not None:
338+
bucket = firebase_config.storage_bucket
339+
if bucket is None:
340+
raise ValueError(
341+
"Missing bucket name. If you are unit testing, please specify a bucket name"
342+
" by providing a bucket name directly to the event handler or by setting the"
343+
" FIREBASE_CONFIG environment variable.")
335344
event_filters: _typing.Any = {
336-
"bucket": self.bucket,
345+
"bucket": bucket,
337346
}
338347
event_trigger = _manifest.EventTrigger(
339348
eventType=kwargs["event_type"],

src/firebase_functions/private/util.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
15-
1614
"""
1715
Module for internal utilities.
1816
"""
1917

18+
import os as _os
19+
import json as _json
2020
import typing as _typing
2121
import dataclasses as _dataclasses
2222
import enum as _enum
@@ -243,3 +243,44 @@ def on_call_check_tokens(request: _Request,) -> _OnCallTokenVerification:
243243
log_payload)
244244

245245
return verifications
246+
247+
248+
@_dataclasses.dataclass(frozen=True)
249+
class FirebaseConfig():
250+
"""
251+
A collection of configuration options needed to
252+
initialize a firebase App.
253+
"""
254+
255+
storage_bucket: _typing.Optional[str]
256+
"""
257+
The name of the Google Cloud Storage bucket used for storing application data.
258+
This is the bucket name without any prefixes or additions (without "gs://").
259+
"""
260+
261+
# TODO more to be added later when they are required
262+
263+
264+
def firebase_config() -> None | FirebaseConfig:
265+
config_file = _os.getenv("FIREBASE_CONFIG")
266+
if not config_file:
267+
return None
268+
if config_file.startswith('{'):
269+
json_str = config_file
270+
else:
271+
# Firebase Tools will always use a JSON blob in prod, but docs
272+
# explicitly state that the user can set the env to a file:
273+
# https://firebase.google.com/docs/admin/setup#initialize-without-parameters
274+
try:
275+
with open(config_file, 'r') as json_file:
276+
json_str = json_file.read()
277+
except Exception as err:
278+
raise ValueError('Unable to read file {}. {}'.format(
279+
config_file, err))
280+
try:
281+
json_data: dict = _json.loads(json_str)
282+
except Exception as err:
283+
raise ValueError(
284+
'FIREBASE_CONFIG JSON string "{0}" is not valid json. {1}'.format(
285+
json_str, err))
286+
return FirebaseConfig(storage_bucket=json_data.get('storageBucket'))

tests/firebase_config_test.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"storageBucket": "python-functions-testing.appspot.com"
3+
}

tests/test_util.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2022 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""
15+
Internal utils tests.
16+
"""
17+
from os import environ, path
18+
from firebase_functions.private.util import firebase_config
19+
20+
test_bucket = "python-functions-testing.appspot.com"
21+
test_config_file = path.join(path.dirname(path.realpath(__file__)),
22+
"firebase_config_test.json")
23+
24+
25+
def test_firebase_config_loads_from_env_json():
26+
"""
27+
Testing firebase_config can be read from the
28+
FIREBASE_CONFIG env var as a JSON string.
29+
"""
30+
environ["FIREBASE_CONFIG"] = '{"storageBucket": "%s"}' % test_bucket
31+
assert firebase_config().storage_bucket == test_bucket, (
32+
"Failure, firebase_config did not load from env variable.")
33+
34+
35+
def test_firebase_config_loads_from_env_file():
36+
"""
37+
Testing firebase_config can be read from the
38+
FIREBASE_CONFIG env var as a file path.
39+
"""
40+
environ["FIREBASE_CONFIG"] = test_config_file
41+
assert firebase_config().storage_bucket == test_bucket, (
42+
"Failure, firebase_config did not load from env variable.")

0 commit comments

Comments
 (0)