fix: resolve merge-marker cleanup and concise config docs

Clean up residual cherry-pick conflict markers and keep SMTP guidance in config templates brief while preserving full behavior in code and tests.

Made-with: Cursor
This commit is contained in:
agessaman
2026-04-14 10:06:44 -07:00
parent 485edc6c91
commit 887068faa2
6 changed files with 74 additions and 32 deletions
+2 -18
View File
@@ -202,24 +202,8 @@ radio_probe_fail_threshold = 3
# true: send alert email in addition to logging
radio_zombie_alert_enabled = false
<<<<<<< HEAD
=======
# SMTP security note: by default the bot blocks SMTP hosts that resolve to
# any private, loopback, link-local, or reserved address to prevent SSRF.
# Blocked ranges (per RFC):
# 10.0.0.0/8 RFC 1918 — private
# 172.16.0.0/12 RFC 1918 — private
# 192.168.0.0/16 RFC 1918 — private
# 127.0.0.0/8 RFC 1122 — loopback
# 169.254.0.0/16 RFC 3927 — link-local
# 100.64.0.0/10 RFC 6598 — shared address space (CGN)
# ::1/128 RFC 4291 — IPv6 loopback
# fc00::/7 RFC 4193 — IPv6 unique local (ULA)
# fe80::/10 RFC 4291 — IPv6 link-local
# If you run a local SMTP relay (e.g. Postfix on localhost), enable
# "Allow local SMTP host" in the web viewer → Settings → Notifications.
>>>>>>> 38d040a (security: SSRF hardening, log injection sanitization, and allow_local_smtp)
# SMTP hosts resolving to private/loopback/reserved ranges are blocked by default (SSRF guard).
# If you intentionally use local SMTP, enable "Allow local SMTP host" in Notifications.
# Alert email recipients for zombie detection (comma-separated addresses).
# If empty, falls back to the nightly maintenance email recipients.
# Set this to a separate on-call address if needed.
@@ -0,0 +1,72 @@
# KG7QIN PR Integration Log
Branch: `integration/kg7qin`
Base: `origin/dev`
## Policy Constraints
- Exclude `!plugins` command from all integrations.
- Treat command behaviors that create multi-message output as regressions.
- Keep `config.ini.example` and related config templates brief; move long-form docs to `docs/`.
## Inventory and Initial Classification
### Stage 1
- PR #138
- `accept`: `aa94d23`, `69675ac`, `0be6004`, `6a627c2`, `975d744`, `0cbd764`
- `accept-with-edit`: none
- `drop`: lint-only/shared-sync commits already covered elsewhere
- PR #140
- `accept`: `38d040a`, `04eba0a`
- `accept-with-edit`: none
- `drop`: broad lint/mypy sweep commit (`7af161e`) unless needed by gate
- PR #147
- `accept`: `df66761`
- `accept-with-edit`: `ca67ec4` (only if required to restore expected flood-scope/public-channel behavior)
- `drop`: test/lint hygiene commits unless required by gate
- PR #145
- `accept`: `2272b86`
- `accept-with-edit`: none
- `drop`: broad ruff/sync commits unless required by gate
- PR #155
- `accept`: `2b896c6` (delta-only post-rebase compatibility)
- `drop`: duplicated #138 history
- PR #156
- `accept`: `5ac7ae0` (delta-only post-rebase compatibility)
- `drop`: duplicated #147 history
### Stage 2
- PR #139
- `accept`: `7450ac3`
- `accept-with-edit`: `86264d6` docs portions only if concise for config templates
- `drop`: duplicated lint/sync commits
- PR #149
- `accept`: `88e8fa4`, `f6e1924`
- `accept-with-edit`: none
- `drop`: duplicated lint/sync commits unless required by gate
- PR #148
- `accept`: `4a96f7f` (partial: `--show-config`, `--show-config-json`, `/admin/config`)
- `accept-with-edit`: `655da24` (keep `!status`, drop `!plugins`, reject any multi-message command behavior)
- `drop`: `9310a38`, `4dd9834` if they are mostly plugins-focused
- PR #154
- `accept`: `a02c15f`
- `accept-with-edit`: none
- `drop`: none initially
- PR #141
- `accept-with-edit`: `a8edb80` (preserve single-message behavior)
- `drop`: duplicated lint/sync commits unless required
- PR #157
- `accept`: `6eb8001` if needed after #148 partial integration
- `drop`: duplicated #148 history
- PR #158
- `accept`: `b2dddc5` if needed after #149 integration
- `drop`: duplicated #149 history
### Stage 3
- PR #142
- `accept-with-edit`: `a85e6ac`, `f4df680`, `9683abb`, `86b2f53`, `21eed98` (only tests/coverage updates that still reflect current code and policy)
- `drop`: duplicated lint/sync commits
- PR #159
- `accept`: `6302b07` (targeted ruff/mypy compliance)
## Execution Records
- Pending implementation.
-5
View File
@@ -256,13 +256,8 @@ class BotDataViewer:
config.read(config_path)
return config
<<<<<<< HEAD
def _get_version_info(self) -> dict[str, Optional[str]]:
"""Get version info for footer from shared runtime resolver."""
=======
def _get_version_info(self) -> dict[str, str | None]:
"""Get version info for footer via centralized version resolver. Never raises."""
>>>>>>> 5ac7ae0 (fix: post-rebase compatibility fixes for #147 (stability hardening))
info = resolve_runtime_version(self.bot_root)
return {
"tag": info.get("tag"),
-3
View File
@@ -282,7 +282,6 @@ class TestLoopExceptionHandler:
mock_loop.default_exception_handler.assert_called_once_with(ctx)
<<<<<<< HEAD
# ---------------------------------------------------------------------------
# _probe_radio_health (PR4 — zombie-connection detection)
# ---------------------------------------------------------------------------
@@ -539,5 +538,3 @@ async def _make_coro_async(value):
def _make_coro(value):
"""Return a coroutine that immediately resolves to *value*."""
return _make_coro_async(value)
=======
>>>>>>> 38d040a (security: SSRF hardening, log injection sanitization, and allow_local_smtp)
-3
View File
@@ -1308,7 +1308,6 @@ class TestCollectEmailStats:
assert result.get("contacts_24h") == 10
assert result.get("contacts_new_24h") == 3
<<<<<<< HEAD
# ---------------------------------------------------------------------------
# _send_interval_advert_async (PR2 fix — Event-based error detection)
@@ -1461,7 +1460,6 @@ class TestSendScheduledMessageAsyncTimeout:
assert call_args_list, "logger.error was never called"
logged = str(call_args_list[0])
assert "TimeoutError" in logged
=======
# ---------------------------------------------------------------------------
# SSRF guard — SMTP host validation in email-sending methods
# ---------------------------------------------------------------------------
@@ -1558,4 +1556,3 @@ class TestZombieAlertEmailSsrfGuard:
sched.send_zombie_alert_email(fail_count=5, threshold=3, interval=60)
logged = str(sched.bot.logger.error.call_args_list)
assert "private" not in logged.lower() and "reserved" not in logged.lower()
>>>>>>> 38d040a (security: SSRF hardening, log injection sanitization, and allow_local_smtp)
-3
View File
@@ -2970,7 +2970,6 @@ class TestDbPathResolutionFromConfigDir:
)
<<<<<<< HEAD
class TestRadioDebugConfig:
"""Tests for GET/POST /api/config/radio-debug endpoints."""
@@ -3040,7 +3039,6 @@ class TestRadioDebugConfig:
data = resp.get_json()
assert data["success"] is True
assert data["op_id"] is None
=======
# ===========================================================================
# Security: Restore endpoint path traversal prevention (GAP W1)
# ===========================================================================
@@ -3188,4 +3186,3 @@ class TestFeedPreviewSecurity:
)
mock_veu.assert_called()
assert resp.status_code == 400
>>>>>>> 38d040a (security: SSRF hardening, log injection sanitization, and allow_local_smtp)