Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
9 commits
Select commit Hold shift + click to select a range
3924177
๋ณด์•ˆ ํ–ฅ์ƒ: CI ์Šคํฌ๋ฆฝํŠธ์˜ subprocess ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ฐ ๋ฏผ๊ฐ ์ •๋ณด ์ œ๊ฑฐ
seonghobae Jun 29, 2026
48698aa
Merge remote-tracking branch 'origin/main' into pr-117
seonghobae Jun 29, 2026
983559f
๋ณด์•ˆ ํ–ฅ์ƒ: CI ์Šคํฌ๋ฆฝํŠธ์˜ subprocess ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋ฐ ๋ฏผ๊ฐ ์ •๋ณด ์ œ๊ฑฐ
seonghobae Jun 29, 2026
c9c017f
Resolve merge conflicts with origin/main
Copilot Jul 1, 2026
77dc0c1
Increase OpenCode model pool retry resilience
Copilot Jul 1, 2026
db69a32
๐Ÿ›ก๏ธ Sentinel: [๋ณด์•ˆ ํ–ฅ์ƒ] CI ์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์„ธ์Šค ์ถœ๋ ฅ ๋‚ด ๋ฏผ๊ฐ ์ •๋ณด ๋งˆ์Šคํ‚น ์ ์šฉ
seonghobae Jul 1, 2026
56a9a47
๐Ÿ›ก๏ธ Sentinel: [๋ณด์•ˆ ํ–ฅ์ƒ] CI ์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ ๋กœ๊น… ๋ฐ ํ”„๋กœ์„ธ์Šค ์ถœ๋ ฅ ๋‚ด ๋ฏผ๊ฐ ์ •๋ณด ์œ ์ถœ ๋ฐฉ์ง€
seonghobae Jul 1, 2026
6da3a2e
๐Ÿ›ก๏ธ Sentinel: [๋ฒ„๊ทธ ์ˆ˜์ •] JSON ๋””์ฝ”๋”ฉ ์ค‘๋ณต ๋ฐฉ์ง€ (์„ฑ๋Šฅ ๋ฐ ๋™์ž‘ ๊ฐœ์„ )
seonghobae Jul 1, 2026
dd9cff9
๐Ÿ›ก๏ธ Sentinel: [๋ณด์•ˆ ํ–ฅ์ƒ] CI ์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์„ธ์Šค ์ถœ๋ ฅ ๋‚ด ๋ฏผ๊ฐ ์ •๋ณด ๋งˆ์Šคํ‚น ์ ์šฉ
seonghobae Jul 1, 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
14 changes: 7 additions & 7 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2239,21 +2239,21 @@ jobs:
id: opencode_review_model_pool
if: needs.coverage-evidence.result == 'success'
continue-on-error: true
timeout-minutes: 20
timeout-minutes: 60
env:
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
GITHUB_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
USE_GITHUB_TOKEN: "true"
SHARE: "false"
NPM_CONFIG_IGNORE_SCRIPTS: "true"
NO_COLOR: "1"
OPENCODE_MODEL_CANDIDATES: "github-models/openai/gpt-5-nano"
OPENCODE_MODEL_ATTEMPTS: "1"
OPENCODE_RUN_TIMEOUT_SECONDS: "240"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "360"
OPENCODE_MODEL_CANDIDATES: "github-models/openai/gpt-5-chat github-models/openai/gpt-5-mini github-models/openai/gpt-5-nano github-models/openai/o3 github-models/openai/o3-mini github-models/openai/o4-mini 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"
OPENCODE_MODEL_ATTEMPTS: "2"
OPENCODE_RUN_TIMEOUT_SECONDS: "600"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "180"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "3600"
OPENCODE_BACKOFF_INITIAL_SECONDS: "30"
OPENCODE_BACKOFF_MAX_SECONDS: "30"
OPENCODE_BACKOFF_MAX_SECONDS: "300"
OPENCODE_FIRST_ATTEMPT_AGENT: ci-review
OPENCODE_AGENT: ci-review-fallback
OPENCODE_EVIDENCE_FILE: ${{ runner.temp }}/opencode-review-evidence.md
Expand Down
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@
**Vulnerability:** Server-Side Request Forgery (SSRF) / Local File Inclusion
**Learning:** Functions that fetch URLs provided via user inputs (e.g., `wait_for_url` fetching `--backend-ready-url` in CI scripts) can inadvertently read local files if they do not validate the scheme. Python's `urllib.request.urlopen` supports `file://` schemes, allowing attackers to access arbitrary file contents from the host machine or sandbox if they can control the URL parameter.
**Prevention:** Always validate URL inputs to restrict allowed schemes. Check that URLs explicitly start with `http://` or `https://` before fetching them with standard libraries like `urllib`.
## 2026-06-29 - Prevent Silent Failure by Capturing stderr in CI Scripts
**Vulnerability:** Silent Failure / Secret Leakage Risk
**Learning:** In `scripts/ci/opencode_review_approve_gate.sh`, `subprocess.run` dropped `stderr` entirely (`stderr=subprocess.DEVNULL`). This hides potential Git errors and causes maintainability regressions. Blindly logging `stderr` instead, however, risks leaking sensitive credentials injected by GitHub Actions.
**Prevention:** Capture `stderr` and filter out known credential patterns (e.g., bearer credentials, GitHub PATs) before writing errors to `sys.stderr`. Never drop `stderr` completely on subprocess failures.
26 changes: 2 additions & 24 deletions PR_GOVERNANCE_AUDIT.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ onboarding exception before relying on autonomous PR queue draining.
| Bucket | Repositories | Scheduler implication |
|---|---|---|
| Public target repos with central required Strix, OpenCode, and scheduler | `.github`, `ContextualWisdomLab.github.io`, `appguardrail`, `bandscope`, `clearfolio`, `codec-carver`, `contextual-orchestrator`, `hyosung-itx-slogan-brief`, `naruon`, `newsdom-api`, `pg-erd-cloud`, `scopeweave` | Treat central required workflows as the rollout mechanism. Do not add repo-local copies only to satisfy governance. |
| Public target repos missing central required Strix, OpenCode, and scheduler | `aFIPC` | Do not drain or merge the PR queue until organization ruleset `18156473` targets the default branch and produces current-head central review evidence. |
| Public target repos with repo-local Strix/OpenCode/scheduler copies | `.github`, `ContextualWisdomLab.github.io`, `appguardrail`, `clearfolio`, `codec-carver`, `naruon`, `newsdom-api`, `pg-erd-cloud`, `scopeweave` | Retire thick local copies only after central required workflow runs prove stable for that repo's current heads. |
| Public target repos with partial or no local governance workflow footprint | `bandscope`, `contextual-orchestrator`, `hyosung-itx-slogan-brief` | They are still centrally governed by ruleset `18156473`; local absence is not a required-workflow gap. |
| Private target repos missing central required workflow onboarding | `xtrmLLMBatchPython` | Treat missing central Strix/OpenCode/scheduler checks as an organization ruleset onboarding gap. Do not bypass review or weaken repository approval rules to drain the queue. |
Expand All @@ -161,7 +160,6 @@ onboarding exception before relying on autonomous PR queue draining.
| Repo | Flow | Default | Auto | Central required workflows | Repo rules/protection | Repo required checks | Stale dismissal | Open PRs | Local workflow footprint | Recent merged actor |
|---|---:|---:|---:|---|---|---|---:|---:|---|---|
| `ContextualWisdomLab/.github` | GitHub Flow | `main` | on | Strix; OpenCode; scheduler | `Lock default branch` | none | ruleset true | 25 | Copilot; OpenCode Review; PR Review Merge Scheduler; Strix Security Scan | #80 `seonghobae`; #79 `seonghobae`; #78 `seonghobae` |
| `ContextualWisdomLab/aFIPC` | GitHub Flow | `master` | off | missing on PR #78 | repo ruleset `PR` only | `check`, `quality`, `secret-and-workflow-audit` | ruleset false | 1 | CodeQL; Dependency Review; R-CMD-check; quality/security audit | #45 `seonghobae`; #43 `seonghobae`; #38 `seonghobae` |
| `ContextualWisdomLab/ContextualWisdomLab.github.io` | GitHub Flow | `main` | on | Strix; OpenCode; scheduler | `Lock default branch` | none | ruleset true | 9 | Copilot; OpenCode Review; PR Review Merge Scheduler; Strix Security Scan; Pages | #25 `seonghobae`; #15 `seonghobae`; #14 `seonghobae` |
| `ContextualWisdomLab/appguardrail` | Git Flow | `develop` | on | Strix; OpenCode; scheduler | `Lock default branch`, `PR` | none | mixed: true/false by repo ruleset | 0 | CodeQL; OpenCode Review; PR Review Merge Scheduler; release/security; Strix Security Scan | #133 `seonghobae`; #131 `seonghobae`; #115 `seonghobae` |
| `ContextualWisdomLab/bandscope` | Git Flow | `develop` | on | Strix; OpenCode; scheduler | `Lock default branch`; classic branch protection | `CodeQL`, `ci / build-and-test`, `dependency-review`, `gate / build / macos`, `gate / build / windows`, `release-preflight`, `sbom`, `security-audit`, `trivy-fs-scan` | ruleset true; classic false | 81 | OpenCode Review; PR Review Merge Scheduler; many app/security workflows | #451 `github-actions`; #459 `seonghobae`; #458 `seonghobae` |
Expand Down Expand Up @@ -224,7 +222,6 @@ both separately; a change can improve one while harming the other.
| `ContextualWisdomLab.github.io` | Site and documentation changes make reader-facing UX review concrete. | Review comments that say only that a check failed do not help the site reader or maintainer understand the issue. | Treat documentation clarity, homepage behavior, and status-check explanations as UX surfaces. |
| `hyosung-itx-slogan-brief` | The repo now inherits the central required workflows and has local review/merge workflow names without heavier required checks, which makes it a lightweight GitHub Flow fixture. | It lacks the default-branch lock/stale-dismissal policy used by most organization repos. | Leave autonomous merge disabled unless that policy gap is intentional; otherwise add the standard default-branch lock before relying on autonomous merge. |
| `contextual-orchestrator` | It now inherits central required workflows without carrying local governance workflow copies, which is the desired no-copy posture. | With no local branch lock, no stale-dismissal policy, no auto-merge, and no open PRs, inherited checks alone do not prove useful runtime behavior. | Use the next real PR as a proof fixture; add a default-branch lock only if autonomous merge is desired. |
| `aFIPC` | It has real PR pressure and a domain-specific requirement: fixed parameter item calibration changes must reproduce true parameters before estimates can be trusted. | PR #78 shows the central required workflows are absent; the repo ruleset requires only local checks and zero approvals, so a direct merge would bypass the central review contract. | Add or repair the organization required-workflow ruleset target for `master`, then require current-head OpenCode approval, Strix, scheduler, and the true-parameter FIPC test before merging lower-number PRs. |

