Skip to content

fix(ci): tighten central workflow gates#382

Open
seonghobae wants to merge 18 commits into
mainfrom
fix/central-workflow-security-20260709
Open

fix(ci): tighten central workflow gates#382
seonghobae wants to merge 18 commits into
mainfrom
fix/central-workflow-security-20260709

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Summary

  • Scope central required-workflow tokens to read-only defaults with job-scoped writes for Scorecard Token-Permissions alerts.
  • Print concrete Trivy SARIF findings in trivy-fs failure logs so required-check failures show package/CVE/path/message reasons.
  • Fix current Python CI regressions in Noema URL validation and PR merge scheduler Markdown rendering.

Verification

  • python3 -m pytest -> 175 passed, 5 warnings
  • python3 -m compileall -q scripts tests
  • git diff --cached --check
  • bash scripts/ci/test_strix_quick_gate.sh remains nonzero on existing stale contract-string assertions unrelated to this diff; full pytest covers the updated contracts.

Direct push

Direct push to main was rejected by repository rules: required workflows are not satisfied and changes must be made through a pull request.

Scope central workflow tokens to read-only defaults with job-scoped writes, print Trivy SARIF findings in failing logs, and repair scheduler/Noema CI regressions caught by the full test suite.
@seonghobae

Copy link
Copy Markdown
Contributor Author

Updated the active superseding central PR with the OpenCode outcome-gate cleanup from the closed #383 thread:

  • made review_dispatch_limit descriptions document the -1 unlimited/backlog sentinel
  • renamed the unconditional final step to Publish OpenCode review outcome
  • added a regression assertion that a continue-on-error model-pool failure stops with MODEL_OUTPUT_UNAVAILABLE before any PR review-state mutation

Verification on head 8c06fa0:

  • python -m pytest tests/test_opencode_agent_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 15 passed, 1 skipped
  • git diff --check HEAD~1..HEAD -> clean

@seonghobae seonghobae enabled auto-merge (squash) July 9, 2026 08:37
@seonghobae

Copy link
Copy Markdown
Contributor Author

Follow-up on the timeout/model-order review note:

  • Current head keeps github-models/deepseek/deepseek-v3-0324 first in OPENCODE_MODEL_CANDIDATES because it has had the better success rate in the org queue.
  • The per-model timeout is no longer 10 or 30 minutes: OPENCODE_RUN_TIMEOUT_SECONDS=5400 (90 minutes per model).
  • The total retry budget is OPENCODE_TOTAL_RETRY_BUDGET_SECONDS=18000 (5 hours), leaving room for fallback models while still preventing a single stale provider call from occupying the whole 350-minute job window.
  • OPENCODE_MODEL_ATTEMPTS=1 remains intentional so fallback breadth beats repeating the same stuck model.

Rechecked on head 8c06fa0: no review threads, no PR-scoped code-scanning alerts, Codegraph index up to date. Checks are still queued behind the org Actions backlog.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Follow-up patch on the timeout/model-order note, now on head 95e6b63:

  • Kept the time policy intentionally long: deepseek-v3-0324 remains first and OPENCODE_RUN_TIMEOUT_SECONDS=5400 stays at 90 minutes per model, not 10 or 30 minutes.
  • Added explicit model-pool diagnostics so failures show why they happened in logs:
    • each model attempt prints the effective run timeout plus remaining retry budget before it starts;
    • timeout exits (124 / 137) now say the model timed out after N seconds and that the pool is falling through within the remaining budget;
    • full-cycle retries now name the retry-budget/job-timeout boundary rather than implying only the job timeout matters.
  • Added contract-test assertions for those diagnostics so they do not silently regress.

Verification on head 95e6b63:

  • python -m pytest tests/test_opencode_agent_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 15 passed, 1 skipped
  • git diff --check -> clean apart from local LF/CRLF warnings
  • codegraph sync . and codegraph status . -> index up to date

