Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
65 changes: 7 additions & 58 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ jobs:
repository: ContextualWisdomLab/.github
fetch-depth: 1
persist-credentials: false
ref: ${{ steps.trusted_source.outputs.ref }}
ref: ${{ github.workflow_sha }}

- name: Report coverage source materialization failure
if: needs.coverage-source-tree.result != 'success'
Expand Down Expand Up @@ -1375,7 +1375,7 @@ jobs:
repository: ContextualWisdomLab/.github
fetch-depth: 0
persist-credentials: false
ref: ${{ steps.trusted_source.outputs.ref }}
ref: ${{ github.workflow_sha }}

- name: Exchange OpenCode app token for target repository review reads
id: review_read_app_token
Expand Down Expand Up @@ -1605,62 +1605,11 @@ jobs:
run: |
set -euo pipefail
context_env_file="${RUNNER_TEMP:-.}/opencode-review-context.env"
python3 <<'PY' >"$context_env_file"
import json
import os
import re
import sys

event_path = os.environ.get("GITHUB_EVENT_PATH")
if not event_path:
print("::error::GITHUB_EVENT_PATH is not available for OpenCode review context resolution.", file=sys.stderr)
raise SystemExit(1)

try:
with open(event_path, encoding="utf-8") as handle:
event = json.load(handle)
except (OSError, json.JSONDecodeError) as exc:
print(f"::error::Could not read GitHub event payload for OpenCode review context: {exc}", file=sys.stderr)
raise SystemExit(1)

inputs = event.get("inputs") or {}
pull_request = event.get("pull_request") or {}
base = pull_request.get("base") or {}
head = pull_request.get("head") or {}
base_repo = base.get("repo") or {}
values = {
"GH_REPOSITORY": str(
base_repo.get("full_name") or inputs.get("target_repository") or os.environ.get("GITHUB_REPOSITORY") or ""
).strip(),
"PR_NUMBER": str(pull_request.get("number") or inputs.get("pr_number") or "").strip(),
"PR_BASE_SHA": str(base.get("sha") or inputs.get("pr_base_sha") or "").strip(),
"PR_HEAD_SHA": str(head.get("sha") or inputs.get("pr_head_sha") or "").strip(),
}
values["HEAD_SHA"] = values["PR_HEAD_SHA"]

validators = {
"GH_REPOSITORY": r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+",
"PR_NUMBER": r"[1-9][0-9]*",
"PR_BASE_SHA": r"[0-9a-fA-F]{40}",
"PR_HEAD_SHA": r"[0-9a-fA-F]{40}",
"HEAD_SHA": r"[0-9a-fA-F]{40}",
}
for name, pattern in validators.items():
if not re.fullmatch(pattern, values[name]):
print(f"::error::Invalid OpenCode review context value for {name}.", file=sys.stderr)
raise SystemExit(1)

for name, value in values.items():
print(f"{name}={value}")
PY
while IFS='=' read -r name value; do
case "$name" in
GH_REPOSITORY|PR_NUMBER|PR_BASE_SHA|PR_HEAD_SHA|HEAD_SHA)
printf -v "$name" '%s' "$value"
export "$name"
;;
esac
done <"$context_env_file"
python3 scripts/ci/opencode_review_context.py \
--event-path "$GITHUB_EVENT_PATH" \
--env-file "$context_env_file"
# shellcheck source=/dev/null
. "$context_env_file"
printf 'Resolved bounded OpenCode review context for %s#%s at %s.\n' \
"$GH_REPOSITORY" "$PR_NUMBER" "$PR_HEAD_SHA"

