Skip to content

Commit 04c7d29

Browse files
committed
fix(code-review): fullscan Claude 400 사유 노출 + 프롬프트 상한 축소
- call_claude: HTTPError 시 응답 본문을 읽어 'Anthropic API 400: <사유>'로 노출 (기존엔 'HTTP Error 400'만 떠서 모델/길이 원인 불명이었음). - main: 호출 전 모델·프롬프트 크기 로그 + 실패 시 힌트(모델 id / 프롬프트 길이). - DEFAULT_TOTAL_MAX 200K→120K (프롬프트 과대 400 방지).
1 parent fbc149f commit 04c7d29

1 file changed

Lines changed: 21 additions & 4 deletions

File tree

scripts/code_review_fullscan.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import json
1616
import os
1717
import sys
18+
import urllib.error
1819
import urllib.request
1920

2021
# 소스 코드로 볼 확장자(로직 취약점 리뷰 대상). 문서/락파일/바이너리는 제외.
@@ -28,7 +29,7 @@
2829
".next", ".nuxt", "target", "bin", "obj", ".terraform", "migrations", "backups",
2930
}
3031
PER_FILE_MAX = 60_000 # 파일당 상한(대형 생성물 제외)
31-
DEFAULT_TOTAL_MAX = 200_000 # 1회 전송 총량 상한(토큰·비용 통제)
32+
DEFAULT_TOTAL_MAX = 120_000 # 1회 전송 총량 상한(토큰·비용·400 방지)
3233

3334
_SCHEMA_HINT = (
3435
'Return ONLY JSON: {"findings":[{"file":"path","line":N,"severity":"HIGH|MEDIUM|LOW",'
@@ -128,8 +129,16 @@ def call_claude(api_key: str, model: str, prompt: str, *, max_tokens: int = 4096
128129
headers={"x-api-key": api_key, "anthropic-version": "2023-06-01",
129130
"content-type": "application/json"},
130131
)
131-
with urllib.request.urlopen(req, timeout=180) as resp: # noqa: S310 (fixed host)
132-
data = json.loads(resp.read())
132+
try:
133+
with urllib.request.urlopen(req, timeout=180) as resp: # noqa: S310 (fixed host)
134+
data = json.loads(resp.read())
135+
except urllib.error.HTTPError as exc: # 400 등 — 실제 사유(모델/길이)를 노출
136+
detail = ""
137+
try:
138+
detail = exc.read().decode("utf-8", "replace")[:600]
139+
except Exception:
140+
detail = getattr(exc, "reason", "")
141+
raise RuntimeError(f"Anthropic API {exc.code}: {detail}") from exc
133142
chunks = [c.get("text", "") for c in data.get("content", []) if c.get("type") == "text"]
134143
return "".join(chunks)
135144

@@ -164,10 +173,18 @@ def main() -> int:
164173
print("스캔할 소스 파일 없음 — 0건으로 기록")
165174
findings: list[dict] = []
166175
else:
176+
prompt = build_prompt(files)
177+
print(f"Claude 호출: 모델={model}, 프롬프트≈{len(prompt):,}자")
167178
try:
168-
findings = parse_findings(call_claude(api_key, model, build_prompt(files)))
179+
findings = parse_findings(call_claude(api_key, model, prompt))
169180
except Exception as exc:
170181
print(f"Claude 리뷰 실패: {exc}", file=sys.stderr)
182+
msg = str(exc).lower()
183+
if "model" in msg:
184+
print("힌트: CLAUDE_MODEL 을 계정에서 지원하는 모델 id로 지정하세요 "
185+
"(예: claude-sonnet-4-5, 워크플로 env CLAUDE_MODEL).", file=sys.stderr)
186+
elif "long" in msg or "max" in msg or "token" in msg:
187+
print("힌트: 프롬프트가 큽니다 — DEFAULT_TOTAL_MAX 를 더 낮추세요.", file=sys.stderr)
171188
return 1
172189
print(f"findings: {len(findings)}건 (모델 {model})")
173190
try:

0 commit comments

Comments
 (0)