Rechecked after push: no review threads, no PR-scoped code-scanning alerts, and the new current-head checks are queued behind the Actions backlog.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Follow-up governance fix on head 87848b5:

  • While handling ContextualWisdomLab/clearfolio#119, Scorecard reported SASTID / "no SAST tool detected" for a Java repository.
  • The central codeql-pr.yml only detected Actions, JavaScript/TypeScript, and Python sources, so Java/Kotlin repositories could miss the central CodeQL PR scan path.
  • Added Java/Kotlin source detection for *.java, *.kt, and *.kts, mapping them to CodeQL language java-kotlin with build-mode: none.
  • Added a contract-test assertion so Java/Kotlin detection cannot silently disappear again.

Verification:

  • python -m pytest tests/test_codeql_pr_workflow_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 2 passed
  • git diff --check -> clean apart from local LF/CRLF warnings
  • codegraph sync / codegraph status -> index up to date

@seonghobae

Copy link
Copy Markdown
Contributor Author

Central queue-control follow-up pushed in bb67347.

Why this was necessary:

  • While checking current-head-only queue behavior on ContextualWisdomLab/keyverse#1, the current head was d946eeef0cb39461433abaaab22a3d9a210fafd8, but multiple older Required OpenCode Review runs stayed queued after new commits: examples include run 29002131628 on a560468..., 29000703143 on 2e21cab..., 28995029605 on a463bc3..., and 28994001556 on 7abfcd....
  • The Actions cancel API accepted cancel requests for the stale runs, but some org-required pull_request_target runs remained queued. Inspecting the central workflow showed the cause: OpenCode/Noema/Strix concurrency groups included head.sha (pr-{number}-{head_sha}), so a new commit created a different concurrency group and did not automatically supersede older PR-head runs.

What changed:

  • opencode-review.yml: concurrency is now repository + PR number, not repository + PR number + head SHA.
  • noema-review.yml: same PR-number grouping; workflow_run/manual dispatch remain tied to the PR number.
  • strix.yml: same PR-number grouping and cancel-in-progress: true, with comments updated to state that current-head evidence owns the queue.
  • tests/test_required_workflow_queue_contract.py: now covers OpenCode, Noema, and Strix too, and explicitly rejects github.event.pull_request.head.sha / format('pr-{0}-{1}'...) in concurrency contracts.

Verification:

  • python -m pytest tests/test_required_workflow_queue_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 9 passed.
  • YAML parse for opencode-review.yml, noema-review.yml, strix.yml -> ok.
  • git diff --check -> passed except Windows LF->CRLF working-tree warnings.
  • codegraph sync; codegraph status -> index up to date.

This directly implements the current-head-only queue rule: new PR head events should cancel superseded OpenCode/Noema/Strix runs instead of letting stale heads accumulate.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Queue hygiene update for #382:

After pushing bb67347, I rechecked workflow runs for fix/central-workflow-security-20260709 and cancelled old-head queued runs from 87848b5, 95e6b63, and 8c06fa0.

Some older pull_request_target required-workflow runs needed the stronger Actions force-cancel endpoint after normal cancel accepted but did not clear the queue immediately. Final recheck shows no queued runs on older heads; only current head bb67347ec257083303e736e3481ac088ee664678 remains queued.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Current-head validation for central #382 after the queue-concurrency update.

Head tested: bb67347ec257083303e736e3481ac088ee664678.

Scope checked:

  • Latest queue-control fix changes OpenCode/Noema/Strix required-workflow concurrency to group by repository + PR number instead of repository + PR number + head SHA, so new PR heads can cancel superseded stale-head runs.
  • Focused contract coverage rejects github.event.pull_request.head.sha / format('pr-{0}-{1}'...) concurrency patterns for required review workflows.