Expand Down
4 changes: 4 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Historical false-positive GitHub-token fixtures from scheduler secret-scrubbing tests.
# The live tests now construct these token-like strings at runtime; new findings remain blocking.
995d6b3606e0effe6722c422b369da9ef0171824:tests/test_pr_review_merge_scheduler.py:github-pat:2900
995d6b3606e0effe6722c422b369da9ef0171824:tests/test_pr_review_merge_scheduler.py:github-pat:2908
995d6b3606e0effe6722c422b369da9ef0171824:tests/test_pr_review_merge_scheduler.py:github-pat:2923
995d6b3606e0effe6722c422b369da9ef0171824:tests/test_pr_review_merge_scheduler.py:github-pat:2928
123bddb83426e21367f61affa004f9259b101fe8:tests/test_pr_review_merge_scheduler.py:github-pat:224
123bddb83426e21367f61affa004f9259b101fe8:tests/test_pr_review_merge_scheduler.py:github-pat:227
14655a9304c2dbe1e2ad6c963af4a2a0b7bd4b89:tests/test_pr_review_merge_scheduler.py:github-pat:2770
Expand Down
92 changes: 92 additions & 0 deletions scripts/ci/opencode_review_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Resolve bounded OpenCode review context from a GitHub event payload."""

from __future__ import annotations

import argparse
import json
import os
import re
import shlex
import sys
from collections.abc import Mapping, Sequence
from pathlib import Path


CONTEXT_VALIDATORS = {
"GH_REPOSITORY": re.compile(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+\Z"),
"PR_NUMBER": re.compile(r"[1-9][0-9]*\Z"),
"PR_BASE_SHA": re.compile(r"[0-9a-fA-F]{40}\Z"),
"PR_HEAD_SHA": re.compile(r"[0-9a-fA-F]{40}\Z"),
"HEAD_SHA": re.compile(r"[0-9a-fA-F]{40}\Z"),
}


def load_event(path: Path) -> Mapping[str, object]:
"""Load a GitHub event payload as a JSON object."""
try:
event = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
print(f"::error::Could not read GitHub event payload for OpenCode review context: {exc}", file=sys.stderr)
raise SystemExit(1) from exc
if not isinstance(event, dict):
print("::error::GitHub event payload for OpenCode review context was not a JSON object.", file=sys.stderr)
raise SystemExit(1)
return event


def object_value(value: object) -> Mapping[str, object]:
"""Return object mappings and coerce every other JSON value to an empty object."""
return value if isinstance(value, dict) else {}


def resolve_context(event: Mapping[str, object], default_repository: str) -> dict[str, str]:
"""Resolve and validate the OpenCode review context values."""
inputs = object_value(event.get("inputs"))
pull_request = object_value(event.get("pull_request"))
base = object_value(pull_request.get("base"))
head = object_value(pull_request.get("head"))
base_repo = object_value(base.get("repo"))
values = {
"GH_REPOSITORY": str(
base_repo.get("full_name") or inputs.get("target_repository") or default_repository or ""
).strip(),
"PR_NUMBER": str(pull_request.get("number") or inputs.get("pr_number") or "").strip(),
"PR_BASE_SHA": str(base.get("sha") or inputs.get("pr_base_sha") or "").strip(),
"PR_HEAD_SHA": str(head.get("sha") or inputs.get("pr_head_sha") or "").strip(),
}
values["HEAD_SHA"] = values["PR_HEAD_SHA"]
for name, pattern in CONTEXT_VALIDATORS.items():
if not pattern.fullmatch(values[name]):
print(f"::error::Invalid OpenCode review context value for {name}.", file=sys.stderr)
raise SystemExit(1)
return values


def write_shell_exports(path: Path, values: Mapping[str, str]) -> None:
"""Write validated values as shell export statements."""
path.write_text(
"".join(f"export {name}={shlex.quote(value)}\n" for name, value in values.items()),
encoding="utf-8",
)


def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--event-path", required=True, type=Path)
parser.add_argument("--env-file", required=True, type=Path)
parser.add_argument("--default-repository", default=os.environ.get("GITHUB_REPOSITORY", ""))
return parser.parse_args(argv)


def main(argv: Sequence[str] | None = None) -> int:
"""Resolve context files for the OpenCode review workflow."""
args = parse_args(argv)
event = load_event(args.event_path)
values = resolve_context(event, args.default_repository)
write_shell_exports(args.env_file, values)
return 0


if __name__ == "__main__":
raise SystemExit(main())
3 changes: 2 additions & 1 deletion scripts/ci/opencode_review_normalize_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
r"(?![A-Za-z0-9_])"
r"|(?<![A-Za-z0-9_])(?:Dockerfile|Makefile|README|LICENSE|AGENTS\.md)(?![A-Za-z0-9_])"
)
BULLET_PREFIX_PATTERN = re.compile(r"^[-*+]\s+")

APPROVAL_VERIFICATION_LABELS = (
"approval sufficiency:",
Expand Down Expand Up @@ -530,7 +531,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
4 changes: 2 additions & 2 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$workflow_file" "covr package_coverage unavailable after package tests; treating missing-line report as advisory." "opencode R package coverage does not block on covr installation reproduction after tests pass"
assert_file_contains "$workflow_file" "R coverage tooling packages unavailable after install" "opencode R coverage verifies covr/testthat are loadable after installation"
assert_file_contains "$workflow_file" "repository: ContextualWisdomLab/.github" "opencode required workflow checks out the central source repository"
assert_file_contains "$workflow_file" 'ref: ${{ steps.trusted_source.outputs.ref }}' "opencode required workflow checks out the resolved central ref"
assert_file_contains "$workflow_file" 'ref: ${{ github.workflow_sha }}' "opencode required workflow checks out the resolved central workflow SHA"
assert_file_contains "$workflow_file" "target_repository:" "opencode workflow_dispatch can target a repository whose PR does not inherit required workflows"
assert_file_contains "$workflow_file" "Materialize pull request merge tree for coverage measurement" "opencode coverage measures the PR merge tree instead of exposing secrets to untrusted checkout actions"
assert_file_contains "$workflow_file" 'TARGET_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.event.inputs.target_repository || github.repository }}' "opencode pull_request_target coverage fetches exact base/head commits from the target repository"
Expand Down Expand Up @@ -685,7 +685,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$workflow_file" "Coverage merge tree could not be materialized" "coverage evidence logs an actionable merge-tree failure reason"
assert_file_contains "$workflow_file" "--require-hashes" "coverage tooling installs from a hash-pinned lock"
assert_file_contains "$workflow_file" "--only-binary=:all: -r requirements-opencode-review-ci-hashes.txt" "coverage tooling installs only binary packages from the pinned lock"
assert_file_contains "$workflow_file" 'ref: ${{ steps.trusted_source.outputs.ref }}' "OpenCode review checks out central trusted scripts for same-head validation"
assert_file_contains "$workflow_file" 'ref: ${{ github.workflow_sha }}' "OpenCode review checks out central trusted scripts for same-head validation"
assert_file_contains "$workflow_file" 'COVERAGE_EVIDENCE_RESULT: ${{ needs.coverage-evidence.result || '\''skipped'\'' }}' "opencode approval receives the coverage-evidence job conclusion"
assert_file_contains "$workflow_file" 'PR_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.inputs.pr_base_sha }}' "coverage evidence receives the PR base SHA for changed-file scoped measurement"
assert_file_contains "$workflow_file" "emit_captured_log()" "coverage evidence emits captured command logs through a shared first-and-tail helper"
Expand Down
10 changes: 7 additions & 3 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,14 @@ def is_reasoning_capable(model_name: str) -> bool:


def test_opencode_trusted_source_ref_is_not_controlled_by_workflow_inputs():
"""Resolve trusted source checkouts from workflow identity, not dispatch input."""
"""Check out trusted source directly from the workflow identity SHA."""
workflow = Path(".github/workflows/opencode-review.yml").read_text(encoding="utf-8")

assert "canonical_ref:" not in workflow
assert "INPUT_CANONICAL_REF" not in workflow
assert "github.event.inputs.canonical_ref" not in workflow
assert "steps.trusted_source.outputs.ref" not in workflow
assert workflow.count("ref: ${{ github.workflow_sha }}") == 2
assert workflow.count("JOB_CONTEXT_JSON: ${{ toJSON(job) }}") == 2
assert workflow.count("GITHUB_CONTEXT_JSON: ${{ toJSON(github) }}") == 2
assert workflow.count('job_context.get("workflow_sha") or github_context.get("workflow_sha")') == 2
Expand All @@ -158,8 +160,10 @@ def test_opencode_bounded_evidence_context_is_resolved_from_event_payload():
assert "PR_BASE_SHA: ${{ github.event.pull_request" not in step
assert "PR_HEAD_SHA: ${{ github.event.pull_request" not in step
assert "HEAD_SHA: ${{ github.event.pull_request" not in step
assert "GITHUB_EVENT_PATH" in step
assert "Invalid OpenCode review context value for" in step
assert "python3 scripts/ci/opencode_review_context.py" in step
assert "--event-path \"$GITHUB_EVENT_PATH\"" in step
assert "printf -v" not in step
assert "event.get(\"pull_request\")" not in step
assert "Resolved bounded OpenCode review context for %s#%s at %s." in step
assert "GITHUB_ENV" not in step

Expand Down
Loading
Loading