mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 15:03:16 +00:00
* feat: CI auto-fix and PR babysitting for agent PRs Watch CI failures and review feedback on PRs Open SWE opened, then dispatch confidence-gated fix runs on the originating agent thread. Adds CI webhook ingestion (check_run/check_suite/workflow_run/status), a per-PR @open-swe autofix on|off toggle, auto-response to review comments, and a polling ci_monitor graph that also flags merge conflicts. Gated by the existing autofix_mode/trigger_mode settings, the enabled-repos opt-in, base-branch and human-commit skip rules, dedupe, and a per-PR attempt cap. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> * fix: address review feedback on CI auto-fix - Security: gate the no-mention review-feedback path on author trust — require a trusted author_association (OWNER/MEMBER/COLLABORATOR) plus a GitHub write/maintain/admin permission check before dispatching a write-capable agent run, preventing privilege escalation from read/triage/outside reviewers. - Auth: reuse the originating PR thread's source + login/email when dispatching fix runs so the GitHub-token resolver authenticates them in non-bot-token deployments (bespoke github_ci source failed to resolve). - Docs: document the Commit statuses: Read-only permission required for the Status webhook event. Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
51 lines
1.8 KiB
Python
51 lines
1.8 KiB
Python
"""Per-PR auto-fix opt-out, stored in the LangGraph Store.
|
|
|
|
Team-wide auto-fix is gated by :func:`agent.dashboard.team_settings.is_autofix_enabled`.
|
|
On top of that, a single PR can be silenced with ``@open-swe autofix off`` (and
|
|
re-enabled with ``@open-swe autofix on``), mirroring Cursor's
|
|
``@cursor autofix off`` per-PR control. The toggle lives here rather than on the
|
|
agent thread so a disable command is honored even before any fix run exists.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import UTC, datetime
|
|
|
|
from langgraph_sdk import get_client
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
AUTOFIX_PR_STATE_NAMESPACE: list[str] = ["autofix_pr_state"]
|
|
|
|
|
|
def _client():
|
|
return get_client()
|
|
|
|
|
|
def _key(owner: str, repo: str, pr_number: int) -> str:
|
|
return f"{owner.lower()}/{repo.lower()}#{pr_number}"
|
|
|
|
|
|
async def is_pr_autofix_disabled(owner: str, repo: str, pr_number: int) -> bool:
|
|
"""Return whether auto-fix has been turned off for a specific PR."""
|
|
try:
|
|
item = await _client().store.get_item(
|
|
AUTOFIX_PR_STATE_NAMESPACE, _key(owner, repo, pr_number)
|
|
)
|
|
except Exception as e: # noqa: BLE001
|
|
logger.debug("autofix PR state lookup failed: %s", e)
|
|
return False
|
|
if item is None:
|
|
return False
|
|
value = item.get("value") if isinstance(item, dict) else getattr(item, "value", None)
|
|
return bool(value.get("disabled")) if isinstance(value, dict) else False
|
|
|
|
|
|
async def set_pr_autofix_disabled(owner: str, repo: str, pr_number: int, disabled: bool) -> None:
|
|
"""Persist the per-PR auto-fix opt-out flag."""
|
|
await _client().store.put_item(
|
|
AUTOFIX_PR_STATE_NAMESPACE,
|
|
_key(owner, repo, pr_number),
|
|
{"disabled": disabled, "updated_at": datetime.now(UTC).isoformat()},
|
|
)
|