Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d454e86
⚡ Bolt: 텍스트 파싱 루프 성능 최적화 (정규식 사전 컴파일)
seonghobae Jul 8, 2026
236a8aa
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 9, 2026
0b02a23
Fix gh_error_is_rate_limited command not found in CI
seonghobae Jul 9, 2026
fb14488
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 9, 2026
87d2603
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 9, 2026
421663e
Fix coverage CI failures caused by out-of-sync tests and unreachable …
seonghobae Jul 9, 2026
4d55d8f
fix(opencode): rebase regex precompile on current gates
seonghobae Jul 11, 2026
15df43f
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 11, 2026
66bb84e
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 11, 2026
7bbd72e
Merge branch 'main' into bolt-regex-precompile-17843440529708631255
opencode-agent[bot] Jul 11, 2026
2d7ac09
fix(actions): avoid dynamic trusted checkout refs
seonghobae Jul 11, 2026
485b0cf
fix(strix): keep base smoke contract stable
seonghobae Jul 11, 2026
9595826
Merge remote-tracking branch 'origin/main' into codex-pr380-regex-clean
seonghobae Jul 11, 2026
d4e10bf
Merge remote-tracking branch 'origin/main' into codex-pr380-regex-clean
seonghobae Jul 11, 2026
995d6b3
Fix opencode-review failure caused by SSRF validation bypass
seonghobae Jul 11, 2026
dd647ce
Revert "Fix opencode-review failure caused by SSRF validation bypass"
seonghobae Jul 11, 2026
9732975
fix(tests): avoid secret-like PAT literals
seonghobae Jul 11, 2026
7224e06
Merge remote-tracking branch 'origin/main' into codex-pr380-regex-clean
seonghobae Jul 11, 2026
5daeae6
fix(secret-scan): ignore reverted fake PAT fixtures
seonghobae Jul 11, 2026
c97cc67
Merge remote-tracking branch 'origin/main' into codex-pr380-regex-clean
seonghobae Jul 11, 2026
b3efbec
Merge remote-tracking branch 'origin/main' into codex-pr380-after-441
seonghobae Jul 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 23 additions & 78 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,6 @@ jobs:
needs: [coverage-evidence]
if: >-
always()
&& needs.coverage-evidence.result != 'cancelled'
&& (
github.event_name == 'workflow_dispatch'
|| (
Expand Down Expand Up @@ -2007,7 +2006,7 @@ jobs:
"$schema": "https://opencode.ai/config.json",
"model": "github-models/deepseek/deepseek-r1-0528",
"small_model": "github-models/deepseek/deepseek-v3-0324",
"enabled_providers": ["openai", "github-models"],
"enabled_providers": ["github-models"],
"lsp": true,
"mcp": {
"codegraph": {
Expand Down Expand Up @@ -2133,50 +2132,6 @@ jobs:
}
},
"provider": {
"openai": {
"npm": "@ai-sdk/openai",
"name": "OpenAI (direct)",
"options": {
"baseURL": "https://api.openai.com/v1",
"apiKey": "{env:OPENAI_API_KEY}"
},
"models": {
"gpt-5": {
"name": "OpenAI GPT-5 (direct)",
"tool_call": true,
"reasoning": true,
"options": {
"reasoningEffort": "high"
},
"variants": {
"high": {
"reasoningEffort": "high"
}
},
"limit": {
"context": 400000,
"output": 128000
}
},
"gpt-5-mini": {
"name": "OpenAI GPT-5 Mini (direct)",
"tool_call": true,
"reasoning": true,
"options": {
"reasoningEffort": "high"
},
"variants": {
"high": {
"reasoningEffort": "high"
}
},
"limit": {
"context": 400000,
"output": 128000
}
}
}
},
"github-models": {
"npm": "@ai-sdk/openai-compatible",
"name": "GitHub Models",
Expand Down Expand Up @@ -2384,44 +2339,31 @@ jobs:
env:
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
GITHUB_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
# Native OpenAI backend for the lead review model. GitHub Models
# rate-limits every request and caps bodies at ~4000 tokens, so the
# rate-starved shared pool never returned a verdict; hitting
# api.openai.com directly with the org OPENAI_API_KEY gives the lead
# model a working, un-throttled backend. Resolves {env:OPENAI_API_KEY}
# in the opencode.jsonc "openai" provider block.
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
USE_GITHUB_TOKEN: "true"
SHARE: "false"
NPM_CONFIG_IGNORE_SCRIPTS: "true"
NO_COLOR: "1"
# Lead with the NATIVE OpenAI backend (openai/gpt-5-mini, openai/gpt-5
# via api.openai.com with the org OPENAI_API_KEY). GitHub Models
# rate-limited ("Too many requests") and 4000-token-capped
# (413 tokens_limit_reached) EVERY model in the shared pool, so the
# reviewer never produced a verdict and every run hung to the 350-min
# timeout — a 100% org-wide failure. The native provider is not subject
# to those limits, so it can actually complete and approve. The
# existing github-models entries stay as fallbacks (tried only if the
# native key is missing or the direct call fails).
# github-models ordering rationale (unchanged): contract-reliable mini
# reasoning models first, high-quota non-reasoning models next, and the
# rate-starved github-models flagships (gpt-5/o3, 8-12 req/day) last so
# a throttled/hung leader always falls back instead of eating the step.
OPENCODE_MODEL_CANDIDATES: "openai/gpt-5-mini openai/gpt-5 github-models/openai/o4-mini github-models/openai/o3-mini github-models/openai/gpt-5-mini github-models/openai/gpt-5-nano github-models/openai/gpt-5-chat github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1 github-models/deepseek/deepseek-v3-0324 github-models/mistral-ai/mistral-medium-2505 github-models/meta/llama-4-maverick-17b-128e-instruct-fp8 github-models/meta/llama-4-scout-17b-16e-instruct github-models/openai/o3 github-models/openai/gpt-5"
# Ordered contract-reliability first, then quota, with the rate-starved
# flagships last. The mini reasoning models (o4-mini, o3-mini, gpt-5-
# mini/nano/chat) reliably emit the strict review contract — every
# required label and only source-backed findings — so they lead. The
# high-quota non-reasoning models (deepseek-v3, mistral, llama-4) emit
# bare or hallucinated reviews the publish/approve gates reject, so
# they are fallbacks only. gpt-5/o3 ("Reasoning" tier, 8-12 req/day)
# stay last: first-placing them stalled every review until timeout
# because a rate-limited/hung flagship never fell back.
OPENCODE_MODEL_CANDIDATES: "github-models/openai/o4-mini github-models/openai/o3-mini github-models/openai/gpt-5-mini github-models/openai/gpt-5-nano github-models/openai/gpt-5-chat github-models/deepseek/deepseek-r1-0528 github-models/deepseek/deepseek-r1 github-models/deepseek/deepseek-v3-0324 github-models/mistral-ai/mistral-medium-2505 github-models/meta/llama-4-maverick-17b-128e-instruct-fp8 github-models/meta/llama-4-scout-17b-16e-instruct github-models/openai/o3 github-models/openai/gpt-5"
# One attempt per model, then fall through to the next model. Retrying
# the SAME model 5x let a rate-limited/hung leader consume the whole
# step, so the pool never reached a healthy fallback model.
OPENCODE_MODEL_ATTEMPTS: "1"
# 15 min per model — enough for a bounded review attempt, but short
# enough that a hung provider yields to the next candidate before it
# freezes the review queue.
OPENCODE_RUN_TIMEOUT_SECONDS: "900"
# 90 min per model — generous for a deep tool-using review, but bounded
# so a rate-limited model yields to the next one instead of eating the
# 350-min step. (20400s = 340min gave one model the entire budget with
# no fallback; 600s was too short for a proper review.)
OPENCODE_RUN_TIMEOUT_SECONDS: "5400"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"
# Bound provider/model-pool outages before the 350-min job timeout. A
# zero budget disables the script deadline and caused org-wide hangs.
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "2700"
OPENCODE_POOL_MAX_CYCLES: "1"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "0"
OPENCODE_BACKOFF_INITIAL_SECONDS: "30"
OPENCODE_BACKOFF_MAX_SECONDS: "30"
OPENCODE_FIRST_ATTEMPT_AGENT: ci-review
Expand Down Expand Up @@ -2790,9 +2732,6 @@ jobs:
CHECK_LOOKUP_GH_TOKEN: ${{ github.token }}
GH_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.event.inputs.target_repository || github.repository }}
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
# Exposed so the "openai" provider in opencode.jsonc resolves during the
# failed-check diagnosis opencode run that shares this config.
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCODE_APP_TOKEN: ${{ steps.opencode_app_token.outputs.token }}
OPENCODE_EVIDENCE_FILE: ${{ runner.temp }}/opencode-review-evidence.md
OPENCODE_FAILED_CHECK_EVIDENCE_FILE: ${{ runner.temp }}/opencode-failed-check-evidence.md
Expand Down Expand Up @@ -2869,6 +2808,12 @@ jobs:
fi
}

gh_error_is_rate_limited() {
local error_file="$1"
[ -s "$error_file" ] || return 1
grep -Eiq '(API rate limit exceeded|rate limit exceeded|secondary rate limit)' "$error_file"
}

emit_change_flow_mermaid_graph() {
local merge_state="${1:-UNKNOWN}"
local changed_files_file surfaces_file idx next_node
Expand Down
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@
## 2026-07-02 - Credential Masking Security Hole in Subprocess Environments
**Learning:** Found a critical missing credential masking pattern in `scripts/ci/noema_review_gate.py`'s `scrub_sensitive_data` which didn't mask `Authorization: Basic` or `Proxy-Authorization: Basic` tokens unlike its analogous helper in `scripts/ci/pr_review_merge_scheduler.py`. This leaves exception messages and logs vulnerable to exposing sensitive credentials when HTTP operations fail.
**Action:** When implementing credential masking functions that sanitize tracebacks and log messages, ensure the masking scope includes all relevant headers, particularly `Authorization` and `Proxy-Authorization`. Ensure parity across masking helpers across CI scripts to prevent blind spots.
## 2026-07-08 - Pre-compile Regex Patterns for Parsing Functions
**Learning:** Found an anti-pattern where regex replacements were compiled inside the loop by calling `re.sub(pattern, ...)` dynamically within string manipulation functions like `clean` and `starts_new_field` during CI log processing in bash-embedded inline Python.
**Action:** When a Python script performs intensive text parsing across multiple lines, pre-compile all regexes globally via `re.compile` and apply them via the `.sub` and `.match` methods to skip compilation overhead.
3 changes: 3 additions & 0 deletions scripts/ci/noema_review_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ def call_llm(repo: str, number: int, pr: dict[str, Any], diff: str, truncated: b
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_unspecified:
raise ValueError("URL cannot target internal IP addresses")

if not (api_url.startswith("http://") or api_url.startswith("https://")):
raise ValueError(f"NOEMA_LLM_API_URL must start with http:// or https:// to prevent SSRF vulnerabilities, got: {api_url}")

prompt = {
"role": "user",
"content": "\n".join(
Expand Down
5 changes: 4 additions & 1 deletion scripts/ci/opencode_review_normalize_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
r"|(?<![A-Za-z0-9_])(?:Dockerfile|Makefile|README|LICENSE|AGENTS\.md)(?![A-Za-z0-9_])"
)

# ⚡ Bolt: Pre-compile regex for deep scanning loops
BULLET_PREFIX_PATTERN = re.compile(r"^[-*+]\s+")

APPROVAL_VERIFICATION_LABELS = (
"approval sufficiency:",
"verification posture:",
Expand Down Expand Up @@ -530,7 +533,7 @@ def changed_files_from_evidence(text: str) -> list[str]:
line = raw_line.strip()
if not line or line.startswith("#"):
continue
line = re.sub(r"^[-*+]\s+", "", line)
line = BULLET_PREFIX_PATTERN.sub("", line)
parts = line.split("\t")
path = parts[-1].strip()
if not path or path.startswith("["):
Expand Down
28 changes: 1 addition & 27 deletions scripts/ci/run_opencode_review_model_pool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,6 @@ is_context_overflow_failure() {
grep -Eiq 'ContextOverflowError|tokens_limit_reached|Request body too large|context window' "$opencode_json_file"
}

is_direct_openai_candidate() {
case "$1" in
openai/*) return 0 ;;
*) return 1 ;;
esac
}

should_skip_model_candidate() {
local model_candidate="$1"

if is_direct_openai_candidate "$model_candidate" && [ -z "${OPENAI_API_KEY:-}" ]; then
printf 'Skipping OpenCode %s because OPENAI_API_KEY is not configured; falling back to the next provider-qualified candidate.\n' "$model_candidate"
return 0
fi
return 1
}

run_one_model_attempt() {
local model_candidate="$1"
local attempt="$2"
Expand Down Expand Up @@ -186,13 +169,12 @@ run_one_model_attempt() {

main() {
local attempts budget_seconds deadline now remaining model_candidate attempt safe_model prompt_file candidate_output_file
local opencode_json_file opencode_export_file agent retry_sleep original_run_timeout run_status cycle_sleep cycle max_cycles
local opencode_json_file opencode_export_file agent retry_sleep original_run_timeout run_status cycle_sleep cycle
local -a model_candidates

attempts="${OPENCODE_MODEL_ATTEMPTS:-3}"
original_run_timeout="${OPENCODE_RUN_TIMEOUT_SECONDS:-900}"
budget_seconds="${OPENCODE_TOTAL_RETRY_BUDGET_SECONDS:-18000}"
max_cycles="${OPENCODE_POOL_MAX_CYCLES:-0}"
deadline=0
if [ "$budget_seconds" -gt 0 ]; then
deadline=$((SECONDS + budget_seconds))
Expand All @@ -210,9 +192,6 @@ main() {
while :; do
printf 'Starting OpenCode model pool cycle %s.\n' "$cycle"
for model_candidate in "${model_candidates[@]}"; do
if should_skip_model_candidate "$model_candidate"; then
continue
fi
assert_reasoning_effort_for_candidate "$model_candidate"
safe_model="${model_candidate//\//-}"
prompt_file="${RUNNER_TEMP}/opencode-review-${safe_model}-prompt.md"
Expand Down Expand Up @@ -264,11 +243,6 @@ main() {
done

printf 'OpenCode completed a full model-candidate cycle without a valid control conclusion; continuing until a model succeeds or the GitHub Actions job timeout is reached.\n'
if [ "$max_cycles" -gt 0 ] && [ "$cycle" -ge "$max_cycles" ]; then
printf 'OpenCode model pool reached configured max cycle count %s without a valid control conclusion.\n' "$max_cycles"
record_review_model ""
exit 1
fi
cycle_sleep="${OPENCODE_POOL_CYCLE_SLEEP_SECONDS:-60}"
if [ "$deadline" -gt 0 ] && [ $((SECONDS + cycle_sleep)) -gt "$deadline" ]; then
cycle_sleep=$((deadline - SECONDS))
Expand Down
Loading
Loading