Skip to content

Commit 0cc95b3

Browse files
authored
SNOW-676736: get file results in change of file permissions does not inherit parent folder permission (#1338)
1 parent d016d81 commit 0cc95b3

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

DESCRIPTION.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
88

99
# Release Notes
1010

11+
- v2.8.3(Unreleased)
12+
- Fixed a bug where the permission of the file downloaded via GET command is changed
13+
1114
- v2.8.2(November 18,2022)
1215

1316
- Improved performance of OCSP response caching

src/snowflake/connector/encryption_util.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from .compat import PKCS5_OFFSET, PKCS5_PAD, PKCS5_UNPAD
2020
from .constants import UTF8, EncryptionMetadata, MaterialDescriptor, kilobyte
21+
from .util_text import random_string
2122

2223
block_size = int(algorithms.AES.block_size / 8) # in bytes
2324

@@ -238,12 +239,13 @@ def decrypt_file(
238239
Returns:
239240
The decrypted file's location.
240241
"""
241-
temp_output_fd, temp_output_file = tempfile.mkstemp(
242-
text=False, dir=tmp_dir, prefix=os.path.basename(in_filename) + "#"
243-
)
242+
temp_output_file = f"{os.path.basename(in_filename)}#{random_string()}"
243+
if tmp_dir:
244+
temp_output_file = os.path.join(tmp_dir, temp_output_file)
245+
244246
logger.debug("encrypted file: %s, tmp file: %s", in_filename, temp_output_file)
245247
with open(in_filename, "rb") as infile:
246-
with os.fdopen(temp_output_fd, "wb") as outfile:
248+
with open(temp_output_file, "wb") as outfile:
247249
SnowflakeEncryptionUtil.decrypt_stream(
248250
metadata, encryption_material, infile, outfile, chunk_size
249251
)

test/integ/test_put_get.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,3 +671,27 @@ def test_get_empty_file(tmp_path, conn_cnx):
671671
with pytest.raises(OperationalError, match=".*the file does not exist.*$"):
672672
cur.execute(f"GET @{stage_name}/foo.csv file://{tmp_path}")
673673
assert not empty_file.exists()
674+
675+
676+
@pytest.mark.skipolddriver
677+
def test_get_file_permission(tmp_path, conn_cnx):
678+
test_file = tmp_path / "data.csv"
679+
test_file.write_text("1,2,3\n")
680+
stage_name = random_string(5, "test_get_empty_file_")
681+
with conn_cnx() as cnx:
682+
with cnx.cursor() as cur:
683+
cur.execute(f"create temporary stage {stage_name}")
684+
filename_in_put = str(test_file).replace("\\", "/")
685+
cur.execute(
686+
f"PUT 'file://{filename_in_put}' @{stage_name}",
687+
)
688+
689+
cur.execute(f"GET @{stage_name}/data.csv file://{tmp_path}")
690+
# get the default mask, usually it is 0o022
691+
default_mask = os.umask(0)
692+
os.umask(default_mask)
693+
# files by default are given the permission 644 (Octal)
694+
# umask is for denial, we need to negate
695+
assert (
696+
oct(os.stat(test_file).st_mode)[-3:] == oct(0o666 & ~default_mask)[-3:]
697+
)

0 commit comments

Comments
 (0)