mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-06-18 21:55:59 +00:00
fix(channels): harden runtime credential management APIs (#3581)
* fix(channels): harden runtime credential management APIs * fix(channels): address review feedback on credential hardening Follow-up to the runtime credential-hardening pass, resolving five review findings: - WeChat auth persistence now writes through a 0o600 NamedTemporaryFile + Path.replace instead of write_text-then-chmod, so the iLink bot_token is never briefly readable at umask defaults (mirrors ChannelRuntimeConfigStore). - The post-write chmod is split into its own try/except: a chmod failure on a filesystem without POSIX perms now logs at debug instead of masquerading as a "failed to persist" warning. - Extracted the three near-identical _require_admin_user helpers (mcp, channel_connections, channels) into a single require_admin_user(request, *, detail) in app/gateway/deps.py; each router supplies its own detail string. - Strengthened the runtime-config-store chmod coverage: a new test injects a temp-file chmod failure and asserts it is logged at debug while the destination is still owner-only (mutation-verified to fail if the chmod is dropped), plus a loose-pre-existing-file case. - Removed the unused _FakeRepo from the blocking-io test: its isinstance gate routes through the repo-less 503 path, so neither stub was ever invoked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
"""Router tests for legacy IM channel management endpoints."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
from uuid import UUID
|
||||
|
||||
from _router_auth_helpers import make_authed_test_app
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.gateway.auth.models import User
|
||||
from app.gateway.routers import channels
|
||||
|
||||
|
||||
def _admin_user() -> User:
|
||||
return User(
|
||||
id=UUID("11111111-2222-3333-4444-555555555555"),
|
||||
email="admin@example.com",
|
||||
password_hash="x",
|
||||
system_role="admin",
|
||||
)
|
||||
|
||||
|
||||
def _non_admin_user() -> User:
|
||||
return User(
|
||||
id=UUID("99999999-8888-7777-6666-555555555555"),
|
||||
email="user@example.com",
|
||||
password_hash="x",
|
||||
system_role="user",
|
||||
)
|
||||
|
||||
|
||||
def test_restart_channel_requires_admin(monkeypatch):
|
||||
service = SimpleNamespace(restart_channel=AsyncMock(return_value=True))
|
||||
monkeypatch.setattr("app.channels.service.get_channel_service", lambda: service)
|
||||
app = make_authed_test_app(user_factory=_non_admin_user)
|
||||
app.include_router(channels.router)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.post("/api/channels/slack/restart")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert "Admin privileges" in response.json()["detail"]
|
||||
service.restart_channel.assert_not_awaited()
|
||||
|
||||
|
||||
def test_restart_channel_allows_admin(monkeypatch):
|
||||
service = SimpleNamespace(restart_channel=AsyncMock(return_value=True))
|
||||
monkeypatch.setattr("app.channels.service.get_channel_service", lambda: service)
|
||||
app = make_authed_test_app(user_factory=_admin_user)
|
||||
app.include_router(channels.router)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.post("/api/channels/slack/restart")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"success": True,
|
||||
"message": "Channel slack restarted successfully",
|
||||
}
|
||||
service.restart_channel.assert_awaited_once_with("slack")
|
||||
|
||||
|
||||
def test_get_channels_status_remains_read_only(monkeypatch):
|
||||
service = SimpleNamespace(
|
||||
get_status=lambda: {
|
||||
"service_running": True,
|
||||
"channels": {
|
||||
"slack": {
|
||||
"enabled": True,
|
||||
"running": True,
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
monkeypatch.setattr("app.channels.service.get_channel_service", lambda: service)
|
||||
app = make_authed_test_app(user_factory=_non_admin_user)
|
||||
app.include_router(channels.router)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.get("/api/channels/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["service_running"] is True
|
||||
assert response.json()["channels"]["slack"]["running"] is True
|
||||
Reference in New Issue
Block a user