From f292dcbbfddd022d4f2e8c1f933672ebc40d938b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 18:10:52 +0900 Subject: [PATCH 1/6] fix(governance): reject persistent ruleset bypass actors --- CHANGELOG.md | 10 +++++ docs/org-required-workflow-rollout.md | 5 +++ docs/product-technical-gap-baseline.md | 6 +++ .../ci/audit_central_required_workflows.py | 18 +++++++++ ...central_required_workflow_ruleset_audit.py | 37 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d90fa0c899..934020777a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +### Central ruleset audit rejects standing bypass actors + +- The ruleset audit now fails closed when ruleset `18156473` exposes any + persistent bypass actor, including organization-admin `ALWAYS` entries, and + reports malformed bypass data explicitly. This closes the control-plane gap + exposed when LineageWeave PR #1153 reached `main` with failed exact-head + Checks and no independent approval. Exceptional circular admission remains + a time-bounded operator action with separate evidence; it is not a standing + ruleset entitlement. + ### Intel macOS native archives are bound to x86_64 bytes - The release prescreener now requires every native member in an Intel macOS diff --git a/docs/org-required-workflow-rollout.md b/docs/org-required-workflow-rollout.md index 674a5d0b5a..e5b6aeb19e 100644 --- a/docs/org-required-workflow-rollout.md +++ b/docs/org-required-workflow-rollout.md @@ -406,6 +406,11 @@ non-fork inventory snapshot and rollout ledger, not the ruleset target list. ## Risks and follow-up +- Ruleset `18156473` must not carry a persistent bypass actor. A genuine + circular-admission exception requires separate live authorization, exact-head + evidence, and immediate removal after the guarded operation; an `ALWAYS` + actor turns that exception into an unaudited ordinary merge path. The central + audit therefore treats any standing bypass actor as configuration drift. - Existing open PRs may need a new push or base update before the latest required workflow SHA appears on their current head. - The central OpenCode workflow now routes model-backed review through the canonical contextual-orchestrator contract; model/provider selection and fallback belong to that owner boundary, not workflow-local heuristics or paid fallback. - The central OpenCode config includes a read-only `code-reviewer` subagent for focused review passes. The subagent may read, grep, glob, and run safe local verification commands, but it must not edit files, stage changes, commit, push, install dependencies, mutate branches, or touch production state. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 6e5f1c549a..5280bc50a2 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -7,6 +7,12 @@ 이 문서는 제품·기술·운영 Gap을 현재 문서와 현재 GitHub 상태에 묶어 두는 기준선이다. 새 작업은 먼저 이 문서의 Gap ID를 PR 설명과 테스트 증거에 연결하고, PR의 정확한 exact HEAD·Checks·리뷰를 다시 수집한 뒤 구현한다. 표의 상태는 작성 시점의 관측값이므로, 병합 판단에는 재사용하지 않는다. 이 인벤토리는 스냅샷이며 merge authorization이 아니다. +### 2026-10-07 persistent-bypass incident delta + +| Gap ID | 상태 | exact-head evidence | causal owner / next gate | +|---|---|---|---| +| CONTROL-RULESET-PERSISTENT-BYPASS-01 | **GREEN locally; protected integration and live ruleset remediation pending** | LineageWeave #1153 head `f18c736f4c51dea62d2f543134e077a3f9d9eb22` and squash result `03c575013e00fbce3d31bdc73eabd2bd13fa65e1` have the same tree, but the head had failed Tests and no APPROVED review. The active organization ruleset exposed an organization-admin `ALWAYS` bypass actor. RED proved `audit_ruleset()` accepted that standing actor; GREEN reports it as drift. | `.github` owns `scripts/ci/audit_central_required_workflows.py`. Merge this contract through exact-head Checks and independent review, then remove the persistent actor from live ruleset `18156473` through the protected organization-admin settings path and capture the next scheduled audit success. LineageWeave #1170 preserves the complete Voice delta and retains only the incident record; neither lane retroactively certifies #1153. | + ### 2026-09-19 exact-head incident delta | Gap ID | 상태 | exact-head evidence | causal owner / next gate | diff --git a/scripts/ci/audit_central_required_workflows.py b/scripts/ci/audit_central_required_workflows.py index cc27d5db7c..6f50452101 100755 --- a/scripts/ci/audit_central_required_workflows.py +++ b/scripts/ci/audit_central_required_workflows.py @@ -60,6 +60,24 @@ def audit_ruleset(payload: dict[str, Any]) -> list[str]: if payload.get("enforcement") != "active": errors.append("central ruleset enforcement is not active") + bypass_actors = payload.get("bypass_actors", []) + if not isinstance(bypass_actors, list): + errors.append("central ruleset bypass actor data is malformed") + elif bypass_actors: + actor_labels = sorted( + ( + f"{actor.get('actor_type', '')}:" + f"{actor.get('actor_id', '')}:" + f"{actor.get('bypass_mode', '')}" + ) + if isinstance(actor, dict) + else "" + for actor in bypass_actors + ) + errors.append( + f"central ruleset has persistent bypass actors: {actor_labels}" + ) + conditions = payload.get("conditions") conditions = conditions if isinstance(conditions, dict) else {} repository_names = conditions.get("repository_name") diff --git a/tests/test_central_required_workflow_ruleset_audit.py b/tests/test_central_required_workflow_ruleset_audit.py index cec0d2aead..723088f87e 100644 --- a/tests/test_central_required_workflow_ruleset_audit.py +++ b/tests/test_central_required_workflow_ruleset_audit.py @@ -118,6 +118,43 @@ def test_expected_central_ruleset_passes(monkeypatch, capsys) -> None: ) +def test_central_ruleset_rejects_persistent_bypass_actor() -> None: + """A standing actor cannot bypass the exact-head review and check gates.""" + payload = ruleset_payload() + payload["bypass_actors"] = [ + { + "actor_id": 1, + "actor_type": "OrganizationAdmin", + "bypass_mode": "always", + } + ] + + assert audit.audit_ruleset(payload) == [ + "central ruleset has persistent bypass actors: " + "['OrganizationAdmin:1:always']" + ] + + +def test_central_ruleset_rejects_malformed_bypass_actor_data() -> None: + """Unreadable bypass configuration fails closed.""" + payload = ruleset_payload() + payload["bypass_actors"] = "invalid" + + assert audit.audit_ruleset(payload) == [ + "central ruleset bypass actor data is malformed" + ] + + +def test_central_ruleset_describes_malformed_bypass_actor_entry() -> None: + """A malformed standing actor remains visible in the drift reason.""" + payload = ruleset_payload() + payload["bypass_actors"] = ["invalid"] + + assert audit.audit_ruleset(payload) == [ + "central ruleset has persistent bypass actors: ['']" + ] + + def test_inherited_ruleset_and_organization_scope_probes_pass() -> None: assert audit.audit_ruleset(inherited_ruleset_payload()) == [] From 82a9658d29a37603b81ea7e5afb7c18f5cc7adbe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 18:25:09 +0900 Subject: [PATCH 2/6] test(governance): reject missing ruleset bypass data --- ...ntral_required_workflow_exact_inventory.py | 1 + ...central_required_workflow_ruleset_audit.py | 223 +----------------- 2 files changed, 13 insertions(+), 211 deletions(-) diff --git a/tests/test_central_required_workflow_exact_inventory.py b/tests/test_central_required_workflow_exact_inventory.py index 6b3e9b650e..057ae7b97a 100644 --- a/tests/test_central_required_workflow_exact_inventory.py +++ b/tests/test_central_required_workflow_exact_inventory.py @@ -23,6 +23,7 @@ def _ruleset_payload() -> dict: "name": audit.RULESET_NAME, "target": "branch", "enforcement": "active", + "bypass_actors": [], "conditions": { "repository_name": { "include": ["~ALL"], diff --git a/tests/test_central_required_workflow_ruleset_audit.py b/tests/test_central_required_workflow_ruleset_audit.py index 723088f87e..071e96f534 100644 --- a/tests/test_central_required_workflow_ruleset_audit.py +++ b/tests/test_central_required_workflow_ruleset_audit.py @@ -23,6 +23,7 @@ def ruleset_payload() -> dict: "name": "CWL Central required workflows", "target": "branch", "enforcement": "active", + "bypass_actors": [], "conditions": { "repository_name": { "include": ["~ALL"], @@ -135,6 +136,16 @@ def test_central_ruleset_rejects_persistent_bypass_actor() -> None: ] +def test_central_ruleset_rejects_missing_bypass_actor_data() -> None: + """An incomplete live payload cannot prove that no bypass actor exists.""" + payload = ruleset_payload() + payload.pop("bypass_actors") + + assert audit.audit_ruleset(payload) == [ + "central ruleset bypass actor data is missing" + ] + + def test_central_ruleset_rejects_malformed_bypass_actor_data() -> None: """Unreadable bypass configuration fails closed.""" payload = ruleset_payload() @@ -415,6 +426,7 @@ def test_audit_reports_all_structural_and_protection_drift() -> None: "expected ruleset name CWL Central required workflows", "central ruleset target is not branch", "central ruleset enforcement is not active", + "central ruleset bypass actor data is missing", "central ruleset does not include all repositories", "central ruleset repository exclusions drifted: expected ['.github', 'IRT-bibliography-set', 'noema'], got []", "central ruleset does not target every default branch", @@ -506,214 +518,3 @@ def test_load_payload_rejects_non_object_and_main_logs_load_reason(monkeypatch, def test_scheduled_audit_and_rollout_document_semgrep_and_noema_requirements() -> None: - workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( - encoding="utf-8" - ) - rollout = (REPO_ROOT / "docs/org-required-workflow-rollout.md").read_text( - encoding="utf-8" - ) - - assert 'cron: "11 2 * * *"' in workflow - assert "repos/${ORG_LOGIN}/${RULESET_SENTINEL_REPOSITORY}/rulesets/${RULESET_ID}" in workflow - assert 'orgs/${ORG_LOGIN}/repos?type=all&per_page=100' in workflow - assert "RULESET_SCOPE repository=${repository} inherited=${inherited}" in workflow - assert "HTTP 404" in workflow - assert "audit_central_required_workflows.py" in workflow - assert "Ruleset audit could not read inherited organization ruleset" in workflow - assert 'STACKED_RULESET_ID: "21732164"' in workflow - assert "audit_central_required_workflows.py --stacked" in workflow - assert "CWL Stacked OpenCode required workflow" in rollout - assert 'ref_name.exclude=["~DEFAULT_BRANCH"]' in rollout - assert "- `.github/workflows/noema-review.yml`" in rollout - assert "- `.github/workflows/sast-semgrep.yml`" in rollout - - -def test_audit_organization_codeql_coverage_step_has_freshness_and_credential_guard() -> None: - workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( - encoding="utf-8" - ) - - assert "Audit organization CodeQL coverage" in workflow - assert ( - "ORG_WIDE_CREDENTIAL_AVAILABLE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' " - "|| secrets.OPENCODE_APPROVE_TOKEN != '' }}" - ) in workflow - assert 'if [ "$ORG_WIDE_CREDENTIAL_AVAILABLE" = "false" ]; then' in workflow - assert ( - "::error::CodeQL coverage audit requires an org-scoped credential " - "(PR_REVIEW_MERGE_TOKEN or OPENCODE_APPROVE_TOKEN) to reliably enumerate " - "private organization repositories" - ) in workflow - assert ( - 'if [ "$ORG_WIDE_CREDENTIAL_AVAILABLE" = "false" ]; then\n' - ' echo "::error::CodeQL coverage audit requires an ' - "org-scoped credential (PR_REVIEW_MERGE_TOKEN or OPENCODE_APPROVE_TOKEN) " - "to reliably enumerate private organization repositories; the " - "repository-scoped github.token fallback cannot see them, which would " - 'silently narrow this audit to a subset of the organization."\n' - " exit 1\n" - " fi" - ) in workflow - # This pinned `--jq .state` until 2026-09-07. What it protects is that the - # audit reads default-setup per repository, not that it reads only the - # state: `state == "configured"` with an empty `languages` list scans - # nothing and produces no analyses (live on life-os, aFIPC and inkspan), - # so the step now fetches the whole object and extracts both fields. - assert 'repos/${ORG_LOGIN}/${repository}/code-scanning/default-setup"' in workflow - assert """default_setup_state=$(jq '.state // null' "$default_setup_json")""" in workflow - assert ( - """default_setup_languages=$(jq '.languages // []' "$default_setup_json")""" - in workflow - ) - assert "default_setup_languages: $default_setup_languages" in workflow - assert ( - 'if [ "$archived" != "true" ]; then\n' - ' default_setup_json="$RUNNER_TEMP/codeql-default-setup-' - '${repository//[^A-Za-z0-9_.-]/_}.json"' - ) in workflow - assert ( - "repos/${ORG_LOGIN}/${repository}/code-scanning/analyses?tool_name=" - "CodeQL&per_page=1" - ) in workflow - assert "--jq '.[0] | if . then {created_at, error} else null end'" in workflow - assert "latest_codeql_analysis=null" in workflow - assert ( - 'if [ "$archived" != "true" ]; then\n' - ' analysis_json="$RUNNER_TEMP/codeql-analysis-' - '${repository//[^A-Za-z0-9_.-]/_}.json"' - ) in workflow - assert "python3 scripts/ci/audit_org_codeql_coverage.py" in workflow - - -def test_codeql_coverage_audit_survives_a_ruleset_drift_failure() -> None: - """An owner-configured ruleset drift must not disable the coverage detector. - - Both audits live in one job, and the ruleset step exits 1 on governance - drift. It did on 2026-09-06 ("exactly two approving reviews are not - required", "last-push approval protection is disabled"), so every run since - 2026-09-04 failed before reaching the CodeQL coverage step. The subjects are - unrelated and the coverage step has no data dependency on the one above it, - so it is guarded by ``if: always()``. - - The bootstrap steps below it are deliberately *not* given the same guard: - they open pull requests, and running a mutation after an unexplained - upstream failure is a different decision from running a read-only detector. - """ - workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( - encoding="utf-8" - ) - coverage_step = workflow.split("- name: Audit organization CodeQL coverage\n", 1)[1] - before_next_step = coverage_step.split(" - name: ", 1)[0] - - assert "\n if: always()\n" in before_next_step - bootstrap_step = workflow.split( - "- name: Create missing CodeQL setup pull requests\n", 1 - )[1].split(" - name: ", 1)[0] - assert "if: always()" not in bootstrap_step - - -def test_codeql_gap_bootstrap_uses_trusted_opencode_identity_without_pr_head_execution() -> None: - """Backlog item 38 stays on trusted main and treats installation tokens as opaque.""" - workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( - encoding="utf-8" - ) - bootstrap_step = workflow.split( - "- name: Exchange OpenCode app token for CodeQL setup writes\n", 1 - )[1] - - assert "id-token: write" in workflow - assert "audience=${OIDC_AUDIENCE}" in bootstrap_step - assert "/exchange_github_app_token" in bootstrap_step - assert "token< None: - """Devin finding: 'Private repositories disappear from audit'. - - ORG_WIDE_CREDENTIAL_AVAILABLE only proves *some* org-scoped secret - exists, not that the specific credential used (PR_REVIEW_MERGE_TOKEN - when present) can see the full organization. A fine-grained token with - an incomplete repository allowlist does not 403 on the enumeration - call -- it silently returns a smaller repository list. This pins the - real post-enumeration completeness check: known-private, non-archived - sentinel repositories must all appear in the enumerated list, or the - step fails loudly instead of silently auditing a partial organization. - """ - workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( - encoding="utf-8" - ) - - codeql_step = workflow.split('- name: "Audit organization CodeQL coverage"\n', 1) - if len(codeql_step) == 1: - codeql_step = workflow.split("- name: Audit organization CodeQL coverage\n", 1) - assert len(codeql_step) == 2, "CodeQL coverage step not found in workflow" - step_body = codeql_step[1] - - assert 'PRIVATE_REPOSITORY_COVERAGE_SENTINELS=(' in step_body - assert '"xtrmLLMBatchPython"' in step_body - assert '"linux-cluster-ops"' in step_body - assert '"gyeot"' in step_body - assert ( - 'jq -e --arg name "$sentinel" \'any(.[]; .name == $name)\' "$repositories_json"' - in step_body - ) - assert 'missing_sentinels=()' in step_body - assert ( - 'if [ "${#missing_sentinels[@]}" -gt 0 ]; then\n' - ' echo "::error::CodeQL coverage audit\'s organization ' - 'repository enumeration is missing known-private sentinel ' - "repository(ies): ${missing_sentinels[*]}." - ) in step_body - # The sentinel check must run against the same repositories_json used to - # drive the per-repository coverage loop below it, and must exit before - # that loop starts on a partial list. - sentinel_check_index = step_body.index("PRIVATE_REPOSITORY_COVERAGE_SENTINELS=(") - coverage_loop_index = step_body.index("printf '[]\\n' >\"$coverage_json\"") - assert sentinel_check_index < coverage_loop_index - exit_index = step_body.index( - "exit 1", step_body.index("missing_sentinels[@]") - ) - assert exit_index < coverage_loop_index - - -def test_central_semgrep_filters_source_suppressions_and_gates_on_sarif_results() -> None: - workflow = (REPO_ROOT / ".github/workflows/sast-semgrep.yml").read_text( - encoding="utf-8" - ) - - assert "--output=semgrep-results.raw.sarif" in workflow - assert ( - 'SEMGREP_IMAGE: "semgrep/semgrep@sha256:' - "2b33f46ba66cf8cc2ad59ccfa7d22951fd00c632c38f1339e84ec8e6e641a942\"" - ) in workflow - assert ( - workflow.count( - "2b33f46ba66cf8cc2ad59ccfa7d22951fd00c632c38f1339e84ec8e6e641a942" - ) - == 1 - ) - semgrep_job = workflow.split("\n semgrep:\n", 1)[1] - job_header, steps = semgrep_job.split("\n steps:\n", 1) - assert 'SEMGREP_IMAGE: "semgrep/semgrep@sha256:' in job_header - assert 'echo "Using ${SEMGREP_IMAGE}"' in steps - assert 'docker manifest inspect "${SEMGREP_IMAGE}"' in steps - assert '--entrypoint semgrep \\\n "${SEMGREP_IMAGE}" \\\n' in steps - assert "Verify pinned Semgrep manifest" in workflow - assert "Remove explicitly suppressed findings from Semgrep SARIF" in workflow - assert ".suppressions // []" in workflow - assert "SEMGREP_SUPPRESSED_COUNT" in workflow - assert "semgrep_sarif.outputs.finding_count != '0'" in workflow - assert 'SEMGREP_FINDING_COUNT:-missing}' in workflow - assert "--output=semgrep-results.sarif" not in workflow From bbc520f712750eee9d3d73cef2808529baf4d3e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 7 Oct 2026 18:29:19 +0900 Subject: [PATCH 3/6] fix(governance): fail closed when bypass data is absent --- CHANGELOG.md | 387 +----------------- docs/org-required-workflow-rollout.md | 3 +- docs/product-technical-gap-baseline.md | 2 +- .../ci/audit_central_required_workflows.py | 6 +- 4 files changed, 8 insertions(+), 390 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 934020777a..92e0456920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ - The ruleset audit now fails closed when ruleset `18156473` exposes any persistent bypass actor, including organization-admin `ALWAYS` entries, and - reports malformed bypass data explicitly. This closes the control-plane gap + reports missing or malformed bypass data explicitly. This closes the control-plane gap exposed when LineageWeave PR #1153 reached `main` with failed exact-head Checks and no independent approval. Exceptional circular admission remains a time-bounded operator action with separate evidence; it is not a standing @@ -1198,388 +1198,3 @@ Semantic Versioning where the repository publishes a release. docs-only PR. Trivial: the Evidence trail's upstream-issue citation still named only `#926`/`#927`, missing `#932` -- added. Cross-reference gap, not a new architectural question: Layer 1's `160s` worst case (Decision - §3) still didn't reference `ContextualWisdomLab/.github#1455` (the - discovery-timing gap filed and fully reasoned during the implementation - pass) anywhere in this ADR's own text -- added the cross-reference at the - point of definition and in Consequences, without reopening the - underlying question #1455 already tracks. Genuinely new, verified real: - the shared, catalog-order-consumed `REVIEW_PREFLIGHT_MAX_ESCALATIONS` - budget can deny a later-sorting, healthy candidate its own escalation - attempt once 4 earlier candidates have claimed the budget -- catalog - order is deterministic, not random, but not purely alphabetical either: - `build_zdr_prioritized_catalog` sorts by `(cost_evidence_rank, - zdr_attested_rank, provider, model)`, so alphabetical `(provider, model)` - is only the tie-breaker within each same-cost/same-ZDR-status group. - Considered reordering (round-robin, random shuffling) as a cheap fix and - rejected it: no selection policy for a fixed-size shared budget removes - the underlying trade-off, only changes which arbitrary policy governs - it, and picking one without real evidence would itself be the kind of - unjustified heuristic this ADR already rejects elsewhere. Documented as - a known, accepted, tracked limitation (`ContextualWisdomLab/.github#1458`, - matching the `#1454`/`#1455`/`#932` pattern) rather than redesigned. - Informational, no change: the gap-baseline's repeated review-round - narrative is this repo's own documented, intentional convention - (ADR-0002: the baseline is "an operational snapshot," not a duplicate of - the ADR's design record), not accidental redundancy.- Raise `contextual_orchestrator_review_sidecar.sh`'s - `ORCHESTRATOR_CATALOG_FAMILY_CAP` default from 4 to 8: root-caused the - live "no provider route passed the Strix plain-chat preflight" outage - blocking `noema-review`/`opencode-review`/`strix` org-wide to - `contextual_orchestrator_review_policy.py`'s family-cap candidate - selection deterministically admitting the same 4 alphabetically-first - `nvidia_nim`/`nvidia_nim_sub` free-model candidates on every run — 2 of - which are confirmed NVIDIA-retired model ids returning HTTP 404 forever — - while ~19 other healthy free candidates in the same discovery report - never got a chance. See the 2026-08-30 sidecar-preflight gap-baseline - entry for the full evidence trail, the exact trade-off reasoned through - (not live-verified, since this session lacks provider credentials), and - the more complete fix if this proves insufficient. -- Switch Strix from `orchestrator/auto` to `orchestrator/free`, matching - OpenCode and Noema: `strix.yml`'s `STRIX_MODEL`/`CONTEXTUAL_ORCHESTRATOR_POOL` - default and both model-override allowlists, and - `scripts/ci/strix_quick_gate.sh`'s `is_contextual_orchestrator_model`, now - accept only `orchestrator/free`. This is an explicit, informed owner - override of `docs/adr/0003-contextual-orchestrator-vendored-free-zdr.md`'s - original `orchestrator/auto` decision (see that ADR's 2026-08-30 - amendment and the matching gap-baseline entry for the full trade-off and - evidence trail): Strix no longer has a paid-model fallback and can go - fully dark during the class of single-provider-family-collapse incident - the original decision was written to survive, until the free-catalog's - stale-model and provider-diversity gaps are separately closed. -- Strengthen `scripts/ci/zdr_policy.py`'s `nvidia_nim`/`nvidia_nim_sub` ZDR - attestation with a direct primary-source citation: NVIDIA's own current - *NVIDIA API Trial Terms of Service* (v. September 19, 2025), Section - 3.3(iv), states User Content and Generated Content are collected "to - improve NVIDIA products and services, including AI models" — affirmative - evidence against zero data retention, not just an absence of attestation. - `zero_data_retention` stays `False` as it already was; only the citation - and note change. See the 2026-08-30 ZDR/NIM-routing gap-baseline entry for - the full architecture review this citation was part of. -- Bump the vendored `contextual-orchestrator` review-sidecar pin from - `5f2753a` (the #1422 pin) to current `main` `30c6d716`, picking up - `ContextualWisdomLab/contextual-orchestrator#919`: generalizes the - Models.dev free-cost join beyond `opencode_zen` to `nvidia_nim`/ - `nvidia_nim_sub`/`openai`, and fixes the actual root cause — `_fetch_json` - sent no `User-Agent`, so Cloudflare-fronted `models.dev` rejected every - discovery request with HTTP 403, silently breaking the Models.dev join for - every provider (including the pre-existing `opencode_zen` path). See the - 2026-08-30 gap-baseline entry for the merge/bypass rationale. -- Keep the required OpenCode bootstrap's Pingora policy step unconditional - within its pull-request-only workflow, so the static bootstrap contract does - not depend on event payload fields. (Ported from #1414, not yet merged, to - unblock this PR's own `exact-head-path-policy` check.) -- Bump the vendored `contextual-orchestrator` review-sidecar pin from - `b2164511` (103 commits stale) to current `main` `5f2753a`, so the - gateway's model-discovery/ZDR/pool-selection fixes landed since the old pin - reach `opencode-review`/`noema-review`. The stale pin's discovery logic was - failing the sidecar's own preflight with a gateway 502 before any review - could post, which is why `opencode-review` and `noema-review` were failing - closed on most `contextual-orchestrator` PRs and several `.github` PRs. -- Skip trusted base Python lock materialization for exact-head reviews with no - Python source or dependency-manifest changes, while preserving the - fail-closed wheel-only path when Python coverage is relevant. -- Route required Strix scans through the contextual-orchestrator - `orchestrator/auto` pool so the five configured provider credentials form - real cross-provider failover. Priced routes require finite, nonnegative - published prompt/completion prices and an explicit currency; unknown pricing - fails closed. Private-target ZDR enforcement and the no-external-fallback - contract remain unchanged. -- Allow the protected Strix required-workflow smoke to recognize only the - existing `orchestrator/free` route or the provider-diverse - `orchestrator/auto` route. This provides a fail-closed two-phase migration - path without admitting direct-provider model identifiers. -- Give stacked pull requests a separately bounded organization-sweep - OpenCode dispatch budget, so default-branch review traffic cannot leave a - stacked PR at `OpenCode review absent` without changing the protected merge - or exact-head evidence rules. -- Add a bounded hourly LineageWeave stacked-PR review-repair caller while - preserving the existing review-agent, model-routing, and protected-merge - boundaries. Product-gap development remains a separately gated coordinator - capability and is not claimed by this caller. The shared repair scheduler - now treats an explicit `*` base scope as all branch bases so stacked pull - requests are inspected instead of silently filtered out. -- Ensure the central Security Scan and SAST Semgrep pull-request workflows - trigger for stacked PRs targeting feature branches, preserving the same - diff-scoped dependency and repository-wide filesystem security coverage. -- Harden the contextual-orchestrator Strix sidecar by rejecting line-breaking - bearer tokens and masking the token before clone, install, launch, or health - diagnostics can emit it. The raw bearer no longer enters `GITHUB_ENV` (where - a later step header could render it before masking); only a mode-0600 token - file path crosses steps, and each model consumer validates and masks the file - inside its own step. The bounded required-workflow smoke now parses every - governed shell input independently, including the sidecar and token loader. - Strix also qualifies only the loopback child model as - `openai/orchestrator/free`, which satisfies LiteLLM's explicit-provider - contract while preserving `orchestrator/free` at the gateway boundary; a - missing, empty, or non-pinned contextual-orchestrator API base fails closed. -- Restore OpenCode coverage honesty and mermaid surfaces stacked on main after #1360 squash `17052a7c`: `publish_fallback_diff_review` posts a COMMENT product-file review then `request_changes_for_coverage_evidence_failure` sets the status comment to `COVERAGE_BLOCKED` so a coverage miss never looks finished as `Gate result: COMMENT`; mermaid labels crates/packages instead of generic `Changed file (N files)` and does not invent class edges; findings say `Review process` instead of `.github/workflows/opencode-review.yml:1` unless that file is in the diff. Does not change `noema-review.yml` (PM owns `feat/noema-orchestrator-free-zdr`) and is not NIM-2h or GitHub Models. -- Required OpenCode dispatch and Strix now use the vendored - `contextual-orchestrator/orchestrator/free` gateway for model execution and - failed-check diagnosis. The generated OpenCode config contains only the - gateway provider, Strix rejects non-gateway model overrides and external - fallbacks, and private-target visibility enables the sidecar's attested ZDR - requirement. The sidecar installs its vendored dependencies with the - hash-pinned lock, and gateway provider exhaustion remains fail-closed. -- Required Noema review now routes through the same vendored - `contextual-orchestrator` sidecar as the autofix writer: `noema-review.yml` - provisions the gateway with the five provider secrets, points the LLM step - at the loopback `orchestrator/free` pool (ZDR-first auto-discovery), and - deletes the public-repo NVIDIA NIM hardcode. `call_llm` keeps SSRF closed - for arbitrary private and `localhost` targets and allows only the - orchestrator sidecar loopback (`127.0.0.1` / `::1`) only when it matches the - exact configured sidecar base URL. Reviewer identity - is unchanged (`NOEMA_REVIEW_TOKEN` / GitHub App / OIDC; never - `github.token`). The hourly-review-repair roster is untouched. -- Central review now routes through the vendored `contextual-orchestrator` - gateway sidecar: the write-capable PR autofix and the shared `opencode.jsonc` - default use the fail-closed zero-cost pool `orchestrator/free`, with - ZDR-compliant (zero-data-retention) routes prioritized inside it. The five - provider secrets (`BYTEZ_API_KEY`, `NVIDIA_NIM_API_KEY`, - `NVIDIA_NIM_API_KEY_SUB`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`) are - registered into the gateway's process-local KV as bootstrap transport, model - selection is delegated to the orchestrator's auto model discovery, and the - previous direct NVIDIA NIM pin is gone from the autofix writer. Adds - `scripts/ci/zdr_policy.py`, - `scripts/ci/contextual_orchestrator_review_policy.py`, - `scripts/ci/contextual_orchestrator_review_launcher.py`, and - `scripts/ci/contextual_orchestrator_review_sidecar.sh` with contract-test and - ZDR/audit evidence (`docs/adr/0003-contextual-orchestrator-vendored-free-zdr.md`, - `docs/doctoring/contextual-orchestrator-vendored-sidecar.md`). Mutation - authority is unchanged: app-token-only, never `github.token`. -- Dependency updates now keep coverage evidence when the lock file passes - validation. If validation reports a problem, refresh the lock file and run - the review again before merging. -- Route Strix cross-provider fallbacks to explicit direct-OpenAI models - (`openai-direct/...`) through the OpenAI inference endpoint instead of - inheriting a provider-specific primary base: the workflow now provisions - `STRIX_OPENAI_FALLBACK_API_BASE_FILE` (`https://api.openai.com/v1`), while - standalone caller-supplied `LLM_API_BASE_FILE` values remain honored for - OpenAI-compatible endpoints. Known GitHub Models, NVIDIA NIM, and OpenRouter - bases are never inherited, and LiteLLM uses native OpenAI defaults only when - no base is supplied. A non-https override fails configuration. This removes the NVIDIA-NIM-edge - `404 page not found` that made the contracted final fallback unreachable - after NIM exhaustion. -- Align stale `gpt-5.6-luna` test expectations with the valid `gpt-5.4` - contract left behind by the earlier model rename. -- Honor each trusted base project's exact, integrity-bearing pnpm - `packageManager` specification in OpenCode coverage images through the pinned - Node distribution's Corepack runtime, instead of admitting the specification - during materialization and then rejecting every version except pnpm 11.5.3; - route generic coverage and docstring package scripts through the same - Corepack boundary instead of invoking a removed bare `pnpm` binary. -- Review scans now run in a controlled order so each pull request receives a - complete result instead of a rate-limit interruption. Open the pull request - after the active scan finishes to review the latest result. -- Closed pull-request cleanup now preserves the review record and reports any - authorization or malformed-data issue for follow-up. Reopen the pull request - or update its credentials when the cleanup message asks you to act. -- Keep `--trust-lockfile` only for pnpm 11.3 and newer - (`trustLockfile` landed in pnpm 11.3). pnpm 9, 10, and 11.0–11.2 reject - that flag and previously failed LineageWeave JavaScript coverage before - tests could run. Jest test scripts still receive `--coverage` because Jest - documents a native coverage flag. -- Run declared JavaScript test scripts without synthesizing `--coverage` when - the package does not declare a compatible coverage command, but keep the - coverage result failed until the repository adds a lock-pinned provider and - owned coverage command. A generic `c8`, `nyc`, or Istanbul dependency no - longer makes an unrelated test runner receive an unsupported flag. -- Fix OpenCode coverage evidence for exact-base, organization-owned Python VCS - dependencies without weakening registry hashes or the networkless PR sandbox, - reject namespace, ambiguous, linked, native-extension, and installed-metadata - layouts, and make exact roots readable by the unprivileged coverage user. - -### Added - -- Refresh the live product and technical gap baseline against the current - open-PR queue after ContextualWisdomLab/.github#1252 merged, with SHA-bound - snapshot rows, a same-session open/close delta, ADR Figma File ID N/A, and - APA 7th doctoring. The inventory is not merge authorization. - -- Classify Strix `ModelBehaviorError` and provider exhaustion as typed - `STRIX_PROVIDER_UNAVAILABLE` evidence while preserving a nonzero required - check. Incomplete scans and reported vulnerabilities both fail closed. - -- Added an hourly organization commercial-readiness coordinator that discovers writable repositories, honors enabled dedicated writer leases and fully paginated live writer runs, refetches exact repository/workflow/run/PR state before dispatch, rotates bounded review-repair and opt-in NVIDIA OpenCode product-development targets, fails nonzero on fleet-wide inspection or dispatch outages, retains three-day JSON receipts, and keeps the existing 15-minute merge scheduler authoritative. -- Added a dedicated Quarantine Sandbox Runtime hourly caller at minute 14 that targets protected `develop`, dispatches at most one exact-head repair, applies a two-hour same-head retry floor, preserves non-cancelling single-flight execution, and maps only the established scheduler credentials with job-scoped OIDC. -- Added a dedicated OriginWeave hourly caller that invokes the product-neutral central scheduler with the exact repository, protected `main` branch, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, job-scoped OIDC, and only the established scheduler credentials. -- Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate. -- Added an organization-owned reusable exact-artifact SBOM attestation boundary that validates inert six-file wheel/sdist evidence, binds CycloneDX 1.7 predicates to exact SHA-256 subjects, signs through least-privilege GitHub artifact attestations, and exports online and offline verification bundles. -- Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence. -- Added a permanent exact-head contract workflow for the hourly review-repair scheduler, immutable reusable-workflow source, NVIDIA NIM model boundary, credential isolation, and fail-closed unattended-agent permissions. -- Added a dedicated Clearfolio hourly caller that invokes the product-neutral central scheduler with the exact repository, protected base branch, one-dispatch budget, one-hour retry floor, single-flight concurrency, and only the established scheduler credentials. -- Added a dedicated DiskSage hourly caller that invokes the same product-neutral RCA and remediation-feasibility scheduler with an exact repository target, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, and explicit established scheduler credentials. -- Added a dedicated fast-mlsirm hourly caller that preserves Rust-owned psychometric arithmetic while dispatching at most one exact-head, root-cause-driven repair with a two-hour same-head retry floor. -- Added a dedicated Orgmetra hourly caller at minute 58 that targets protected `develop`, dispatches at most one exact-head repair, preserves a two-hour same-head retry floor and non-cancelling single-flight execution, and maps only the established scheduler credentials. - -### Changed - -- Require the PR Review Merge Scheduler to observe both GitHub's aggregate - `APPROVED` decision and the latest effective non-author, non-OpenCode formal - approval bound to the exact live head before direct merge or auto-merge. - A later same-head change request revokes that reviewer's earlier approval, - and existing auto-merge is disarmed when either authorization is absent. -- Emit completed repository pull-list requests as they finish in the five-minute - agent-mention sweep, while retaining the four-worker ceiling, rotation, and - exact-name dispatch ledger, so one slow repository cannot hide ready sibling - repositories. -- Require the hourly repair worker to establish an exact-head root cause, enumerate the smallest remediation candidates, and prove writer authority, sealed-path scope, credentials, dependency order, verifiability, and causal effect before editing; infeasible or external blockers leave the tree unchanged while the broader loop continues with another eligible PR or buyer-visible product gap. -- Run the bounded Quarantine Sandbox Runtime heartbeat at minute 14 without granting the caller model secrets, repository mutation permissions, approval, merge, release, artifact-execution, or final security-verdict authority. -- Run the bounded Clearfolio PR review-feedback repair caller at minute 23 of every hour while keeping the shared scheduler free of product-specific timers and repository names for modular reuse by naruon, contextual-orchestrator, Inkspan, and other CWL services. -- Run the bounded DiskSage repair heartbeat at minute 37 of every hour, dispatch no more than one exact-head repair, and wait two hours before redispatching an unchanged head so legitimate OpenCode or NVIDIA NIM latency does not create duplicate writers. -- Run the bounded fast-mlsirm repair heartbeat at minute 49 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening true-parameter recovery, CPU/GPU parity, skipped-test, or Rust-ownership gates. -- Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603` with explicit high reasoning for scheduled repair and `nvidia/nemotron-3-nano-30b-a3b` for bounded helper work instead of GitHub Models in the write-capable autofix worker. -- Apply one NUL-delimited exact-path and complete pre/post-worktree verification contract to both ordinary review repair and merge-conflict repair rather than relying on a visible post-model diff for the ordinary path. - -### Changed - -- Avoided the expensive R/testthat failure-summary regular expression on marker-absent bounded logs by checking the required terminal marker first, while preserving fail-closed handling for incomplete or malformed failure evidence. - -### Fixed - -- Prefer the job-scoped `github.token` when the central OpenCode dispatch - publishes a commit status back to the same `.github` repository. The job's - declared `statuses: write` permission now reaches the endpoint instead of an - unrelated OpenCode App installation token that can lack commit-status write - permission; cross-repository status publication keeps the existing explicit - PAT/App credential chain. -- Keep the central required-workflow coverage placeholder from superseding a - failed repository-dispatch coverage run; coverage retry and merge decisions - now use authoritative execution evidence for the central scheduler. -- Re-dispatch an exact-head OpenCode review after its coverage-only blocker is - cleared, selecting the newest coverage rerun by timestamp across workflow - names and ignoring only the superseded `opencode-review` failure and central - required-workflow placeholder. Conflicting heads and failed sibling jobs in an - OpenCode workflow remain fail-closed alongside unresolved threads, Strix, - coverage, and unrelated failed checks. -- Stop the organization PR sweep after the first exhausted shared GitHub App - installation bucket, rather than repeating up to three reset-aware waits and - follow-on queue-hygiene reads for every remaining repository. The current - target is recorded as deferred, the run remains non-fatal for this external - capacity condition, and later rotations retry the unfinished repository set. -- Close a gap in the above deferral: a shared-installation rate limit hit - mid-scan (inside a single PR's `inspect_pr()` call — an active-run read, - cancellation, dispatch, merge, or branch update — rather than the - once-per-repository `fetch_open_prs()`/`fetch_pr()` call before the loop) - previously fell back to an ordinary `action_error` decision and kept - scanning the repository's remaining PRs with the same exhausted bucket, - and returned exit 0, so the workflow's "API rate limit exceeded" - skip-and-defer branch — which only triggers on a non-zero sweep exit — - never saw it and later repositories in the same rotation kept spending - the bucket too. It now stops the repository's scan and propagates the - error like the pre-loop path already did. -- Web verification now checks services through local readiness addresses only. - Start the backend and frontend on this computer and use their local health - URLs when running the check. -- Review results now separate cosmetic notices from blocking failures. Open the - failure details and correct the requested issue before running the check - again. -- Resolve Strix visibility from the trusted GitHub event for ordinary push, - schedule, and pull-request runs, reserving API retries for cross-repository - dispatches whose workflow token may not see the target repository. -- Reconciled the Strix required-workflow smoke contract and the privileged - OpenCode model pool with the current `gpt-5.4` direct-OpenAI fallback after - `gpt-5.6-luna` was retired. This prevents every consumer repository's - required Strix check from failing on a stale central assertion or selecting a - nonexistent direct model. -- Publish only the sanitized cumulative Strix report tree, avoiding a later - copy of relative scanner output that could reintroduce known internal warning - text into uploaded security evidence. - -- Retry configured Strix fallback models when the primary provider records a - rate-limit or infrastructure failure only in its structured report log, and - evaluate each fallback against its newest report without letting an older - failed attempt poison a complete later report. - -- Include the exact `backend/app/*.py` package context in PR-scoped Strix - scans when a module in that package changes. The trusted resolver uses a - NUL-delimited exact-head tree listing, copies unchanged dependencies from - the trusted base, and keeps changed-file attribution and provider failures - fail-closed. -- Include the exact `contextual_orchestrator/*.py` sibling-import context under - the same NUL-delimited exact-head and fail-closed path boundary without - expanding changed-file finding attribution. -- Treat Rust source and Cargo manifests as governed Strix inputs and include - trusted Cargo, toolchain, and `deny.toml` context when a workflow change - scopes a Rust workspace. -- Run Strix with an explicit canonical scan target from a temporary working - directory outside that target, so scanner state and relative reports cannot - become self-scanned source findings; preserve those reports as gate evidence. - PR-scoped Python scans also include the PostgreSQL introspection security - helpers when that package exists in the target repository. PR scopes now live - below the gate's private runtime directory so unrelated temporary-file - cleanup cannot remove scan input during PR-head materialization. -- Classify Strix `ModelBehaviorError` with zero reported vulnerabilities as - retryable model-protocol evidence, while keeping `Vulnerabilities [1-9]` and - other severity signals fail-closed. -- Derived `org-queue-sweep`'s rotation index (added in `ContextualWisdomLab/.github#1220` to stop the walk-order starvation from `ContextualWisdomLab/.github#1219`) from a persistent `ORG_SWEEP_ROTATION_COUNTER` repository variable incremented by exactly one at the start of every actual sweep execution, instead of `github.run_number` (which increments on every trigger of this workflow, not only the sweep schedule — Devin review finding on `#1220`) or a wall-clock tick alone (which can repeat an offset when this single-flight, up-to-60-minute job runs behind schedule by an exact multiple of the repository count — CodeRabbit review finding on `#1223`). Falls back to the wall-clock tick only if the persistent counter itself is unavailable, so a fairness mechanism never blocks the sweep's review-dispatch/merge work. -- Retried the Strix scan up to `STRIX_TRANSIENT_RETRY_PER_MODEL` times, same model, when the log shows the upstream strix-agent Caido sandbox bootstrap timing race (`loginAsGuest failed after N attempts` / `Failed to connect to 127.0.0.1 port `; tracked upstream as usestrix/strix#1036, #1037, #1056). A slow CI runner can exceed strix-agent's fixed 10-attempt sandbox-login budget before its local intercepting proxy is reachable, even though the penetration test itself never started and no vulnerability evidence was produced or lost; the Docker image is already cached from the failed attempt, so a same-model retry is cheap and typically clears the one-off boot race. Not wired into cross-model fallback, since switching LLM models cannot change local sandbox container boot timing. -- Replaced nonexistent `job.workflow_repository` / `job.workflow_sha` / `job.workflow_ref` / `job.workflow_file_path` context references (actionlint: "property ... is not defined in object type") in `pr-review-fix-scheduler.yml`'s called-workflow source verification and `exact-artifact-sbom-attestation.yml`'s trusted-verifier checkout. Both always failed closed on the missing properties (ContextualWisdomLab/.github#1212) or, for the SBOM attestation checkout, silently resolved an empty repository/ref instead of the pinned trusted source (downstream `gh attestation verify --signer-repo`/`--signer-workflow`, using the separately hardcoded `SIGNER_REPOSITORY` constant rather than any workflow_ref, still failed closed on the resulting empty signer identity). `github.workflow_ref`/`github.workflow_sha` are real, documented properties, but for a `workflow_call` target they reflect the top-level *calling* workflow, not the reusable workflow's own file — a prefix match against the reusable workflow's own path can never succeed. `exact-artifact-sbom-attestation.yml`'s checkout now uses `github.workflow_sha` (correct today: it has no callers yet); `pr-review-fix-scheduler.yml`'s identity check instead validates `github.repository`, since every current caller uses a local, same-repo `uses: ./...` where caller and callee share one commit and `github.workflow_sha` is still the right pin. Tracked follow-up for the SBOM attestation checkout once a real (potentially cross-repo) caller exists: ContextualWisdomLab/.github#1228. -- Used the receiving repository's workflow token for same-repository scheduler - Actions inventory and read calls, while retaining the established mutation - credential chain. An exhausted organization-wide OpenCode App installation - budget can no longer prevent a central `.github` PR from dispatching its - exact-head review; cross-repository targets still require an explicit - credential. -- Kept independently valid root-level Python lock environments separate during - trusted base coverage installation. A directory with more than two candidate - locks no longer collapses unrelated OpenCode, security, and application - environments into one impossible resolver transaction; incomplete hash - closures remain skipped, while each complete hash-pinned closure installs - independently. -- Rotated `org-queue-sweep`'s repository walk order by the workflow's own run number before applying the shared organization-wide review-dispatch/branch-update budget, so a fixed early repository in the unsorted `gh api /orgs/{org}/repos` walk order can no longer permanently starve every later repository's ready, all-green, zero-open-thread pull requests of the single per-tick dispatch (`ContextualWisdomLab/.github#1219`). The total per-tick budget is unchanged; only which repository consumes it rotates. -- Forward `trigger_reviews=true` explicitly from the trusted OpenCode mention wrapper to the authoritative scheduler while retaining GitHub's ten-key dispatch limit. Source-comment identity remains bound in the verified invocation claim and durable ledger instead of occupying an unused scheduler field, so a successfully routed `@opencode-agent` request now dispatches review work rather than entering queue maintenance with reviews disabled. -- Allowed an allowlisted base repository's open fork-head PR to enter the central exact-head OpenCode review path. The scheduler and privileged reviewer still re-read the live PR, bind base/head refs and SHAs, reject malformed repository identities, keep fork source as untrusted data, preserve the existing maintainer-writable update rule, and reserve the final external-head merge for a maintainer. -- Confined OSV base and head repository checkouts to the same `source/` child directory, so a cross-fork head checkout can replace that repository without deleting the base-scan JSON held at the workspace root. Both scans retain identical source paths and the required base/head vulnerability comparison remains fail-closed. -- Restored 100% docstring coverage for the commercial-readiness GitHub transport constructor. -- Refused PR Review Merge Scheduler head mutations, `update-branch` and the last-push approval head restamp, whenever the resolved mutation credential is the workflow `GITHUB_TOKEN`. GitHub starts no workflow run for events created with that credential, so the moved head collected no current-head required checks and the PR stayed permanently `BLOCKED` with a `github-actions[bot]` merge commit that no later scheduler run could repair, because the branch was no longer behind. The scheduler now waits with `head_mutation_credential_upgrade` guidance naming `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, and the OpenCode app token exchange. -- Parsed `opencode.jsonc` as JSONC (stripping `//` and `/* */` comments outside string literals) in the reasoning-effort guard and its contract tests, instead of raw `json.loads`, which rejected the file the moment it carried its first explanatory comment (added for the `contextual-orchestrator` provider block) with `Expecting property name enclosed in double quotes`. Comment markers inside string values, such as the `$schema` URL, are left untouched. -- Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109). -- Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109). -- Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories. -- Bound the central Semgrep job to one `SEMGREP_IMAGE` digest for log evidence, manifest inspection, and `docker run`, so a buyer reconstructing the scan can prove the logged scanner is the scanner that ran. -- Published substantive OpenCode LLM probes when they already carried an independent proof and exact source-line digest but omitted a duplicated `path:line` citation, so NVIDIA NIM / OpenCode review evidence is no longer discarded as `NO_CONCLUSION`. -- Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367). -- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context. -- Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. -- Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed. -- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped. -- Hardened exact-artifact SBOM verification with strict finite RFC 8259 JSON, integer CycloneDX document versions, deterministic UUIDv5 subject identities, exact filename properties and single SHA-256 root bindings, environment-only shell input transfer, pinned Ubuntu 24.04 quality runners, and checksum-sealed beginner-readable offline evidence. -- Bound both trusted-uv quality jobs to `github.event.pull_request.head.sha` and added a permanent two-checkout regression contract so exact-head compatibility, coverage, docstring, and compilation claims cannot silently measure GitHub's generated pull-request merge revision. -- Made Strix treat only a single LiteLLM provider-error line containing NVIDIA NIM context and model-catalog 404 evidence as cross-model fallback evidence, rejecting cross-line signal assembly and provider-like target source literals; moved the public default to Nemotron 3 Super 120B and added a second NVIDIA hosted candidate before GitHub Models without neutralizing reported vulnerabilities. -- Bind reusable scheduler implementation to the validated called-workflow repository, SHA, ref, and file path, and verify the checked-out commit before executing privileged scheduler logic. -- Removed the ambiguous central-repository schedule fallback that could scan `.github` instead of Clearfolio when no external variable was configured; the active product caller now names Clearfolio explicitly while the reusable engine retains caller and dispatch overrides. -- Corrected the conflict-ordering regression contract to select the conflict-specific snapshot and verification after the ordinary path adopted the same trusted helper. -- Retried the Strix target-repository visibility lookup up to six times with linear backoff before failing closed, matching the existing PR-head-fetch retry convention in the same workflow. A single transient `gh api` failure (observed as a shared GitHub App installation token hitting its hourly rate limit while dozens of org repositories run hourly review schedulers concurrently) previously failed the entire required Strix check immediately, blocking otherwise mergeable, fully reviewed pull requests fleet-wide with no code defect involved. - -### Security - -- Fail closed when GitHub dependency-review evidence is unavailable (non-200, transport failure, or truncated compare) instead of treating HTTP 403/404 as a clean skip; the probe checks out the exact head SHA and never prints the API body. -- Keep the Quarantine Sandbox Runtime caller read-only and model-secret-free, grant only job-scoped OIDC to the reusable scheduler, and preserve the product boundary in which the sandbox returns artifact-analysis evidence while hosts retain WAF/IDS, admission, final verdict, incident, and retention authority. -- Reject `.github/` and `scripts/ci/` from review-thread-derived autofix path authority so an untrusted inline reviewer cannot authorize the write-capable repair agent to modify workflows, CODEOWNERS, actions, scheduler code, or CI helpers that govern its own control plane. -- Require the model-write snapshot and exact-path allowlist to remain outside the pull-request worktree, checking both absolute and resolved locations so repository-local controls and outside-looking symlinks resolving into the repository fail closed before they can authorize or verify model changes. -- Snapshot the complete pre-model worktree for ordinary and conflict repair and reject every model-caused created, deleted, modified, mode-changed, retargeted, ignored, dangling, directory-backed, external-link, metadata-race, or out-of-scope path before staging or push. -- Add ignored-path inventory through Git's tracked, other, and `--others --ignored --exclude-standard` views so model-created caches, credentials, or build output cannot evade comparison merely because ordinary Git publication omits them. -- Deny `.git` and `.git/*` in both OpenCode permission maps, disable repository hooks for privileged commit and push through `core.hooksPath=/dev/null`, and push only to an explicit revalidated repository URL so model-mutable Git metadata cannot control publication. -- Keep the Clearfolio caller and reusable scheduler read-only at workflow and job scope; authorize mutation only through explicitly mapped `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, or the short-lived OpenCode GitHub App token exchanged from OIDC, with explicit pre-write guards and no `github.token` mutation fallback. -- Keep the DiskSage caller read-only and pass only the established scheduler credentials; do not inherit secrets, expose the NVIDIA NIM model credential to the queue scanner, use a GitHub Copilot token, or grant the caller repository mutation permissions. -- Keep the fast-mlsirm caller read-only and model-secret-free; preserve independent approval, exact-head evidence, and Rust production-arithmetic ownership while centralizing only bounded review repair. -- Bind `NVIDIA_NIM_API_KEY` only to the two OpenCode model execution steps, fail closed when the secret is absent, and remove GitHub and Actions OIDC credentials from both model subprocesses. The decision record now cites CWE-367 so a later default-branch push cannot replace privileged repair helpers after `repository_dispatch` has already selected the workflow revision. -- Recorded the org control-plane architecture, including the hourly NVIDIA NIM repair gate, so agents reconstruct the write-capable worker trust boundary from the repo instead of private memory. -- Deny unnecessary non-file OpenCode interactions and preserve the independent read-only reviewer workflow and its credential/model-pool contract byte-for-byte. -- Pin the repository-dispatch autofix helper checkout to the exact workflow-run SHA rather than a moving default branch. -- Pass only `PR_REVIEW_MERGE_TOKEN` and `OPENCODE_APPROVE_TOKEN` from the Clearfolio schedule caller; do not use `secrets: inherit` and do not expose the NVIDIA model credential to the queue-scanning workflow. - -### Documentation - -- Added Quarantine Sandbox Runtime operator and APA 7 doctoring for the hourly RCA loop, source-agnostic leaf boundary, protected-`develop` activation, bounded retry cadence, OIDC and secret scope, independent approval, verification, and rollback. -- Rewrote the root README for org operators and sibling-repo maintainers: org profile plus central required workflows, standalone run, and how siblings consume ruleset `18156473` without copying workflow files. Moved bot/agent PR-review procedure to `docs/pr-review-and-merge-procedure.md`. -- Retargeted the Strix quality-gate prose contract to the review procedure document. -- Added an APA 7 doctoring record for conflict-control evidence isolation, including the Strix-reported trust-boundary failure, test-first remediation, canonical-path rule, operator contract, rollback, MITRE CWE-22, and current GitHub Actions secure-use guidance. -- Added operator and APA 7 doctoring records for the hourly cadence, immutable source identity, NVIDIA NIM provider and secret boundary, high-reasoning Mistral Small 4 writer, model-process credential isolation, modular MSA ownership, product-specific caller activation, verification contract, and rollback. -- Added DiskSage operational documentation for the hourly RCA loop, bounded retry cadence, permission model, standalone and MSA reuse, verification, rollback, and APA 7 references. -- Added fast-mlsirm operational documentation for the hourly RCA loop, psychometric scientific gates, Rust ownership, bounded retry cadence, credential isolation, modular reuse, rollback, and APA 7 references. -- Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. -- Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. - -- Added an organization-owned reusable exact-artifact SBOM attestation boundary that validates inert six-file wheel/sdist evidence, binds CycloneDX 1.7 predicates to exact SHA-256 subjects, signs through least-privilege GitHub artifact attestations, and exports online and offline verification bundles. -- Hardened exact-artifact SBOM verification with strict finite RFC 8259 JSON, integer CycloneDX document versions, deterministic UUIDv5 subject identities, exact filename properties and single SHA-256 root bindings, environment-only shell input transfer, pinned Ubuntu 24.04 quality runners, and checksum-sealed beginner-readable offline evidence. The decision record now cites Bray (2017) so NaN and Infinity cannot be treated as sealed SBOM numbers. -- Recorded the org control-plane architecture, including exact-artifact SBOM attestation, so agents reconstruct the signing trust boundary from the repo instead of private memory. diff --git a/docs/org-required-workflow-rollout.md b/docs/org-required-workflow-rollout.md index e5b6aeb19e..83db348060 100644 --- a/docs/org-required-workflow-rollout.md +++ b/docs/org-required-workflow-rollout.md @@ -410,7 +410,8 @@ non-fork inventory snapshot and rollout ledger, not the ruleset target list. circular-admission exception requires separate live authorization, exact-head evidence, and immediate removal after the guarded operation; an `ALWAYS` actor turns that exception into an unaudited ordinary merge path. The central - audit therefore treats any standing bypass actor as configuration drift. + audit therefore treats any standing bypass actor, or a missing or malformed + `bypass_actors` collection that cannot prove its absence, as configuration drift. - Existing open PRs may need a new push or base update before the latest required workflow SHA appears on their current head. - The central OpenCode workflow now routes model-backed review through the canonical contextual-orchestrator contract; model/provider selection and fallback belong to that owner boundary, not workflow-local heuristics or paid fallback. - The central OpenCode config includes a read-only `code-reviewer` subagent for focused review passes. The subagent may read, grep, glob, and run safe local verification commands, but it must not edit files, stage changes, commit, push, install dependencies, mutate branches, or touch production state. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 5280bc50a2..c562d6ed48 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -11,7 +11,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| -| CONTROL-RULESET-PERSISTENT-BYPASS-01 | **GREEN locally; protected integration and live ruleset remediation pending** | LineageWeave #1153 head `f18c736f4c51dea62d2f543134e077a3f9d9eb22` and squash result `03c575013e00fbce3d31bdc73eabd2bd13fa65e1` have the same tree, but the head had failed Tests and no APPROVED review. The active organization ruleset exposed an organization-admin `ALWAYS` bypass actor. RED proved `audit_ruleset()` accepted that standing actor; GREEN reports it as drift. | `.github` owns `scripts/ci/audit_central_required_workflows.py`. Merge this contract through exact-head Checks and independent review, then remove the persistent actor from live ruleset `18156473` through the protected organization-admin settings path and capture the next scheduled audit success. LineageWeave #1170 preserves the complete Voice delta and retains only the incident record; neither lane retroactively certifies #1153. | +| CONTROL-RULESET-PERSISTENT-BYPASS-01 | **GREEN locally; protected integration and live ruleset remediation pending** | LineageWeave #1153 head `f18c736f4c51dea62d2f543134e077a3f9d9eb22` and squash result `03c575013e00fbce3d31bdc73eabd2bd13fa65e1` have the same tree, but the head had failed Tests and no APPROVED review. The active organization ruleset exposed an organization-admin `ALWAYS` bypass actor. RED proved `audit_ruleset()` accepted both that standing actor and a payload that omitted `bypass_actors`; GREEN reports the standing actor plus missing or malformed actor data as drift. | `.github` owns `scripts/ci/audit_central_required_workflows.py`. Merge this contract through exact-head Checks and independent review, then remove the persistent actor from live ruleset `18156473` through the protected organization-admin settings path and capture the next scheduled audit success. LineageWeave #1170 preserves the complete Voice delta and retains only the incident record; neither lane retroactively certifies #1153. | ### 2026-09-19 exact-head incident delta diff --git a/scripts/ci/audit_central_required_workflows.py b/scripts/ci/audit_central_required_workflows.py index 6f50452101..8bf33020ef 100755 --- a/scripts/ci/audit_central_required_workflows.py +++ b/scripts/ci/audit_central_required_workflows.py @@ -60,8 +60,10 @@ def audit_ruleset(payload: dict[str, Any]) -> list[str]: if payload.get("enforcement") != "active": errors.append("central ruleset enforcement is not active") - bypass_actors = payload.get("bypass_actors", []) - if not isinstance(bypass_actors, list): + bypass_actors = payload.get("bypass_actors") + if "bypass_actors" not in payload: + errors.append("central ruleset bypass actor data is missing") + elif not isinstance(bypass_actors, list): errors.append("central ruleset bypass actor data is malformed") elif bypass_actors: actor_labels = sorted( From 0c5d1be7b21e0092bf97bf0c795980ae50a46faf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 9 Oct 2026 14:05:19 +0900 Subject: [PATCH 4/6] test(governance): restore ruleset audit contracts --- CHANGELOG.md | 399 +++++++++++++++++- ...central_required_workflow_ruleset_audit.py | 239 +++++++++++ 2 files changed, 630 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e0456920..4f625b3914 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,10 @@ -### Central ruleset audit rejects standing bypass actors +### Central ruleset audit detects standing bypass actors -- The ruleset audit now fails closed when ruleset `18156473` exposes any - persistent bypass actor, including organization-admin `ALWAYS` entries, and - reports missing or malformed bypass data explicitly. This closes the control-plane gap - exposed when LineageWeave PR #1153 reached `main` with failed exact-head - Checks and no independent approval. Exceptional circular admission remains - a time-bounded operator action with separate evidence; it is not a standing - ruleset entitlement. +- The ruleset audit now fails closed when the visible payload for ruleset + `18156473` exposes a persistent bypass actor or omits/malforms + `bypass_actors`. This closes the detector gap exposed by LineageWeave PR + #1153; it does not claim that the live actor has been removed. Protected + settings cleanup and a subsequent scheduled audit remain required evidence. ### Intel macOS native archives are bound to x86_64 bytes @@ -1198,3 +1196,388 @@ Semantic Versioning where the repository publishes a release. docs-only PR. Trivial: the Evidence trail's upstream-issue citation still named only `#926`/`#927`, missing `#932` -- added. Cross-reference gap, not a new architectural question: Layer 1's `160s` worst case (Decision + §3) still didn't reference `ContextualWisdomLab/.github#1455` (the + discovery-timing gap filed and fully reasoned during the implementation + pass) anywhere in this ADR's own text -- added the cross-reference at the + point of definition and in Consequences, without reopening the + underlying question #1455 already tracks. Genuinely new, verified real: + the shared, catalog-order-consumed `REVIEW_PREFLIGHT_MAX_ESCALATIONS` + budget can deny a later-sorting, healthy candidate its own escalation + attempt once 4 earlier candidates have claimed the budget -- catalog + order is deterministic, not random, but not purely alphabetical either: + `build_zdr_prioritized_catalog` sorts by `(cost_evidence_rank, + zdr_attested_rank, provider, model)`, so alphabetical `(provider, model)` + is only the tie-breaker within each same-cost/same-ZDR-status group. + Considered reordering (round-robin, random shuffling) as a cheap fix and + rejected it: no selection policy for a fixed-size shared budget removes + the underlying trade-off, only changes which arbitrary policy governs + it, and picking one without real evidence would itself be the kind of + unjustified heuristic this ADR already rejects elsewhere. Documented as + a known, accepted, tracked limitation (`ContextualWisdomLab/.github#1458`, + matching the `#1454`/`#1455`/`#932` pattern) rather than redesigned. + Informational, no change: the gap-baseline's repeated review-round + narrative is this repo's own documented, intentional convention + (ADR-0002: the baseline is "an operational snapshot," not a duplicate of + the ADR's design record), not accidental redundancy.- Raise `contextual_orchestrator_review_sidecar.sh`'s + `ORCHESTRATOR_CATALOG_FAMILY_CAP` default from 4 to 8: root-caused the + live "no provider route passed the Strix plain-chat preflight" outage + blocking `noema-review`/`opencode-review`/`strix` org-wide to + `contextual_orchestrator_review_policy.py`'s family-cap candidate + selection deterministically admitting the same 4 alphabetically-first + `nvidia_nim`/`nvidia_nim_sub` free-model candidates on every run — 2 of + which are confirmed NVIDIA-retired model ids returning HTTP 404 forever — + while ~19 other healthy free candidates in the same discovery report + never got a chance. See the 2026-08-30 sidecar-preflight gap-baseline + entry for the full evidence trail, the exact trade-off reasoned through + (not live-verified, since this session lacks provider credentials), and + the more complete fix if this proves insufficient. +- Switch Strix from `orchestrator/auto` to `orchestrator/free`, matching + OpenCode and Noema: `strix.yml`'s `STRIX_MODEL`/`CONTEXTUAL_ORCHESTRATOR_POOL` + default and both model-override allowlists, and + `scripts/ci/strix_quick_gate.sh`'s `is_contextual_orchestrator_model`, now + accept only `orchestrator/free`. This is an explicit, informed owner + override of `docs/adr/0003-contextual-orchestrator-vendored-free-zdr.md`'s + original `orchestrator/auto` decision (see that ADR's 2026-08-30 + amendment and the matching gap-baseline entry for the full trade-off and + evidence trail): Strix no longer has a paid-model fallback and can go + fully dark during the class of single-provider-family-collapse incident + the original decision was written to survive, until the free-catalog's + stale-model and provider-diversity gaps are separately closed. +- Strengthen `scripts/ci/zdr_policy.py`'s `nvidia_nim`/`nvidia_nim_sub` ZDR + attestation with a direct primary-source citation: NVIDIA's own current + *NVIDIA API Trial Terms of Service* (v. September 19, 2025), Section + 3.3(iv), states User Content and Generated Content are collected "to + improve NVIDIA products and services, including AI models" — affirmative + evidence against zero data retention, not just an absence of attestation. + `zero_data_retention` stays `False` as it already was; only the citation + and note change. See the 2026-08-30 ZDR/NIM-routing gap-baseline entry for + the full architecture review this citation was part of. +- Bump the vendored `contextual-orchestrator` review-sidecar pin from + `5f2753a` (the #1422 pin) to current `main` `30c6d716`, picking up + `ContextualWisdomLab/contextual-orchestrator#919`: generalizes the + Models.dev free-cost join beyond `opencode_zen` to `nvidia_nim`/ + `nvidia_nim_sub`/`openai`, and fixes the actual root cause — `_fetch_json` + sent no `User-Agent`, so Cloudflare-fronted `models.dev` rejected every + discovery request with HTTP 403, silently breaking the Models.dev join for + every provider (including the pre-existing `opencode_zen` path). See the + 2026-08-30 gap-baseline entry for the merge/bypass rationale. +- Keep the required OpenCode bootstrap's Pingora policy step unconditional + within its pull-request-only workflow, so the static bootstrap contract does + not depend on event payload fields. (Ported from #1414, not yet merged, to + unblock this PR's own `exact-head-path-policy` check.) +- Bump the vendored `contextual-orchestrator` review-sidecar pin from + `b2164511` (103 commits stale) to current `main` `5f2753a`, so the + gateway's model-discovery/ZDR/pool-selection fixes landed since the old pin + reach `opencode-review`/`noema-review`. The stale pin's discovery logic was + failing the sidecar's own preflight with a gateway 502 before any review + could post, which is why `opencode-review` and `noema-review` were failing + closed on most `contextual-orchestrator` PRs and several `.github` PRs. +- Skip trusted base Python lock materialization for exact-head reviews with no + Python source or dependency-manifest changes, while preserving the + fail-closed wheel-only path when Python coverage is relevant. +- Route required Strix scans through the contextual-orchestrator + `orchestrator/auto` pool so the five configured provider credentials form + real cross-provider failover. Priced routes require finite, nonnegative + published prompt/completion prices and an explicit currency; unknown pricing + fails closed. Private-target ZDR enforcement and the no-external-fallback + contract remain unchanged. +- Allow the protected Strix required-workflow smoke to recognize only the + existing `orchestrator/free` route or the provider-diverse + `orchestrator/auto` route. This provides a fail-closed two-phase migration + path without admitting direct-provider model identifiers. +- Give stacked pull requests a separately bounded organization-sweep + OpenCode dispatch budget, so default-branch review traffic cannot leave a + stacked PR at `OpenCode review absent` without changing the protected merge + or exact-head evidence rules. +- Add a bounded hourly LineageWeave stacked-PR review-repair caller while + preserving the existing review-agent, model-routing, and protected-merge + boundaries. Product-gap development remains a separately gated coordinator + capability and is not claimed by this caller. The shared repair scheduler + now treats an explicit `*` base scope as all branch bases so stacked pull + requests are inspected instead of silently filtered out. +- Ensure the central Security Scan and SAST Semgrep pull-request workflows + trigger for stacked PRs targeting feature branches, preserving the same + diff-scoped dependency and repository-wide filesystem security coverage. +- Harden the contextual-orchestrator Strix sidecar by rejecting line-breaking + bearer tokens and masking the token before clone, install, launch, or health + diagnostics can emit it. The raw bearer no longer enters `GITHUB_ENV` (where + a later step header could render it before masking); only a mode-0600 token + file path crosses steps, and each model consumer validates and masks the file + inside its own step. The bounded required-workflow smoke now parses every + governed shell input independently, including the sidecar and token loader. + Strix also qualifies only the loopback child model as + `openai/orchestrator/free`, which satisfies LiteLLM's explicit-provider + contract while preserving `orchestrator/free` at the gateway boundary; a + missing, empty, or non-pinned contextual-orchestrator API base fails closed. +- Restore OpenCode coverage honesty and mermaid surfaces stacked on main after #1360 squash `17052a7c`: `publish_fallback_diff_review` posts a COMMENT product-file review then `request_changes_for_coverage_evidence_failure` sets the status comment to `COVERAGE_BLOCKED` so a coverage miss never looks finished as `Gate result: COMMENT`; mermaid labels crates/packages instead of generic `Changed file (N files)` and does not invent class edges; findings say `Review process` instead of `.github/workflows/opencode-review.yml:1` unless that file is in the diff. Does not change `noema-review.yml` (PM owns `feat/noema-orchestrator-free-zdr`) and is not NIM-2h or GitHub Models. +- Required OpenCode dispatch and Strix now use the vendored + `contextual-orchestrator/orchestrator/free` gateway for model execution and + failed-check diagnosis. The generated OpenCode config contains only the + gateway provider, Strix rejects non-gateway model overrides and external + fallbacks, and private-target visibility enables the sidecar's attested ZDR + requirement. The sidecar installs its vendored dependencies with the + hash-pinned lock, and gateway provider exhaustion remains fail-closed. +- Required Noema review now routes through the same vendored + `contextual-orchestrator` sidecar as the autofix writer: `noema-review.yml` + provisions the gateway with the five provider secrets, points the LLM step + at the loopback `orchestrator/free` pool (ZDR-first auto-discovery), and + deletes the public-repo NVIDIA NIM hardcode. `call_llm` keeps SSRF closed + for arbitrary private and `localhost` targets and allows only the + orchestrator sidecar loopback (`127.0.0.1` / `::1`) only when it matches the + exact configured sidecar base URL. Reviewer identity + is unchanged (`NOEMA_REVIEW_TOKEN` / GitHub App / OIDC; never + `github.token`). The hourly-review-repair roster is untouched. +- Central review now routes through the vendored `contextual-orchestrator` + gateway sidecar: the write-capable PR autofix and the shared `opencode.jsonc` + default use the fail-closed zero-cost pool `orchestrator/free`, with + ZDR-compliant (zero-data-retention) routes prioritized inside it. The five + provider secrets (`BYTEZ_API_KEY`, `NVIDIA_NIM_API_KEY`, + `NVIDIA_NIM_API_KEY_SUB`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`) are + registered into the gateway's process-local KV as bootstrap transport, model + selection is delegated to the orchestrator's auto model discovery, and the + previous direct NVIDIA NIM pin is gone from the autofix writer. Adds + `scripts/ci/zdr_policy.py`, + `scripts/ci/contextual_orchestrator_review_policy.py`, + `scripts/ci/contextual_orchestrator_review_launcher.py`, and + `scripts/ci/contextual_orchestrator_review_sidecar.sh` with contract-test and + ZDR/audit evidence (`docs/adr/0003-contextual-orchestrator-vendored-free-zdr.md`, + `docs/doctoring/contextual-orchestrator-vendored-sidecar.md`). Mutation + authority is unchanged: app-token-only, never `github.token`. +- Dependency updates now keep coverage evidence when the lock file passes + validation. If validation reports a problem, refresh the lock file and run + the review again before merging. +- Route Strix cross-provider fallbacks to explicit direct-OpenAI models + (`openai-direct/...`) through the OpenAI inference endpoint instead of + inheriting a provider-specific primary base: the workflow now provisions + `STRIX_OPENAI_FALLBACK_API_BASE_FILE` (`https://api.openai.com/v1`), while + standalone caller-supplied `LLM_API_BASE_FILE` values remain honored for + OpenAI-compatible endpoints. Known GitHub Models, NVIDIA NIM, and OpenRouter + bases are never inherited, and LiteLLM uses native OpenAI defaults only when + no base is supplied. A non-https override fails configuration. This removes the NVIDIA-NIM-edge + `404 page not found` that made the contracted final fallback unreachable + after NIM exhaustion. +- Align stale `gpt-5.6-luna` test expectations with the valid `gpt-5.4` + contract left behind by the earlier model rename. +- Honor each trusted base project's exact, integrity-bearing pnpm + `packageManager` specification in OpenCode coverage images through the pinned + Node distribution's Corepack runtime, instead of admitting the specification + during materialization and then rejecting every version except pnpm 11.5.3; + route generic coverage and docstring package scripts through the same + Corepack boundary instead of invoking a removed bare `pnpm` binary. +- Review scans now run in a controlled order so each pull request receives a + complete result instead of a rate-limit interruption. Open the pull request + after the active scan finishes to review the latest result. +- Closed pull-request cleanup now preserves the review record and reports any + authorization or malformed-data issue for follow-up. Reopen the pull request + or update its credentials when the cleanup message asks you to act. +- Keep `--trust-lockfile` only for pnpm 11.3 and newer + (`trustLockfile` landed in pnpm 11.3). pnpm 9, 10, and 11.0–11.2 reject + that flag and previously failed LineageWeave JavaScript coverage before + tests could run. Jest test scripts still receive `--coverage` because Jest + documents a native coverage flag. +- Run declared JavaScript test scripts without synthesizing `--coverage` when + the package does not declare a compatible coverage command, but keep the + coverage result failed until the repository adds a lock-pinned provider and + owned coverage command. A generic `c8`, `nyc`, or Istanbul dependency no + longer makes an unrelated test runner receive an unsupported flag. +- Fix OpenCode coverage evidence for exact-base, organization-owned Python VCS + dependencies without weakening registry hashes or the networkless PR sandbox, + reject namespace, ambiguous, linked, native-extension, and installed-metadata + layouts, and make exact roots readable by the unprivileged coverage user. + +### Added + +- Refresh the live product and technical gap baseline against the current + open-PR queue after ContextualWisdomLab/.github#1252 merged, with SHA-bound + snapshot rows, a same-session open/close delta, ADR Figma File ID N/A, and + APA 7th doctoring. The inventory is not merge authorization. + +- Classify Strix `ModelBehaviorError` and provider exhaustion as typed + `STRIX_PROVIDER_UNAVAILABLE` evidence while preserving a nonzero required + check. Incomplete scans and reported vulnerabilities both fail closed. + +- Added an hourly organization commercial-readiness coordinator that discovers writable repositories, honors enabled dedicated writer leases and fully paginated live writer runs, refetches exact repository/workflow/run/PR state before dispatch, rotates bounded review-repair and opt-in NVIDIA OpenCode product-development targets, fails nonzero on fleet-wide inspection or dispatch outages, retains three-day JSON receipts, and keeps the existing 15-minute merge scheduler authoritative. +- Added a dedicated Quarantine Sandbox Runtime hourly caller at minute 14 that targets protected `develop`, dispatches at most one exact-head repair, applies a two-hour same-head retry floor, preserves non-cancelling single-flight execution, and maps only the established scheduler credentials with job-scoped OIDC. +- Added a dedicated OriginWeave hourly caller that invokes the product-neutral central scheduler with the exact repository, protected `main` branch, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, job-scoped OIDC, and only the established scheduler credentials. +- Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate. +- Added an organization-owned reusable exact-artifact SBOM attestation boundary that validates inert six-file wheel/sdist evidence, binds CycloneDX 1.7 predicates to exact SHA-256 subjects, signs through least-privilege GitHub artifact attestations, and exports online and offline verification bundles. +- Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence. +- Added a permanent exact-head contract workflow for the hourly review-repair scheduler, immutable reusable-workflow source, NVIDIA NIM model boundary, credential isolation, and fail-closed unattended-agent permissions. +- Added a dedicated Clearfolio hourly caller that invokes the product-neutral central scheduler with the exact repository, protected base branch, one-dispatch budget, one-hour retry floor, single-flight concurrency, and only the established scheduler credentials. +- Added a dedicated DiskSage hourly caller that invokes the same product-neutral RCA and remediation-feasibility scheduler with an exact repository target, one-dispatch budget, two-hour same-head retry floor, non-cancelling single-flight heartbeat, and explicit established scheduler credentials. +- Added a dedicated fast-mlsirm hourly caller that preserves Rust-owned psychometric arithmetic while dispatching at most one exact-head, root-cause-driven repair with a two-hour same-head retry floor. +- Added a dedicated Orgmetra hourly caller at minute 58 that targets protected `develop`, dispatches at most one exact-head repair, preserves a two-hour same-head retry floor and non-cancelling single-flight execution, and maps only the established scheduler credentials. + +### Changed + +- Require the PR Review Merge Scheduler to observe both GitHub's aggregate + `APPROVED` decision and the latest effective non-author, non-OpenCode formal + approval bound to the exact live head before direct merge or auto-merge. + A later same-head change request revokes that reviewer's earlier approval, + and existing auto-merge is disarmed when either authorization is absent. +- Emit completed repository pull-list requests as they finish in the five-minute + agent-mention sweep, while retaining the four-worker ceiling, rotation, and + exact-name dispatch ledger, so one slow repository cannot hide ready sibling + repositories. +- Require the hourly repair worker to establish an exact-head root cause, enumerate the smallest remediation candidates, and prove writer authority, sealed-path scope, credentials, dependency order, verifiability, and causal effect before editing; infeasible or external blockers leave the tree unchanged while the broader loop continues with another eligible PR or buyer-visible product gap. +- Run the bounded Quarantine Sandbox Runtime heartbeat at minute 14 without granting the caller model secrets, repository mutation permissions, approval, merge, release, artifact-execution, or final security-verdict authority. +- Run the bounded Clearfolio PR review-feedback repair caller at minute 23 of every hour while keeping the shared scheduler free of product-specific timers and repository names for modular reuse by naruon, contextual-orchestrator, Inkspan, and other CWL services. +- Run the bounded DiskSage repair heartbeat at minute 37 of every hour, dispatch no more than one exact-head repair, and wait two hours before redispatching an unchanged head so legitimate OpenCode or NVIDIA NIM latency does not create duplicate writers. +- Run the bounded fast-mlsirm repair heartbeat at minute 49 of every hour with one-dispatch scope and a two-hour same-head floor, without weakening true-parameter recovery, CPU/GPU parity, skipped-test, or Rust-ownership gates. +- Use NVIDIA NIM `mistralai/mistral-small-4-119b-2603` with explicit high reasoning for scheduled repair and `nvidia/nemotron-3-nano-30b-a3b` for bounded helper work instead of GitHub Models in the write-capable autofix worker. +- Apply one NUL-delimited exact-path and complete pre/post-worktree verification contract to both ordinary review repair and merge-conflict repair rather than relying on a visible post-model diff for the ordinary path. + +### Changed + +- Avoided the expensive R/testthat failure-summary regular expression on marker-absent bounded logs by checking the required terminal marker first, while preserving fail-closed handling for incomplete or malformed failure evidence. + +### Fixed + +- Prefer the job-scoped `github.token` when the central OpenCode dispatch + publishes a commit status back to the same `.github` repository. The job's + declared `statuses: write` permission now reaches the endpoint instead of an + unrelated OpenCode App installation token that can lack commit-status write + permission; cross-repository status publication keeps the existing explicit + PAT/App credential chain. +- Keep the central required-workflow coverage placeholder from superseding a + failed repository-dispatch coverage run; coverage retry and merge decisions + now use authoritative execution evidence for the central scheduler. +- Re-dispatch an exact-head OpenCode review after its coverage-only blocker is + cleared, selecting the newest coverage rerun by timestamp across workflow + names and ignoring only the superseded `opencode-review` failure and central + required-workflow placeholder. Conflicting heads and failed sibling jobs in an + OpenCode workflow remain fail-closed alongside unresolved threads, Strix, + coverage, and unrelated failed checks. +- Stop the organization PR sweep after the first exhausted shared GitHub App + installation bucket, rather than repeating up to three reset-aware waits and + follow-on queue-hygiene reads for every remaining repository. The current + target is recorded as deferred, the run remains non-fatal for this external + capacity condition, and later rotations retry the unfinished repository set. +- Close a gap in the above deferral: a shared-installation rate limit hit + mid-scan (inside a single PR's `inspect_pr()` call — an active-run read, + cancellation, dispatch, merge, or branch update — rather than the + once-per-repository `fetch_open_prs()`/`fetch_pr()` call before the loop) + previously fell back to an ordinary `action_error` decision and kept + scanning the repository's remaining PRs with the same exhausted bucket, + and returned exit 0, so the workflow's "API rate limit exceeded" + skip-and-defer branch — which only triggers on a non-zero sweep exit — + never saw it and later repositories in the same rotation kept spending + the bucket too. It now stops the repository's scan and propagates the + error like the pre-loop path already did. +- Web verification now checks services through local readiness addresses only. + Start the backend and frontend on this computer and use their local health + URLs when running the check. +- Review results now separate cosmetic notices from blocking failures. Open the + failure details and correct the requested issue before running the check + again. +- Resolve Strix visibility from the trusted GitHub event for ordinary push, + schedule, and pull-request runs, reserving API retries for cross-repository + dispatches whose workflow token may not see the target repository. +- Reconciled the Strix required-workflow smoke contract and the privileged + OpenCode model pool with the current `gpt-5.4` direct-OpenAI fallback after + `gpt-5.6-luna` was retired. This prevents every consumer repository's + required Strix check from failing on a stale central assertion or selecting a + nonexistent direct model. +- Publish only the sanitized cumulative Strix report tree, avoiding a later + copy of relative scanner output that could reintroduce known internal warning + text into uploaded security evidence. + +- Retry configured Strix fallback models when the primary provider records a + rate-limit or infrastructure failure only in its structured report log, and + evaluate each fallback against its newest report without letting an older + failed attempt poison a complete later report. + +- Include the exact `backend/app/*.py` package context in PR-scoped Strix + scans when a module in that package changes. The trusted resolver uses a + NUL-delimited exact-head tree listing, copies unchanged dependencies from + the trusted base, and keeps changed-file attribution and provider failures + fail-closed. +- Include the exact `contextual_orchestrator/*.py` sibling-import context under + the same NUL-delimited exact-head and fail-closed path boundary without + expanding changed-file finding attribution. +- Treat Rust source and Cargo manifests as governed Strix inputs and include + trusted Cargo, toolchain, and `deny.toml` context when a workflow change + scopes a Rust workspace. +- Run Strix with an explicit canonical scan target from a temporary working + directory outside that target, so scanner state and relative reports cannot + become self-scanned source findings; preserve those reports as gate evidence. + PR-scoped Python scans also include the PostgreSQL introspection security + helpers when that package exists in the target repository. PR scopes now live + below the gate's private runtime directory so unrelated temporary-file + cleanup cannot remove scan input during PR-head materialization. +- Classify Strix `ModelBehaviorError` with zero reported vulnerabilities as + retryable model-protocol evidence, while keeping `Vulnerabilities [1-9]` and + other severity signals fail-closed. +- Derived `org-queue-sweep`'s rotation index (added in `ContextualWisdomLab/.github#1220` to stop the walk-order starvation from `ContextualWisdomLab/.github#1219`) from a persistent `ORG_SWEEP_ROTATION_COUNTER` repository variable incremented by exactly one at the start of every actual sweep execution, instead of `github.run_number` (which increments on every trigger of this workflow, not only the sweep schedule — Devin review finding on `#1220`) or a wall-clock tick alone (which can repeat an offset when this single-flight, up-to-60-minute job runs behind schedule by an exact multiple of the repository count — CodeRabbit review finding on `#1223`). Falls back to the wall-clock tick only if the persistent counter itself is unavailable, so a fairness mechanism never blocks the sweep's review-dispatch/merge work. +- Retried the Strix scan up to `STRIX_TRANSIENT_RETRY_PER_MODEL` times, same model, when the log shows the upstream strix-agent Caido sandbox bootstrap timing race (`loginAsGuest failed after N attempts` / `Failed to connect to 127.0.0.1 port `; tracked upstream as usestrix/strix#1036, #1037, #1056). A slow CI runner can exceed strix-agent's fixed 10-attempt sandbox-login budget before its local intercepting proxy is reachable, even though the penetration test itself never started and no vulnerability evidence was produced or lost; the Docker image is already cached from the failed attempt, so a same-model retry is cheap and typically clears the one-off boot race. Not wired into cross-model fallback, since switching LLM models cannot change local sandbox container boot timing. +- Replaced nonexistent `job.workflow_repository` / `job.workflow_sha` / `job.workflow_ref` / `job.workflow_file_path` context references (actionlint: "property ... is not defined in object type") in `pr-review-fix-scheduler.yml`'s called-workflow source verification and `exact-artifact-sbom-attestation.yml`'s trusted-verifier checkout. Both always failed closed on the missing properties (ContextualWisdomLab/.github#1212) or, for the SBOM attestation checkout, silently resolved an empty repository/ref instead of the pinned trusted source (downstream `gh attestation verify --signer-repo`/`--signer-workflow`, using the separately hardcoded `SIGNER_REPOSITORY` constant rather than any workflow_ref, still failed closed on the resulting empty signer identity). `github.workflow_ref`/`github.workflow_sha` are real, documented properties, but for a `workflow_call` target they reflect the top-level *calling* workflow, not the reusable workflow's own file — a prefix match against the reusable workflow's own path can never succeed. `exact-artifact-sbom-attestation.yml`'s checkout now uses `github.workflow_sha` (correct today: it has no callers yet); `pr-review-fix-scheduler.yml`'s identity check instead validates `github.repository`, since every current caller uses a local, same-repo `uses: ./...` where caller and callee share one commit and `github.workflow_sha` is still the right pin. Tracked follow-up for the SBOM attestation checkout once a real (potentially cross-repo) caller exists: ContextualWisdomLab/.github#1228. +- Used the receiving repository's workflow token for same-repository scheduler + Actions inventory and read calls, while retaining the established mutation + credential chain. An exhausted organization-wide OpenCode App installation + budget can no longer prevent a central `.github` PR from dispatching its + exact-head review; cross-repository targets still require an explicit + credential. +- Kept independently valid root-level Python lock environments separate during + trusted base coverage installation. A directory with more than two candidate + locks no longer collapses unrelated OpenCode, security, and application + environments into one impossible resolver transaction; incomplete hash + closures remain skipped, while each complete hash-pinned closure installs + independently. +- Rotated `org-queue-sweep`'s repository walk order by the workflow's own run number before applying the shared organization-wide review-dispatch/branch-update budget, so a fixed early repository in the unsorted `gh api /orgs/{org}/repos` walk order can no longer permanently starve every later repository's ready, all-green, zero-open-thread pull requests of the single per-tick dispatch (`ContextualWisdomLab/.github#1219`). The total per-tick budget is unchanged; only which repository consumes it rotates. +- Forward `trigger_reviews=true` explicitly from the trusted OpenCode mention wrapper to the authoritative scheduler while retaining GitHub's ten-key dispatch limit. Source-comment identity remains bound in the verified invocation claim and durable ledger instead of occupying an unused scheduler field, so a successfully routed `@opencode-agent` request now dispatches review work rather than entering queue maintenance with reviews disabled. +- Allowed an allowlisted base repository's open fork-head PR to enter the central exact-head OpenCode review path. The scheduler and privileged reviewer still re-read the live PR, bind base/head refs and SHAs, reject malformed repository identities, keep fork source as untrusted data, preserve the existing maintainer-writable update rule, and reserve the final external-head merge for a maintainer. +- Confined OSV base and head repository checkouts to the same `source/` child directory, so a cross-fork head checkout can replace that repository without deleting the base-scan JSON held at the workspace root. Both scans retain identical source paths and the required base/head vulnerability comparison remains fail-closed. +- Restored 100% docstring coverage for the commercial-readiness GitHub transport constructor. +- Refused PR Review Merge Scheduler head mutations, `update-branch` and the last-push approval head restamp, whenever the resolved mutation credential is the workflow `GITHUB_TOKEN`. GitHub starts no workflow run for events created with that credential, so the moved head collected no current-head required checks and the PR stayed permanently `BLOCKED` with a `github-actions[bot]` merge commit that no later scheduler run could repair, because the branch was no longer behind. The scheduler now waits with `head_mutation_credential_upgrade` guidance naming `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, and the OpenCode app token exchange. +- Parsed `opencode.jsonc` as JSONC (stripping `//` and `/* */` comments outside string literals) in the reasoning-effort guard and its contract tests, instead of raw `json.loads`, which rejected the file the moment it carried its first explanatory comment (added for the `contextual-orchestrator` provider block) with `Expecting property name enclosed in double quotes`. Comment markers inside string values, such as the `$schema` URL, are left untouched. +- Download the pinned `uv` 0.12.1 exporter from the official GitHub Releases URL instead of `releases.astral.sh`, which now returns HTTP 403 and blocks org-wide OpenCode `coverage-evidence`. The SHA-256 pin is unchanged. The opener may follow one hop onto `release-assets.githubusercontent.com` or `objects.githubusercontent.com` and still rejects every other host, userinfo, non-HTTPS scheme, and nondefault port (ContextualWisdomLab/.github#1109). +- Compared the trusted `uv` executable's post-install `--version` output against the real GitHub Releases build's full string, `uv 0.12.1 (x86_64-unknown-linux-gnu)`, instead of the bare `uv 0.12.1` the prior check required; the genuine release binary always prints the target triple, so every installation was failing the pin check immediately after the archive download itself was fixed (ContextualWisdomLab/.github#1109). +- Excluded relative `-r` and `--requirement` referrers from generated flat base-lock publication while retaining bounded include syntax diagnostics and discovering independently complete direct `.txt` children of `requirements` directories. +- Bound the central Semgrep job to one `SEMGREP_IMAGE` digest for log evidence, manifest inspection, and `docker run`, so a buyer reconstructing the scan can prove the logged scanner is the scanner that ran. +- Published substantive OpenCode LLM probes when they already carried an independent proof and exact source-line digest but omitted a duplicated `path:line` citation, so NVIDIA NIM / OpenCode review evidence is no longer discarded as `NO_CONCLUSION`. +- Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367). +- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context. +- Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. +- Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed. +- Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped. +- Hardened exact-artifact SBOM verification with strict finite RFC 8259 JSON, integer CycloneDX document versions, deterministic UUIDv5 subject identities, exact filename properties and single SHA-256 root bindings, environment-only shell input transfer, pinned Ubuntu 24.04 quality runners, and checksum-sealed beginner-readable offline evidence. +- Bound both trusted-uv quality jobs to `github.event.pull_request.head.sha` and added a permanent two-checkout regression contract so exact-head compatibility, coverage, docstring, and compilation claims cannot silently measure GitHub's generated pull-request merge revision. +- Made Strix treat only a single LiteLLM provider-error line containing NVIDIA NIM context and model-catalog 404 evidence as cross-model fallback evidence, rejecting cross-line signal assembly and provider-like target source literals; moved the public default to Nemotron 3 Super 120B and added a second NVIDIA hosted candidate before GitHub Models without neutralizing reported vulnerabilities. +- Bind reusable scheduler implementation to the validated called-workflow repository, SHA, ref, and file path, and verify the checked-out commit before executing privileged scheduler logic. +- Removed the ambiguous central-repository schedule fallback that could scan `.github` instead of Clearfolio when no external variable was configured; the active product caller now names Clearfolio explicitly while the reusable engine retains caller and dispatch overrides. +- Corrected the conflict-ordering regression contract to select the conflict-specific snapshot and verification after the ordinary path adopted the same trusted helper. +- Retried the Strix target-repository visibility lookup up to six times with linear backoff before failing closed, matching the existing PR-head-fetch retry convention in the same workflow. A single transient `gh api` failure (observed as a shared GitHub App installation token hitting its hourly rate limit while dozens of org repositories run hourly review schedulers concurrently) previously failed the entire required Strix check immediately, blocking otherwise mergeable, fully reviewed pull requests fleet-wide with no code defect involved. + +### Security + +- Fail closed when GitHub dependency-review evidence is unavailable (non-200, transport failure, or truncated compare) instead of treating HTTP 403/404 as a clean skip; the probe checks out the exact head SHA and never prints the API body. +- Keep the Quarantine Sandbox Runtime caller read-only and model-secret-free, grant only job-scoped OIDC to the reusable scheduler, and preserve the product boundary in which the sandbox returns artifact-analysis evidence while hosts retain WAF/IDS, admission, final verdict, incident, and retention authority. +- Reject `.github/` and `scripts/ci/` from review-thread-derived autofix path authority so an untrusted inline reviewer cannot authorize the write-capable repair agent to modify workflows, CODEOWNERS, actions, scheduler code, or CI helpers that govern its own control plane. +- Require the model-write snapshot and exact-path allowlist to remain outside the pull-request worktree, checking both absolute and resolved locations so repository-local controls and outside-looking symlinks resolving into the repository fail closed before they can authorize or verify model changes. +- Snapshot the complete pre-model worktree for ordinary and conflict repair and reject every model-caused created, deleted, modified, mode-changed, retargeted, ignored, dangling, directory-backed, external-link, metadata-race, or out-of-scope path before staging or push. +- Add ignored-path inventory through Git's tracked, other, and `--others --ignored --exclude-standard` views so model-created caches, credentials, or build output cannot evade comparison merely because ordinary Git publication omits them. +- Deny `.git` and `.git/*` in both OpenCode permission maps, disable repository hooks for privileged commit and push through `core.hooksPath=/dev/null`, and push only to an explicit revalidated repository URL so model-mutable Git metadata cannot control publication. +- Keep the Clearfolio caller and reusable scheduler read-only at workflow and job scope; authorize mutation only through explicitly mapped `PR_REVIEW_MERGE_TOKEN`, `OPENCODE_APPROVE_TOKEN`, or the short-lived OpenCode GitHub App token exchanged from OIDC, with explicit pre-write guards and no `github.token` mutation fallback. +- Keep the DiskSage caller read-only and pass only the established scheduler credentials; do not inherit secrets, expose the NVIDIA NIM model credential to the queue scanner, use a GitHub Copilot token, or grant the caller repository mutation permissions. +- Keep the fast-mlsirm caller read-only and model-secret-free; preserve independent approval, exact-head evidence, and Rust production-arithmetic ownership while centralizing only bounded review repair. +- Bind `NVIDIA_NIM_API_KEY` only to the two OpenCode model execution steps, fail closed when the secret is absent, and remove GitHub and Actions OIDC credentials from both model subprocesses. The decision record now cites CWE-367 so a later default-branch push cannot replace privileged repair helpers after `repository_dispatch` has already selected the workflow revision. +- Recorded the org control-plane architecture, including the hourly NVIDIA NIM repair gate, so agents reconstruct the write-capable worker trust boundary from the repo instead of private memory. +- Deny unnecessary non-file OpenCode interactions and preserve the independent read-only reviewer workflow and its credential/model-pool contract byte-for-byte. +- Pin the repository-dispatch autofix helper checkout to the exact workflow-run SHA rather than a moving default branch. +- Pass only `PR_REVIEW_MERGE_TOKEN` and `OPENCODE_APPROVE_TOKEN` from the Clearfolio schedule caller; do not use `secrets: inherit` and do not expose the NVIDIA model credential to the queue-scanning workflow. + +### Documentation + +- Added Quarantine Sandbox Runtime operator and APA 7 doctoring for the hourly RCA loop, source-agnostic leaf boundary, protected-`develop` activation, bounded retry cadence, OIDC and secret scope, independent approval, verification, and rollback. +- Rewrote the root README for org operators and sibling-repo maintainers: org profile plus central required workflows, standalone run, and how siblings consume ruleset `18156473` without copying workflow files. Moved bot/agent PR-review procedure to `docs/pr-review-and-merge-procedure.md`. +- Retargeted the Strix quality-gate prose contract to the review procedure document. +- Added an APA 7 doctoring record for conflict-control evidence isolation, including the Strix-reported trust-boundary failure, test-first remediation, canonical-path rule, operator contract, rollback, MITRE CWE-22, and current GitHub Actions secure-use guidance. +- Added operator and APA 7 doctoring records for the hourly cadence, immutable source identity, NVIDIA NIM provider and secret boundary, high-reasoning Mistral Small 4 writer, model-process credential isolation, modular MSA ownership, product-specific caller activation, verification contract, and rollback. +- Added DiskSage operational documentation for the hourly RCA loop, bounded retry cadence, permission model, standalone and MSA reuse, verification, rollback, and APA 7 references. +- Added fast-mlsirm operational documentation for the hourly RCA loop, psychometric scientific gates, Rust ownership, bounded retry cadence, credential isolation, modular reuse, rollback, and APA 7 references. +- Documented the ordinary and conflict repair write-scope parity, ignored-path and symlink inventory, Git-control-file denial, hook suppression, explicit push destination, RED/GREEN evidence, operator response, and local-versus-protected evidence boundary. +- Documented the review-authentication boundary that excludes autonomous writer control-plane paths from review-derived file authority, its test-first Strix security evidence, exact-head coverage contract, and rollback prohibition. + +- Added an organization-owned reusable exact-artifact SBOM attestation boundary that validates inert six-file wheel/sdist evidence, binds CycloneDX 1.7 predicates to exact SHA-256 subjects, signs through least-privilege GitHub artifact attestations, and exports online and offline verification bundles. +- Hardened exact-artifact SBOM verification with strict finite RFC 8259 JSON, integer CycloneDX document versions, deterministic UUIDv5 subject identities, exact filename properties and single SHA-256 root bindings, environment-only shell input transfer, pinned Ubuntu 24.04 quality runners, and checksum-sealed beginner-readable offline evidence. The decision record now cites Bray (2017) so NaN and Infinity cannot be treated as sealed SBOM numbers. +- Recorded the org control-plane architecture, including exact-artifact SBOM attestation, so agents reconstruct the signing trust boundary from the repo instead of private memory. diff --git a/tests/test_central_required_workflow_ruleset_audit.py b/tests/test_central_required_workflow_ruleset_audit.py index 071e96f534..48bb441bbf 100644 --- a/tests/test_central_required_workflow_ruleset_audit.py +++ b/tests/test_central_required_workflow_ruleset_audit.py @@ -518,3 +518,242 @@ def test_load_payload_rejects_non_object_and_main_logs_load_reason(monkeypatch, def test_scheduled_audit_and_rollout_document_semgrep_and_noema_requirements() -> None: + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + rollout = (REPO_ROOT / "docs/org-required-workflow-rollout.md").read_text( + encoding="utf-8" + ) + + assert 'cron: "11 2 * * *"' in workflow + assert "repos/${ORG_LOGIN}/${RULESET_SENTINEL_REPOSITORY}/rulesets/${RULESET_ID}" in workflow + assert 'orgs/${ORG_LOGIN}/repos?type=all&per_page=100' in workflow + assert "RULESET_SCOPE repository=${repository} inherited=${inherited}" in workflow + assert "HTTP 404" in workflow + assert "audit_central_required_workflows.py" in workflow + assert "Ruleset audit could not read inherited organization ruleset" in workflow + assert 'STACKED_RULESET_ID: "21732164"' in workflow + assert "audit_central_required_workflows.py --stacked" in workflow + assert "CWL Stacked OpenCode required workflow" in rollout + assert 'ref_name.exclude=["~DEFAULT_BRANCH"]' in rollout + assert "- `.github/workflows/noema-review.yml`" in rollout + assert "- `.github/workflows/sast-semgrep.yml`" in rollout + + +def test_ruleset_audit_requires_dedicated_write_credential() -> None: + """The bypass audit must not confuse hidden fields with live drift.""" + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + ruleset_step = workflow.split( + "- name: Read live inherited organization ruleset and repository scope\n", 1 + )[1].split(" - name: ", 1)[0] + coverage_step = workflow.split( + "- name: Audit organization CodeQL coverage\n", 1 + )[1].split(" - name: ", 1)[0] + + assert ( + "GH_TOKEN: ${{ secrets.CWL_RULESET_AUDIT_TOKEN || '' }}" in ruleset_step + ) + assert ( + "RULESET_WRITE_CREDENTIAL_AVAILABLE: " + "${{ secrets.CWL_RULESET_AUDIT_TOKEN != '' }}" in ruleset_step + ) + assert 'if [ "$RULESET_WRITE_CREDENTIAL_AVAILABLE" = "false" ]; then' in ruleset_step + assert "requires CWL_RULESET_AUDIT_TOKEN with ruleset write access" in ruleset_step + assert "github.token" not in ruleset_step + assert ( + "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN " + "|| secrets.OPENCODE_APPROVE_TOKEN || '' }}" in coverage_step + ) + + +def test_audit_organization_codeql_coverage_step_has_freshness_and_credential_guard() -> None: + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + + assert "Audit organization CodeQL coverage" in workflow + assert ( + "ORG_WIDE_CREDENTIAL_AVAILABLE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' " + "|| secrets.OPENCODE_APPROVE_TOKEN != '' }}" + ) in workflow + assert 'if [ "$ORG_WIDE_CREDENTIAL_AVAILABLE" = "false" ]; then' in workflow + assert ( + "::error::CodeQL coverage audit requires an org-scoped credential " + "(PR_REVIEW_MERGE_TOKEN or OPENCODE_APPROVE_TOKEN) to reliably enumerate " + "private organization repositories" + ) in workflow + assert ( + 'if [ "$ORG_WIDE_CREDENTIAL_AVAILABLE" = "false" ]; then\n' + ' echo "::error::CodeQL coverage audit requires an ' + "org-scoped credential (PR_REVIEW_MERGE_TOKEN or OPENCODE_APPROVE_TOKEN) " + "to reliably enumerate private organization repositories; the " + "repository-scoped github.token fallback cannot see them, which would " + 'silently narrow this audit to a subset of the organization."\n' + " exit 1\n" + " fi" + ) in workflow + # This pinned `--jq .state` until 2026-09-07. What it protects is that the + # audit reads default-setup per repository, not that it reads only the + # state: `state == "configured"` with an empty `languages` list scans + # nothing and produces no analyses (live on life-os, aFIPC and inkspan), + # so the step now fetches the whole object and extracts both fields. + assert 'repos/${ORG_LOGIN}/${repository}/code-scanning/default-setup"' in workflow + assert """default_setup_state=$(jq '.state // null' "$default_setup_json")""" in workflow + assert ( + """default_setup_languages=$(jq '.languages // []' "$default_setup_json")""" + in workflow + ) + assert "default_setup_languages: $default_setup_languages" in workflow + assert ( + 'if [ "$archived" != "true" ]; then\n' + ' default_setup_json="$RUNNER_TEMP/codeql-default-setup-' + '${repository//[^A-Za-z0-9_.-]/_}.json"' + ) in workflow + assert ( + "repos/${ORG_LOGIN}/${repository}/code-scanning/analyses?tool_name=" + "CodeQL&per_page=1" + ) in workflow + assert "--jq '.[0] | if . then {created_at, error} else null end'" in workflow + assert "latest_codeql_analysis=null" in workflow + assert ( + 'if [ "$archived" != "true" ]; then\n' + ' analysis_json="$RUNNER_TEMP/codeql-analysis-' + '${repository//[^A-Za-z0-9_.-]/_}.json"' + ) in workflow + assert "python3 scripts/ci/audit_org_codeql_coverage.py" in workflow + + +def test_codeql_coverage_audit_survives_a_ruleset_drift_failure() -> None: + """An owner-configured ruleset drift must not disable the coverage detector. + + Both audits live in one job, and the ruleset step exits 1 on governance + drift. It did on 2026-09-06 ("exactly two approving reviews are not + required", "last-push approval protection is disabled"), so every run since + 2026-09-04 failed before reaching the CodeQL coverage step. The subjects are + unrelated and the coverage step has no data dependency on the one above it, + so it is guarded by ``if: always()``. + + The bootstrap steps below it are deliberately *not* given the same guard: + they open pull requests, and running a mutation after an unexplained + upstream failure is a different decision from running a read-only detector. + """ + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + coverage_step = workflow.split("- name: Audit organization CodeQL coverage\n", 1)[1] + before_next_step = coverage_step.split(" - name: ", 1)[0] + + assert "\n if: always()\n" in before_next_step + bootstrap_step = workflow.split( + "- name: Create missing CodeQL setup pull requests\n", 1 + )[1].split(" - name: ", 1)[0] + assert "if: always()" not in bootstrap_step + + +def test_codeql_gap_bootstrap_uses_trusted_opencode_identity_without_pr_head_execution() -> None: + """Backlog item 38 stays on trusted main and treats installation tokens as opaque.""" + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + bootstrap_step = workflow.split( + "- name: Exchange OpenCode app token for CodeQL setup writes\n", 1 + )[1] + + assert "id-token: write" in workflow + assert "audience=${OIDC_AUDIENCE}" in bootstrap_step + assert "/exchange_github_app_token" in bootstrap_step + assert "token< None: + """Devin finding: 'Private repositories disappear from audit'. + + ORG_WIDE_CREDENTIAL_AVAILABLE only proves *some* org-scoped secret + exists, not that the specific credential used (PR_REVIEW_MERGE_TOKEN + when present) can see the full organization. A fine-grained token with + an incomplete repository allowlist does not 403 on the enumeration + call -- it silently returns a smaller repository list. This pins the + real post-enumeration completeness check: known-private, non-archived + sentinel repositories must all appear in the enumerated list, or the + step fails loudly instead of silently auditing a partial organization. + """ + workflow = (REPO_ROOT / ".github/workflows/audit-central-ruleset.yml").read_text( + encoding="utf-8" + ) + + codeql_step = workflow.split('- name: "Audit organization CodeQL coverage"\n', 1) + if len(codeql_step) == 1: + codeql_step = workflow.split("- name: Audit organization CodeQL coverage\n", 1) + assert len(codeql_step) == 2, "CodeQL coverage step not found in workflow" + step_body = codeql_step[1] + + assert 'PRIVATE_REPOSITORY_COVERAGE_SENTINELS=(' in step_body + assert '"xtrmLLMBatchPython"' in step_body + assert '"linux-cluster-ops"' in step_body + assert '"gyeot"' in step_body + assert ( + 'jq -e --arg name "$sentinel" \'any(.[]; .name == $name)\' "$repositories_json"' + in step_body + ) + assert 'missing_sentinels=()' in step_body + assert ( + 'if [ "${#missing_sentinels[@]}" -gt 0 ]; then\n' + ' echo "::error::CodeQL coverage audit\'s organization ' + 'repository enumeration is missing known-private sentinel ' + "repository(ies): ${missing_sentinels[*]}." + ) in step_body + # The sentinel check must run against the same repositories_json used to + # drive the per-repository coverage loop below it, and must exit before + # that loop starts on a partial list. + sentinel_check_index = step_body.index("PRIVATE_REPOSITORY_COVERAGE_SENTINELS=(") + coverage_loop_index = step_body.index("printf '[]\\n' >\"$coverage_json\"") + assert sentinel_check_index < coverage_loop_index + exit_index = step_body.index( + "exit 1", step_body.index("missing_sentinels[@]") + ) + assert exit_index < coverage_loop_index + + +def test_central_semgrep_filters_source_suppressions_and_gates_on_sarif_results() -> None: + workflow = (REPO_ROOT / ".github/workflows/sast-semgrep.yml").read_text( + encoding="utf-8" + ) + + assert "--output=semgrep-results.raw.sarif" in workflow + assert ( + 'SEMGREP_IMAGE: "semgrep/semgrep@sha256:' + "2b33f46ba66cf8cc2ad59ccfa7d22951fd00c632c38f1339e84ec8e6e641a942\"" + ) in workflow + assert ( + workflow.count( + "2b33f46ba66cf8cc2ad59ccfa7d22951fd00c632c38f1339e84ec8e6e641a942" + ) + == 1 + ) + semgrep_job = workflow.split("\n semgrep:\n", 1)[1] + job_header, steps = semgrep_job.split("\n steps:\n", 1) + assert 'SEMGREP_IMAGE: "semgrep/semgrep@sha256:' in job_header + assert 'echo "Using ${SEMGREP_IMAGE}"' in steps + assert 'docker manifest inspect "${SEMGREP_IMAGE}"' in steps + assert '--entrypoint semgrep \\\n "${SEMGREP_IMAGE}" \\\n' in steps + assert "Verify pinned Semgrep manifest" in workflow + assert "Remove explicitly suppressed findings from Semgrep SARIF" in workflow + assert ".suppressions // []" in workflow + assert "SEMGREP_SUPPRESSED_COUNT" in workflow + assert "semgrep_sarif.outputs.finding_count != '0'" in workflow + assert 'SEMGREP_FINDING_COUNT:-missing}' in workflow + assert "--output=semgrep-results.sarif" not in workflow From f10a05f44b2e02d6c086ce8ecd8dcdf48786b65d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 9 Oct 2026 14:05:26 +0900 Subject: [PATCH 5/6] fix(governance): require ruleset audit authority --- .github/workflows/audit-central-ruleset.yml | 9 +++++++-- docs/org-required-workflow-rollout.md | 7 ++++++- docs/product-technical-gap-baseline.md | 2 +- tests/test_central_required_workflow_ruleset_audit.py | 3 ++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/audit-central-ruleset.yml b/.github/workflows/audit-central-ruleset.yml index 655a319835..65a054e1d4 100644 --- a/.github/workflows/audit-central-ruleset.yml +++ b/.github/workflows/audit-central-ruleset.yml @@ -26,8 +26,6 @@ jobs: audit: name: Audit organization ruleset 18156473 runs-on: ${{ github.repository == 'ContextualWisdomLab/.github' && endsWith(github.workflow_ref, '@refs/heads/main') && fromJSON('{"group":"CWL MCP remediation","labels":["self-hosted","linux","x64"]}') || fromJSON('["ubuntu-24.04"]') }} - env: - GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 @@ -41,12 +39,18 @@ jobs: - name: Read live inherited organization ruleset and repository scope env: + GH_TOKEN: ${{ secrets.CWL_RULESET_AUDIT_TOKEN || '' }} ORG_LOGIN: ContextualWisdomLab + RULESET_WRITE_CREDENTIAL_AVAILABLE: ${{ secrets.CWL_RULESET_AUDIT_TOKEN != '' }} RULESET_ID: "18156473" STACKED_RULESET_ID: "21732164" RULESET_SENTINEL_REPOSITORY: naruon run: | set -euo pipefail + if [ "$RULESET_WRITE_CREDENTIAL_AVAILABLE" = "false" ]; then + echo "::error::Ruleset bypass audit requires CWL_RULESET_AUDIT_TOKEN with ruleset write access; github.token and review/merge credentials are not accepted as substitutes." + exit 1 + fi ruleset_json="$RUNNER_TEMP/central-required-workflow-ruleset.json" ruleset_with_scope_json="$RUNNER_TEMP/central-required-workflow-ruleset-with-scope.json" ruleset_error="$RUNNER_TEMP/central-required-workflow-ruleset.error" @@ -118,6 +122,7 @@ jobs: # unrelated failure. if: always() env: + GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || '' }} ORG_LOGIN: ContextualWisdomLab ORG_WIDE_CREDENTIAL_AVAILABLE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' || secrets.OPENCODE_APPROVE_TOKEN != '' }} run: | diff --git a/docs/org-required-workflow-rollout.md b/docs/org-required-workflow-rollout.md index 83db348060..20ee607f72 100644 --- a/docs/org-required-workflow-rollout.md +++ b/docs/org-required-workflow-rollout.md @@ -411,7 +411,12 @@ non-fork inventory snapshot and rollout ledger, not the ruleset target list. evidence, and immediate removal after the guarded operation; an `ALWAYS` actor turns that exception into an unaudited ordinary merge path. The central audit therefore treats any standing bypass actor, or a missing or malformed - `bypass_actors` collection that cannot prove its absence, as configuration drift. + `bypass_actors` collection that cannot prove its absence, as configuration + drift. The ruleset read uses only the dedicated `CWL_RULESET_AUDIT_TOKEN`, + provisioned with ruleset-write access so GitHub returns `bypass_actors`; an + absent credential fails before the read. The repository `github.token` and + review/merge credentials are not ruleset-audit fallbacks. The separate CodeQL + coverage step retains its org-repository read credentials. - Existing open PRs may need a new push or base update before the latest required workflow SHA appears on their current head. - The central OpenCode workflow now routes model-backed review through the canonical contextual-orchestrator contract; model/provider selection and fallback belong to that owner boundary, not workflow-local heuristics or paid fallback. - The central OpenCode config includes a read-only `code-reviewer` subagent for focused review passes. The subagent may read, grep, glob, and run safe local verification commands, but it must not edit files, stage changes, commit, push, install dependencies, mutate branches, or touch production state. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c562d6ed48..2953004d2e 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -11,7 +11,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| -| CONTROL-RULESET-PERSISTENT-BYPASS-01 | **GREEN locally; protected integration and live ruleset remediation pending** | LineageWeave #1153 head `f18c736f4c51dea62d2f543134e077a3f9d9eb22` and squash result `03c575013e00fbce3d31bdc73eabd2bd13fa65e1` have the same tree, but the head had failed Tests and no APPROVED review. The active organization ruleset exposed an organization-admin `ALWAYS` bypass actor. RED proved `audit_ruleset()` accepted both that standing actor and a payload that omitted `bypass_actors`; GREEN reports the standing actor plus missing or malformed actor data as drift. | `.github` owns `scripts/ci/audit_central_required_workflows.py`. Merge this contract through exact-head Checks and independent review, then remove the persistent actor from live ruleset `18156473` through the protected organization-admin settings path and capture the next scheduled audit success. LineageWeave #1170 preserves the complete Voice delta and retains only the incident record; neither lane retroactively certifies #1153. | +| CONTROL-RULESET-PERSISTENT-BYPASS-01 | **GREEN locally; protected integration, credential provisioning, and live ruleset remediation pending** | LineageWeave #1153 head `f18c736f4c51dea62d2f543134e077a3f9d9eb22` and squash result `03c575013e00fbce3d31bdc73eabd2bd13fa65e1` have the same tree, but the head had failed Tests and no APPROVED review. The active organization ruleset exposed an organization-admin `ALWAYS` bypass actor. RED proved `audit_ruleset()` accepted both that standing actor and a payload that omitted `bypass_actors`; GREEN reports the standing actor plus missing or malformed actor data as drift. The scheduled read now requires the dedicated `CWL_RULESET_AUDIT_TOKEN` capability and never falls back to `github.token`; an absent token or hidden `bypass_actors` fails closed. | `.github` owns `scripts/ci/audit_central_required_workflows.py` and the audit credential boundary. Merge this contract through exact-head Checks and independent review, provision `CWL_RULESET_AUDIT_TOKEN` with ruleset-write access, then remove the persistent actor from live ruleset `18156473` through the protected organization-admin settings path and capture the next scheduled audit success. LineageWeave #1170 preserves the complete Voice delta and retains only the incident record; neither lane retroactively certifies #1153. | ### 2026-09-19 exact-head incident delta diff --git a/tests/test_central_required_workflow_ruleset_audit.py b/tests/test_central_required_workflow_ruleset_audit.py index 48bb441bbf..a8d34010a1 100644 --- a/tests/test_central_required_workflow_ruleset_audit.py +++ b/tests/test_central_required_workflow_ruleset_audit.py @@ -561,7 +561,8 @@ def test_ruleset_audit_requires_dedicated_write_credential() -> None: ) assert 'if [ "$RULESET_WRITE_CREDENTIAL_AVAILABLE" = "false" ]; then' in ruleset_step assert "requires CWL_RULESET_AUDIT_TOKEN with ruleset write access" in ruleset_step - assert "github.token" not in ruleset_step + assert "|| github.token" not in ruleset_step + assert "GH_TOKEN: ${{ github.token }}" not in ruleset_step assert ( "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN " "|| secrets.OPENCODE_APPROVE_TOKEN || '' }}" in coverage_step From 9dff74e5180908b4cf85f9961c7d3f2d873d33b5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 9 Oct 2026 14:05:29 +0900 Subject: [PATCH 6/6] test(governance): keep freshness fixtures current --- tests/test_audit_org_codeql_coverage.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/tests/test_audit_org_codeql_coverage.py b/tests/test_audit_org_codeql_coverage.py index 0ffc8fa749..375958b060 100644 --- a/tests/test_audit_org_codeql_coverage.py +++ b/tests/test_audit_org_codeql_coverage.py @@ -35,9 +35,13 @@ def default_setup_scanning_nothing(name: str) -> dict: } -def covered_by_recent_analysis(name: str, *, days_ago: int = 1) -> dict: +def covered_by_recent_analysis( + name: str, *, days_ago: int = 1, reference_time: datetime = NOW +) -> dict: """Return a repository payload covered by a recent, successful CodeQL analysis.""" - created_at = (NOW - timedelta(days=days_ago)).isoformat().replace("+00:00", "Z") + created_at = (reference_time - timedelta(days=days_ago)).isoformat().replace( + "+00:00", "Z" + ) return { "name": name, "archived": False, @@ -263,7 +267,13 @@ def test_null_latest_analysis_is_not_coverage() -> None: def test_audit_codeql_coverage_defaults_now_to_current_time() -> None: - repositories = [covered_by_recent_analysis("DefaultNowRepo", days_ago=0)] + repositories = [ + covered_by_recent_analysis( + "DefaultNowRepo", + days_ago=0, + reference_time=datetime.now(timezone.utc), + ) + ] assert audit.audit_codeql_coverage(repositories) == [] @@ -302,7 +312,14 @@ def test_main_fail_path_reports_gaps_from_stdin(monkeypatch, capsys) -> None: def test_main_pass_path_reports_from_file_arg(tmp_path, capsys) -> None: payload_path = tmp_path / "repositories.json" payload_path.write_text( - json.dumps([covered_by_default_setup("ELUNVERA"), covered_by_recent_analysis("Orgmetra")]), + json.dumps( + [ + covered_by_default_setup("ELUNVERA"), + covered_by_recent_analysis( + "Orgmetra", reference_time=datetime.now(timezone.utc) + ), + ] + ), encoding="utf-8", )