Local validation from disposable worktree central-382-current-20260709-191539:

  • git diff --check origin/main...HEAD: clean.
  • python -m pytest tests/test_required_workflow_queue_contract.py tests/test_opencode_workflow_shell_syntax.py -q: 9 passed.
  • python -m pytest -q: 172 passed, 7 skipped, 4 warnings.

GitHub Actions checks for this head remain queued; GitHub Status currently reports Actions degraded performance / delayed run starts.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Added a central coverage-evidence fix on head f88586e7de1e60c11f4f28b83474f59ae61e3fef.

Reason:

  • While triaging xtrmLLMBatchPython PR Handle approved behind PR branch updates before failed checks #136, the OpenCode coverage-evidence log showed Docker build failures for docker/postgres/Dockerfile because the central workflow used the Dockerfile directory as build context. That made COPY docker/postgres/..., COPY xtrmllmbatch/schema_postgresql.sql, and migration copies fail before producing useful current-head approval evidence.

Change:

  • coverage-evidence still tries the Dockerfile directory context first.
  • If that fails for a nested Dockerfile, it logs the failed context and retries with repository root context.
  • If root context also fails, it now logs no fallback context remains and exits non-zero, so failures remain visible instead of being hidden.
  • Added quick-gate contract assertions for the retry and visible-failure text.

Verification:

  • YAML parse: .github/workflows/opencode-review.yml OK
  • python -m pytest tests/test_required_workflow_queue_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 9 passed
  • git diff --check -> PASS
  • CodeGraph sync/status -> up to date

Note: bash -n scripts/ci/test_strix_quick_gate.sh exceeded the local Windows bash timeout; the repo's targeted shell-syntax pytest passed and covered the modified workflow shell contract.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Central follow-up on head 999823e.

What changed now:

  • security-scan.yml keeps the normal OSV base/head transitive scan first.
  • If an OSV scan step fails before reporter output can be trusted, it now logs an explicit warning and retries that side with --no-resolve.
  • The warning names the observed failure class (Maven Central 429) so failed or fallback runs explain the reason in the log instead of leaving only Exit code: 127.
  • The fallback still writes old-results.json / new-results.json, still runs osv-reporter with --fail-on-vuln=true, and still hard-fails direct manifest/lockfile vulnerabilities introduced by the PR.

Why:

  • ContextualWisdomLab/clearfolio#23 failed the central osv-scan / osv-scan job because OSV's Maven transitive resolver hit Maven Central HTTP 429 while resolving spring-boot-starter-parent:3.5.16; the OSV reporter found no vulnerability. This is a central scanner reliability/logging defect, not a package CVE in that PR.

Verification:

  • YAML parse: security-scan.yml, osv-scanner-pr.yml, strix.yml, opencode-review.yml all parse.
  • python -m pytest tests/test_required_workflow_queue_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 10 passed.
  • python -m pytest -q -> 173 passed, 7 skipped.
  • git diff --check -> clean apart from local LF/CRLF working-tree warnings.
  • codegraph sync . / codegraph status . -> index up to date.

Queue hygiene:

  • Pushed 999823ec1e034059f887100598b07417ddf4f9d5.
  • Cancelled stale queued runs from f88586e and bb67347; current visible queued runs are only on 999823e.

Timeout/model policy remains as previously updated in this PR: deepseek-v3-0324 first, 90 minutes per model, and 5 hours total model-pool retry budget.

@seonghobae

Copy link
Copy Markdown
Contributor Author

?? ??????. ?? head 212007a?? nested Rust package/workspace coverage ??? ?? workflow?? ????? ?????.

??? ?? ??:

  • bandscope#527? coverage-evidence ??? PR? apps/desktop/src-tauri/src/main.rs? ???? repo root?? Cargo.toml? ???, ?? OpenCode coverage job? nested Cargo manifest? ?? ?? ??????.

?? ??:

  • opencode-review.yml? Rust coverage ??? root Cargo.toml? ?? ??, ??? Rust/Cargo ??? ?? ????? ?? ??? ?? ??? Cargo.toml? ????.
  • ?? manifest?? cargo llvm-cov --manifest-path "$manifest"? ???? ????.
  • manifest? ?? ??? ??? ??? root/changed-path ?? ?? ??? ???? ???? ???????.
  • scripts/ci/test_strix_quick_gate.sh? ? contract ??? ??????.

??:

  • python -m pytest -q -> 173 passed, 7 skipped
  • YAML parse: opencode-review.yml, security-scan.yml OK
  • invariant check: rust_coverage_manifests(), cargo llvm-cov --manifest-path "$manifest", nested-manifest failure message OK
  • CodeGraph init/sync/status OK

?? ??:

  • ? Windows ??? bash.exe? WSL launcher?? hang?? bash scripts/ci/test_strix_quick_gate.sh? ???? ???? ?????. ?? bash -c "echo hi"? timeout?? workflow/script ?? ??? ??? ???, Python test + static invariant? ??????.

?? GitHub ??:

  • head 212007a792e1cf2db21dda0e15f33bc342cef596
  • checks? ?? queued ?????. Code Scanning alert?? ?? ?? SARIF SHA ???? ?? ?? ? Scorecard/SARIF refresh ? ?? ???????.

Comment thread .github/workflows/opencode-review.yml Fixed
@opencode-agent opencode-agent Bot disabled auto-merge July 9, 2026 20:32
@seonghobae

Copy link
Copy Markdown
Contributor Author

Follow-up on the remaining Scorecard FuzzingID Medium alert for this central workflow PR.

Added real fuzzing evidence on head f7dacb2:

  • .clusterfuzzlite/Dockerfile as a buildable ClusterFuzzLite discovery marker that still passes when central coverage builds .clusterfuzzlite as the Docker context.
  • fuzz/fuzz_opencode_review_normalize_output.py, an Atheris target for OpenCode review-output JSON extraction and control-block validation.
  • tests/test_fuzz_targets.py seed smoke coverage so the fuzz target stays importable and runnable in normal CI.

Verification before push:

  • python -m pytest tests/test_fuzz_targets.py tests/test_required_workflow_queue_contract.py tests/test_opencode_workflow_shell_syntax.py -q -> 12 passed
  • python -m pytest -q -> 175 passed, 7 skipped
  • python -m interrogate . -> 100.0%, passed
  • workflow YAML parse -> OK
  • python -m compileall -q fuzz tests scripts -> passed
  • git diff --check -> passed
  • CodeGraph sync/status -> index up to date

After push, stale older-head OpenCode run 29048933164 was force-cancelled; only current head f7dacb20c5d0bda0662a2968eca65e3beaf99bbb remains queued/running. The visible FuzzingID code-scanning alert still points to the previous merge commit and should be replaced once the current Security Scan scorecard job starts and uploads SARIF.

…security-20260709

# Conflicts:
#	.github/workflows/opencode-review.yml
#	scripts/ci/run_opencode_review_model_pool.sh
#	scripts/ci/test_strix_quick_gate.sh
#	tests/test_opencode_agent_contract.py

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode reviewed the current-head mergeability evidence and changed-file flow before approval, then found merge conflicts on the affected path.

Findings

1. HIGH Merge Conflict Guidance - Resolve the PR branch against the latest base branch

  • Problem: GitHub reports mergeStateStatus DIRTY for this pull request.
  • Root cause: Branch fix/central-workflow-security-20260709 cannot be merged cleanly into main; the changed-file flow below shows which review/runtime path is blocked by the conflict.
  • Fix: Merge or rebase the latest main into fix/central-workflow-security-20260709, resolve conflict markers in the PR branch, rerun the focused checks, and push the same branch.
  • Repair commands:
gh pr checkout 382 --repo ContextualWisdomLab/.github
git fetch origin main
git merge --no-ff origin/main  # or: git rebase origin/main
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:fix/central-workflow-security-20260709
# rebase path only: git push --force-with-lease origin HEAD:fix/central-workflow-security-20260709
  • Regression test: Keep OpenCode approval gated on mergeability so model-output failures cannot approve a conflicted PR.