## Current Scheduler Contract

Expand Down Expand Up @@ -300,35 +297,17 @@ PR #381: wait: OpenCode review is already in progress
4. Treat fork and non-fork repositories uniformly for onboarding. At runtime,
classify only the PR head mutation capability: observable/reviewable,
updateable, auto-mergeable, or mergeable.
5. Do not leave an active public fork PR queue in the inventory-only state.
When a public fork such as `html4tree` has open PRs targeting the
organization-owned fork, it must either be included in the organization required-workflow ruleset
for Strix, OpenCode Review, and PR Review Merge
Scheduler, or carry a temporary thin caller that invokes the central
`.github` workflows until the ruleset can cover it. The fork label is not a
reason to merge without same-head central review evidence.
6. Keep repo-specific product/build/autofix/security workflows repo-local only
5. Keep repo-specific product/build/autofix/security workflows repo-local only
when they are not part of the governance contract. `pg-erd-cloud` autofix
stays repo-local; Strix, OpenCode review, and PR review/merge governance
should not.
7. Use `contextual-orchestrator` as the no-copy onboarding fixture when it next
6. Use `contextual-orchestrator` as the no-copy onboarding fixture when it next
has a real PR. It now inherits central required workflows, but lacks
repo-local branch-lock/stale-dismissal policy and has no open PR to prove
runtime behavior.

