Fix .env override priority and password whitespace stripping

Change load_dotenv() to load_dotenv(override=False) so real environment
variables always take priority over stale .env files. This prevents a
hardcoded or outdated REDMINE_API_KEY in .env from silently overriding
a fresh token exported in the shell (#15).

Add .strip() to get_redmine_password() for consistency with all other
config getters — trailing whitespace in .env no longer causes silent
auth failures (#35).

Closes #15, closes #35
This commit is contained in:
Артём Кокос
2026-06-25 21:06:19 +07:00
parent 3956decd4e
commit 3a6d1b7ba7
2 changed files with 26 additions and 2 deletions

View File

@@ -3,7 +3,7 @@ from typing import Union
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv() load_dotenv(override=False)
DEFAULT_REDMINE_VERIFY = "/etc/ssl/certs/ca-certificates.crt" DEFAULT_REDMINE_VERIFY = "/etc/ssl/certs/ca-certificates.crt"
FALSE_VALUES = {"0", "false", "no", "off"} FALSE_VALUES = {"0", "false", "no", "off"}
@@ -25,7 +25,7 @@ class Config:
@classmethod @classmethod
def get_redmine_password(cls) -> str: def get_redmine_password(cls) -> str:
return os.getenv("REDMINE_PASSWORD", "") return os.getenv("REDMINE_PASSWORD", "").strip()
@classmethod @classmethod
def get_redmine_verify(cls) -> Union[bool, str]: def get_redmine_verify(cls) -> Union[bool, str]:

View File

@@ -99,3 +99,27 @@ def test_get_redmine_verify_true_values(value):
@mock.patch.dict(os.environ, {"REDMINE_VERIFY": "/tmp/redmine-ca.pem"}, clear=True) @mock.patch.dict(os.environ, {"REDMINE_VERIFY": "/tmp/redmine-ca.pem"}, clear=True)
def test_get_redmine_verify_custom_path(): def test_get_redmine_verify_custom_path():
assert Config.get_redmine_verify() == "/tmp/redmine-ca.pem" assert Config.get_redmine_verify() == "/tmp/redmine-ca.pem"
# -- #15: .env не должен переопределять переменные окружения --
@mock.patch("dotenv.load_dotenv")
def test_env_var_takes_priority_over_dotenv(mock_load):
"""load_dotenv вызывается с override=False — env vars не перебиваются .env."""
import importlib
from redmine_reporter import config as cfg_mod
importlib.reload(cfg_mod)
mock_load.assert_called_once_with(override=False)
# -- #35: get_redmine_password должен делать .strip() --
@mock.patch.dict(os.environ, {"REDMINE_PASSWORD": " secret123 "}, clear=True)
def test_get_redmine_password_strips_whitespace():
"""Пароль обрезается от whitespace, как и все остальные геттеры."""
assert Config.get_redmine_password() == "secret123"