mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 09:13:14 +00:00
fix: gate Open SWE in docs-plz Slack channel (#1605)
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
parent
39681102d6
commit
fb467e84fd
2 changed files with 105 additions and 0 deletions
|
|
@ -108,6 +108,7 @@ from .utils.slack import (
|
|||
fetch_slack_thread_messages,
|
||||
format_slack_messages_for_prompt,
|
||||
get_slack_channel_description,
|
||||
get_slack_channel_info,
|
||||
get_slack_user_info,
|
||||
get_slack_user_names,
|
||||
post_slack_thread_reply,
|
||||
|
|
@ -172,6 +173,10 @@ DEFAULT_REPO_OWNER = os.environ.get("DEFAULT_REPO_OWNER", "langchain-ai")
|
|||
DEFAULT_REPO_NAME = os.environ.get("DEFAULT_REPO_NAME", "")
|
||||
SLACK_REPO_OWNER = os.environ.get("SLACK_REPO_OWNER", "") or DEFAULT_REPO_OWNER
|
||||
SLACK_REPO_NAME = os.environ.get("SLACK_REPO_NAME", "") or DEFAULT_REPO_NAME
|
||||
DOCS_PLZ_SLACK_CHANNEL_NAME = "docs-plz"
|
||||
DOCS_PLZ_SLACK_GATE_REPLY = (
|
||||
"Please don't use Open SWE here, instead ask the Fleet docs-plz agent to implement the docs"
|
||||
)
|
||||
|
||||
LANGGRAPH_URL = os.environ.get("LANGGRAPH_URL") or os.environ.get(
|
||||
"LANGGRAPH_URL_PROD", "http://localhost:2024"
|
||||
|
|
@ -419,6 +424,22 @@ def _run_id_for_logging(run: Any) -> str:
|
|||
return run_id if isinstance(run_id, str) and run_id else "<unknown>"
|
||||
|
||||
|
||||
async def _is_docs_plz_slack_channel(channel_id: str) -> bool:
|
||||
"""Check whether a Slack channel is the docs-plz handoff channel."""
|
||||
try:
|
||||
channel = await get_slack_channel_info(channel_id)
|
||||
except Exception: # noqa: BLE001
|
||||
logger.exception("Failed to resolve Slack channel info for docs-plz gate")
|
||||
return False
|
||||
if not isinstance(channel, dict):
|
||||
return False
|
||||
candidate_names = (channel.get("name"), channel.get("name_normalized"))
|
||||
return any(
|
||||
isinstance(name, str) and name.strip().lower() == DOCS_PLZ_SLACK_CHANNEL_NAME
|
||||
for name in candidate_names
|
||||
)
|
||||
|
||||
|
||||
def _is_repo_allowed(repo_config: dict[str, str]) -> bool:
|
||||
"""Check if the repo is in the allowlist.
|
||||
|
||||
|
|
@ -1588,6 +1609,15 @@ async def slack_webhook(request: Request, background_tasks: BackgroundTasks) ->
|
|||
if bot_user_id and user_id == bot_user_id:
|
||||
return {"status": "ignored", "reason": "Event from this bot user"}
|
||||
|
||||
if await _is_docs_plz_slack_channel(channel_id):
|
||||
background_tasks.add_task(
|
||||
post_slack_thread_reply,
|
||||
channel_id,
|
||||
thread_ts,
|
||||
DOCS_PLZ_SLACK_GATE_REPLY,
|
||||
)
|
||||
return {"status": "accepted", "message": "Slack mention gated for docs-plz"}
|
||||
|
||||
event_data = {
|
||||
"channel_id": channel_id,
|
||||
"thread_ts": thread_ts,
|
||||
|
|
|
|||
|
|
@ -521,6 +521,81 @@ def test_github_webhook_ignores_review_requested(monkeypatch) -> None:
|
|||
}
|
||||
|
||||
|
||||
def test_is_docs_plz_slack_channel_matches_name(monkeypatch) -> None:
|
||||
async def fake_get_slack_channel_info(channel_id: str) -> dict[str, object]:
|
||||
assert channel_id == "C_DOCS"
|
||||
return {"name": "docs-plz"}
|
||||
|
||||
monkeypatch.setattr(webapp, "get_slack_channel_info", fake_get_slack_channel_info)
|
||||
|
||||
assert asyncio.run(webapp._is_docs_plz_slack_channel("C_DOCS")) is True
|
||||
|
||||
|
||||
def test_is_docs_plz_slack_channel_matches_normalized_name(monkeypatch) -> None:
|
||||
async def fake_get_slack_channel_info(channel_id: str) -> dict[str, object]:
|
||||
assert channel_id == "C_DOCS"
|
||||
return {"name": "Docs Plz", "name_normalized": "docs-plz"}
|
||||
|
||||
monkeypatch.setattr(webapp, "get_slack_channel_info", fake_get_slack_channel_info)
|
||||
|
||||
assert asyncio.run(webapp._is_docs_plz_slack_channel("C_DOCS")) is True
|
||||
|
||||
|
||||
def test_slack_webhook_gates_docs_plz_channel(monkeypatch) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
async def fake_is_docs_plz_slack_channel(channel_id: str) -> bool:
|
||||
captured["checked_channel_id"] = channel_id
|
||||
return True
|
||||
|
||||
async def fake_post_slack_thread_reply(channel_id: str, thread_ts: str, text: str) -> bool:
|
||||
captured["reply"] = {"channel_id": channel_id, "thread_ts": thread_ts, "text": text}
|
||||
return True
|
||||
|
||||
async def fail_get_slack_repo_config(
|
||||
channel_id: str, thread_ts: str, slack_user_id: str | None = None
|
||||
) -> dict[str, str]:
|
||||
raise AssertionError("docs-plz gate should skip repo resolution")
|
||||
|
||||
async def fail_process_slack_mention(
|
||||
event_data: dict[str, object], repo_config: dict[str, str]
|
||||
) -> None:
|
||||
raise AssertionError("docs-plz gate should not start the agent")
|
||||
|
||||
monkeypatch.setattr(webapp, "SLACK_SIGNING_SECRET", _TEST_SLACK_SECRET)
|
||||
monkeypatch.setattr(webapp, "SLACK_BOT_USER_ID", "UBOT")
|
||||
monkeypatch.setattr(webapp, "SLACK_BOT_USERNAME", "open-swe")
|
||||
monkeypatch.setattr(slack_utils.time, "time", lambda: 1700000000)
|
||||
monkeypatch.setattr(webapp, "_is_docs_plz_slack_channel", fake_is_docs_plz_slack_channel)
|
||||
monkeypatch.setattr(webapp, "post_slack_thread_reply", fake_post_slack_thread_reply)
|
||||
monkeypatch.setattr(webapp, "get_slack_repo_config", fail_get_slack_repo_config)
|
||||
monkeypatch.setattr(webapp, "process_slack_mention", fail_process_slack_mention)
|
||||
|
||||
client = TestClient(webapp.app)
|
||||
response = _post_slack_webhook(
|
||||
client,
|
||||
{
|
||||
"type": "event_callback",
|
||||
"event": {
|
||||
"type": "app_mention",
|
||||
"channel": "C_DOCS",
|
||||
"ts": "1700000000.000100",
|
||||
"user": "U123",
|
||||
"text": "<@UBOT> please update docs",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"status": "accepted", "message": "Slack mention gated for docs-plz"}
|
||||
assert captured["checked_channel_id"] == "C_DOCS"
|
||||
assert captured["reply"] == {
|
||||
"channel_id": "C_DOCS",
|
||||
"thread_ts": "1700000000.000100",
|
||||
"text": webapp.DOCS_PLZ_SLACK_GATE_REPLY,
|
||||
}
|
||||
|
||||
|
||||
def test_slack_webhook_routes_review_command_to_agent(monkeypatch) -> None:
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue