Skip to content

Commit f27861f

Browse files
SNOW-2161716: Fix config file permissions check and skip warning using env variable (#2488)
Co-authored-by: Maxim Mishchenko <[email protected]>
1 parent ac6bf6c commit f27861f

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

DESCRIPTION.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ https://docs.snowflake.com/
77
Source code is also available at: https://github.com/snowflakedb/snowflake-connector-python
88

99
# Release Notes
10+
- v3.18(TBD)
11+
- Enhanced configuration file permission warning messages.
12+
- Improved warning messages for readable permission issues to include clear instructions on how to skip warnings using the `SF_SKIP_WARNING_FOR_READ_PERMISSIONS_ON_CONFIG_FILE` environment variable.
13+
1014
- v3.17.2(August 23,2025)
1115
- Fixed a bug where platform_detection was retrying failed requests with warnings to non-existent endpoints.
1216
- Added disabling endpoint-based platform detection by setting `platform_detection_timeout_seconds` to zero.

src/snowflake/connector/config_manager.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
READABLE_BY_OTHERS = stat.S_IRGRP | stat.S_IROTH
3030

3131

32+
SKIP_WARNING_ENV_VAR = "SF_SKIP_WARNING_FOR_READ_PERMISSIONS_ON_CONFIG_FILE"
33+
34+
35+
def _should_skip_warning_for_read_permissions_on_config_file() -> bool:
36+
"""Check if the warning should be skipped based on environment variable."""
37+
return os.getenv(SKIP_WARNING_ENV_VAR, "false").lower() == "true"
38+
39+
3240
class ConfigSliceOptions(NamedTuple):
3341
"""Class that defines settings individual configuration files."""
3442

@@ -329,6 +337,7 @@ def read_config(
329337
)
330338
continue
331339

340+
# Check for readable by others or wrong ownership - this should warn
332341
if (
333342
not IS_WINDOWS # Skip checking on Windows
334343
and sliceoptions.check_permissions # Skip checking if this file couldn't hold sensitive information
@@ -342,9 +351,10 @@ def read_config(
342351
and filep.stat().st_uid != os.getuid()
343352
)
344353
):
345-
chmod_message = f'.\n * To change owner, run `chown $USER "{str(filep)}"`.\n * To restrict permissions, run `chmod 0600 "{str(filep)}"`.\n'
354+
chmod_message = f'.\n * To change owner, run `chown $USER "{str(filep)}"`.\n * To restrict permissions, run `chmod 0600 "{str(filep)}"`.\n * To skip this warning, set environment variable {SKIP_WARNING_ENV_VAR}=true.\n'
346355

347-
warn(f"Bad owner or permissions on {str(filep)}{chmod_message}")
356+
if not _should_skip_warning_for_read_permissions_on_config_file():
357+
warn(f"Bad owner or permissions on {str(filep)}{chmod_message}")
348358
LOGGER.debug(f"reading configuration file from {str(filep)}")
349359
try:
350360
read_config_piece = tomlkit.parse(filep.read_text())

test/unit/test_configmanager.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ def test_warn_config_file_owner(tmp_path, monkeypatch):
567567
assert (
568568
str(c[0].message)
569569
== f"Bad owner or permissions on {str(c_file)}"
570-
+ f'.\n * To change owner, run `chown $USER "{str(c_file)}"`.\n * To restrict permissions, run `chmod 0600 "{str(c_file)}"`.\n'
570+
+ f'.\n * To change owner, run `chown $USER "{str(c_file)}"`.\n * To restrict permissions, run `chmod 0600 "{str(c_file)}"`.\n * To skip this warning, set environment variable SF_SKIP_WARNING_FOR_READ_PERMISSIONS_ON_CONFIG_FILE=true.\n'
571571
)
572572

573573

@@ -587,7 +587,7 @@ def test_warn_config_file_permissions(tmp_path):
587587
with warnings.catch_warnings(record=True) as c:
588588
assert c1["b"] is True
589589
assert len(c) == 1
590-
chmod_message = f'.\n * To change owner, run `chown $USER "{str(c_file)}"`.\n * To restrict permissions, run `chmod 0600 "{str(c_file)}"`.\n'
590+
chmod_message = f'.\n * To change owner, run `chown $USER "{str(c_file)}"`.\n * To restrict permissions, run `chmod 0600 "{str(c_file)}"`.\n * To skip this warning, set environment variable SF_SKIP_WARNING_FOR_READ_PERMISSIONS_ON_CONFIG_FILE=true.\n'
591591
assert (
592592
str(c[0].message)
593593
== f"Bad owner or permissions on {str(c_file)}" + chmod_message
@@ -639,6 +639,30 @@ def test_log_debug_config_file_parent_dir_permissions(tmp_path, caplog):
639639
shutil.rmtree(tmp_dir)
640640

641641

642+
@pytest.mark.skipif(IS_WINDOWS, reason="chmod doesn't work on Windows")
643+
def test_skip_warning_config_file_permissions(tmp_path, monkeypatch):
644+
c_file = tmp_path / "config.toml"
645+
c1 = ConfigManager(file_path=c_file, name="root_parser")
646+
c1.add_option(name="b", parse_str=lambda e: e.lower() == "true")
647+
c_file.write_text(
648+
dedent(
649+
"""\
650+
b = true
651+
"""
652+
)
653+
)
654+
# Make file readable by others (would normally trigger warning)
655+
c_file.chmod(stat.S_IMODE(c_file.stat().st_mode) | stat.S_IROTH)
656+
657+
with monkeypatch.context() as m:
658+
# Set environment variable to skip warning
659+
m.setenv("SF_SKIP_WARNING_FOR_READ_PERMISSIONS_ON_CONFIG_FILE", "true")
660+
with warnings.catch_warnings(record=True) as c:
661+
assert c1["b"] is True
662+
# Should have no warnings when skip is enabled
663+
assert len(c) == 0
664+
665+
642666
def test_configoption_missing_root_manager():
643667
with pytest.raises(
644668
TypeError,

0 commit comments

Comments
 (0)