## Remaining Proof Gaps

- 2026-06-29 KST `html4tree` onboarding gap: PR #3 is the lowest open PR and is
cleanly mergeable by GitHub, but current head
`d0c4cbc2bb267aed407e4bf6308f4f3cfd3b504c` has no check runs and no reviews.
The PR title claims an XSS/attribute-injection fix, while the diff only
changes indentation in `src/main/kotlin/html4tree/util.kt`. This proves that
`html4tree` cannot be merged by queue order until central Strix, OpenCode
Review, and scheduler evidence run on the same head and OpenCode either
requests changes or approves real code/test evidence. The required process
repair is to add `html4tree` to the organization required-workflow target set
or add a temporary thin caller that delegates to `.github`; do not bypass the review gate
with a manual or forced merge.
- 2026-06-26 17:53 KST continuation snapshot: `.github` PR #68 is merged at merge commit `590b4ecb2ac9eac700019a183081309e28d8f25b`; `bandscope` PR #459 is merged at merge commit `a7173e45304d8681f02fdf43e4de5a6b6540bb44`; `.github` PR #79 and #80 are merged, and organization ruleset `18156473` now requires central Strix, OpenCode, and scheduler workflows from `.github@807254a04efafd5f806e0f70cb067ecf050cfd11`. The live organization target inventory contains 12 public non-fork repositories and confirms `appguardrail` is present while `VibeSec` is not in that set.
- PR #80 proved the no-copy required-workflow path after the ruleset update: `scan-pr-queue` ran as a required check in `ContextualWisdomLab/.github`, passed in 7s, used `PULL_REQUEST_NUMBER=80`, and reported `OpenCode review is already in progress` instead of scanning or mutating the entire queue. The same PR passed central Strix in 3m20s and OpenCode in 4m36s on current head `23ee41076b8f3cec21cff3afd3cd5b4380decf12`.
- `bandscope` scheduler run `28192186833` is the current live fixture. PR #450 produced conflict guidance with `gh pr checkout 450`, `git fetch origin develop`, merge-or-rebase, `git status --short`, same-branch push, and `--force-with-lease` only for rebase. PR #451 and PR #446 were updated through the workflow `GITHUB_TOKEN`; the resulting head commits were authored by `github-actions[bot]`.
Expand All @@ -347,7 +326,6 @@ PR #381: wait: OpenCode review is already in progress
- `naruon` PR #756 completed the repo-local rollout for the scheduler contract. Its initial head failed backend governance and Scorecard because `actions: write`/`contents: write` were broader than the repo policy allows; the amended and merged head restores minimal `GITHUB_TOKEN` permissions, keeps `trigger_reviews` and `enable_auto_merge` defaulted off, keeps `update_branches` defaulted on, and still dry-runs PR #694/#721 as `update_branch`.
- `update-branch` `422/403` now has a safe fixture: unit tests simulate both permission-denied and stale `expected_head_sha` failures, assert they become `action_error`, and assert later PRs are still inspected. A real live `422/403` case is still useful as operational evidence, but it is no longer missing from the decision contract test surface.
- `bandscope` PR #378 exposed a self-referential failed-check loop after manual retry run `28155083916`: the retry run succeeded and approved step execution, but the check rollup still contained the cancelled older `OpenCode Review/opencode-review` run `28152862698`, so OpenCode posted current-head `CHANGES_REQUESTED` review `4569063977` with the banned generic `No deterministic missing-string markers...` text. The collector now excludes OpenCode's own check by check name and by both actual (`OpenCode Review`) and legacy (`OpenCode PR Review`) workflow names before failed-check fallback evidence is built.
- `aFIPC` PR #78 is the current negative fixture for target coverage drift: head `bc78373f59310b6fbee76d1a5a72fb3d84fc84eb` has local `check`, `quality`, and `secret-and-workflow-audit` checks, but no central `opencode-review`, `strix`, or `scan-pr-queue`; repository ruleset `12815994` requires zero approving reviews. This PR must not be merged until organization required-workflow evidence exists on the current head.
- Public repo drift is real, not hypothetical: only `.github` matched the central scheduler/workflow byte-for-byte in the 2026-06-26 scan. Some drift is policy-specific and should not be overwritten blindly, but `bandscope` had behaviorally unsafe drift and now has PR #459 merged downstream.
- The previous drift response still over-indexed on copying. `bandscope` PR
#460 proved the correction: even when the copied scheduler produced the right
Expand Down
1 change: 0 additions & 1 deletion requirements-opencode-review-ci.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
coverage==7.14.3
interrogate==1.7.0
pytest==9.1.1
uv==0.11.25
35 changes: 32 additions & 3 deletions scripts/ci/emit_opencode_failed_check_fallback_findings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,31 @@ emit_pytest_failure_findings() {
return 0
fi

check_label="GitHub Check"
step_label="test step"
check_label="$(
awk '
/^## Failed check: / {
sub(/^## Failed check: /, "")
print
exit
}
' "$clean_file"
)"
if [ -z "$check_label" ]; then
check_label="GitHub Check"
fi
step_label="$(
awk '
/^- step [0-9]+: / {
sub(/^- step [0-9]+: /, "")
sub(/ \(failure\)$/, "")
print
exit
}
' "$clean_file"
)"
if [ -z "$step_label" ]; then
step_label="test step"
fi
term="$(
perl -ne 'if (/assert [\x27"]([^\x27"]+)[\x27"] not in/) { print "$1\n"; exit }' "$clean_file"
)"
Expand Down Expand Up @@ -552,7 +575,13 @@ emit_cancelled_check_findings() {
if [ -z "$check_label" ]; then
continue
fi
printf 'Non-source-backed cancelled check queue state: %s reported %s. Wait for or rerun the newest same-head check; no repository source edit is justified by this cancelled check alone.\n' "$check_label" "$annotation" >&2
finding_index=$((finding_index + 1))
printf '### %s. MEDIUM GitHub Checks queue - %s was cancelled by a newer queued request\n' "$finding_index" "$check_label"
printf -- '- Problem: `%s` did not produce reviewable source evidence; GitHub reported `%s`.\n' "$check_label" "$annotation"
printf -- '- Root cause: GitHub Actions cancelled an older queued or running check because a higher-priority request for the same PR was waiting. This is a check orchestration state, not a source-code defect.\n'
printf -- '- Fix: Do not approve from this cancelled context and do not paste only the workflow URL. Wait for the newest same-head check run, or rerun the check after the queue settles, then review its actual logs.\n'
printf -- '- Regression test: Keep failed-check fallback reviews explaining cancelled check contexts separately from source-code findings so cancelled jobs cannot hide an actionable pytest or Strix failure.\n'
printf -- '- Suggested edit: no repository source edit is justified by this cancelled check alone; the actionable next step is to rerun or wait for the current-head check that superseded it.\n\n'
done <"$cancelled_file"
}

