fix: warn when TLS verification is disabled

REDMINE_VERIFY=false / verify_ssl: false silently disabled TLS
certificate verification, exposing the connection to MITM attacks.
Config.validate() now prints a warning to stderr when verification
is disabled (exactly False; True or a CA-bundle path stays quiet).
validate() runs exactly once at CLI startup, so the warning is
emitted once per run and is visible in every scenario.

Closes #57
This commit is contained in:
Кокос Артем Николаевич
2026-07-17 12:50:40 +07:00
parent a1febd6999
commit b624a8b8c2
3 changed files with 49 additions and 0 deletions

View File

@@ -318,3 +318,4 @@ mypy redmine_reporter
- Используйте аккаунт с минимальными правами, достаточными для чтения time entries и задач.
- Инструмент работает только в режиме чтения и не изменяет данные в Redmine.
- `REDMINE_URL` обязан использовать HTTPS: API-ключ передаётся в заголовках запроса, и без TLS он может быть перехвачен.
- `REDMINE_VERIFY=false` (или `verify_ssl: false`) отключает проверку TLS-сертификата — соединение уязвимо для MITM-атак; при старте выводится предупреждение. Используйте только в доверенной сети.

View File

@@ -1,5 +1,6 @@
import logging
import os
import sys
from dataclasses import dataclass, field
from datetime import date, timedelta
from pathlib import Path
@@ -406,6 +407,13 @@ class Config:
"REDMINE_URL must use HTTPS: the API key is sent in request "
"headers and requires TLS"
)
if cls.get_redmine_verify() is False:
print(
"⚠️ TLS certificate verification is disabled "
"(REDMINE_VERIFY=false / verify_ssl: false): connection is "
"vulnerable to MITM attacks",
file=sys.stderr,
)
if cls.get_redmine_api_key():
return
if not (cls.get_redmine_user() and cls.get_redmine_password()):

View File

@@ -176,6 +176,46 @@ class TestConfigRequiresHttpsUrl:
Config.validate()
# -- #57: предупреждение при отключённой проверке TLS --
class TestWarnWhenTlsVerificationDisabled:
"""verify_ssl: false должен давать видимый warning в stderr (риск MITM)."""
_ENV = {"REDMINE_URL": "https://red.eltex.loc/", "REDMINE_API_KEY": "token"}
def _validate_env(self, verify: str):
return {**self._ENV, "REDMINE_VERIFY": verify}
def test_verify_false_warns_in_stderr(self, capsys):
with mock.patch.dict(os.environ, self._validate_env("false"), clear=True):
Config.validate()
err = capsys.readouterr().err
assert "⚠️" in err
assert "TLS" in err or "SSL" in err
def test_verify_true_no_warning(self, capsys):
with mock.patch.dict(os.environ, self._validate_env("true"), clear=True):
Config.validate()
assert capsys.readouterr().err == ""
def test_verify_ca_path_no_warning(self, capsys):
with mock.patch.dict(
os.environ, self._validate_env("/tmp/redmine-ca.pem"), clear=True
):
Config.validate()
assert capsys.readouterr().err == ""
def test_verify_default_no_warning(self, capsys):
with mock.patch.dict(os.environ, self._ENV, clear=True):
Config.validate()
assert capsys.readouterr().err == ""
# -- #15: .env не должен переопределять переменные окружения --