Skip to content

Commit e726878

Browse files
authored
fix(bigframes): world-readable temp zip in create_cloud_function (#17522)
Repro against the unpatched `create_cloud_function` archive step: archive_path : /tmp/tmpXXXX.zip # sibling of the 0700 TemporaryDirectory dir removed : True zip remains : True # survives TemporaryDirectory cleanup zip perms : 0o644 world-readable: True `shutil.make_archive(directory, "zip", directory)` appends `.zip` to `base_name`, so the archive lands at `<tempdir>.zip`, a sibling of the temp dir rather than inside it. That copy of the generated cloud function source (which embeds the cloudpickled UDF) is created mode 0644 in the shared system temp directory and is not removed when the `TemporaryDirectory` is cleaned up, so any other local user can read it. Fix keeps the sources in a subdirectory and writes the archive inside the 0700 `TemporaryDirectory`, so it inherits the restrictive permissions and is cleaned up with the rest of the scratch space. - [x] Ensure the tests and linter pass - [x] Code coverage does not decrease (if any source code was changed) - [ ] Appropriate docs were updated (if necessary)
1 parent 2f893b1 commit e726878

1 file changed

Lines changed: 11 additions & 2 deletions

File tree

packages/bigframes/bigframes/functions/_function_client.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,13 +358,22 @@ def create_cloud_function(
358358
config = func_def
359359

360360
# Build and deploy folder structure containing cloud function
361-
with tempfile.TemporaryDirectory() as directory:
361+
with tempfile.TemporaryDirectory() as scratch_dir:
362+
# Keep the generated sources in a subdirectory so the archive can be
363+
# written inside the 0700 TemporaryDirectory. shutil.make_archive
364+
# appends ".zip" to base_name, so archiving `directory` into itself
365+
# would leave a world-readable copy of the (pickled) user code as a
366+
# sibling of the temp dir that also survives the cleanup.
367+
directory = os.path.join(scratch_dir, "src")
368+
os.mkdir(directory)
362369
entry_point = self._generate_cloud_function_code(
363370
config.code,
364371
directory,
365372
udf_signature=config.signature,
366373
)
367-
archive_path = shutil.make_archive(directory, "zip", directory)
374+
archive_path = shutil.make_archive(
375+
os.path.join(scratch_dir, "source"), "zip", directory
376+
)
368377

369378
# We are creating cloud function source code from the currently running
370379
# python version. Use the same version to deploy. This is necessary

0 commit comments

Comments
 (0)