Expand Down
41 changes: 27 additions & 14 deletions scripts/ci/opencode_review_approve_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,32 +162,45 @@ def normalized_line(value: str) -> str:
return " ".join(value.strip().split())


def scrub_sensitive_data(text: str | None) -> str | None:
if not text:
return text
text = re.sub(r'(?i)(bearer\s+)[^\s"\'\\]+', r'\1***', text)
text = re.sub(r'(?i)(token\s+)[^\s"\'\\]+', r'\1***', text)
text = re.sub(r'(ghp_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+)', '***', text)
return text
Comment on lines +167 to +173

def changed_new_lines(path_value: str) -> set[int]:
if not pr_base_sha or not pr_head_sha:
return set()
try:
argv = [
"git",
"-C",
str(source_root),
"diff",
"--unified=0",
"--no-ext-diff",
pr_base_sha,
pr_head_sha,
"--",
path_value,
]
completed = subprocess.run(
[
"git",
"-C",
str(source_root),
"diff",
"--unified=0",
"--no-ext-diff",
pr_base_sha,
pr_head_sha,
"--",
path_value,
],
argv,
check=False,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
capture_output=True,
shell=False,
)
except OSError:
return set()

if completed.returncode not in {0, 1}:
if completed.stderr:
scrubbed_args = scrub_sensitive_data(" ".join(argv))
scrubbed_stderr = scrub_sensitive_data(completed.stderr)
sys.stderr.write(f"Command failed ({completed.returncode}): {scrubbed_args}\n{scrubbed_stderr}\n")
return set()

line_numbers: set[int] = set()
Expand Down
Loading
Loading