Skip to content

Commit dfd891a

Browse files
chelsea-lintswastshobsi
authored
feat: warn if default ingress_settings is used in remote_functions (#1419)
* feat: warn if default ingress_settings is used in remote_functions * Apply suggestions from code review Co-authored-by: Tim Sweña (Swast) <[email protected]> * add tests to verify warning * Update bigframes/functions/_function_session.py Co-authored-by: Shobhit Singh <[email protected]> --------- Co-authored-by: Tim Sweña (Swast) <[email protected]> Co-authored-by: Shobhit Singh <[email protected]>
1 parent 14a7787 commit dfd891a

File tree

4 files changed

+58
-21
lines changed

4 files changed

+58
-21
lines changed

bigframes/functions/_function_session.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ def remote_function(
121121
cloud_function_max_instances: Optional[int] = None,
122122
cloud_function_vpc_connector: Optional[str] = None,
123123
cloud_function_memory_mib: Optional[int] = 1024,
124-
cloud_function_ingress_settings: Literal[
125-
"all", "internal-only", "internal-and-gclb"
126-
] = "all",
124+
cloud_function_ingress_settings: Optional[
125+
Literal["all", "internal-only", "internal-and-gclb"]
126+
] = None,
127127
):
128128
"""Decorator to turn a user defined function into a BigQuery remote function.
129129
@@ -311,8 +311,9 @@ def remote_function(
311311
https://cloud.google.com/functions/docs/configuring/memory.
312312
cloud_function_ingress_settings (str, Optional):
313313
Ingress settings controls dictating what traffic can reach the
314-
function. By default `all` will be used. It must be one of:
315-
`all`, `internal-only`, `internal-and-gclb`. See for more details
314+
function. Options are: `all`, `internal-only`, or `internal-and-gclb`.
315+
If no setting is provided, `all` will be used by default and a warning
316+
will be issued. See for more details
316317
https://cloud.google.com/functions/docs/networking/network-settings#ingress_settings.
317318
"""
318319
# Some defaults may be used from the session if not provided otherwise
@@ -429,6 +430,16 @@ def remote_function(
429430
" For more details see https://cloud.google.com/functions/docs/securing/cmek#before_you_begin"
430431
)
431432

433+
if cloud_function_ingress_settings is None:
434+
cloud_function_ingress_settings = "all"
435+
msg = (
436+
"The `cloud_function_ingress_settings` are set to 'all' by default, "
437+
"which will change to 'internal-only' for enhanced security in future version 2.0 onwards. "
438+
"However, you will be able to explicitly pass cloud_function_ingress_settings='all' if you need. "
439+
"See https://cloud.google.com/functions/docs/networking/network-settings#ingress_settings for details."
440+
)
441+
warnings.warn(msg, category=FutureWarning, stacklevel=2)
442+
432443
bq_connection_manager = session.bqconnectionmanager
433444

434445
def wrapper(func):

bigframes/pandas/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ def remote_function(
8080
cloud_function_max_instances: Optional[int] = None,
8181
cloud_function_vpc_connector: Optional[str] = None,
8282
cloud_function_memory_mib: Optional[int] = 1024,
83-
cloud_function_ingress_settings: Literal[
84-
"all", "internal-only", "internal-and-gclb"
85-
] = "all",
83+
cloud_function_ingress_settings: Optional[
84+
Literal["all", "internal-only", "internal-and-gclb"]
85+
] = None,
8686
):
8787
return global_session.with_default_session(
8888
bigframes.session.Session.remote_function,

bigframes/session/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,9 +1199,9 @@ def remote_function(
11991199
cloud_function_max_instances: Optional[int] = None,
12001200
cloud_function_vpc_connector: Optional[str] = None,
12011201
cloud_function_memory_mib: Optional[int] = 1024,
1202-
cloud_function_ingress_settings: Literal[
1203-
"all", "internal-only", "internal-and-gclb"
1204-
] = "all",
1202+
cloud_function_ingress_settings: Optional[
1203+
Literal["all", "internal-only", "internal-and-gclb"]
1204+
] = None,
12051205
):
12061206
"""Decorator to turn a user defined function into a BigQuery remote function. Check out
12071207
the code samples at: https://cloud.google.com/bigquery/docs/remote-functions#bigquery-dataframes.
@@ -1373,8 +1373,9 @@ def remote_function(
13731373
https://cloud.google.com/functions/docs/configuring/memory.
13741374
cloud_function_ingress_settings (str, Optional):
13751375
Ingress settings controls dictating what traffic can reach the
1376-
function. By default `all` will be used. It must be one of:
1377-
`all`, `internal-only`, `internal-and-gclb`. See for more details
1376+
function. Options are: `all`, `internal-only`, or `internal-and-gclb`.
1377+
If no setting is provided, `all` will be used by default and a warning
1378+
will be issued. See for more details
13781379
https://cloud.google.com/functions/docs/networking/network-settings#ingress_settings.
13791380
Returns:
13801381
collections.abc.Callable:

tests/system/large/functions/test_remote_function.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import sys
2222
import tempfile
2323
import textwrap
24+
import warnings
2425

2526
import google.api_core.exceptions
2627
from google.cloud import bigquery, functions_v2, storage
@@ -2363,40 +2364,64 @@ def generate_stats(row: pandas.Series) -> list[int]:
23632364

23642365

23652366
@pytest.mark.parametrize(
2366-
("ingress_settings_args", "effective_ingress_settings"),
2367+
("ingress_settings_args", "effective_ingress_settings", "expected_warning"),
23672368
[
23682369
pytest.param(
2369-
{}, functions_v2.ServiceConfig.IngressSettings.ALLOW_ALL, id="no-set"
2370+
{},
2371+
functions_v2.ServiceConfig.IngressSettings.ALLOW_ALL,
2372+
FutureWarning,
2373+
id="no-set",
2374+
),
2375+
pytest.param(
2376+
{"cloud_function_ingress_settings": None},
2377+
functions_v2.ServiceConfig.IngressSettings.ALLOW_ALL,
2378+
FutureWarning,
2379+
id="set-none",
23702380
),
23712381
pytest.param(
23722382
{"cloud_function_ingress_settings": "all"},
23732383
functions_v2.ServiceConfig.IngressSettings.ALLOW_ALL,
2384+
None,
23742385
id="set-all",
23752386
),
23762387
pytest.param(
23772388
{"cloud_function_ingress_settings": "internal-only"},
23782389
functions_v2.ServiceConfig.IngressSettings.ALLOW_INTERNAL_ONLY,
2390+
None,
23792391
id="set-internal-only",
23802392
),
23812393
pytest.param(
23822394
{"cloud_function_ingress_settings": "internal-and-gclb"},
23832395
functions_v2.ServiceConfig.IngressSettings.ALLOW_INTERNAL_AND_GCLB,
2396+
None,
23842397
id="set-internal-and-gclb",
23852398
),
23862399
],
23872400
)
23882401
@pytest.mark.flaky(retries=2, delay=120)
23892402
def test_remote_function_ingress_settings(
2390-
session, scalars_dfs, ingress_settings_args, effective_ingress_settings
2403+
session,
2404+
scalars_dfs,
2405+
ingress_settings_args,
2406+
effective_ingress_settings,
2407+
expected_warning,
23912408
):
23922409
try:
2410+
# Verify the function raises the expected security warning message.
2411+
with warnings.catch_warnings(record=True) as w:
23932412

2394-
def square(x: int) -> int:
2395-
return x * x
2413+
def square(x: int) -> int:
2414+
return x * x
23962415

2397-
square_remote = session.remote_function(reuse=False, **ingress_settings_args)(
2398-
square
2399-
)
2416+
square_remote = session.remote_function(
2417+
reuse=False, **ingress_settings_args
2418+
)(square)
2419+
2420+
if expected_warning is not None:
2421+
assert issubclass(w[0].category, FutureWarning)
2422+
assert "Consider using 'internal-only' for enhanced security." in str(
2423+
w[0].message
2424+
)
24002425

24012426
# Assert that the GCF is created with the intended maximum timeout
24022427
gcf = session.cloudfunctionsclient.get_function(

0 commit comments

Comments
 (0)