Merge Conflict Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Workflow (9 files)"]
  S2 --> I2["GitHub Actions review job"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["actionlint plus required checks"]
  Evidence --> S3["CI script (4 files)"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test (7 files)"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading
  • Result: REQUEST_CHANGES
  • Reason: mergeStateStatus is DIRTY; mergeable is CONFLICTING.
  • Head SHA: cc66bb541ce92b121acd30af4d06be5e304cb4b6
  • Workflow run: 29052503121
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Workflow (9 files)"]
  S2 --> I2["GitHub Actions review job"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["actionlint plus required checks"]
  Evidence --> S3["CI script (4 files)"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test (7 files)"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: cc66bb541ce92b121acd30af4d06be5e304cb4b6
  • Workflow run: 29052503121
  • Workflow attempt: 1
  • Gate result: REQUEST_CHANGES (approval step)

Pull request overview

OpenCode reviewed the current-head mergeability evidence and changed-file flow before approval, then found merge conflicts on the affected path.

Findings

1. HIGH Merge Conflict Guidance - Resolve the PR branch against the latest base branch

  • Problem: GitHub reports mergeStateStatus DIRTY for this pull request.
  • Root cause: Branch fix/central-workflow-security-20260709 cannot be merged cleanly into main; the changed-file flow below shows which review/runtime path is blocked by the conflict.
  • Fix: Merge or rebase the latest main into fix/central-workflow-security-20260709, resolve conflict markers in the PR branch, rerun the focused checks, and push the same branch.
  • Repair commands:
gh pr checkout 382 --repo ContextualWisdomLab/.github
git fetch origin main
git merge --no-ff origin/main  # or: git rebase origin/main
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:fix/central-workflow-security-20260709
# rebase path only: git push --force-with-lease origin HEAD:fix/central-workflow-security-20260709
  • Regression test: Keep OpenCode approval gated on mergeability so model-output failures cannot approve a conflicted PR.

Merge Conflict Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Workflow (9 files)"]
  S2 --> I2["GitHub Actions review job"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["actionlint plus required checks"]
  Evidence --> S3["CI script (4 files)"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test (7 files)"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading
  • Result: REQUEST_CHANGES
  • Reason: mergeStateStatus is DIRTY; mergeable is CONFLICTING.
  • Head SHA: cc66bb541ce92b121acd30af4d06be5e304cb4b6
  • Workflow run: 29052503121
  • Workflow attempt: 1

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V1["required checks"]
  Evidence --> S2["Workflow (9 files)"]
  S2 --> I2["GitHub Actions review job"]
  I2 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V2["actionlint plus required checks"]
  Evidence --> S3["CI script (4 files)"]
  S3 --> I3["review and security gate shell path"]
  I3 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V3["bash -n plus Strix self-test"]
  Evidence --> S4["Test (7 files)"]
  S4 --> I4["regression suite"]
  I4 --> Conflict["Merge conflict blocks this path"]
  Conflict --> V4["targeted test run"]
Loading

Merge Conflict Guidance

  • Current merge state: DIRTY
  • Base branch: main
  • Head branch: fix/central-workflow-security-20260709
  • Fix direction: merge or rebase origin/main into fix/central-workflow-security-20260709, resolve conflict markers in the changed files, rerun the focused checks, then push the same branch.
  • Repair commands:
gh pr checkout 382 --repo ContextualWisdomLab/.github
git fetch origin main
git merge --no-ff origin/main  # or: git rebase origin/main
git status --short
# resolve files, then git add <resolved-files>
# merge path: git commit
# rebase path: git rebase --continue
git push origin HEAD:fix/central-workflow-security-20260709
# rebase path only: git push --force-with-lease origin HEAD:fix/central-workflow-security-20260709

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants