"""Data-only OpenCode reviews. Never execute PR or issue content.""" from __future__ import annotations import base64 import hashlib import html import json import os import re import sys import time import urllib.error import urllib.parse import urllib.request from http.client import HTTPException from pathlib import Path GO_URL = "https://opencode.ai/inference/go/openai/v1/chat/completions" DEFAULT_MODEL = "glm-5.3-flash" REVIEW_MODELS = (("go", GO_URL, "deepseek-v4.1-flash"), ("go", GO_URL, DEFAULT_MODEL)) ALLOWED_MODELS = frozenset(model for _, _, model in REVIEW_MODELS) PROVIDER_FAILURES = frozenset({"timeout", "transport", "malformed_json", "response_too_large"}) # Bound individual network responses, not review eligibility or Go usage. HTTP_RESPONSE_LIMIT = 16 * 1024 * 1024 ISSUE_PROMPT_LIMIT = 300 * 1024 ISSUE_SOURCE_LIMIT = 256 * 1024 MAX_RESULT = 24 * 1024 SHA = re.compile(r"[0-9a-f]{40}") REPO = re.compile(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+") HUNK = re.compile(r"@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(?:.*)") MARKER = "" # Bound pagination; do not assume absence if the history is too large. for page in range(1, 11): reviews = self.api(f"{self.pull}/reviews?per_page=100&page={page}") require(isinstance(reviews, list), "Invalid review history.") for review in reviews: if (review.get("user", {}).get("login") == "github-actions[bot]" and review.get("user", {}).get("type") == "Bot" and review.get("state") == "COMMENTED" and review.get("commit_id") == head and review.get("body", "").startswith(marker)): return True if len(reviews) < 100: return False raise ReviewError("Review history exceeds duplicate-check limit.") def parse_patch(file): """Validate every hunk count and totals, retaining right-side locations.""" patch = file.get("patch") require(isinstance(patch, str) and patch, "Missing/binary/incomplete patch; review refused.") added = removed = 0 old_left = new_left = 0 line = 0 locations = {} seen_hunk = False for entry in patch.splitlines(): match = HUNK.fullmatch(entry) if match: require(old_left == new_left == 0, "Truncated diff hunk; review refused.") old_left = int(match[2] or 1) new_left = int(match[4] or 1) line = int(match[3]) seen_hunk = True elif entry == "\\ No newline at end of file": continue else: require(seen_hunk and bool(entry), "Malformed diff hunk; review refused.") prefix, content = entry[0], entry[1:] require(prefix in {"+", "-", " "}, "Malformed diff line; review refused.") if prefix != "+": old_left -= 1 if prefix != "-": new_left -= 1 locations[line] = content line += 1 added += prefix == "+" removed += prefix == "-" require(old_left >= 0 and new_left >= 0, "Diff hunk count mismatch.") require(seen_hunk and old_left == new_left == 0, "Truncated diff hunk; review refused.") require(added == file["additions"] and removed == file["deletions"], "Incomplete diff totals; review refused.") return locations def collect(gh, head, *, context): pr = gh.current(head) require(type(pr["changed_files"]) is int and pr["changed_files"] > 0, "Invalid or empty diff.") files = [] while len(files) < pr["changed_files"]: page = gh.api(f"{gh.pull}/files?per_page=100&page={len(files) // 100 + 1}") require(isinstance(page, list) and 0 < len(page) <= 100 and len(files) + len(page) <= pr["changed_files"], "Incomplete file list; review refused.") files.extend(page) require(len(page) == 100 or len(files) == pr["changed_files"], "Incomplete file list; review refused.") require(sum(f["additions"] for f in files) == pr["additions"] and sum(f["deletions"] for f in files) == pr["deletions"], "Diff changed during collection.") data, locations = [], {} for file in files: path = file["filename"] require(isinstance(path, str) and 0 < len(path) <= 512 and not any(ord(c) < 32 or ord(c) == 127 for c in path) and not path.startswith("/") and not any(part in {".", ".."} for part in path.split("/")) and path not in locations, "Invalid or duplicate diff path.") right = parse_patch(file) locations[path] = right item = {"path": path, "status": file["status"], "patch": file["patch"]} if context and file["status"] != "removed": # Never use raw_url/download_url or any URL/ref supplied by PR content. quoted = urllib.parse.quote(path, safe="/") source = gh.api(f"{gh.root}/contents/{quoted}?ref={head}") require(source.get("type") == "file" and source.get("encoding") == "base64" and source.get("sha") == file["sha"] and type(source.get("size")) is int and source["size"] >= 0, "Head source is unavailable or not a regular file.") raw = base64.b64decode(source["content"].replace("\n", ""), validate=True) require(len(raw) == source["size"] and b"\0" not in raw, "Unsupported head source.") lines = raw.decode("utf-8").splitlines() require(all(0 < n <= len(lines) and lines[n - 1] == text for n, text in right.items()), "Patch does not match exact head source.") selected = set() for n in right: selected.update(range(max(1, n - 12), min(len(lines), n + 12) + 1)) item["head_context"] = [{"line": n, "text": lines[n - 1]} for n in sorted(selected)] data.append(item) gh.current(head) no_secrets(data, (gh.token,)) return data, locations def validate_findings(value, locations): require(isinstance(value, dict) and set(value) == {"findings"}, "Invalid findings schema.") findings = value["findings"] require(isinstance(findings, list) and len(findings) <= 5, "Invalid finding count.") seen = set() for finding in findings: require(isinstance(finding, dict) and set(finding) == {"path", "line", "title", "body"}, "Invalid finding fields.") path, line = finding["path"], finding["line"] if not (isinstance(path, str) and path in locations and type(line) is int and line in locations[path]): raise SecurityError("Finding location is outside validated right-side diff.") for key, bound in (("title", 160), ("body", 1200)): text = finding[key] require(isinstance(text, str) and 0 < len(text.strip()) <= bound and not any(ord(c) < 32 or ord(c) == 127 for c in text), "Invalid finding text.") require((path, line) not in seen, "Duplicate finding location.") seen.add((path, line)) no_secrets(value) require(len(json_bytes(value)) <= MAX_RESULT, "Findings exceed output limit.") return findings def completion_text(response, limit): require(isinstance(response, dict), "Invalid completion object.") choices = response.get("choices") require(isinstance(choices, list) and len(choices) == 1 and isinstance(choices[0], dict), "Invalid completion choices.") choice = choices[0] require(choice.get("finish_reason") == "stop", "Incomplete completion rejected.") message = choice.get("message") require(isinstance(message, dict) and message.get("role") == "assistant" and not message.get("tool_calls") and not message.get("function_call") and not message.get("refusal"), "Non-text completion rejected.") content = message.get("content") require(isinstance(content, str) and bool(content.strip()) and len(content.encode()) <= limit, "Invalid completion content.") return content def attempt_metadata(http, route, model, outcome, response=None, *, failure=None): """Only fixed enums, booleans, and bounded integer counts may reach logs.""" require((route, model) in {(r, m) for r, _, m in REVIEW_MODELS}, "Invalid diagnostic model.") require(outcome in {"http_error", "request_failed", "invalid_completion", "accepted", "security_rejected"}, "Invalid diagnostic outcome.") require(failure is None or (outcome == "request_failed" and failure in PROVIDER_FAILURES), "Invalid diagnostic failure category.") data = {"route": route, "model": model, "outcome": outcome, "failure": failure, "http_status": http.last_status if type(http.last_status) is int and 100 <= http.last_status <= 599 else None} response = response if isinstance(response, dict) else {} choices = response.get("choices") choice = choices[0] if isinstance(choices, list) and len(choices) == 1 else None choice = choice if isinstance(choice, dict) else {} reason = choice.get("finish_reason") reasons = {"stop", "length", "tool_calls", "function_call", "content_filter", "sensitive", "model_context_window_exceeded", "network_error"} data["finish_reason"] = reason if isinstance(reason, str) and reason in reasons else "unknown" message = choice.get("message") message = message if isinstance(message, dict) else {} content = message.get("content") data["assistant_role"] = message.get("role") == "assistant" data["text_nonempty"] = isinstance(content, str) and bool(content.strip()) data["tool_or_refusal"] = bool(message.get("tool_calls") or message.get("function_call") or message.get("refusal")) usage = response.get("usage") usage = usage if isinstance(usage, dict) else {} details = usage.get("completion_tokens_details") details = details if isinstance(details, dict) else {} for name, value in (("prompt_tokens", usage.get("prompt_tokens")), ("completion_tokens", usage.get("completion_tokens")), ("total_tokens", usage.get("total_tokens")), ("reasoning_tokens", details.get("reasoning_tokens"))): data[name] = value if type(value) is int and 0 <= value <= 10_000_000 else None print("OpenCode attempt " + json_bytes(data).decode()) def infer(http, prepared, key, model, *, go_no_overage_confirmed=False, issue_kind=None): require(bool(key), "OPENCODE_API_KEY is missing; no review completed.") # Keep the existing variable compatible, but it cannot reorder the fixed policy. require(model == DEFAULT_MODEL, "OPENCODE_GO_MODEL must remain glm-5.3-flash; review order is fixed.") require(type(go_no_overage_confirmed) is bool, "Invalid no-overage confirmation.") no_secrets(prepared, (key,)) if issue_kind is None: prompt = json_bytes({"head_sha": prepared["head"], "files": prepared["files"]}).decode() system = SYSTEM else: require(issue_kind in ISSUE_KINDS and prepared["kind"] == issue_kind, "Invalid issue review kind.") prompt = json_bytes(prepared).decode() system = ISSUE_SYSTEM + ISSUE_SYSTEMS[issue_kind] session = hashlib.sha256(f'{prepared["repo"]}:{prepared["number"]}:{prepared["head"]}'.encode()).hexdigest() if issue_kind is not None: session = hashlib.sha256(f'{session}:{issue_kind}:{prepared["snapshot"]}'.encode()).hexdigest() messages = [{"role": "system", "content": system}, {"role": "user", "content": prompt}] for route, url, model_used in REVIEW_MODELS: require(go_no_overage_confirmed, "Go review blocked until Use balance is confirmed disabled; no review completed.") payload = {"model": model_used, "messages": messages, "stream": False} try: response = http.request("POST", url, key, provider=True, session=session, limit=HTTP_RESPONSE_LIMIT, payload=payload) except ProviderHTTPError as error: http.last_status = error.status attempt_metadata(http, route, model_used, "http_error") continue except ProviderError as error: attempt_metadata(http, route, model_used, "request_failed", failure=error.category) continue try: # Check the whole response, including reasoning, before any diagnostics. no_secrets(response, (key,)) content = completion_text(response, MAX_RESULT) findings = (validate_findings(json.loads(content), prepared["locations"]) if issue_kind is None else validate_issue_report(json.loads(content), prepared)) no_secrets(findings, (key,)) except SecurityError: attempt_metadata(http, route, model_used, "security_rejected") raise except (ReviewError, ValueError, TypeError, RecursionError): attempt_metadata(http, route, model_used, "invalid_completion", response) continue attempt_metadata(http, route, model_used, "accepted", response) if issue_kind is not None: return {"repo": prepared["repo"], "number": prepared["number"], "head": prepared["head"], "snapshot": prepared["snapshot"], "kind": issue_kind, "model": model_used, "report": findings} return {"repo": prepared["repo"], "number": prepared["number"], "head": prepared["head"], "model": model_used, "findings": findings} raise ReviewError("Both OpenCode Go models failed; no review completed or published.") def plain(text): # Escape all Markdown and HTML; suppress mentions and autolinks in model text. # Quotes are safe in text nodes. Numeric apostrophe entities would be broken # by the Markdown '#' escape below. Literal input entities remain literal. text = html.escape(text, quote=False).replace("@", "@\u200b").replace(":", ":\u200b").replace(".", ".\u200b") return re.sub(r"([\\`*_{}\[\]()#+!|~>\-])", r"\\\1", text) def source_link(result, item): path, line = item["path"], item["line"] link = (f'https://github.com/{result["repo"]}/blob/{result["head"]}/' f'{urllib.parse.quote(path, safe="/")}#L{line}') return f"[{plain(path)}:{line}]({link})" def review_footer(result): model = {"deepseek-v4.1-flash": "DeepSeek V4.1 Flash", "glm-5.3-flash": "GLM 5.3 Flash"}[result["model"]] label = "main" if result.get("kind") else "head" link = f'https://github.com/{result["repo"]}/commit/{result["head"]}' return f"Advisory · {model} · [{label} {result['head'][:7]}]({link})\n" def review_body(result): body = f"{MARKER}{result['head']} -->\n" for finding in result["findings"]: body += (f"- **{plain(finding['title'])}** ({source_link(result, finding)})\n" f" {plain(finding['body'])}\n") if not result["findings"]: body += "No supported findings in the supplied diff.\n" body += "\nStatic review; no tests run.\n\n" + review_footer(result) require(len(body.encode()) <= 60000, "Review body too large.") return body def publish(gh, result, head): require(isinstance(result, dict) and set(result) == {"repo", "number", "head", "model", "findings"}, "Invalid review artifact.") require(result["repo"] == gh.repo and result["number"] == gh.number and result["head"] == head, "Review artifact identity mismatch.") require(result["model"] in ALLOWED_MODELS, "Invalid artifact model.") gh.current(head) if gh.duplicate(head): raise Skip("Head already reviewed; duplicate discarded.") _, locations = collect(gh, head, context=False) validate_findings({"findings": result["findings"]}, locations) no_secrets(result, (gh.token,)) body = review_body(result) # Last network call before POST is the current-head/draft check. # GitHub has no compare-and-swap review API; commit_id still binds a race to the old SHA. gh.current(head) gh.api(f"{gh.pull}/reviews", payload={"commit_id": head, "event": "COMMENT", "body": body}) def load_json(path, limit=None): # Only trusted, workflow-generated PR context is read without a size limit. with Path(path).open("rb") as stream: raw = stream.read() if limit is None else stream.read(limit + 1) require(limit is None or len(raw) <= limit, "Local input exceeds size limit.") return json.loads(raw) def require_default_dispatch(event): require(os.environ["GITHUB_EVENT_NAME"] == "workflow_dispatch", "Manual dispatch required.") repository = event["repository"] require(repository["full_name"] == os.environ["GITHUB_REPOSITORY"], "Dispatch repository mismatch.") require(os.environ["GITHUB_REF"] == f"refs/heads/{repository['default_branch']}", "Manual review must run from the default branch.") def review_target(http, event, mode): """Authorize one explicit request; pin the API-resolved head at preparation.""" repo = os.environ["GITHUB_REPOSITORY"] event_name = os.environ["GITHUB_EVENT_NAME"] if event_name == "workflow_dispatch": require_default_dispatch(event) number_text = event.get("inputs", {}).get("pr_number") require(isinstance(number_text, str) and re.fullmatch(r"[1-9][0-9]{0,8}", number_text), "Manual PR number must be a positive canonical integer.") gh = GitHub(http, repo, int(number_text), os.environ["GH_TOKEN"]) else: require(event_name == "issue_comment", "Unsupported review event.") comment, issue = event.get("comment", {}), event.get("issue", {}) author = comment.get("user", {}) body = comment.get("body") if (event.get("action") != "created" or not issue.get("pull_request") or not isinstance(body, str) or body.strip() != "/opencode review" or author.get("type") != "User"): raise Skip("Not a human-created PR review command; no review requested.") repository = event["repository"] require(repository["full_name"] == repo, "Comment repository mismatch.") require(os.environ["GITHUB_REF"] == f"refs/heads/{repository['default_branch']}", "Comment review must run from the default branch.") login = author.get("login") require(isinstance(login, str) and re.fullmatch(r"[A-Za-z0-9-]{1,39}", login), "Invalid comment author.") gh = GitHub(http, repo, issue["number"], os.environ["GH_TOKEN"]) # Association is not authority. Check current repository access at both stages. permission = gh.api(f"{gh.root}/collaborators/{login}/permission") if permission.get("permission") not in {"write", "maintain", "admin"}: raise Skip("Review command requires repository write permission.") head = (gh.api(gh.pull)["head"]["sha"] if mode == "prepare" else os.environ.get("EXPECTED_HEAD_SHA", "")) require(isinstance(head, str) and SHA.fullmatch(head), "Invalid head SHA.") return gh, head # Issue intake shares routing, HTTP, secret checks and escaped rendering above. # No agent runtime, link fetching or issue-controlled execution exists. ISSUE_KINDS = ("product", "code") ISSUE_MARKER = "" def issue_duplicate(gh, kind, snapshot): marker = issue_marker(kind, snapshot) for page in range(1, 11): comments = gh.api(f"{gh.root}/issues/{gh.number}/comments?per_page=100&page={page}") require(isinstance(comments, list), "Invalid issue comment history.") for comment in comments: if (comment.get("user", {}).get("login") == "github-actions[bot]" and comment.get("user", {}).get("type") == "Bot" and comment.get("body", "").startswith(marker)): return True if len(comments) < 100: return False raise ReviewError("Issue comment history exceeds duplicate-check limit.") def issue_source(gh, head, path): quoted = urllib.parse.quote(path, safe="/") source = gh.api(f"{gh.root}/contents/{quoted}?ref={head}", limit=512 * 1024) require(source.get("type") == "file" and source.get("encoding") == "base64" and type(source.get("size")) is int and 0 <= source["size"] <= ISSUE_SOURCE_LIMIT, "Issue source is unavailable, oversized or not a regular file.") raw = base64.b64decode(source["content"].replace("\n", ""), validate=True) require(len(raw) == source["size"] and b"\0" not in raw, "Unsupported issue source.") return raw.decode("utf-8") def issue_excerpt(text, terms): if len(text.encode()) <= ISSUE_EXCERPT: return {"text": text, "first_line": 1, "complete": True} lines = text.splitlines(keepends=True) # Fixed deterministic selection, no model tools or issue-controlled commands. def score(index): return len(set(re.findall(r"[a-z][a-z0-9]{2,}", lines[index].lower())) & terms) anchor = max(range(len(lines)), key=score) start = max(0, anchor - 25) selected, size = [], 0 for line in lines[start:]: size += len(line.encode()) if size > ISSUE_EXCERPT: break selected.append(line) return {"text": "".join(selected), "first_line": start + 1, "complete": False} def collect_issue(gh, head, snapshot, kind): require(kind in ISSUE_KINDS and isinstance(head, str) and SHA.fullmatch(head), "Invalid issue context.") context = {} for path in ("docs/product-charter.md", "docs/architecture.md"): text = issue_source(gh, head, path) lines = text.splitlines() if kind == "code" and path.endswith("architecture.md"): text = "\n".join(lines[:135]) context[path] = {"text": text, "first_line": 1, "complete": text.splitlines() == lines} if kind == "code": commit = gh.api(f"{gh.root}/git/commits/{head}") tree_sha = commit.get("tree", {}).get("sha") require(commit.get("sha") == head and isinstance(tree_sha, str) and SHA.fullmatch(tree_sha), "Invalid main commit tree.") tree = gh.api(f"{gh.root}/git/trees/{tree_sha}?recursive=1", limit=4 * 1024 * 1024) require(tree.get("sha") == tree_sha and tree.get("truncated") is False and isinstance(tree.get("tree"), list) and len(tree["tree"]) <= 10000, "Incomplete main tree; intake refused.") paths = [item["path"] for item in tree["tree"] if item.get("type") == "blob" and item.get("mode") in {"100644", "100755"} and isinstance(item.get("path"), str) and item["path"].startswith(("src/", "tests/", "scripts/")) and item["path"].endswith((".rs", ".py", ".sh"))] terms = set(re.findall(r"[a-z][a-z0-9]{2,}", (snapshot["title"] + " " + snapshot["body"]).lower())) terms -= {"the", "and", "for", "with", "this", "that", "from", "when", "have", "not", "but", "are", "was", "kei", "issue", "test", "tests", "src", "scripts", "rs"} def score(path): words = set(re.findall(r"[a-z][a-z0-9]{2,}", path.lower())) return 1000 * (path in snapshot["body"] or path in snapshot["title"]) + len(words & terms) ranked = sorted((path for path in paths if score(path)), key=lambda path: (-score(path), path)) sources = [path for path in ranked if path.startswith(("src/", "scripts/")) and "/tests" not in path and not Path(path).name.startswith(("test_", "tests."))] tests = [path for path in ranked if path not in sources] selected = sources[:6] + tests[:4] for path in selected: text = issue_source(gh, head, path) context[path] = issue_excerpt(text, terms) selection = {"eligible_files": len(paths), "matched_files": len(ranked), "selected_files": selected, "limit": ISSUE_FILES, "method": "literal path or path-word matches; bounded issue-word source windows"} else: selection = {"method": "complete charter and architecture only"} data = {"repo": gh.repo, "number": gh.number, "head": head, "kind": kind, "snapshot": issue_fingerprint(snapshot), "issue": snapshot, "context": context, "selection": selection, "execution": "not_performed", "linked_material": "not_fetched"} no_secrets(data, (gh.token,)) require(len(json_bytes(data)) <= ISSUE_PROMPT_LIMIT, "Issue context exceeds prompt byte limit.") current_issue(gh, snapshot) issue_main(gh, head) return data def validate_issue_report(value, prepared): kind = prepared["kind"] require(kind in ISSUE_KINDS and isinstance(value, dict), "Invalid issue report.") classification = "decision" if kind == "product" else "status" fields = {classification, "summary", "rationale", "next_step", "evidence"} require(set(value) == fields, "Invalid issue report fields.") choices = ({"address", "defer", "out_of_scope", "needs_information"} if kind == "product" else {"confirmed", "plausible_unverified", "not_reproduced", "insufficient_evidence"}) require(isinstance(value[classification], str) and value[classification] in choices, "Invalid issue conclusion.") if kind == "code": require(value["status"] != "not_reproduced", "No trusted reproduction was performed.") for key in fields - {classification, "evidence"}: text = value[key] require(isinstance(text, str) and 0 < len(text.strip()) <= (600 if key == "rationale" else 240) and not any(ord(c) < 32 or ord(c) == 127 for c in text), "Invalid issue report text.") evidence = value["evidence"] require(isinstance(evidence, list) and len(evidence) <= 3, "Invalid issue evidence count.") seen = set() for item in evidence: require(isinstance(item, dict) and set(item) == {"path", "line"}, "Invalid issue evidence.") path, line = item["path"], item["line"] if not (isinstance(path, str) and path in prepared["context"] and type(line) is int and prepared["context"][path]["first_line"] <= line < prepared["context"][path]["first_line"] + len(prepared["context"][path]["text"].splitlines())): raise SecurityError("Issue evidence is outside supplied main context.") require((path, line) not in seen, "Duplicate issue evidence.") seen.add((path, line)) require(kind != "product" or bool(evidence), "Product review requires charter evidence.") require(kind != "code" or value["status"] != "confirmed" or any(item["path"].startswith(("src/", "scripts/")) for item in evidence), "Confirmed code report requires static source evidence.") no_secrets(value) require(len(json_bytes(value)) <= MAX_RESULT, "Issue report exceeds output limit.") return value def issue_body(result): kind, report = result["kind"], result["report"] title = "Product Review" if kind == "product" else "Code Validation" verdict = report["decision" if kind == "product" else "status"] classification = {"address": "Address", "defer": "Defer", "out_of_scope": "Out of scope", "needs_information": "Needs verification", "confirmed": "Confirmed by static evidence", "plausible_unverified": "Plausible, unverified", "insufficient_evidence": "Not confirmed"}[verdict] notice = " No tests or reproduction were run." if kind == "code" else "" body = (f'{issue_marker(kind, result["snapshot"])}\n' f'**{title}: {classification}.** {plain(report["summary"])}\n\n' f'{plain(report["rationale"])}{notice}\n\nNext: {plain(report["next_step"])}\n') if report["evidence"]: body += "\nEvidence: " + ", ".join(source_link(result, item) for item in report["evidence"]) + ".\n" body += "\n" + review_footer(result) require(len(body.encode()) <= 60000, "Issue comment too large.") return body def publish_issue(gh, snapshot, result, head, kind): require(isinstance(result, dict) and set(result) == {"repo", "number", "head", "snapshot", "kind", "model", "report"}, "Invalid issue artifact.") fingerprint = issue_fingerprint(snapshot) require(result["repo"] == gh.repo and type(result["number"]) is int and result["number"] == gh.number and result["head"] == head and result["kind"] == kind and result["snapshot"] == fingerprint and result["model"] in ALLOWED_MODELS, "Issue artifact identity mismatch.") current_issue(gh, snapshot) issue_main(gh, head) if issue_duplicate(gh, kind, fingerprint): raise Skip("Issue review already published; duplicate discarded.") prepared = collect_issue(gh, head, snapshot, kind) validate_issue_report(result["report"], prepared) no_secrets(result, (gh.token,)) body = issue_body(result) # No atomic issue-content/main-and-comment API exists. Body pins both identities. issue_main(gh, head) current_issue(gh, snapshot) gh.api(f"{gh.root}/issues/{gh.number}/comments", payload={"body": body}) def issue_command(http, mode): if mode == "issue-infer": prepared = load_json("issue-review-input.json", ISSUE_PROMPT_LIMIT) confirmed = os.environ.get("OPENCODE_GO_NO_OVERAGE_CONFIRMED") or "false" require(confirmed in {"true", "false"}, "Invalid no-overage configuration.") result = infer(http, prepared, os.environ.get("OPENCODE_API_KEY", ""), os.environ.get("OPENCODE_GO_MODEL") or DEFAULT_MODEL, go_no_overage_confirmed=confirmed == "true", issue_kind=os.environ["ISSUE_REVIEW_KIND"]) Path("issue-review-result.json").write_bytes(json_bytes(result)) return event = load_json(os.environ["GITHUB_EVENT_PATH"], 2 * 1024 * 1024) gh, snapshot = issue_target(http, event) fingerprint = issue_fingerprint(snapshot) current_issue(gh, snapshot) if mode == "issue-pin": head = issue_main(gh) if all(issue_duplicate(gh, kind, fingerprint) for kind in ISSUE_KINDS): raise Skip("Both issue reviews already published.") with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output: output.write(f"prepared=true\nhead={head}\nsnapshot={fingerprint}\n") return require(mode in {"issue-prepare", "issue-publish"}, "Unknown issue mode.") head, kind = os.environ["EXPECTED_MAIN_SHA"], os.environ["ISSUE_REVIEW_KIND"] require(SHA.fullmatch(head) and kind in ISSUE_KINDS and os.environ["EXPECTED_ISSUE_SNAPSHOT"] == fingerprint, "Issue intake identity mismatch.") issue_main(gh, head) if mode == "issue-prepare": if issue_duplicate(gh, kind, fingerprint): raise Skip("Issue review already published; no additional inference needed.") prepared = collect_issue(gh, head, snapshot, kind) Path("issue-review-input.json").write_bytes(json_bytes(prepared)) with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output: output.write("prepared=true\n") else: publish_issue(gh, snapshot, load_json("result/issue-review-result.json", MAX_RESULT + 1024), head, kind) def main(): # Paths/commands come only from literal base workflow steps, never PR data. mode = sys.argv[1] require(mode in {"prepare", "infer", "publish", "issue-pin", "issue-prepare", "issue-infer", "issue-publish"}, "Unknown review mode.") http = HTTP() if mode.startswith("issue-"): issue_command(http, mode) return if mode == "infer": prepared = load_json("review-input.json") # JSON object keys are strings. Restore validated integer line locations. prepared["locations"] = {p: {int(n): t for n, t in v.items()} for p, v in prepared["locations"].items()} confirmed = os.environ.get("OPENCODE_GO_NO_OVERAGE_CONFIRMED", "false") or "false" require(confirmed in {"true", "false"}, "Invalid no-overage configuration.") result = infer(http, prepared, os.environ.get("OPENCODE_API_KEY", ""), os.environ.get("OPENCODE_GO_MODEL") or DEFAULT_MODEL, go_no_overage_confirmed=confirmed == "true") Path("review-result.json").write_bytes(json_bytes(result)) print(f"Model output validated for {result['model']}; publication remains pending.") return event = load_json(os.environ["GITHUB_EVENT_PATH"], 2 * 1024 * 1024) require(mode in {"prepare", "publish"}, "Unknown review mode.") gh, head = review_target(http, event, mode) repo, number = gh.repo, gh.number if mode == "prepare": gh.current(head) if gh.duplicate(head): raise Skip("Head already reviewed; no additional request needed.") files, locations = collect(gh, head, context=True) prepared = {"repo": repo, "number": number, "head": head, "files": files, "locations": locations} Path("review-input.json").write_bytes(json_bytes(prepared)) with Path(os.environ["GITHUB_OUTPUT"]).open("a") as output: output.write(f"prepared=true\nhead={head}\n") print("Complete diff prepared from exact head; no PR code executed.") elif mode == "publish": publish(gh, load_json("result/review-result.json", MAX_RESULT + 1024), head) print("Advisory COMMENT review published for the exact head SHA.") else: raise ReviewError("Unknown review mode.") if __name__ == "__main__": try: main() except Skip as error: print(str(error)) except ReviewError as error: print(f"::error::{error}", file=sys.stderr) raise SystemExit(1) from None except Exception: # noqa: BLE001 - remote errors must never expose response bodies or credentials. # Never print provider response/error bodies, source, URLs, or tracebacks. print("::error::Review failed closed on invalid or unavailable data; no completed review confirmed.", file=sys.stderr) raise SystemExit(1) from None