From 0f63b7177a73207d218e6990bd4bb8184465b9fc Mon Sep 17 00:00:00 2001 From: Molecule AI Core-DevOps Date: Mon, 11 May 2026 23:28:24 +0000 Subject: [PATCH] fix(sre): add explicit 15s timeout to gate-check-v3 HTTP calls (closes #603) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds DEFAULT_TIMEOUT=15 to gate_check.py and passes it to all urlopen() calls (api_get, comment POST, comment PATCH). Adds socket.setdefaulttimeout(15) to the inline Python in the workflow's cron step, catching the PR-polling loop too. Defence-in-depth: the real fix is provisioning SOP_TIER_CHECK_TOKEN in Gitea; this caps worst-case wall-clock at ~15 s per call when the token is missing or Gitea is unreachable. Fixes issue #603. Note: PR #603 (da1487ad) has the same changes but is missing `import socket` in the inline Python — that version would NameError at runtime. This branch carries the complete fix. Co-Authored-By: Claude Opus 4.7 --- .gitea/workflows/gate-check-v3.yml | 6 +++++- tools/gate-check-v3/gate_check.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/gate-check-v3.yml b/.gitea/workflows/gate-check-v3.yml index f8d2b42c..b1a6a2b0 100644 --- a/.gitea/workflows/gate-check-v3.yml +++ b/.gitea/workflows/gate-check-v3.yml @@ -71,8 +71,12 @@ jobs: run: | set -euo pipefail # Fetch all open PRs and run gate-check on each + # socket.setdefaulttimeout(15): defence-in-depth for missing SOP_TIER_CHECK_TOKEN. + # gate_check.py uses timeout=15 on every urlopen call; this catches the + # inline Python polling loop too (issue #603). pr_numbers=$(python3 -c " - import urllib.request, json, os + import socket, urllib.request, json, os + socket.setdefaulttimeout(15) token = os.environ['GITEA_TOKEN'] req = urllib.request.Request( 'https://git.moleculesai.app/api/v1/repos/${{ github.repository }}/pulls?state=open&limit=100', diff --git a/tools/gate-check-v3/gate_check.py b/tools/gate-check-v3/gate_check.py index f25be93e..5bff579a 100644 --- a/tools/gate-check-v3/gate_check.py +++ b/tools/gate-check-v3/gate_check.py @@ -35,6 +35,12 @@ GITEA_HOST = os.environ.get("GITEA_HOST", "git.moleculesai.app") GITEA_TOKEN = os.environ.get("GITEA_TOKEN", os.environ.get("GITHUB_TOKEN", "")) API_BASE = f"https://{GITEA_HOST}/api/v1" +# Timeout in seconds for all HTTP calls. Defence-in-depth: ensures a missing or +# invalid SOP_TIER_CHECK_TOKEN causes a fast (~15 s) failure rather than an +# indefinite hang. The real fix is provisioning the token; this caps worst-case +# wall-clock on a broken/unreachable Gitea host. +DEFAULT_TIMEOUT = 15 + def api_get(path: str) -> dict | list: url = f"{API_BASE}{path}" @@ -46,7 +52,7 @@ def api_get(path: str) -> dict | list: }, ) try: - with urllib.request.urlopen(req) as r: + with urllib.request.urlopen(req, timeout=DEFAULT_TIMEOUT) as r: return json.loads(r.read()) except urllib.error.HTTPError as e: body = e.read().decode(errors="replace") @@ -521,12 +527,12 @@ def run(repo: str, pr_number: int, post_comment: bool = False) -> dict: comment_id = our_comments[-1]["id"] url = f"{API_BASE}/repos/{owner}/{name}/issues/comments/{comment_id}" req = urllib.request.Request(url, data=json.dumps({"body": comment_body}).encode(), headers=headers, method="PATCH") - with urllib.request.urlopen(req) as r: + with urllib.request.urlopen(req, timeout=DEFAULT_TIMEOUT) as r: r.read() else: url = f"{API_BASE}/repos/{owner}/{name}/issues/{pr_number}/comments" req = urllib.request.Request(url, data=json.dumps({"body": comment_body}).encode(), headers=headers, method="POST") - with urllib.request.urlopen(req) as r: + with urllib.request.urlopen(req, timeout=DEFAULT_TIMEOUT) as r: r.read() except urllib.error.HTTPError as e: if e.code == 403: