diff --git a/.github/workflows/accounting-information-platform-hourly-review-repair.yml b/.github/workflows/accounting-information-platform-hourly-review-repair.yml deleted file mode 100644 index 83e1190f0..000000000 --- a/.github/workflows/accounting-information-platform-hourly-review-repair.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Accounting Information Platform Hourly Review Repair - -on: - schedule: - # Minute 27 avoids existing organization product callers and minute-zero pressure. - - cron: "27 * * * *" - -concurrency: - group: accounting-information-platform-hourly-review-repair - # Central OpenCode, Noema, and exact-head accounting checks can exceed one hour. - cancel-in-progress: false - -permissions: - contents: read - -jobs: - dispatch-review-repair: - permissions: - contents: read - id-token: write - uses: ./.github/workflows/pr-review-fix-scheduler.yml - with: - target_repository: ContextualWisdomLab/accounting-information-platform - base_branch: develop - max_prs: "50" - max_dispatches: "1" - retry_hours: "2" - secrets: - PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} diff --git a/.github/workflows/bandscope-hourly-review-repair.yml b/.github/workflows/bandscope-hourly-review-repair.yml deleted file mode 100644 index 78e5276ec..000000000 --- a/.github/workflows/bandscope-hourly-review-repair.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: BandScope Hourly Review Repair - -on: - schedule: - # Minute 53 avoids established product-specific heartbeat minutes. - - cron: "53 * * * *" - -concurrency: - group: bandscope-hourly-review-repair - # Preserve a legitimate long-running root-cause analysis across heartbeats. - cancel-in-progress: false - -permissions: - contents: read - -jobs: - dispatch-review-repair: - permissions: - contents: read - id-token: write - uses: ./.github/workflows/pr-review-fix-scheduler.yml - with: - target_repository: ContextualWisdomLab/bandscope - base_branch: develop - max_prs: "50" - max_dispatches: "1" - # Music, browser, Rust, and NVIDIA-backed review work can exceed one hour. - retry_hours: "2" - secrets: - PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} diff --git a/.github/workflows/governance-risk-compliance-hourly-review-repair.yml b/.github/workflows/governance-risk-compliance-hourly-review-repair.yml deleted file mode 100644 index 08bcab6b7..000000000 --- a/.github/workflows/governance-risk-compliance-hourly-review-repair.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Governance Risk Compliance Hourly Review Repair - -on: - schedule: - # Minute 43 avoids minute-zero pressure and the existing product callers. - - cron: "43 * * * *" - -concurrency: - group: governance-risk-compliance-hourly-review-repair - # Preserve an in-flight exact-head RCA when the next heartbeat arrives. - cancel-in-progress: false - -permissions: - contents: read - -jobs: - dispatch-review-repair: - uses: ./.github/workflows/pr-review-fix-scheduler.yml - with: - target_repository: ContextualWisdomLab/governance-risk-compliance - base_branch: develop - max_prs: "50" - max_dispatches: "1" - # Central OpenCode, Noema, Strix, and security evidence can exceed one hour. - retry_hours: "2" - secrets: - PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} diff --git a/.github/workflows/hourly-nvidia-nim-review-repair.yml b/.github/workflows/hourly-nvidia-nim-review-repair.yml index 0cb5e33dc..5fb02ea17 100644 --- a/.github/workflows/hourly-nvidia-nim-review-repair.yml +++ b/.github/workflows/hourly-nvidia-nim-review-repair.yml @@ -6,21 +6,15 @@ on: - .github/workflows/pr-review-fix-scheduler.yml - scripts/ci/pr_review_fix_scheduler.py - .github/workflows/pr-review-autofix.yml - - .github/workflows/bandscope-hourly-review-repair.yml - .github/workflows/clearfolio-hourly-review-repair.yml - .github/workflows/disksage-hourly-review-repair.yml - .github/workflows/fast-mlsirm-hourly-review-repair.yml - - .github/workflows/governance-risk-compliance-hourly-review-repair.yml - .github/workflows/hourly-nvidia-nim-review-repair.yml - - .github/workflows/originweave-hourly-review-repair.yml - scripts/ci/pr_review_conflict_scope.py - scripts/ci/pr_review_autofix_context.py - - tests/test_bandscope_hourly_review_caller.py - tests/test_disksage_hourly_review_caller.py - tests/test_fast_mlsirm_hourly_review_caller.py - - tests/test_governance_risk_compliance_hourly_review_caller.py - tests/test_hourly_scheduler_runtime_budget.py - - tests/test_originweave_hourly_review_caller.py - tests/test_hourly_autofix_context_quality_gate.py - tests/test_pr_review_conflict_scope.py - tests/test_pr_review_conflict_scope_control_files.py @@ -34,34 +28,25 @@ on: - tests/test_pr_review_autofix_nvidia_nim_contract.py - tests/test_pr_review_autofix_writer_security_contract.py - docs/automation/hourly-review-repair.md - - docs/doctoring/bandscope-hourly-review-caller.md - docs/doctoring/clearfolio-hourly-review-caller.md - docs/doctoring/conflict-control-evidence-isolation.md - docs/doctoring/disksage-hourly-review-caller.md - docs/doctoring/fast-mlsirm-hourly-review-caller.md - - docs/doctoring/governance-risk-compliance-hourly-review-caller.md - docs/doctoring/hourly-nvidia-nim-autofix.md - - docs/doctoring/originweave-hourly-review-caller.md push: paths: - .github/workflows/pr-review-fix-scheduler.yml - scripts/ci/pr_review_fix_scheduler.py - .github/workflows/pr-review-autofix.yml - - .github/workflows/bandscope-hourly-review-repair.yml - .github/workflows/clearfolio-hourly-review-repair.yml - .github/workflows/disksage-hourly-review-repair.yml - .github/workflows/fast-mlsirm-hourly-review-repair.yml - - .github/workflows/governance-risk-compliance-hourly-review-repair.yml - .github/workflows/hourly-nvidia-nim-review-repair.yml - - .github/workflows/originweave-hourly-review-repair.yml - scripts/ci/pr_review_conflict_scope.py - scripts/ci/pr_review_autofix_context.py - - tests/test_bandscope_hourly_review_caller.py - tests/test_disksage_hourly_review_caller.py - tests/test_fast_mlsirm_hourly_review_caller.py - - tests/test_governance_risk_compliance_hourly_review_caller.py - tests/test_hourly_scheduler_runtime_budget.py - - tests/test_originweave_hourly_review_caller.py - tests/test_hourly_autofix_context_quality_gate.py - tests/test_pr_review_conflict_scope.py - tests/test_pr_review_conflict_scope_control_files.py @@ -75,14 +60,11 @@ on: - tests/test_pr_review_autofix_nvidia_nim_contract.py - tests/test_pr_review_autofix_writer_security_contract.py - docs/automation/hourly-review-repair.md - - docs/doctoring/bandscope-hourly-review-caller.md - docs/doctoring/clearfolio-hourly-review-caller.md - docs/doctoring/conflict-control-evidence-isolation.md - docs/doctoring/disksage-hourly-review-caller.md - docs/doctoring/fast-mlsirm-hourly-review-caller.md - - docs/doctoring/governance-risk-compliance-hourly-review-caller.md - docs/doctoring/hourly-nvidia-nim-autofix.md - - docs/doctoring/originweave-hourly-review-caller.md permissions: contents: read @@ -130,12 +112,9 @@ jobs: scripts/ci/pr_review_conflict_scope.py \ scripts/ci/pr_review_autofix_context.py \ tests/test_pr_review_conflict_scope.py \ - tests/test_bandscope_hourly_review_caller.py \ tests/test_disksage_hourly_review_caller.py \ tests/test_fast_mlsirm_hourly_review_caller.py \ - tests/test_governance_risk_compliance_hourly_review_caller.py \ tests/test_hourly_scheduler_runtime_budget.py \ - tests/test_originweave_hourly_review_caller.py \ tests/test_pr_review_conflict_scope_control_files.py \ tests/test_hourly_autofix_context_quality_gate.py \ tests/test_pr_review_conflict_scope_git_executable.py \ @@ -147,4 +126,4 @@ jobs: tests/test_pr_review_autofix_context_head_binding.py \ tests/test_pr_review_autofix_nvidia_nim_contract.py \ tests/test_pr_review_autofix_writer_security_contract.py - git diff --check + git diff --check \ No newline at end of file diff --git a/.github/workflows/organization-commercial-readiness-loop-quality-ci.yml b/.github/workflows/organization-commercial-readiness-loop-quality-ci.yml deleted file mode 100644 index 50729db47..000000000 --- a/.github/workflows/organization-commercial-readiness-loop-quality-ci.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Organization Commercial Readiness Loop Quality CI - -on: - pull_request: - branches: [main] - paths: - - ".github/workflows/organization-commercial-readiness-loop.yml" - - ".github/workflows/organization-commercial-readiness-loop-quality-ci.yml" - - "scripts/ci/organization_commercial_readiness_loop.py" - - "organization_commercial_readiness_fixtures.py" - - "tests/test_organization_commercial_readiness_loop*.py" - - "docs/doctoring/organization-commercial-readiness-loop.md" - - "CHANGELOG.md" - -permissions: - contents: read - -concurrency: - group: organization-commercial-readiness-loop-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - exact-head-policy: - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact source revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.event.pull_request.head.sha }} - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - - - name: Install exact hash-verified quality dependencies - env: - PIP_DISABLE_PIP_VERSION_CHECK: "1" - PIP_NO_INPUT: "1" - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - cat >"${RUNNER_TEMP}/organization-loop-quality-requirements.txt" <<'EOF' - coverage==7.15.2 --hash=sha256:b9a6367e4aff723e8ee8190836836124284e8fcd4265e307c844010cfa074f3f - iniconfig==2.1.0 --hash=sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760 - packaging==26.2 --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e - pluggy==1.6.0 --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 - pygments==2.20.0 --hash=sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176 - pytest==9.1.1 --hash=sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c - EOF - python -m pip install \ - --only-binary=:all: \ - --require-hashes \ - -r "${RUNNER_TEMP}/organization-loop-quality-requirements.txt" - - - name: Prove exact-head policy and full branch coverage - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - test "$(git rev-parse HEAD)" = "${{ github.event.pull_request.head.sha }}" - python -m coverage run \ - --branch \ - -m pytest --import-mode=importlib tests/test_organization_commercial_readiness_loop*.py -q - python -m coverage report \ - --include='scripts/ci/organization_commercial_readiness_loop.py' \ - --show-missing \ - --fail-under=100 - python -m compileall -q \ - scripts/ci/organization_commercial_readiness_loop.py \ - organization_commercial_readiness_fixtures.py \ - tests/test_organization_commercial_readiness_loop*.py - git diff --exit-code diff --git a/.github/workflows/organization-commercial-readiness-loop.yml b/.github/workflows/organization-commercial-readiness-loop.yml deleted file mode 100644 index 521495617..000000000 --- a/.github/workflows/organization-commercial-readiness-loop.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Organization Commercial Readiness Loop - -on: - schedule: - - cron: "7 * * * *" - -concurrency: - group: organization-commercial-readiness-loop - cancel-in-progress: false - -permissions: - contents: read - -jobs: - coordinate: - if: >- - github.repository == 'ContextualWisdomLab/.github' && - github.ref == format('refs/heads/{0}', github.event.repository.default_branch) - runs-on: ubuntu-24.04 - timeout-minutes: 25 - env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - ORGANIZATION: ContextualWisdomLab - ROTATION_SEED: ${{ github.run_number }} - MAX_REPOSITORIES: "200" - MAX_REVIEW_DISPATCHES: "1" - MAX_DEVELOPMENT_DISPATCHES: "1" - steps: - - name: Harden runner - uses: step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.13.2 - with: - egress-policy: block - allowed-endpoints: >- - api.github.com:443 - github.com:443 - objects.githubusercontent.com:443 - release-assets.githubusercontent.com:443 - results-receiver.actions.githubusercontent.com:443 - *.actions.githubusercontent.com:443 - *.blob.core.windows.net:443 - - - name: Checkout exact trusted coordinator source - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ github.sha }} - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - - - name: Coordinate one bounded fleet pass - env: - GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - shell: bash --noprofile --norc -e -o pipefail {0} - run: | - if [ -z "${GH_TOKEN:-}" ]; then - echo "::error::PR_REVIEW_MERGE_TOKEN is required; neither the reviewer credential nor repository-scoped GITHUB_TOKEN is accepted." - exit 1 - fi - echo "::add-mask::$GH_TOKEN" - test "$(git rev-parse HEAD)" = "${GITHUB_SHA}" - - python scripts/ci/organization_commercial_readiness_loop.py \ - --organization "$ORGANIZATION" \ - --rotation-seed "$ROTATION_SEED" \ - --max-repositories "$MAX_REPOSITORIES" \ - --max-review-dispatches "$MAX_REVIEW_DISPATCHES" \ - --max-development-dispatches "$MAX_DEVELOPMENT_DISPATCHES" \ - --json-output "$RUNNER_TEMP/organization-commercial-readiness-loop.json" - python -m json.tool "$RUNNER_TEMP/organization-commercial-readiness-loop.json" >/dev/null - - - name: Preserve the exact fleet receipt - if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: organization-commercial-readiness-${{ github.run_id }}-${{ github.run_attempt }} - path: ${{ runner.temp }}/organization-commercial-readiness-loop.json - if-no-files-found: error - retention-days: 3 diff --git a/.github/workflows/originweave-hourly-review-repair.yml b/.github/workflows/originweave-hourly-review-repair.yml deleted file mode 100644 index 195a09e50..000000000 --- a/.github/workflows/originweave-hourly-review-repair.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: OriginWeave Hourly Review Repair - -on: - schedule: - # Minute 10 avoids pg-llm-batch (1), aFIPC (2), kaefa (3), LineageWeave (4), - # codec-carver (5), life-os (6), Wardnet (7), mightyETL (8), - # psychometrics-commons (9), naruon (11), pg-erd-cloud (13), - # orchestrator (17), noema (19), Clearfolio (23), Keyverse (29), - # Scopeweave (31), DiskSage (37), Appguardrail (41), newsdom-api (43), - # Inkspan (47), fast-mlsirm (49), BandScope (53), and - # semantic-data-portal (59). - - cron: "10 * * * *" - -concurrency: - group: originweave-hourly-review-repair - # A later heartbeat must not cancel an in-flight agent-browser RCA. - cancel-in-progress: false - -permissions: - contents: read - -jobs: - dispatch-review-repair: - permissions: - contents: read - id-token: write - uses: ./.github/workflows/pr-review-fix-scheduler.yml - with: - target_repository: ContextualWisdomLab/OriginWeave - base_branch: main - max_prs: "50" - max_dispatches: "1" - retry_hours: "2" - secrets: - PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }} - OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }} diff --git a/.gitignore b/.gitignore index b98cb1f1d..ddf814fe1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__/ .coverage .pytest_cache/ .codegraph/ +venv diff --git a/.jules/bolt.md b/.jules/bolt.md index 420e6d7e2..a86b7aafd 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -43,7 +43,3 @@ ## 2026-07-09 - Avoid N+1 API blocking in SBOM aggregator **Learning:** The `collect_inventories` function in `scripts/ci/sbom_inventory_aggregator.py` was fetching SBOMs from the GitHub dependency graph synchronously for every repository in the organization. For large organizations (up to 500 repos), this N+1 network/CLI bottleneck significantly stalled the aggregation workflow. **Action:** Use `concurrent.futures.ThreadPoolExecutor` to fetch SBOMs concurrently when multiple repositories are provided, bounded by a `max_workers` limit (e.g., 10) to avoid overwhelming the CLI/API, while preserving the fast serial path for single-item inputs. - -## 2026-08-09 - [대용량 로그 스캔 시 정규표현식 실행 전 O(N) 서브스트링 검증 선행] -**Learning:** `classify_testthat_failure`에서 테스트 실패 내역이 없는 2MB 로그 파일을 대상으로 정규표현식을 실행하면 약 20ms가 소요되지만, 단순 문자열 검색은 약 1ms만 소요됩니다. 문자열 존재 여부가 정규표현식 매칭의 전제 조건일 때, 콜드 패스(Cold Path)에서 순서 최적화는 매우 큰 성능 차이를 만듭니다. -**Action:** 대용량 텍스트 입력(CI 로그 등)에서 복잡한 정규표현식을 파싱하기 전에 항상 빠른 O(N) 문자열 존재 여부 확인을 먼저 수행하십시오. diff --git a/.jules/sentinel.md b/.jules/sentinel.md index be2dfa4bb..96977f528 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -35,3 +35,11 @@ **Vulnerability:** Command Injection **Learning:** Fixing a `shell=True` vulnerability by replacing it with `shell=False` and wrapping the command string in `["/bin/bash", "-lc", command]` is incomplete and still leaves the code vulnerable to shell injection. It acts as security theater, as it misleads linters while executing untrusted input via the bash wrapper. The vulnerability was still present in `sandboxed_web_e2e.py`. **Prevention:** Remove `/bin/bash` wrapper from `subprocess` calls in CI scripts. Always use `shlex.split(command)` to safely parse strings into a list of arguments and pass the list directly to `subprocess.Popen` or `subprocess.run`. +## 2026-08-16 - Add explicit shell=False to Subprocess in CI Python Scripts +**Vulnerability:** Implicit shell execution risk and linter requirement bypassing +**Learning:** `subprocess.run` and `subprocess.Popen` without explicit `shell=False` arguments fail security linting checks and leave ambiguity about shell execution intentions. Linters like bandit require `shell=False` for validation even if the default behavior is safe. +**Prevention:** Always explicitly define `shell=False` in `subprocess.run` and `subprocess.Popen` calls. +## 2026-08-16 - Add hostname validation to prevent SSRF +**Vulnerability:** Server-Side Request Forgery (SSRF) +**Learning:** Functions that accept URLs and make requests, like `wait_for_url` in `sandboxed_web_e2e.py`, must restrict the destination host to prevent an attacker from probing internal services or endpoints via malicious input parameters. +**Prevention:** Always validate that the parsed URL hostname explicitly points to a safe destination, such as `localhost` or `127.0.0.1`, before making a request. diff --git a/AGENTS.md b/AGENTS.md index 0fda888c7..16f0981c0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,4 +5,3 @@ Materialize accepts only exact SHA-256 pins or a bounded relative `-r` include (no `.`/`..`); a lone `--require-hashes` directive is not trust evidence. See [`docs/doctoring/hourly-nvidia-nim-autofix.md`](docs/doctoring/hourly-nvidia-nim-autofix.md). Conflict-scope roots fail closed when the immediate parent directory is a symbolic link. -OriginWeave hourly NVIDIA NIM repair is a thin caller at minute 10. See [`docs/doctoring/originweave-hourly-review-caller.md`](docs/doctoring/originweave-hourly-review-caller.md). diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 01f634ec5..6fe6621b6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -25,13 +25,6 @@ flowchart LR Products -->|"standalone or as module"| Buyer ``` -## OriginWeave hourly caller - -`originweave-hourly-review-repair.yml` is a thin, read-only caller at minute -10. It names `ContextualWisdomLab/OriginWeave` and protected `main`, maps -only established scheduler credentials, and grants job-scoped -`id-token: write`. The reusable engine stays product-neutral. - ## Hourly NVIDIA NIM repair gate ```mermaid @@ -101,9 +94,7 @@ sequenceDiagram `scripts/ci/` ships with 100% statement/branch coverage and 100% docstrings. CI installs Python tools only with `pip install --require-hashes`. Contract -tests pin workflow structure and governance prose so drift fails closed. The -trusted `uv` exporter is downloaded from the literal GitHub Releases URL for -`uv` 0.12.1; `releases.astral.sh` is not the network sink. +tests pin workflow structure and governance prose so drift fails closed. ## Related durable documents diff --git a/CHANGELOG.md b/CHANGELOG.md index da15d1dcb..1de9130a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,6 @@ Semantic Versioning where the repository publishes a release. ### Added -- 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 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 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. @@ -26,14 +24,8 @@ Semantic Versioning where the repository publishes a release. - 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 -- 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). - 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. - 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). - 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. diff --git a/CLAUDE.md b/CLAUDE.md index 65ee3ce81..7127d3c1c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -114,9 +114,6 @@ repeatable compile command. without running the test suite will break CI. - **100% coverage and 100% docstrings on `scripts/ci/`** are hard gates, not aspirations. New helper code needs matching tests and docstrings. -- **Product hourly callers** stay thin. Do not hard-code OriginWeave, naruon, or Keyverse - into `pr-review-fix-scheduler.yml`. The model credential remains `NVIDIA_NIM_API_KEY` - on the worker, never `COPILOT_GITHUB_TOKEN`. - **`pull_request_target` trust boundary.** The required review workflows run the *base branch's* trusted scripts. A PR that edits the trusted review workflows can fail its own checks until the base branch catches up; a same-head manual `workflow_dispatch` Strix run may supply review evidence diff --git a/docs/doctoring/bandscope-hourly-review-caller.md b/docs/doctoring/bandscope-hourly-review-caller.md deleted file mode 100644 index 67c281e2d..000000000 --- a/docs/doctoring/bandscope-hourly-review-caller.md +++ /dev/null @@ -1,110 +0,0 @@ -# BandScope hourly review-repair caller - -## Status - -Accepted on 2026-08-18 as the product-specific heartbeat for -`ContextualWisdomLab/bandscope`. The music repository remains the sole writer of -its application, audio-analysis, Rust, Storybook, and Figma-owned product code; -central `.github` owns only the reusable queue, credential, and dispatch control -plane. - -## Buyer problem - -BandScope has a dependency-root and several stacked buyer-visible rehearsal -slices. Repository checks, independent review, and central evidence can complete -at different times. Without a bounded heartbeat, actionable current-head review -findings may remain idle even though another exact-head repair can be performed -without crossing product ownership boundaries. - -## Decision - -The caller runs at minute 53 of every hour and invokes the sealed central -`pr-review-fix-scheduler.yml` with protected base `develop`. Minute 53 avoids the -established product-specific heartbeat minutes already present on protected -central `main`. Each heartbeat scans at most 50 open pull requests and dispatches -at most one writer. The two-hour same-head retry floor prevents a later heartbeat -from duplicating a legitimate OpenCode, Strix, Noema, browser, Rust, or -NVIDIA-backed investigation. The non-cancelling concurrency contract preserves -root-cause analysis already in progress. - -A writer may edit only after it establishes the first causal boundary, compares -bounded remediation candidates, proves remediation feasibility, verifies writer -and dependency ownership, and defines a RED-to-GREEN test. Review latency or a -queued workflow is not itself a reason to stop scanning other eligible work. - -## Music-science merge boundary - -Automation must not convert synthetic success into a product-quality claim. -Every music-information-retrieval or rehearsal-analysis change requires the -metric appropriate to the feature and a real-audio acceptance fixture whose -expected musical result is independently specified. Examples include annotated -beat or onset timing, known chord progression, stem alignment, score-to-audio -correspondence, role range, and section-boundary expectations. Synthetic fixtures -remain useful for edge cases, but they do not replace authorized or openly -licensed recordings and annotation provenance. - -Rust-owned production arithmetic remains in Rust when BandScope assigns an -algorithm or decoder to that layer. Python, TypeScript, browser, and UI code may -orchestrate, validate, visualize, and compare results, but an automated repair -must not silently move owned numerical work into a convenience layer. Changes -must retain CPU/GPU or native/portable parity where the owning product contract -requires it, complete production statement and branch coverage, public docstring -coverage, and realistic regression evidence. - -## Credential and approval boundary - -The workflow-wide token remains read-only. The reusable caller job grants only -`contents: read` and `id-token: write`: the latter permits the already-established -central OpenCode GitHub App exchange when mapped `PR_REVIEW_MERGE_TOKEN` and -`OPENCODE_APPROVE_TOKEN` credentials are unavailable. It does not grant repository -contents, pull-request, issue, action, or status mutation to the caller token. -The caller never uses `secrets: inherit` and does not receive -`NVIDIA_NIM_API_KEY`; that model credential remains sealed inside the central -OpenCode execution step. `COPILOT_GITHUB_TOKEN` is forbidden. Existing reviewer -credential and model-pool contracts are not changed by this caller. - -Before protected merge, organization operators must confirm that -`OPENCODE_REPOSITORY_DISPATCH_TARGETS` includes the exact -`ContextualWisdomLab/bandscope` repository and that the established app/OIDC or -mapped-secret path can dispatch the central workflow without broadening the -allowlist. A missing allowlist entry must fail closed rather than silently turn -the hourly heartbeat into a no-op. - -A repair does not authorize approval or merge. The exact unchanged head still -requires terminal required checks, zero valid unresolved findings, qualifying -independent non-author approval, and ordinary branch-protection acceptance. -Agents must not self-approve, synthesize status evidence, weaken rulesets, or -force-cancel a legitimate long-running analysis. - -## Standalone and ecosystem operation - -BandScope must remain usable as a standalone desktop/web product. Ecosystem -connections to naruon, contextual-orchestrator, Semantic Data Portal, billing, -or other CWL products use versioned package/API/event contracts. The hourly -caller may repair BandScope-owned adapters, but it may not write a dedicated -sibling repository or copy sibling internals into BandScope. - -## Verification and rollback - -The caller, this doctoring record, and their contract test are tracked by the -permanent hourly NVIDIA NIM quality workflow. Verification requires the focused -contract suite, compile checks, complete owned coverage/docstrings, and -exact-current-head protected checks. Rollback removes the product caller and its -focused tracking together; it must not leave a timer that points at a renamed or -unverified reusable workflow. - -## APA 7th references - -Bittner, R. M., Fuentes, M., Rubinstein, D., Jansson, A., Choi, K., & Kell, T. -(2019). mirdata: Software for reproducible usage of datasets. In *Proceedings of -the 20th International Society for Music Information Retrieval Conference* (pp. -99–106). International Society for Music Information Retrieval. - -Raffel, C., McFee, B., Humphrey, E. J., Salamon, J., Nieto, O., Liang, D., Ellis, -D. P. W., & Raffel, C. C. (2014). mir_eval: A transparent implementation of -common MIR metrics. In *Proceedings of the 15th International Society for Music -Information Retrieval Conference* (pp. 367–372). International Society for -Music Information Retrieval. - -GitHub. (2026). *Security hardening for GitHub Actions*. GitHub Docs. -https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions diff --git a/docs/doctoring/governance-risk-compliance-hourly-review-caller.md b/docs/doctoring/governance-risk-compliance-hourly-review-caller.md deleted file mode 100644 index f5155a2b9..000000000 --- a/docs/doctoring/governance-risk-compliance-hourly-review-caller.md +++ /dev/null @@ -1,51 +0,0 @@ -# Governance Risk Compliance Hourly Review Caller - -## Decision - -`ContextualWisdomLab/.github` owns the hourly review-repair scheduler and its privileged OpenCode worker. The GRC product receives a small caller at minute 43 of every hour. Each heartbeat inspects up to 50 open pull requests, dispatches at most one repair, and preserves an in-flight writer. The caller targets the product's protected `develop` branch. - -The scheduler requires root-cause analysis and remediation feasibility before a branch mutation. A two-hour same-head retry floor accommodates central OpenCode, Noema, Strix, security, and coverage work without treating provider or runner latency as a source defect or dispatching duplicate writers. - -## Product ownership boundary - -`ContextualWisdomLab/governance-risk-compliance` owns policy, control, risk, evidence, and compliance-audit truth. It does not absorb central CI/security implementation or another CWL product's authority. - -- Keyverse owns identity and federation. A repair must not invent authentication inside the GRC product or weaken its local-only preview boundary. -- GRC retains exact operational evidence values. Repair must not introduce blanket or destructive PII masking; it must preserve authenticated purpose and tenant authorization, encryption, audit, retention, and purpose-specific omission of unrelated fields. -- Orgmetra, accounting, billing, naruon, enterprise architecture, and semantic data products remain contract consumers or evidence producers within their own ownership boundaries. -- Product repair may change the validated same-repository PR branch only. Central workflows, credentials, rulesets, and provider configuration remain owned by `.github`. - -## Credential and model boundary - -The caller keeps the workflow-generated token read-only and forwards only the established scheduler mutation credentials. It contains no model-provider secret. - -The central worker may use `NVIDIA_NIM_API_KEY` through its reviewed credential boundary. The caller and GRC repository must not use `COPILOT_GITHUB_TOKEN`. The independent read-only reviewer keeps its separate credential and model-pool contract; review and write-capable repair remain distinct controls. - -The scheduler dispatches at most one repair per heartbeat. A repair worker cannot approve its own change, reinterpret failed or queued checks as success, lower protection, merge, publish, or release. - -## Exact-head merge contract - -A GRC pull request may merge only after the unchanged current head has: - -1. terminal-success product, coverage, SAST, security, and supply-chain checks; -2. zero valid unresolved review findings; -3. a current-head semantic review verdict; -4. independent non-author approval when required by live protection; -5. a compatible live base and ordinary expected-head merge authority; and -6. current documentation, CHANGELOG, ADR, and APA 7th references for standards-backed decisions. - -Queued, pending, skipped-required, cancelled, stale, predecessor-head, local-only, author-only, synthetic, or model-only evidence is not acceptance. Review or check latency is not a blocker to examining the next eligible PR or buyer-visible product gap, but it is never permission to bypass a gate. - -## Activation and fail-closed behavior - -GitHub scheduled workflows run from the default branch. The heartbeat becomes active only after this caller reaches protected `.github` `main`. The central scheduler also requires `ContextualWisdomLab/governance-risk-compliance` in the organization target allowlist. A missing target or mutation authority fails closed. - -The caller does not create a second provider configuration, review agent, or merge engine. Rollback removes the caller, focused contract, quality-workflow path tracking, and this doctoring record together; it does not weaken the reusable central scheduler. - -## References - -GitHub, Inc. (n.d.-a). *Events that trigger workflows*. GitHub Docs. Retrieved August 18, 2026, from https://docs.github.com/actions/using-workflows/events-that-trigger-workflows - -GitHub, Inc. (n.d.-b). *Reusing workflow configurations*. GitHub Docs. Retrieved August 18, 2026, from https://docs.github.com/actions/using-workflows/reusing-workflows - -National Institute of Standards and Technology. (2024). *The NIST Cybersecurity Framework (CSF) 2.0* (NIST CSWP 29). U.S. Department of Commerce. https://doi.org/10.6028/NIST.CSWP.29 diff --git a/docs/doctoring/organization-commercial-readiness-loop.md b/docs/doctoring/organization-commercial-readiness-loop.md deleted file mode 100644 index 76ef1fce5..000000000 --- a/docs/doctoring/organization-commercial-readiness-loop.md +++ /dev/null @@ -1,69 +0,0 @@ -# Organization commercial-readiness coordinator - -## Decision - -ContextualWisdomLab uses one organization-central hourly coordinator for repositories that do not already have an enabled dedicated commercial, maintenance, review-repair, or product-development writer. The coordinator complements rather than duplicates the existing 15-minute organization merge scheduler. - -The coordinator may dispatch at most one review-repair workflow and one product-development workflow per hour. These may target different repositories, so review or check latency in one repository does not stop useful work in another. The coordinator never approves, merges, releases, edits source, or interprets a failed check as success by itself. - -## Why this is realistic - -A single workflow cannot safely write every repository merely because it runs in the organization `.github` repository. GitHub's default `GITHUB_TOKEN` is scoped to the repository containing the workflow; cross-repository Actions dispatch therefore requires an explicitly provisioned user or GitHub App credential with the required repository and Actions permissions. This control does not make every repository directly writable. It only considers repositories the live API reports as organization-owned, non-fork, enabled, non-archived, default-branch-bearing, and writable by the authenticated installation. - -The central job therefore refuses both repository-scoped and reviewer-scoped token fallbacks. It requires the maintainer-scoped `PR_REVIEW_MERGE_TOKEN`; `OPENCODE_APPROVE_TOKEN` remains isolated to the reviewer credential chain and `GITHUB_TOKEN` is not accepted for cross-repository coordination. The maintainer token is exposed only to the final dispatch shell step, not checkout, setup, artifact upload, or other third-party actions. The coordinator itself receives neither `NVIDIA_NIM_API_KEY` nor `COPILOT_GITHUB_TOKEN`. Model credentials remain inside separately reviewed repository-local or central workers. - -## Dynamic repository-writer lease - -An active workflow with a scheduled high-signal commercial/development/maintenance/review-repair identity owns the repository writer lease. A queued, in-progress, waiting, pending, or requested run with the same identity also owns a live lease. The organization coordinator skips that repository for the entire pass. - -A disabled workflow does not hold a lease. A manual-only workflow does not hold a lease unless it is already running. If an active high-signal workflow exists but its source cannot be read, the coordinator fails closed and treats the repository as leased. The organization-required merge scheduler is explicitly excluded from this classification because it is a governance gate rather than a product-code writer. - -The coordinator lists workflow metadata for every repository but fetches exact workflow source only for identities that can plausibly be a repository writer. This keeps API use proportional to writer candidates rather than every ordinary CI, packaging, or security workflow. Active-run and pull-request inventories remain fully paginated, including writers beyond the first 100 queued or running executions. - -Before every dispatch, the coordinator refetches the exact default-branch SHA, active workflow identities and source blobs, active runs, and open pull-request heads, bases, draft states, and update timestamps. Any change invalidates the predecessor snapshot. A newly appearing writer causes `skipped_writer_lease`; any other movement causes `skipped_state_changed`. - -## Review-repair boundary - -A repository with at least one non-draft pull request targeting its default branch may receive one `pr-review-fix-scheduler` repository dispatch. Draft and stacked pull requests are not treated as generic repair targets because the coordinator cannot safely infer their dependency order. The established central scheduler and autofix worker remain responsible for thread classification, current-head checks, path bounds, credential isolation, and whether a repair is actually warranted. - -The existing organization merge scheduler continues to own review dispatch, branch updates, exact-head approval evaluation, direct or automatic merge, and branch-protection compliance. The hourly coordinator does not create a second merge implementation. - -## Product-development boundary - -Product development is dispatched only when a repository has zero open pull requests and exposes one active, manual-only, explicitly marked workflow: - -```yaml -# cwl-org-commercial-entrypoint: v1 -on: - workflow_dispatch: -``` - -The entrypoint must contain an explicit `concurrency` contract, use `NVIDIA_NIM_API_KEY`, omit `COPILOT_GITHUB_TOKEN`, have no schedule of its own, and carry a commercial/product-development identity. This opt-in prevents the central coordinator from guessing that an unrelated manual workflow can safely modify product source. Repositories with an existing schedule keep their own lease and are never double-dispatched. - -The repository-local entrypoint remains responsible for its own bounded editable paths, tests, 100% production statement and branch coverage, public docstrings, package and security verification, exact-head publication, and pull-request creation. A missing compliant entrypoint is a deliberate no-op, not permission to inject a generic writer into that repository. - -## Failure, evidence, and operations - -The schedule runs at minute 7 rather than minute 0 to reduce exposure to the documented start-of-hour GitHub Actions load spike. The central workflow has no `workflow_dispatch` entrypoint, so branch-selected coordinator source cannot be executed; scheduled execution occurs only from protected default `main`. Local operators may use the script's `--dry-run` mode from a reviewed checkout without adding a central manual workflow entrypoint. - -Organization, workflow, active-run, and pull-request inventories are paginated. One inaccessible repository is recorded as an inspection error while other independently safe repositories continue. A run fails nonzero when every selected repository inspection fails or when every planned dispatch fails; partial, independently contained failures remain visible without discarding successful work. - -Each run writes one deterministic JSON receipt and the same bounded evidence to the GitHub Actions job summary. The JSON is uploaded through the immutable, SHA-pinned artifact action with a three-day retention period. Artifact upload receives no maintainer or model credential. The receipt proves only coordinator observations and downstream dispatch acceptance; it is not merge, release, or product-quality evidence. - -No queued, pending, skipped-required, cancelled, absent, stale-head, predecessor-head, synthetic-merge-only, or failed check is converted to passing evidence. The coordinator's successful dispatch means only that exact state was revalidated and a bounded downstream workflow was accepted by GitHub. - -Rollback is removal or disabling of `.github/workflows/organization-commercial-readiness-loop.yml`. Repository-local dedicated loops and the existing 15-minute merge scheduler remain independently operational. - -## APA 7 references - -GitHub. (n.d.). *Automatic token authentication*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication - -GitHub. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows - -GitHub. (n.d.). *REST API endpoints for artifacts*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/rest/actions/artifacts - -GitHub. (n.d.). *REST API endpoints for workflows*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/rest/actions/workflows - -GitHub. (n.d.). *REST API endpoints for workflow runs*. GitHub Docs. Retrieved August 8, 2026, from https://docs.github.com/en/rest/actions/workflow-runs - -National Institute of Standards and Technology. (2022). *Secure software development framework (SSDF) version 1.1: Recommendations for mitigating the risk of software vulnerabilities* (NIST Special Publication 800-218). https://doi.org/10.6028/NIST.SP.800-218 diff --git a/docs/doctoring/originweave-hourly-review-caller.md b/docs/doctoring/originweave-hourly-review-caller.md deleted file mode 100644 index 8ed460abb..000000000 --- a/docs/doctoring/originweave-hourly-review-caller.md +++ /dev/null @@ -1,141 +0,0 @@ -# OriginWeave hourly review-repair caller - -검토 기준일: **2026-08-17** - -## Decision - -ContextualWisdomLab operates one protected hourly caller for -`ContextualWisdomLab/OriginWeave` (Chromium-compatible agent web runtime -with isolated sessions, typed actions, resource governance, and -verifiable evidence). The caller runs at minute 10, delegates to the -product-neutral central review-fix scheduler, inspects at most 50 open -pull requests targeting protected `main`, and dispatches at most one -bounded repair per heartbeat. - -A paying buyer of governed agent browsing would feel live OriginWeave -pull requests stalling while hourly NVIDIA NIM repair scanned only -Clearfolio, DiskSage, and fast-mlsirm. Live heads such as -ContextualWisdomLab/OriginWeave#175 (refuse Chrome-as-agent downloads), -ContextualWisdomLab/OriginWeave#173 (document-epoch rotation), -ContextualWisdomLab/OriginWeave#168 (stateless typed MCP routing), and -ContextualWisdomLab/OriginWeave#166 (standard denial-reason contract) -target `main` and never enter those other callers. - -The caller does not implement review or mutation logic itself. -OriginWeave remains standalone; naruon and noema may drive its sessions -without owning the browser runtime. Privileged automation stays in -`ContextualWisdomLab/.github`. - -## Root-cause analysis and remediation feasibility - -The reusable worker performs exact-head root-cause analysis and tests -remediation feasibility before it edits. The reusable worker must: - -1. Refetch the exact live head, base, reviews, checks, changed paths, and - writer state. -2. Establish the causal chain rather than repeat the terminal symptom. -3. Enumerate materially distinct minimal remedies. -4. Reject remedies that lack writer authority, cross sealed paths, require - unavailable credentials or protected-setting changes, violate stack - order, cannot be verified, or do not alter the diagnosed cause. -5. Dispatch at most one feasible repair. Otherwise leave the tree - unchanged. - -A queued or pending check remains a merge blocker but is not itself a -code finding. The independent non-author approval remains an external -authorization gate and is never synthesized by the repair worker. The -worker cannot approve, merge, release, resolve review findings by -inference, change protection, or manufacture passing checks. - -## Cadence and concurrency - -The caller uses a single concurrency group and `cancel-in-progress: false`. -This preserves an in-flight bounded RCA instead of discarding browser -evidence when the next hourly heartbeat arrives. The reusable scheduler -cancels only its own superseded short queue scan. - -The caller sets a **two-hour same-head retry floor**. Central OpenCode and -NVIDIA NIM work, plus download-policy or epoch-rotation analysis, can -legitimately approach two hours. An hourly redispatch of the same -unchanged head would create duplicate writer pressure rather than faster -remediation. - -GitHub scheduled workflows can be delayed under load and execute only -from the default branch. The cron expression is a heartbeat, not a -real-time SLA. - -## Credential and model boundary - -The caller keeps workflow `GITHUB_TOKEN` at `contents: read` and grants -the reusable job `id-token: write` so the central scheduler can mint the -OpenCode GitHub App token from GitHub OIDC when the mapped PAT is absent -(GitHub, n.d.-c). It maps only `PR_REVIEW_MERGE_TOKEN` and -`OPENCODE_APPROVE_TOKEN`. It never uses `secrets: inherit`, receives -`NVIDIA_NIM_API_KEY`, or introduces `COPILOT_GITHUB_TOKEN`. CWE-250 -forbids executing the caller with write or model privileges it does not -need (MITRE, 2026). - -Model execution remains inside the central worker. The model credential -is the GitHub Secret `NVIDIA_NIM_API_KEY`; the caller does not receive or -forward it. - -Before protected-main activation, the repository variable -`OPENCODE_REPOSITORY_DISPATCH_TARGETS` must contain the exact -`ContextualWisdomLab/OriginWeave` target. Missing or mismatched -configuration fails before mutation credential materialization. - -## Security, standalone operation, and modularity - -The caller adds no OriginWeave runtime dependency, database object, -network endpoint, tenant authority, or product credential. OriginWeave -continues to run as a standalone agent-browser runtime. Naruon, noema, -and other CWL services may drive sessions, but they cannot weaken its -exact-head, approval, or security gates. - -## Verification and rollback - -Machine-checkable contracts require the exact target/base, minute 10 -cadence, non-cancelling single-flight group, one dispatch, two-hour -retry floor, explicit secret mapping, read-only contents plus job-scoped -`id-token: write`, focused path-filter coverage, and absence of model or -Copilot credentials. Independent `pull_request`, `push`, and `compileall` -path blocks must each name the caller, doctoring, or contract they own. - -After source integration, closure requires a scheduled or manual -protected-main consumer run proving the exact OriginWeave repository and -`main` base. Source checks alone are not protected-main operational acceptance. -Merge still requires zero unresolved valid findings and a -qualifying independent non-author approval. - -Rollback removes the OriginWeave caller, its focused test, doctoring, and -central path-filter/documentation entries. It must not remove scheduler -dispatch validation or affect independent product callers. - -## APA 7th references - -GitHub, Inc. (n.d.-a). *Events that trigger workflows*. GitHub Docs. -Retrieved August 17, 2026, from -https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule - -GitHub, Inc. (n.d.-b). *Reuse workflows*. GitHub Docs. Retrieved August -17, 2026, from -https://docs.github.com/en/actions/how-tos/sharing-automations/reuse-workflows - -GitHub, Inc. (n.d.-c). *Automatic token authentication*. GitHub Docs. -Retrieved August 17, 2026, from -https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#permissions-for-the-github_token - -MITRE. (2026). *CWE-250: Execution with unnecessary privileges*. -https://cwe.mitre.org/data/definitions/250.html - -National Institute of Standards and Technology. (2022). *Secure software -development framework (SSDF) version 1.1: Recommendations for mitigating -the risk of software vulnerabilities* (NIST Special Publication 800-218). -https://doi.org/10.6028/NIST.SP.800-218 - -NVIDIA. (n.d.). *NVIDIA NIM for large language models documentation*. -Retrieved August 17, 2026, from -https://docs.nvidia.com/nim/large-language-models/latest/ - -OpenCode. (n.d.). *OpenCode documentation*. Retrieved August 17, 2026, -from https://opencode.ai/docs/ diff --git a/docs/doctoring/trusted-uv-lock-materialization.md b/docs/doctoring/trusted-uv-lock-materialization.md index 2d83e8bda..8f78759ca 100644 --- a/docs/doctoring/trusted-uv-lock-materialization.md +++ b/docs/doctoring/trusted-uv-lock-materialization.md @@ -18,16 +18,10 @@ The implementation therefore: absence; 3. installs one process-wide urllib opener with an empty proxy map and a redirect handler that rejects every redirect before urllib creates a target request; -4. downloads one fixed official `uv` archive from the literal GitHub Releases - HTTPS URL and accepts a response only when its parsed origin remains HTTPS on - `github.com`, `release-assets.githubusercontent.com`, or - `objects.githubusercontent.com` with the absent or explicit default port 443; - malformed or nondefault ports, userinfo, and any other host fail closed. The - opener may follow exactly one hop from `github.com` onto those two GitHub - release-asset hosts. `releases.astral.sh` is no longer the network sink - because that vanity host now returns HTTP 403 for the pinned 0.12.1 archive - (ContextualWisdomLab/.github#1109) while the GitHub Releases asset keeps the - same SHA-256 digest; +4. downloads one fixed official Astral `uv` archive from a literal HTTPS URL and + accepts a response only when its parsed origin remains HTTPS, + `releases.astral.sh`, and the absent or explicit default port 443; malformed + or nondefault ports fail closed; 5. verifies the bounded archive with a pinned SHA-256 digest before extraction; 6. accepts only the expected regular-file tar member within explicit size bounds; 7. writes the executable with mode `0755` and verifies that it reports the exact @@ -110,12 +104,10 @@ Regression coverage must prove: - base-revision-only reads and rejection of unsafe revision/path shapes; - an absent sibling project is skipped, but an inventoried project blob that cannot be read propagates a fatal error before uv starts; -- the download opener is cached, disables ambient proxies, and follows only one - `github.com` → GitHub release-asset CDN hop before rejecting every other - redirect; -- fixed HTTPS scheme and hostname validation for GitHub Releases plus the two - official asset hosts, acceptance only of an absent or explicit port 443, - rejection of userinfo, malformed ports, and nondefault ports, bounded reads, +- the download opener is cached, disables ambient proxies, and rejects redirects + before following them; +- fixed HTTPS scheme and hostname validation, acceptance only of an absent or + explicit port 443, rejection of malformed and nondefault ports, bounded reads, archive digest, member type, member size, executable size, executable mode, and exact version; - frozen, offline, cacheless, noninteractive exporter arguments; @@ -179,9 +171,6 @@ accepted by the coverage sandbox. ## References -Astral Software, Inc. (n.d.). *Installation*. uv documentation. Retrieved -August 18, 2026, from https://docs.astral.sh/uv/getting-started/installation/ - Astral Software, Inc. (n.d.). *Exporting a lockfile*. uv documentation. Retrieved August 4, 2026, from https://docs.astral.sh/uv/concepts/projects/export/ @@ -195,16 +184,9 @@ Berners-Lee, T., Fielding, R., & Masinter, L. (2005). *Uniform Resource Identifi (URI): Generic syntax* (STD 66; RFC 3986). Internet Engineering Task Force. https://doi.org/10.17487/RFC3986 -Fielding, R. (Ed.), Nottingham, M. (Ed.), & Reschke, J. (Ed.). (2022). *HTTP -semantics* (RFC 9110). Internet Engineering Task Force. -https://doi.org/10.17487/RFC9110 - GitHub. (n.d.). *actions/checkout*. GitHub. Retrieved August 5, 2026, from https://github.com/actions/checkout -GitHub, Inc. (n.d.). *About releases*. GitHub Docs. Retrieved August 18, 2026, -from https://docs.github.com/en/repositories/releasing-projects-on-github/about-releases - GitHub, Inc. (n.d.). *Events that trigger workflows*. GitHub Docs. Retrieved August 5, 2026, from https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows @@ -215,12 +197,6 @@ Supply-chain Levels for Software Artifacts. (2025). *SLSA specification Supply-chain Levels for Software Artifacts. (2025). *Provenance (version 1.2)*. https://slsa.dev/spec/v1.2/provenance -MITRE. (2026a). *CWE-601: URL redirection to untrusted site ('open redirect')*. -https://cwe.mitre.org/data/definitions/601.html - -MITRE. (2026b). *CWE-918: Server-side request forgery (SSRF)*. -https://cwe.mitre.org/data/definitions/918.html - Supply-chain Levels for Software Artifacts. (2025). *Source: Requirements for producing source (version 1.2)*. https://slsa.dev/spec/v1.2/source-requirements diff --git a/opencode.jsonc b/opencode.jsonc index 3429b88a3..ddd22f5e0 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -1,11 +1,8 @@ { "$schema": "https://opencode.ai/config.json", - // NOT switched to "contextual-orchestrator/contextual-orchestrator" yet: - // that requires CONTEXTUAL_ORCHESTRATOR_BASE_URL/_TOKEN to be provisioned - // first (see the "contextual-orchestrator" provider block below). "model": "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5", "small_model": "nvidia-nim/meta/llama-3.3-70b-instruct", - "enabled_providers": ["nvidia-nim", "github-models", "contextual-orchestrator"], + "enabled_providers": ["nvidia-nim", "github-models"], "lsp": false, "mcp": {}, "permission": { @@ -374,34 +371,6 @@ } } } - }, - // Added (not yet the default -- see model/small_model above): the org's - // contextual-orchestrator LLM gateway. It auto-discovers models across - // Bytez/NVIDIA NIM (x2 keys)/OpenRouter/OpenAI from KV-registered - // credentials and auto-optimizes routing by cost, so pointing OpenCode at - // one model id here delegates upstream selection to the gateway. Requires - // CONTEXTUAL_ORCHESTRATOR_BASE_URL and CONTEXTUAL_ORCHESTRATOR_TOKEN to be - // provisioned as repo/org Actions variables before switching the default - // model/small_model above to "contextual-orchestrator/contextual-orchestrator"; - // until then this provider is defined but unused, so OpenCode keeps working. - "contextual-orchestrator": { - "npm": "@ai-sdk/openai-compatible", - "name": "Contextual Orchestrator", - "options": { - "baseURL": "{env:CONTEXTUAL_ORCHESTRATOR_BASE_URL}", - "apiKey": "{env:CONTEXTUAL_ORCHESTRATOR_TOKEN}" - }, - "models": { - "contextual-orchestrator": { - "name": "Contextual Orchestrator (auto-routed)", - "tool_call": true, - "reasoning": true, - "limit": { - "context": 200000, - "output": 32768 - } - } - } } } } diff --git a/organization_commercial_readiness_fixtures.py b/organization_commercial_readiness_fixtures.py deleted file mode 100644 index d86596196..000000000 --- a/organization_commercial_readiness_fixtures.py +++ /dev/null @@ -1,128 +0,0 @@ -"""Test fixtures for the organization commercial-readiness coordinator.""" - -from __future__ import annotations - -from typing import Any - -from scripts.ci.organization_commercial_readiness_loop import ( - GitHubError, - PullRequestRecord, - RepositorySnapshot, - RunRecord, - WorkflowRecord, -) - - -def workflow( - *, - workflow_id: int = 1, - name: str = "Hourly Product Development", - path: str = ".github/workflows/hourly-product-development.yml", - state: str = "active", - content: str | None = None, -) -> WorkflowRecord: - """Build one workflow record.""" - return WorkflowRecord(workflow_id, name, path, state, f"sha-{workflow_id}", content) - - -def pull( - number: int, - *, - draft: bool = False, - base_ref: str = "main", - head_sha: str | None = None, - updated_at: str = "2026-08-08T00:00:00Z", -) -> PullRequestRecord: - """Build one pull-request record.""" - return PullRequestRecord( - number, draft, base_ref, head_sha or f"{number:040x}", updated_at - ) - - -def snapshot( - repository: str, - *, - default_branch: str = "main", - default_sha: str = "a" * 40, - workflows: tuple[WorkflowRecord, ...] = (), - runs: tuple[RunRecord, ...] = (), - pulls: tuple[PullRequestRecord, ...] = (), -) -> RepositorySnapshot: - """Build one repository snapshot.""" - return RepositorySnapshot( - repository, default_branch, default_sha, workflows, runs, pulls - ) - - -def repository_payload(name: str) -> dict[str, Any]: - """Return one eligible repository response.""" - return { - "full_name": f"ContextualWisdomLab/{name}", - "default_branch": "main", - "archived": False, - "disabled": False, - "fork": False, - "permissions": {"maintain": True}, - } - - -def manual_workflow(*, workflow_id: int = 9) -> WorkflowRecord: - """Return one safe organization-dispatch product entrypoint.""" - return workflow( - workflow_id=workflow_id, - name="Commercial Product Development", - path=".github/workflows/commercial-product-development.yml", - content=( - "# cwl-org-commercial-entrypoint: v1\n" - "on:\n workflow_dispatch:\n" - "concurrency:\n group: product-development\n" - "permissions:\n contents: write\n" - "NVIDIA_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}\n" - ), - ) - - -class FakeClient: - """Deterministic GitHub boundary.""" - - def __init__( - self, - repositories: list[dict[str, Any]], - snapshots: dict[str, list[RepositorySnapshot | Exception]], - ) -> None: - self.repositories = repositories - self.snapshots = snapshots - self.dispatched_repairs: list[tuple[str, str]] = [] - self.dispatched_products: list[tuple[str, int, str]] = [] - - def list_repositories(self, organization: str) -> list[dict[str, Any]]: - """Return configured repositories.""" - assert organization == "ContextualWisdomLab" - return self.repositories - - def snapshot(self, repository: str, default_branch: str) -> RepositorySnapshot: - """Return or raise the next configured snapshot value.""" - value = self.snapshots[repository].pop(0) - if isinstance(value, Exception): - raise value - assert value.default_branch == default_branch - return value - - def dispatch_review_repair(self, repository: str, base_branch: str) -> None: - """Record one repair dispatch.""" - self.dispatched_repairs.append((repository, base_branch)) - - def dispatch_product_workflow( - self, repository: str, workflow_id: int, default_branch: str - ) -> None: - """Record one product dispatch.""" - self.dispatched_products.append((repository, workflow_id, default_branch)) - - -class FailingDispatchClient(FakeClient): - """Reject review dispatches for failure-path tests.""" - - def dispatch_review_repair(self, repository: str, base_branch: str) -> None: - """Raise a bounded API failure.""" - del repository, base_branch - raise GitHubError("dispatch rejected") diff --git a/scripts/ci/agent_mention_router.py b/scripts/ci/agent_mention_router.py index bdb8ac3db..1582af2d3 100644 --- a/scripts/ci/agent_mention_router.py +++ b/scripts/ci/agent_mention_router.py @@ -79,6 +79,7 @@ def request( capture_output=True, check=False, env=environment, + shell=False, ) return_code = int(getattr(completed, "returncode", 0)) if return_code: diff --git a/scripts/ci/assert_opencode_reasoning_effort.py b/scripts/ci/assert_opencode_reasoning_effort.py index 82079d511..cee898619 100644 --- a/scripts/ci/assert_opencode_reasoning_effort.py +++ b/scripts/ci/assert_opencode_reasoning_effort.py @@ -20,66 +20,12 @@ def is_known_reasoning_capable(model_name: str) -> bool: ) -def strip_jsonc_comments(text: str) -> str: - """Return ``text`` with ``//`` and ``/* */`` comments removed outside strings. - - ``opencode.jsonc`` is genuinely JSONC (it carries explanatory ``//`` notes, - e.g. above the ``contextual-orchestrator`` provider block), so a plain - :func:`json.loads` rejects it. Comment markers are only recognized outside - JSON string literals, so a string value that itself contains ``//`` (the - ``"$schema": "https://opencode.ai/config.json"`` line) is preserved - unchanged. Newlines inside removed content are kept so any remaining - ``json.JSONDecodeError`` still reports an accurate line number. - """ - result: list[str] = [] - in_string = False - index = 0 - length = len(text) - while index < length: - char = text[index] - if in_string: - result.append(char) - if char == "\\" and index + 1 < length: - result.append(text[index + 1]) - index += 2 - continue - if char == '"': - in_string = False - index += 1 - continue - if char == '"': - in_string = True - result.append(char) - index += 1 - continue - if char == "/" and index + 1 < length and text[index + 1] == "/": - index += 2 - while index < length and text[index] not in "\r\n": - index += 1 - continue - if char == "/" and index + 1 < length and text[index + 1] == "*": - index += 2 - while index + 1 < length and not ( - text[index] == "*" and text[index + 1] == "/" - ): - if text[index] in "\r\n": - result.append(text[index]) - index += 1 - index += 2 - continue - result.append(char) - index += 1 - return "".join(result) - - def load_config(path: Path) -> dict[str, Any]: - """Load the OpenCode JSONC config, tolerating ``//`` and ``/* */`` comments.""" + """Load the OpenCode JSON config.""" try: - raw_text = path.read_text(encoding="utf-8") + return json.loads(path.read_text(encoding="utf-8")) except FileNotFoundError: raise SystemExit(f"OpenCode config not found: {path}") from None - try: - return json.loads(strip_jsonc_comments(raw_text)) except json.JSONDecodeError as exc: raise SystemExit(f"OpenCode config is not valid JSON: {path}: {exc}") from None @@ -101,29 +47,39 @@ def validate_candidate(config: dict[str, Any], candidate: str) -> list[str]: except ValueError as exc: return [str(exc)] + if not config_for_model and ( + provider == "github-models" or is_known_reasoning_capable(model_name) + ): + return [ + f"OpenCode candidate {candidate} is not defined in opencode.jsonc " + f"under provider {provider}." + ] if not config_for_model: - if provider == "github-models" or is_known_reasoning_capable(model_name): - return [ - f"OpenCode candidate {candidate} is not defined in opencode.jsonc " - f"under provider {provider}." - ] return [] configured_reasoning = config_for_model.get("reasoning") is True - if not (configured_reasoning or is_known_reasoning_capable(model_name)): + should_require_effort = configured_reasoning or is_known_reasoning_capable(model_name) + if not should_require_effort: return [] errors: list[str] = [] - prefix = f"OpenCode reasoning-capable candidate {candidate} must set" - suffix = "in opencode.jsonc." - if not configured_reasoning: - errors.append(f"{prefix} reasoning=true {suffix}") + errors.append( + f"OpenCode reasoning-capable candidate {candidate} must set reasoning=true " + "in opencode.jsonc." + ) if (config_for_model.get("options") or {}).get("reasoningEffort") != "high": - errors.append(f"{prefix} options.reasoningEffort=high {suffix}") - if ((config_for_model.get("variants") or {}).get("high") or {}).get("reasoningEffort") != "high": - errors.append(f"{prefix} variants.high.reasoningEffort=high {suffix}") - + errors.append( + f"OpenCode reasoning-capable candidate {candidate} must set " + "options.reasoningEffort=high in opencode.jsonc." + ) + if ((config_for_model.get("variants") or {}).get("high") or {}).get( + "reasoningEffort" + ) != "high": + errors.append( + f"OpenCode reasoning-capable candidate {candidate} must set " + "variants.high.reasoningEffort=high in opencode.jsonc." + ) return errors diff --git a/scripts/ci/materialize_base_python_requirements.py b/scripts/ci/materialize_base_python_requirements.py index e4ebf473a..7a9c204b8 100755 --- a/scripts/ci/materialize_base_python_requirements.py +++ b/scripts/ci/materialize_base_python_requirements.py @@ -39,17 +39,9 @@ UV_EXPORT_TIMEOUT_SECONDS = 120 TRUSTED_UV_VERSION = "0.12.1" TRUSTED_UV_ARCHIVE_URL = ( - "https://github.com/astral-sh/uv/releases/download/0.12.1/" + "https://releases.astral.sh/github/uv/releases/download/0.12.1/" "uv-x86_64-unknown-linux-gnu.tar.gz" ) -TRUSTED_UV_RELEASE_HOST = "github.com" -TRUSTED_UV_ASSET_HOSTS = frozenset( - { - "release-assets.githubusercontent.com", - "objects.githubusercontent.com", - } -) -TRUSTED_UV_FINAL_HOSTS = frozenset({TRUSTED_UV_RELEASE_HOST, *TRUSTED_UV_ASSET_HOSTS}) TRUSTED_UV_ARCHIVE_SHA256 = ( "90b2f223fb69d19db49e117da601f64978593417988530aa733d456141b4bcbb" ) @@ -58,51 +50,10 @@ TRUSTED_UV_DOWNLOAD_MAX_BYTES = 64 * 1024 * 1024 TRUSTED_UV_BINARY_MAX_BYTES = 64 * 1024 * 1024 TRUSTED_UV_VERSION_TIMEOUT_SECONDS = 10 -TRUSTED_UV_ORIGIN_ERROR = ( - "trusted uv archive redirected outside the fixed GitHub release HTTPS origin" -) - - -def _https_default_port(parsed: urllib.parse.ParseResult) -> bool: - """Return whether one parsed URL uses the implicit or explicit HTTPS port.""" - try: - return parsed.port in (None, 443) - except ValueError: - return False - - -def _is_trusted_uv_https_host( - url: str, - allowed_hosts: frozenset[str], -) -> bool: - """Return whether ``url`` is HTTPS, default-port, and host-allowlisted.""" - parsed = urllib.parse.urlparse(url) - return ( - parsed.scheme == "https" - and parsed.hostname in allowed_hosts - and parsed.username is None - and parsed.password is None - and _https_default_port(parsed) - ) -def _is_trusted_uv_release_request(url: str) -> bool: - """Return whether the current request is still the GitHub Releases origin.""" - return _is_trusted_uv_https_host(url, frozenset({TRUSTED_UV_RELEASE_HOST})) - - -def _is_trusted_uv_asset_location(url: str) -> bool: - """Return whether the next hop is an official GitHub release-asset host.""" - return _is_trusted_uv_https_host(url, TRUSTED_UV_ASSET_HOSTS) - - -def _is_trusted_uv_final_origin(url: str) -> bool: - """Return whether the completed response stayed on a trusted HTTPS origin.""" - return _is_trusted_uv_https_host(url, TRUSTED_UV_FINAL_HOSTS) - - -class _TrustedUvReleaseAssetRedirects(urllib.request.HTTPRedirectHandler): - """Follow one GitHub Releases hop onto the official asset CDN only.""" +class _RejectTrustedUvRedirects(urllib.request.HTTPRedirectHandler): + """Reject every redirect before urllib issues a request to its target.""" def redirect_request( self, @@ -112,31 +63,18 @@ def redirect_request( message: str, headers: Any, new_url: str, - ) -> urllib.request.Request: - """Allow github.com → GitHub asset CDN and reject every other hop.""" - if not _is_trusted_uv_release_request(request.full_url) or not ( - _is_trusted_uv_asset_location(new_url) - ): - raise RuntimeError(TRUSTED_UV_ORIGIN_ERROR) - followed = super().redirect_request( - request, - response, - code, - message, - headers, - new_url, - ) - if followed is None: - raise RuntimeError(TRUSTED_UV_ORIGIN_ERROR) - return followed + ) -> None: + """Fail closed for all redirect status codes and target locations.""" + del request, response, code, message, headers, new_url + raise RuntimeError("trusted uv archive redirects are forbidden") @functools.cache def _install_trusted_uv_url_opener() -> None: - """Install one process-wide no-proxy opener for the fixed GitHub URL.""" + """Install one process-wide no-proxy, no-redirect opener for the fixed URL.""" opener = urllib.request.build_opener( urllib.request.ProxyHandler({}), - _TrustedUvReleaseAssetRedirects(), + _RejectTrustedUvRedirects(), ) urllib.request.install_opener(opener) @@ -288,12 +226,27 @@ def _download_trusted_uv_archive() -> bytes: # prove that neither user data nor repository content selects a scheme, # host, path, query, fragment, method, or request header. with urllib.request.urlopen( # nosemgrep: python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected # nosec B310 - "https://github.com/astral-sh/uv/releases/download/0.12.1/" + "https://releases.astral.sh/github/uv/releases/download/0.12.1/" "uv-x86_64-unknown-linux-gnu.tar.gz", timeout=TRUSTED_UV_DOWNLOAD_TIMEOUT_SECONDS, ) as response: - if not _is_trusted_uv_final_origin(response.geturl()): - raise RuntimeError(TRUSTED_UV_ORIGIN_ERROR) + final_url = urllib.parse.urlparse(response.geturl()) + try: + final_port = final_url.port + except ValueError as exc: + raise RuntimeError( + "trusted uv archive redirected outside the fixed " + "releases.astral.sh HTTPS origin" + ) from exc + if ( + (final_url.scheme, final_url.hostname) + != ("https", "releases.astral.sh") + or final_port not in (None, 443) + ): + raise RuntimeError( + "trusted uv archive redirected outside the fixed " + "releases.astral.sh HTTPS origin" + ) payload = bytearray() while len(payload) <= TRUSTED_UV_DOWNLOAD_MAX_BYTES: chunk = response.read( diff --git a/scripts/ci/organization_commercial_readiness_loop.py b/scripts/ci/organization_commercial_readiness_loop.py deleted file mode 100644 index c00cfa1e0..000000000 --- a/scripts/ci/organization_commercial_readiness_loop.py +++ /dev/null @@ -1,856 +0,0 @@ -#!/usr/bin/env python3 -"""Coordinate bounded commercial-readiness work across an organization. - -The coordinator deliberately does not implement code review, branch repair, or -product development itself. It discovers repositories that do not already have -an active writer, revalidates their exact live state immediately before a -mutation, and dispatches at most one central review-repair run and one -repository-local product-development run per invocation. -""" - -from __future__ import annotations - -import argparse -import base64 -import dataclasses -import enum -import hashlib -import json -import os -import re -import subprocess -import sys -from pathlib import Path -from typing import Any, Callable, Iterable, Mapping, Sequence -from urllib.parse import quote - - -DEFAULT_ORGANIZATION = "ContextualWisdomLab" -ORGANIZATION_RE = re.compile(r"^[A-Za-z0-9_.-]+$") -ENTRYPOINT_MARKER = "# cwl-org-commercial-entrypoint: v1" -CENTRAL_REPOSITORY = f"{DEFAULT_ORGANIZATION}/.github" -CENTRAL_REPAIR_EVENT = "pr-review-fix-scheduler" -ACTIVE_RUN_STATES = frozenset({"queued", "in_progress", "waiting", "pending", "requested"}) -WRITER_SIGNAL_RE = re.compile( - r"(?:hourly|commercial|product[ _-]*development|autonomous|readiness|" - r"maintenance|review[ _-]*repair|review[ _-]*fix|maintainer|pr[ _-]*disposition)", - re.IGNORECASE, -) -MERGE_SCHEDULER_RE = re.compile( - r"(?:required[ _-]*pr[ _-]*review[ _-]*merge[ _-]*scheduler|" - r"pr-review-merge-scheduler)", - re.IGNORECASE, -) -SCHEDULE_RE = re.compile(r"(?m)^\s*schedule\s*:") -WORKFLOW_DISPATCH_RE = re.compile(r"(?m)^\s*workflow_dispatch\s*:") -MAX_WORKFLOW_RECORDS_PER_REPOSITORY = 1_000 -MAX_WORKFLOW_SOURCES_PER_REPOSITORY = 100 -MAX_WORKFLOW_SOURCE_BYTES_PER_FILE = 1_048_576 -MAX_WORKFLOW_SOURCE_BYTES_PER_REPOSITORY = 10 * 1_048_576 - - -class GitHubError(RuntimeError): - """Represent a bounded GitHub API or authentication failure.""" - - -class SnapshotChanged(RuntimeError): - """Signal that a repository moved while one snapshot was materialized.""" - - -class ActionKind(str, enum.Enum): - """Supported coordinator mutation classes.""" - - REVIEW_REPAIR = "review_repair" - PRODUCT_DEVELOPMENT = "product_development" - - -@dataclasses.dataclass(frozen=True) -class WorkflowRecord: - """Describe one repository workflow and its exact inspected source.""" - - workflow_id: int - name: str - path: str - state: str - content_sha: str - content: str | None - - -@dataclasses.dataclass(frozen=True) -class RunRecord: - """Describe one workflow run that may hold a live writer lease.""" - - run_id: int - name: str - path: str - status: str - head_sha: str - - -@dataclasses.dataclass(frozen=True) -class PullRequestRecord: - """Describe the exact pull-request fields used by the selection policy.""" - - number: int - draft: bool - base_ref: str - head_sha: str - updated_at: str - - -@dataclasses.dataclass(frozen=True) -class RepositorySnapshot: - """Bind repository selection evidence to one stable default-branch state.""" - - full_name: str - default_branch: str - default_sha: str - workflows: tuple[WorkflowRecord, ...] - active_runs: tuple[RunRecord, ...] - open_pulls: tuple[PullRequestRecord, ...] - - @property - def fingerprint(self) -> str: - """Return a deterministic digest independent of API result ordering.""" - payload = { - "full_name": self.full_name, - "default_branch": self.default_branch, - "default_sha": self.default_sha, - "workflows": sorted( - ( - item.workflow_id, - item.name, - item.path, - item.state, - item.content_sha, - ) - for item in self.workflows - ), - "active_runs": sorted( - (item.run_id, item.name, item.path, item.status, item.head_sha) - for item in self.active_runs - ), - "open_pulls": sorted( - ( - item.number, - item.draft, - item.base_ref, - item.head_sha, - item.updated_at, - ) - for item in self.open_pulls - ), - } - canonical = json.dumps(payload, sort_keys=True, separators=(",", ":")) - return hashlib.sha256(canonical.encode("utf-8")).hexdigest() - - -@dataclasses.dataclass(frozen=True) -class PlanItem: - """Describe one bounded mutation selected from an initial snapshot.""" - - kind: ActionKind - repository: str - default_branch: str - expected_fingerprint: str - workflow_id: int | None = None - - -@dataclasses.dataclass(frozen=True) -class ActionResult: - """Record the outcome of one revalidated coordinator action.""" - - kind: ActionKind - repository: str - status: str - detail: str - - -@dataclasses.dataclass(frozen=True) -class RunReport: - """Provide machine-readable and operator-readable evidence for one run.""" - - organization: str - inspected_repositories: int - leased_repositories: tuple[str, ...] - inspection_errors: tuple[tuple[str, str], ...] - actions: tuple[ActionResult, ...] - dry_run: bool - - def to_dict(self) -> dict[str, Any]: - """Return a JSON-serializable representation of this report.""" - return { - "organization": self.organization, - "inspected_repositories": self.inspected_repositories, - "leased_repositories": list(self.leased_repositories), - "inspection_errors": [ - {"repository": repository, "error": error} - for repository, error in self.inspection_errors - ], - "actions": [ - { - "kind": action.kind.value, - "repository": action.repository, - "status": action.status, - "detail": action.detail, - } - for action in self.actions - ], - "dry_run": self.dry_run, - } - - def to_json(self) -> str: - """Serialize this report as stable UTF-8 JSON text.""" - return json.dumps(self.to_dict(), ensure_ascii=False, indent=2, sort_keys=True) - - def to_markdown(self) -> str: - """Render a concise GitHub Actions job summary.""" - lines = [ - "# Organization commercial-readiness coordinator", - "", - f"- Organization: `{self.organization}`", - f"- Repositories inspected: **{self.inspected_repositories}**", - f"- Repositories leased to dedicated writers: **{len(self.leased_repositories)}**", - f"- Inspection errors: **{len(self.inspection_errors)}**", - f"- Dry run: **{'yes' if self.dry_run else 'no'}**", - "", - "## Actions", - "", - "| Kind | Repository | Status | Detail |", - "|---|---|---|---|", - ] - if self.actions: - for action in self.actions: - detail = action.detail.replace("|", "\\|").replace("\n", " ") - lines.append( - f"| `{action.kind.value}` | `{action.repository}` | " - f"`{action.status}` | {detail} |" - ) - else: - lines.append("| — | — | `no_action` | No safe target was selected. |") - if self.inspection_errors: - lines.extend(["", "## Inspection errors", ""]) - for repository, error in self.inspection_errors: - lines.append(f"- `{repository}`: {error}") - return "\n".join(lines) + "\n" - - -class GitHubClient: - """Use the GitHub CLI as an authenticated, bounded REST transport.""" - - def __init__(self, token: str, *, timeout_seconds: int = 60) -> None: - if not token: - raise GitHubError("GH_TOKEN is required for organization coordination") - self._token = token - self._timeout_seconds = timeout_seconds - - @classmethod - def from_environment(cls, environ: Mapping[str, str] | None = None) -> GitHubClient: - """Build a client without accepting the repository-scoped GITHUB_TOKEN.""" - values = os.environ if environ is None else environ - token = str(values.get("GH_TOKEN") or "").strip() - if not token: - raise GitHubError("GH_TOKEN is required; no GITHUB_TOKEN fallback is permitted") - return cls(token) - - def _redact_credential(self, value: str) -> str: - """Remove the exact GitHub credential before any diagnostic truncation.""" - return value.replace(self._token, "[REDACTED]") - - def request( - self, - path: str, - *, - method: str = "GET", - payload: Any = None, - ) -> Any: - """Call one GitHub REST endpoint and decode a bounded JSON response.""" - normalized_method = method.upper() - safe_path = self._redact_credential(path) - args = ["gh", "api"] - if normalized_method != "GET": - args.extend(["--method", normalized_method]) - args.append(path) - input_text: str | None = None - if payload is not None: - args.extend(["--input", "-"]) - input_text = json.dumps(payload, separators=(",", ":")) - try: - completed = subprocess.run( - args, - input=input_text, - capture_output=True, - text=True, - timeout=self._timeout_seconds, - env={**os.environ, "GH_TOKEN": self._token}, - check=False, - ) - except (OSError, subprocess.TimeoutExpired) as exc: - raise GitHubError(f"GitHub API transport failed: {type(exc).__name__}") from exc - if completed.returncode != 0: - raw = (completed.stderr or completed.stdout or "GitHub API request failed").strip() - bounded = self._redact_credential(raw)[-900:] - raise GitHubError( - f"GitHub API {normalized_method} {safe_path} failed: {bounded}" - ) - text = completed.stdout.strip() - if not text: - return None - try: - return json.loads(text) - except json.JSONDecodeError as exc: - raise GitHubError( - f"GitHub API returned invalid JSON for {safe_path}" - ) from exc - - def list_repositories(self, organization: str) -> list[dict[str, Any]]: - """Return every repository visible to the coordinator installation.""" - repositories: list[dict[str, Any]] = [] - page = 1 - while True: - result = self.request( - f"/orgs/{organization}/repos?type=all&sort=full_name&per_page=100&page={page}" - ) - batch = list(result or []) - repositories.extend(batch) - if len(batch) < 100: - return repositories - page += 1 - - def default_branch_sha(self, repository: str, default_branch: str) -> str: - """Resolve one exact commit for the repository default branch.""" - branch_ref = quote(default_branch, safe="") - result = self.request(f"/repos/{repository}/commits/{branch_ref}") - sha = str((result or {}).get("sha") or "") - if not re.fullmatch(r"[0-9a-fA-F]{40}", sha): - raise GitHubError(f"repository {repository} returned an invalid default-branch SHA") - return sha.lower() - - def list_workflows(self, repository: str, exact_ref: str) -> tuple[WorkflowRecord, ...]: - """Return a fail-closed, memory-bounded workflow and writer-source inventory.""" - workflows: list[WorkflowRecord] = [] - source_count = 0 - source_bytes = 0 - page = 1 - while True: - result = self.request( - f"/repos/{repository}/actions/workflows?per_page=100&page={page}" - ) - batch = list((result or {}).get("workflows") or []) - if len(workflows) + len(batch) > MAX_WORKFLOW_RECORDS_PER_REPOSITORY: - raise GitHubError( - f"repository {repository} exceeded workflow metadata limit of " - f"{MAX_WORKFLOW_RECORDS_PER_REPOSITORY}" - ) - for raw in batch: - workflow_id = int(raw.get("id") or 0) - path = str(raw.get("path") or "") - name = str(raw.get("name") or path) - state = str(raw.get("state") or "unknown") - content: str | None = None - content_sha = "" - if ( - path - and not path.startswith("dynamic/") - and _writer_signal(name, path) - ): - source_count += 1 - if source_count > MAX_WORKFLOW_SOURCES_PER_REPOSITORY: - raise GitHubError( - f"repository {repository} exceeded workflow source limit of " - f"{MAX_WORKFLOW_SOURCES_PER_REPOSITORY}" - ) - encoded_path = quote(path, safe="/") - try: - source = self.request( - f"/repos/{repository}/contents/{encoded_path}?ref={exact_ref}" - ) - source_size = ( - int(source.get("size") or 0) - if isinstance(source, dict) - else 0 - ) - except (GitHubError, ValueError): - source = None - source_size = 0 - if ( - isinstance(source, dict) - and source.get("type") == "file" - and source_size <= MAX_WORKFLOW_SOURCE_BYTES_PER_FILE - and source.get("encoding") == "base64" - ): - if ( - source_bytes + source_size - > MAX_WORKFLOW_SOURCE_BYTES_PER_REPOSITORY - ): - raise GitHubError( - f"repository {repository} exceeded workflow source byte limit of " - f"{MAX_WORKFLOW_SOURCE_BYTES_PER_REPOSITORY}" - ) - try: - decoded = base64.b64decode( - str(source.get("content") or ""), validate=True - ) - content = decoded.decode("utf-8") - content_sha = str(source.get("sha") or "") - except (ValueError, UnicodeDecodeError): - content = None - content_sha = "" - else: - source_bytes += source_size - workflows.append( - WorkflowRecord( - workflow_id=workflow_id, - name=name, - path=path, - state=state, - content_sha=content_sha, - content=content, - ) - ) - if len(batch) < 100: - return tuple(workflows) - page += 1 - - def list_active_runs(self, repository: str) -> tuple[RunRecord, ...]: - """Return all queued and running workflow evidence for writer lease detection.""" - records: list[RunRecord] = [] - for status in ("queued", "in_progress", "waiting", "pending", "requested"): - page = 1 - while True: - result = self.request( - f"/repos/{repository}/actions/runs?status={status}&per_page=100&page={page}" - ) - batch = list((result or {}).get("workflow_runs") or []) - for raw in batch: - records.append( - RunRecord( - run_id=int(raw.get("id") or 0), - name=str(raw.get("name") or ""), - path=str(raw.get("path") or ""), - status=str(raw.get("status") or status), - head_sha=str(raw.get("head_sha") or ""), - ) - ) - if len(batch) < 100: - break - page += 1 - return tuple(records) - - def list_open_pulls(self, repository: str) -> tuple[PullRequestRecord, ...]: - """Return all open pull requests with exact stack and head identity.""" - records: list[PullRequestRecord] = [] - page = 1 - while True: - result = self.request( - f"/repos/{repository}/pulls?state=open&per_page=100&page={page}" - ) - batch = list(result or []) - for raw in batch: - records.append( - PullRequestRecord( - number=int(raw.get("number") or 0), - draft=bool(raw.get("draft")), - base_ref=str((raw.get("base") or {}).get("ref") or ""), - head_sha=str((raw.get("head") or {}).get("sha") or ""), - updated_at=str(raw.get("updated_at") or ""), - ) - ) - if len(batch) < 100: - return tuple(records) - page += 1 - - def snapshot(self, repository: str, default_branch: str) -> RepositorySnapshot: - """Materialize one snapshot and reject concurrent default-branch movement.""" - before = self.default_branch_sha(repository, default_branch) - workflows = self.list_workflows(repository, before) - runs = self.list_active_runs(repository) - pulls = self.list_open_pulls(repository) - after = self.default_branch_sha(repository, default_branch) - if before != after: - raise SnapshotChanged( - f"default branch moved while inspecting {repository}: {before} -> {after}" - ) - return RepositorySnapshot( - full_name=repository, - default_branch=default_branch, - default_sha=before, - workflows=workflows, - active_runs=runs, - open_pulls=pulls, - ) - - def dispatch_review_repair(self, repository: str, base_branch: str) -> None: - """Ask the established central scheduler for one bounded repair attempt.""" - self.request( - f"/repos/{CENTRAL_REPOSITORY}/dispatches", - method="POST", - payload={ - "event_type": CENTRAL_REPAIR_EVENT, - "client_payload": { - "target_repository": repository, - "base_branch": base_branch, - "max_prs": "50", - "max_dispatches": "1", - "retry_hours": "1", - "dry_run": False, - }, - }, - ) - - def dispatch_product_workflow( - self, repository: str, workflow_id: int, default_branch: str - ) -> None: - """Dispatch an explicitly opted-in repository-local development entrypoint.""" - self.request( - f"/repos/{repository}/actions/workflows/{workflow_id}/dispatches", - method="POST", - payload={"ref": default_branch}, - ) - - -def _writer_signal(name: str, path: str) -> bool: - """Return whether workflow identity indicates a repository writer.""" - identity = f"{name}\n{path}" - return bool(WRITER_SIGNAL_RE.search(identity)) and not bool( - MERGE_SCHEDULER_RE.search(identity) - ) - - -def is_dedicated_writer_workflow(workflow: WorkflowRecord) -> bool: - """Return whether an active scheduled workflow owns the repository writer lease.""" - if workflow.state != "active" or not _writer_signal(workflow.name, workflow.path): - return False - if workflow.content is None: - return True - return bool(SCHEDULE_RE.search(workflow.content)) - - -def is_live_writer_run(run: RunRecord) -> bool: - """Return whether a queued or running high-signal workflow owns a live lease.""" - return run.status in ACTIVE_RUN_STATES and _writer_signal(run.name, run.path) - - -def is_manual_product_entrypoint(workflow: WorkflowRecord) -> bool: - """Return whether a workflow explicitly opts in to central product dispatch.""" - source = workflow.content - if workflow.state != "active" or source is None: - return False - return all( - ( - ENTRYPOINT_MARKER in source, - bool(WORKFLOW_DISPATCH_RE.search(source)), - not bool(SCHEDULE_RE.search(source)), - "NVIDIA_NIM_API_KEY" in source, - "COPILOT_GITHUB_TOKEN" not in source, - "concurrency:" in source, - _writer_signal(workflow.name, workflow.path), - ) - ) - - -def repository_is_eligible(repository: Mapping[str, Any], organization: str) -> bool: - """Return whether one owned repository can participate in organization coordination.""" - full_name = str(repository.get("full_name") or "") - permissions = repository.get("permissions") or {} - write_capable = any(bool(permissions.get(key)) for key in ("push", "maintain", "admin")) - return all( - ( - full_name.startswith(f"{organization}/"), - full_name != f"{organization}/.github", - not bool(repository.get("archived")), - not bool(repository.get("disabled")), - not bool(repository.get("fork")), - bool(repository.get("default_branch")), - write_capable, - ) - ) - - -def choose_rotating(items: Sequence[Any], seed: int, limit: int) -> tuple[Any, ...]: - """Choose a bounded cyclic window so later repositories are not starved.""" - if not items or limit <= 0: - return () - count = min(limit, len(items)) - start = seed % len(items) - return tuple(items[(start + offset) % len(items)] for offset in range(count)) - - -def _has_writer_lease(snapshot: RepositorySnapshot) -> bool: - """Return whether static or live evidence assigns this repository elsewhere.""" - return any(is_dedicated_writer_workflow(item) for item in snapshot.workflows) or any( - is_live_writer_run(item) for item in snapshot.active_runs - ) - - -def _eligible_review_snapshot(snapshot: RepositorySnapshot) -> bool: - """Return whether generic review repair is safe for at least one direct PR.""" - return any( - not pull.draft and pull.base_ref == snapshot.default_branch - for pull in snapshot.open_pulls - ) - - -def _manual_product_workflow(snapshot: RepositorySnapshot) -> WorkflowRecord | None: - """Return the first deterministic opted-in manual development entrypoint.""" - matches = sorted( - (item for item in snapshot.workflows if is_manual_product_entrypoint(item)), - key=lambda item: (item.path, item.workflow_id), - ) - return matches[0] if matches else None - - -def build_plan( - snapshots: Iterable[RepositorySnapshot], - *, - rotation_seed: int, - max_review_dispatches: int = 1, - max_development_dispatches: int = 1, -) -> tuple[PlanItem, ...]: - """Select independent bounded review and product targets from exact snapshots.""" - usable = tuple( - sorted( - ( - item - for item in snapshots - if item.full_name != CENTRAL_REPOSITORY and not _has_writer_lease(item) - ), - key=lambda item: item.full_name, - ) - ) - review_candidates = tuple(item for item in usable if _eligible_review_snapshot(item)) - development_candidates = tuple( - (item, workflow) - for item in usable - if not item.open_pulls - for workflow in (_manual_product_workflow(item),) - if workflow is not None - ) - plan: list[PlanItem] = [] - for item in choose_rotating(review_candidates, rotation_seed, max_review_dispatches): - plan.append( - PlanItem( - kind=ActionKind.REVIEW_REPAIR, - repository=item.full_name, - default_branch=item.default_branch, - expected_fingerprint=item.fingerprint, - ) - ) - for item, workflow in choose_rotating( - development_candidates, rotation_seed, max_development_dispatches - ): - plan.append( - PlanItem( - kind=ActionKind.PRODUCT_DEVELOPMENT, - repository=item.full_name, - default_branch=item.default_branch, - expected_fingerprint=item.fingerprint, - workflow_id=workflow.workflow_id, - ) - ) - return tuple(plan) - - -def _bounded_error(exc: BaseException) -> str: - """Return a stable, bounded error description without stack or credential data.""" - text = f"{type(exc).__name__}: {exc}".replace("\n", " ") - return text[:1000] - - -def run_once( - client: Any, - *, - organization: str, - rotation_seed: int, - max_repositories: int = 200, - max_review_dispatches: int = 1, - max_development_dispatches: int = 1, - dry_run: bool = False, -) -> RunReport: - """Inspect the organization, revalidate targets, and dispatch bounded work.""" - if organization != DEFAULT_ORGANIZATION: - raise GitHubError( - f"organization must be {DEFAULT_ORGANIZATION}; foreign control planes are not supported" - ) - raw_repositories = client.list_repositories(organization) - eligible = sorted( - ( - item - for item in raw_repositories - if repository_is_eligible(item, organization) - ), - key=lambda item: str(item.get("full_name") or ""), - ) - selected_repositories = choose_rotating(eligible, rotation_seed, max_repositories) - snapshots: list[RepositorySnapshot] = [] - errors: list[tuple[str, str]] = [] - leased: list[str] = [] - for repository in selected_repositories: - full_name = str(repository["full_name"]) - default_branch = str(repository["default_branch"]) - try: - current = client.snapshot(full_name, default_branch) - except (GitHubError, SnapshotChanged) as exc: - errors.append((full_name, _bounded_error(exc))) - continue - snapshots.append(current) - if _has_writer_lease(current): - leased.append(full_name) - plan = build_plan( - snapshots, - rotation_seed=rotation_seed, - max_review_dispatches=max_review_dispatches, - max_development_dispatches=max_development_dispatches, - ) - actions: list[ActionResult] = [] - for item in plan: - try: - live = client.snapshot(item.repository, item.default_branch) - except (GitHubError, SnapshotChanged) as exc: - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="skipped_refetch_error", - detail=_bounded_error(exc), - ) - ) - continue - if _has_writer_lease(live): - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="skipped_writer_lease", - detail="a dedicated or live writer appeared before dispatch", - ) - ) - continue - if live.fingerprint != item.expected_fingerprint: - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="skipped_state_changed", - detail="repository, workflow, run, or pull-request state moved before dispatch", - ) - ) - continue - if dry_run: - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="dry_run", - detail="exact state revalidated; mutation intentionally suppressed", - ) - ) - continue - try: - if item.kind is ActionKind.REVIEW_REPAIR: - client.dispatch_review_repair(item.repository, item.default_branch) - else: - if item.workflow_id is None: - raise GitHubError("product-development plan omitted workflow identity") - client.dispatch_product_workflow( - item.repository, item.workflow_id, item.default_branch - ) - except GitHubError as exc: - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="dispatch_failed", - detail=_bounded_error(exc), - ) - ) - else: - actions.append( - ActionResult( - kind=item.kind, - repository=item.repository, - status="dispatched", - detail="exact state revalidated and bounded workflow dispatched", - ) - ) - return RunReport( - organization=organization, - inspected_repositories=len(snapshots), - leased_repositories=tuple(sorted(leased)), - inspection_errors=tuple(errors), - actions=tuple(actions), - dry_run=dry_run, - ) - - -def _non_negative_int(value: str) -> int: - """Parse one non-negative integer command-line bound.""" - parsed = int(value) - if parsed < 0: - raise argparse.ArgumentTypeError("value must be zero or greater") - return parsed - - -def _parser() -> argparse.ArgumentParser: - """Build the command-line parser used by workflow and local dry runs.""" - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--organization", default=DEFAULT_ORGANIZATION) - parser.add_argument("--rotation-seed", type=int, default=0) - parser.add_argument("--max-repositories", type=_non_negative_int, default=200) - parser.add_argument("--max-review-dispatches", type=_non_negative_int, default=1) - parser.add_argument("--max-development-dispatches", type=_non_negative_int, default=1) - parser.add_argument("--dry-run", action="store_true") - parser.add_argument("--json-output", type=Path) - return parser - - -def main( - argv: Sequence[str] | None = None, - *, - client_factory: Callable[[], Any] | None = None, -) -> int: - """Run the coordinator CLI and persist auditable receipts.""" - parser = _parser() - try: - args = parser.parse_args(argv) - except SystemExit: - return 2 - if not ORGANIZATION_RE.fullmatch(args.organization): - print("invalid organization", file=sys.stderr) - return 2 - factory = client_factory or GitHubClient.from_environment - try: - client = factory() - report = run_once( - client, - organization=args.organization, - rotation_seed=args.rotation_seed, - max_repositories=args.max_repositories, - max_review_dispatches=args.max_review_dispatches, - max_development_dispatches=args.max_development_dispatches, - dry_run=args.dry_run, - ) - except (GitHubError, SnapshotChanged, ValueError) as exc: - print(_bounded_error(exc), file=sys.stderr) - return 2 - text = report.to_json() + "\n" - if args.json_output is not None: - args.json_output.parent.mkdir(parents=True, exist_ok=True) - args.json_output.write_text(text, encoding="utf-8") - else: - sys.stdout.write(text) - summary_path = os.environ.get("GITHUB_STEP_SUMMARY") - if summary_path: - with Path(summary_path).open("a", encoding="utf-8") as handle: - handle.write(report.to_markdown()) - all_selected_inspections_failed = ( - report.inspected_repositories == 0 and bool(report.inspection_errors) - ) - all_planned_dispatches_failed = bool(report.actions) and all( - action.status == "dispatch_failed" for action in report.actions - ) - return 1 if all_selected_inspections_failed or all_planned_dispatches_failed else 0 - - -if __name__ == "__main__": # pragma: no cover - exercised through main() - raise SystemExit(main()) \ No newline at end of file diff --git a/scripts/ci/r_coverage_peer_gate.py b/scripts/ci/r_coverage_peer_gate.py index 201f15ee1..c7ef1abe7 100644 --- a/scripts/ci/r_coverage_peer_gate.py +++ b/scripts/ci/r_coverage_peer_gate.py @@ -78,13 +78,8 @@ def classify_testthat_failure( if any(not PACKAGE_NAME_RE.fullmatch(name) for name in allowed_missing): return False allowed_packages.update(allowed_missing) - - # ⚡ Bolt: Fast-path rejection before running expensive regex on potentially 2MB logs - if "Error: Test failures" not in text: - return False - summaries = FAIL_SUMMARY_RE.findall(text) - if not summaries: + if not summaries or "Error: Test failures" not in text: return False failure_count = int(summaries[-1]) if failure_count <= 0: diff --git a/scripts/ci/sandboxed_web_e2e.py b/scripts/ci/sandboxed_web_e2e.py index ae0c3105a..d14b9f339 100644 --- a/scripts/ci/sandboxed_web_e2e.py +++ b/scripts/ci/sandboxed_web_e2e.py @@ -13,6 +13,7 @@ import tempfile import time import urllib.error +import urllib.parse import urllib.request from collections.abc import Sequence from dataclasses import dataclass @@ -110,6 +111,7 @@ def start_service(label: str, command: str, cwd: Path, env: dict[str, str], logs stdout=log_file, stderr=subprocess.STDOUT, start_new_session=True, + shell=False, ) log_file.close() return Service(label=label, command=command, process=process, log_path=log_path) @@ -121,6 +123,9 @@ def wait_for_url(url: str, timeout: int, service: Service) -> bool: return True if not (url.startswith("http://") or url.startswith("https://")): raise ValueError(f"URL must start with http:// or https://, got: {url}") + parsed_url = urllib.parse.urlparse(url) + if parsed_url.hostname not in ("localhost", "127.0.0.1"): + raise ValueError(f"URL must point to localhost or 127.0.0.1, got: {url}") deadline = time.monotonic() + timeout opener = urllib.request.build_opener(NoRedirectHandler()) while time.monotonic() < deadline: @@ -146,6 +151,7 @@ def run_shell(command: str, cwd: Path, env: dict[str, str], timeout: int) -> sub stderr=subprocess.PIPE, timeout=timeout, check=False, + shell=False, ) diff --git a/tests/test_assert_opencode_reasoning_effort.py b/tests/test_assert_opencode_reasoning_effort.py index 73bd8c781..c864beb6a 100644 --- a/tests/test_assert_opencode_reasoning_effort.py +++ b/tests/test_assert_opencode_reasoning_effort.py @@ -117,58 +117,6 @@ def test_load_config_reports_missing_and_invalid_json(tmp_path): guard.load_config(invalid) -def test_strip_jsonc_comments_removes_line_and_block_comments(): - """Line and block comments outside strings are dropped, newlines preserved.""" - text = ( - '{\n' - ' // leading note\n' - ' "a": 1, /* inline block\n' - ' spanning lines */ "b": 2\n' - '}\n' - ) - - stripped = guard.strip_jsonc_comments(text) - - assert json.loads(stripped) == {"a": 1, "b": 2} - assert stripped.count("\n") == text.count("\n") - - -def test_strip_jsonc_comments_preserves_double_slash_inside_strings(): - """A string value containing // (a URL) is not treated as a comment.""" - text = '{\n "$schema": "https://opencode.ai/config.json" // trailing note\n}\n' - - stripped = guard.strip_jsonc_comments(text) - - assert json.loads(stripped) == {"$schema": "https://opencode.ai/config.json"} - - -def test_strip_jsonc_comments_respects_escaped_quotes_in_strings(): - """An escaped quote inside a string does not end string tracking early.""" - text = '{"a": "quote \\" then // not a comment", "b": 1}' - - stripped = guard.strip_jsonc_comments(text) - - assert json.loads(stripped) == {"a": 'quote " then // not a comment', "b": 1} - - -def test_load_config_tolerates_real_opencode_jsonc_comment_style(tmp_path): - """The exact comment style used in the repository's opencode.jsonc loads.""" - config_path = tmp_path / "opencode.jsonc" - config_path.write_text( - '{\n' - ' "$schema": "https://opencode.ai/config.json",\n' - ' // NOT switched to "contextual-orchestrator/contextual-orchestrator" yet:\n' - ' // that requires provisioning first.\n' - ' "model": "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5"\n' - '}\n', - encoding="utf-8", - ) - - config = guard.load_config(config_path) - - assert config["model"] == "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5" - - def test_main_reports_all_candidate_errors(tmp_path, capsys): """The CLI validates every candidate before returning failure.""" config_path = write_config( diff --git a/tests/test_bandscope_hourly_review_caller.py b/tests/test_bandscope_hourly_review_caller.py deleted file mode 100644 index 3c8d96cbf..000000000 --- a/tests/test_bandscope_hourly_review_caller.py +++ /dev/null @@ -1,87 +0,0 @@ -"""Contract tests for BandScope's bounded hourly review-repair caller.""" - -from pathlib import Path - - -CALLER = Path(".github/workflows/bandscope-hourly-review-repair.yml") -DOCTORING = Path("docs/doctoring/bandscope-hourly-review-caller.md") -QUALITY_WORKFLOW = Path(".github/workflows/hourly-nvidia-nim-review-repair.yml") - - -def _read(path: Path) -> str: - """Return one required repository contract file as UTF-8 text.""" - assert path.is_file(), f"missing required contract file: {path}" - return path.read_text(encoding="utf-8") - - -def test_bandscope_caller_is_hourly_bounded_and_non_cancelling() -> None: - """BandScope receives one bounded repair opportunity per hourly heartbeat.""" - caller = _read(CALLER) - - assert 'cron: "53 * * * *"' in caller - assert "group: bandscope-hourly-review-repair" in caller - assert "cancel-in-progress: false" in caller - assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in caller - assert "target_repository: ContextualWisdomLab/bandscope" in caller - assert "base_branch: develop" in caller - assert 'max_prs: "50"' in caller - assert 'max_dispatches: "1"' in caller - assert 'retry_hours: "2"' in caller - - -def test_bandscope_caller_preserves_oidc_and_credential_scope() -> None: - """The caller grants only read and OIDC while mapping scheduler credentials.""" - caller = _read(CALLER) - workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) - pr_review_secret = "$" + "{{ secrets.PR_REVIEW_MERGE_TOKEN }}" - opencode_secret = "$" + "{{ secrets.OPENCODE_APPROVE_TOKEN }}" - - assert "\npermissions:\n contents: read\n" in workflow_scope - assert ( - "\n permissions:\n" - " contents: read\n" - " id-token: write\n" - ) in jobs_scope - assert f"PR_REVIEW_MERGE_TOKEN: {pr_review_secret}" in caller - assert f"OPENCODE_APPROVE_TOKEN: {opencode_secret}" in caller - assert "secrets: inherit" not in caller - assert "NVIDIA_NIM_API_KEY" not in caller - assert "COPILOT_GITHUB_TOKEN" not in caller - for forbidden in ( - "actions: write", - "contents: write", - "issues: write", - "pull-requests: write", - "statuses: write", - ): - assert forbidden not in caller - - -def test_bandscope_doctoring_records_music_and_governance_bounds() -> None: - """Operators retain RCA, music-evidence, credential, and approval contracts.""" - doctoring = _read(DOCTORING) - - for phrase in ( - "root-cause analysis", - "remediation feasibility", - "two-hour same-head retry floor", - "real-audio acceptance", - "Rust-owned production arithmetic", - "independent non-author approval", - "id-token: write", - "OPENCODE_REPOSITORY_DISPATCH_TARGETS", - "NVIDIA_NIM_API_KEY", - "COPILOT_GITHUB_TOKEN", - "ContextualWisdomLab/bandscope", - "APA 7th references", - ): - assert phrase in doctoring - - -def test_focused_quality_workflow_tracks_bandscope_contracts() -> None: - """Caller and doctoring edits always rerun exact-head verification.""" - quality = _read(QUALITY_WORKFLOW) - - assert quality.count(".github/workflows/bandscope-hourly-review-repair.yml") == 2 - assert quality.count("docs/doctoring/bandscope-hourly-review-caller.md") == 2 - assert quality.count("tests/test_bandscope_hourly_review_caller.py") == 3 diff --git a/tests/test_governance_risk_compliance_hourly_review_caller.py b/tests/test_governance_risk_compliance_hourly_review_caller.py deleted file mode 100644 index 525748b4c..000000000 --- a/tests/test_governance_risk_compliance_hourly_review_caller.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Contract tests for the GRC product's bounded hourly review-repair caller.""" - -from pathlib import Path - - -CALLER = Path(".github/workflows/governance-risk-compliance-hourly-review-repair.yml") -DOCTORING = Path("docs/doctoring/governance-risk-compliance-hourly-review-caller.md") -QUALITY_WORKFLOW = Path(".github/workflows/hourly-nvidia-nim-review-repair.yml") - - -def _read(path: Path) -> str: - """Return one repository contract file as UTF-8 text.""" - return path.read_text(encoding="utf-8") - - -def test_grc_caller_is_hourly_bounded_and_non_cancelling() -> None: - """GRC receives one realistic exact-head repair opportunity per heartbeat.""" - caller = _read(CALLER) - - assert 'cron: "43 * * * *"' in caller - assert "group: governance-risk-compliance-hourly-review-repair" in caller - assert "cancel-in-progress: false" in caller - assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in caller - assert "target_repository: ContextualWisdomLab/governance-risk-compliance" in caller - assert "base_branch: develop" in caller - assert 'max_prs: "50"' in caller - assert 'max_dispatches: "1"' in caller - assert 'retry_hours: "2"' in caller - - -def test_grc_caller_preserves_credentials_and_read_only_scope() -> None: - """The caller maps scheduler credentials without exposing provider secrets.""" - caller = _read(CALLER) - workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) - pr_review_secret = "$" + "{{ secrets.PR_REVIEW_MERGE_TOKEN }}" - opencode_secret = "$" + "{{ secrets.OPENCODE_APPROVE_TOKEN }}" - - assert "\npermissions:\n contents: read\n" in workflow_scope - assert "\n permissions:\n" not in jobs_scope - assert f"PR_REVIEW_MERGE_TOKEN: {pr_review_secret}" in caller - assert f"OPENCODE_APPROVE_TOKEN: {opencode_secret}" in caller - assert "secrets: inherit" not in caller - assert "NVIDIA_NIM_API_KEY" not in caller - assert "COPILOT_GITHUB_TOKEN" not in caller - for forbidden in ( - "actions: write", - "contents: write", - "issues: write", - "pull-requests: write", - "statuses: write", - ): - assert forbidden not in caller - - -def test_grc_doctoring_records_product_and_governance_bounds() -> None: - """Operators retain RCA, ownership, credential, and approval contracts.""" - doctoring = _read(DOCTORING) - - for phrase in ( - "root-cause analysis", - "remediation feasibility", - "two-hour same-head retry floor", - "policy, control, risk, evidence, and compliance-audit truth", - "Keyverse", - "independent non-author approval", - "NVIDIA_NIM_API_KEY", - "COPILOT_GITHUB_TOKEN", - "ContextualWisdomLab/governance-risk-compliance", - "APA 7th references", - ): - assert phrase in doctoring - - -def test_focused_quality_workflow_tracks_grc_contracts() -> None: - """Caller, doctoring, and contract edits always rerun exact-head verification.""" - quality = _read(QUALITY_WORKFLOW) - - assert quality.count( - ".github/workflows/governance-risk-compliance-hourly-review-repair.yml" - ) == 2 - assert quality.count( - "docs/doctoring/governance-risk-compliance-hourly-review-caller.md" - ) == 2 - assert quality.count("tests/test_governance_risk_compliance_hourly_review_caller.py") == 3 diff --git a/tests/test_materialize_base_python_requirements.py b/tests/test_materialize_base_python_requirements.py index cc457748b..317ab5f5c 100644 --- a/tests/test_materialize_base_python_requirements.py +++ b/tests/test_materialize_base_python_requirements.py @@ -525,7 +525,7 @@ def _trusted_uv_archive( def test_download_trusted_uv_archive_accepts_fixed_https_origin( monkeypatch: pytest.MonkeyPatch, ) -> None: - """The downloader returns bounded bytes from the fixed GitHub HTTPS origin.""" + """The downloader returns bounded bytes from the fixed Astral HTTPS origin.""" payload = b"archive" response = FakeHttpResponse(materializer.TRUSTED_UV_ARCHIVE_URL, payload) monkeypatch.setattr(materializer.urllib.request, "urlopen", lambda *_a, **_k: response) @@ -533,49 +533,11 @@ def test_download_trusted_uv_archive_accepts_fixed_https_origin( assert materializer._download_trusted_uv_archive() == payload -def test_download_trusted_uv_archive_accepts_github_release_asset_origin( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """The official GitHub release-asset CDN remains a valid final HTTPS origin.""" - payload = b"archive" - response = FakeHttpResponse( - "https://release-assets.githubusercontent.com/" - "github-production-release-asset/699532645/archive", - payload, - ) - monkeypatch.setattr(materializer.urllib.request, "urlopen", lambda *_a, **_k: response) - - assert materializer._download_trusted_uv_archive() == payload - - -def test_download_trusted_uv_archive_accepts_legacy_objects_asset_origin( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """The previous GitHub release-asset hostname remains a valid final origin.""" - payload = b"archive" - response = FakeHttpResponse( - "https://objects.githubusercontent.com/github-production-release-asset/1/file", - payload, - ) - monkeypatch.setattr(materializer.urllib.request, "urlopen", lambda *_a, **_k: response) - - assert materializer._download_trusted_uv_archive() == payload - - -@pytest.mark.parametrize( - "unsafe_url", - [ - "https://example.invalid/uv.tar.gz", - "https://user@github.com/astral-sh/uv/releases/download/0.12.1/uv.tar.gz", - "https://:secret@github.com/astral-sh/uv/releases/download/0.12.1/uv.tar.gz", - ], -) def test_download_trusted_uv_archive_rejects_unsafe_redirect( monkeypatch: pytest.MonkeyPatch, - unsafe_url: str, ) -> None: """A redirect away from the fixed HTTPS release host fails closed.""" - response = FakeHttpResponse(unsafe_url) + response = FakeHttpResponse("https://example.invalid/uv.tar.gz") monkeypatch.setattr(materializer.urllib.request, "urlopen", lambda *_a, **_k: response) with pytest.raises(RuntimeError, match="redirected outside"): diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index a57adb695..5316b67d9 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -8,17 +8,10 @@ import pytest -from scripts.ci.assert_opencode_reasoning_effort import strip_jsonc_comments - - -def load_opencode_jsonc() -> dict: - """Load the repository's opencode.jsonc, tolerating its // comments.""" - return json.loads(strip_jsonc_comments(Path("opencode.jsonc").read_text(encoding="utf-8"))) - def test_code_reviewer_subagent_contract_is_configured(): """Guard the read-only code-reviewer subagent contract.""" - config = load_opencode_jsonc() + config = json.loads(Path("opencode.jsonc").read_text(encoding="utf-8")) agents = config["agent"] reviewer = agents["code-reviewer"] @@ -91,7 +84,7 @@ def test_code_reviewer_subagent_contract_is_configured(): def test_opencode_model_pool_sets_high_effort_for_capable_candidates(): """Guard every review-pool candidate against silent reasoning-effort drift.""" - config = load_opencode_jsonc() + config = json.loads(Path("opencode.jsonc").read_text(encoding="utf-8")) workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text(encoding="utf-8") github_models = config["provider"]["github-models"]["models"] candidates_match = re.search(r'OPENCODE_MODEL_CANDIDATES: "([^"]+)"', workflow) @@ -2301,7 +2294,7 @@ def test_opencode_pending_peer_checks_hold_blocks_required_workflow_until_approv def test_opencode_strix_security_regressions_are_closed(): """Bind the nine current-head Strix findings to fail-closed contracts.""" workflow = Path(".github/workflows/opencode-review-dispatch.yml").read_text(encoding="utf-8") - config = load_opencode_jsonc() + config = json.loads(Path("opencode.jsonc").read_text(encoding="utf-8")) assert " validate-pr-metadata:\n" in workflow assert "^ContextualWisdomLab/[A-Za-z0-9_.-]+$" in workflow diff --git a/tests/test_organization_commercial_readiness_loop_coordinator.py b/tests/test_organization_commercial_readiness_loop_coordinator.py deleted file mode 100644 index 0bd601d26..000000000 --- a/tests/test_organization_commercial_readiness_loop_coordinator.py +++ /dev/null @@ -1,187 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path - -import pytest - -from organization_commercial_readiness_fixtures import ( - FailingDispatchClient, - FakeClient, - manual_workflow, - pull, - repository_payload, - snapshot, - workflow, -) -from scripts.ci.organization_commercial_readiness_loop import ( - ActionKind, - GitHubError, - PlanItem, - SnapshotChanged, - main, - run_once, -) - - -def test_run_dispatches_one_repair_and_one_independent_product() -> None: - """Unchanged exact state authorizes one bounded action of each class.""" - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - product = snapshot( - "ContextualWisdomLab/product", workflows=(manual_workflow(workflow_id=17),) - ) - client = FakeClient( - [repository_payload("review"), repository_payload("product")], - {review.full_name: [review, review], product.full_name: [product, product]}, - ) - report = run_once(client, organization="ContextualWisdomLab", rotation_seed=0) - assert client.dispatched_repairs == [(review.full_name, "main")] - assert client.dispatched_products == [(product.full_name, 17, "main")] - assert [action.status for action in report.actions] == ["dispatched", "dispatched"] - assert json.loads(report.to_json())["inspected_repositories"] == 2 - - -def test_drift_new_lease_and_refetch_error_skip_only_the_target() -> None: - """Pre-dispatch movement invalidates selection without reusing old evidence.""" - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - moved = snapshot( - review.full_name, default_sha="b" * 40, pulls=(pull(1, head_sha="c" * 40),) - ) - product = snapshot("ContextualWisdomLab/product", workflows=(manual_workflow(),)) - newly_leased = snapshot( - product.full_name, - workflows=( - manual_workflow(), - workflow( - workflow_id=8, - content='on:\n schedule:\n - cron: "9 * * * *"\n', - ), - ), - ) - broken = snapshot("ContextualWisdomLab/broken", pulls=(pull(2),)) - client = FakeClient( - [ - repository_payload("review"), - repository_payload("product"), - repository_payload("broken"), - ], - { - review.full_name: [review, moved], - product.full_name: [product, newly_leased], - broken.full_name: [broken, SnapshotChanged("moved")], - }, - ) - report = run_once( - client, - organization="ContextualWisdomLab", - rotation_seed=0, - max_review_dispatches=2, - ) - assert [item.status for item in report.actions] == [ - "skipped_refetch_error", - "skipped_state_changed", - "skipped_writer_lease", - ] - - -def test_initial_errors_leases_and_dry_run_are_reported() -> None: - """An inaccessible repo is contained; initial leases and dry-run stay explicit.""" - leased = snapshot( - "ContextualWisdomLab/leased", - workflows=(workflow(content='on:\n schedule:\n - cron: "7 * * * *"\n'),), - ) - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - client = FakeClient( - [ - repository_payload("broken"), - repository_payload("leased"), - repository_payload("review"), - ], - { - "ContextualWisdomLab/broken": [GitHubError("forbidden")], - leased.full_name: [leased], - review.full_name: [review, review], - }, - ) - report = run_once( - client, - organization="ContextualWisdomLab", - rotation_seed=0, - dry_run=True, - ) - assert report.inspection_errors == ( - ("ContextualWisdomLab/broken", "GitHubError: forbidden"), - ) - assert report.leased_repositories == (leased.full_name,) - assert report.actions[0].status == "dry_run" - assert not client.dispatched_repairs - - -def test_dispatch_failures_and_invalid_internal_product_plan( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """API rejection and an impossible product plan both fail closed per action.""" - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - failing = FailingDispatchClient( - [repository_payload("review")], {review.full_name: [review, review]} - ) - assert run_once( - failing, organization="ContextualWisdomLab", rotation_seed=0 - ).actions[0].status == "dispatch_failed" - - product = snapshot("ContextualWisdomLab/product") - invalid = PlanItem( - ActionKind.PRODUCT_DEVELOPMENT, - product.full_name, - "main", - product.fingerprint, - None, - ) - monkeypatch.setattr( - "scripts.ci.organization_commercial_readiness_loop.build_plan", - lambda *_args, **_kwargs: (invalid,), - ) - client = FakeClient( - [repository_payload("product")], {product.full_name: [product, product]} - ) - assert run_once( - client, organization="ContextualWisdomLab", rotation_seed=0 - ).actions[0].status == "dispatch_failed" - - -def test_main_writes_file_summary_stdout_and_failure_paths( - tmp_path: Path, - monkeypatch: pytest.MonkeyPatch, - capsys: pytest.CaptureFixture[str], -) -> None: - """CLI output and invalid configuration have deterministic exit behavior.""" - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - client = FakeClient( - [repository_payload("review")], {review.full_name: [review, review]} - ) - output, summary = tmp_path / "report.json", tmp_path / "summary.md" - monkeypatch.setenv("GITHUB_STEP_SUMMARY", str(summary)) - assert main( - ["--rotation-seed", "2", "--json-output", str(output)], - client_factory=lambda: client, - ) == 0 - assert json.loads(output.read_text())["actions"][0]["status"] == "dispatched" - assert "ContextualWisdomLab/review" in summary.read_text() - - empty = FakeClient([], {}) - monkeypatch.delenv("GITHUB_STEP_SUMMARY") - assert main( - ["--max-repositories", "0", "--max-review-dispatches", "0"], - client_factory=lambda: empty, - ) == 0 - assert '"inspected_repositories": 0' in capsys.readouterr().out - - assert main( - ["--organization", "bad organization"], client_factory=lambda: empty - ) == 2 - assert "invalid organization" in capsys.readouterr().err - assert main( - [], client_factory=lambda: (_ for _ in ()).throw(GitHubError("auth")) - ) == 2 - assert "GitHubError: auth" in capsys.readouterr().err - assert main(["--max-repositories", "-1"], client_factory=lambda: empty) == 2 diff --git a/tests/test_organization_commercial_readiness_loop_credential_contract.py b/tests/test_organization_commercial_readiness_loop_credential_contract.py deleted file mode 100644 index 3225d5832..000000000 --- a/tests/test_organization_commercial_readiness_loop_credential_contract.py +++ /dev/null @@ -1,21 +0,0 @@ -from pathlib import Path - - -WORKFLOW_PATH = ( - Path(__file__).resolve().parents[1] - / ".github" - / "workflows" - / "organization-commercial-readiness-loop.yml" -) - - -def test_central_schedule_has_no_branch_selected_or_reviewer_credential_path() -> None: - """The fleet coordinator must be schedule-only and use maintainer authority.""" - source = WORKFLOW_PATH.read_text(encoding="utf-8") - - assert "workflow_dispatch:" not in source - assert "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in source - assert "persist-credentials: false" in source - assert "OPENCODE_APPROVE_TOKEN" not in source - assert "DRY_RUN" not in source - assert "inputs.dry_run" not in source diff --git a/tests/test_organization_commercial_readiness_loop_github.py b/tests/test_organization_commercial_readiness_loop_github.py deleted file mode 100644 index aa4bfa576..000000000 --- a/tests/test_organization_commercial_readiness_loop_github.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import annotations - -import base64 -from typing import Any - -import pytest - -from organization_commercial_readiness_fixtures import repository_payload -from scripts.ci.organization_commercial_readiness_loop import ( - GitHubClient, - GitHubError, - SnapshotChanged, -) - - -def test_client_requires_explicit_token_and_decodes_requests( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Organization access never falls back and JSON/empty/error responses stay distinct.""" - with pytest.raises(GitHubError, match="GH_TOKEN"): - GitHubClient("") - with pytest.raises(GitHubError, match="GH_TOKEN"): - GitHubClient.from_environment({}) - assert isinstance(GitHubClient.from_environment({"GH_TOKEN": " token "}), GitHubClient) - monkeypatch.setenv("GH_TOKEN", "live") - assert isinstance(GitHubClient.from_environment(), GitHubClient) - - class Completed: - def __init__(self, code: int, out: str = "", err: str = "") -> None: - self.returncode, self.stdout, self.stderr = code, out, err - - responses = [Completed(0, '{"ok":true}'), Completed(0), Completed(1, err="x" * 2000)] - calls: list[list[str]] = [] - - def fake_run(args: list[str], **kwargs: Any) -> Completed: - calls.append(args) - assert kwargs["env"]["GH_TOKEN"] == "token" # noqa: S105 - return responses.pop(0) - - monkeypatch.setattr("subprocess.run", fake_run) - client = GitHubClient("token") - assert client.request("/ok") == {"ok": True} - assert client.request("/empty", method="POST", payload={"a": 1}) is None - with pytest.raises(GitHubError) as error: - client.request("/fail") - assert len(str(error.value)) < 1200 - assert calls[1][:4] == ["gh", "api", "--method", "POST"] - - -def test_client_transport_and_invalid_json_fail_closed( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Transport and JSON failures never become empty successful evidence.""" - client = GitHubClient("secret") - monkeypatch.setattr( - "subprocess.run", - lambda *_args, **_kwargs: (_ for _ in ()).throw(OSError("network")), - ) - with pytest.raises(GitHubError, match="transport failed"): - client.request("/transport") - - class Completed: - returncode, stdout, stderr = 0, "not-json", "" - - monkeypatch.setattr("subprocess.run", lambda *_args, **_kwargs: Completed()) - with pytest.raises(GitHubError, match="invalid JSON"): - client.request("/invalid") - - -def test_repository_pagination_and_default_sha_validation( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Fleet discovery spans pages and exact default evidence is mandatory.""" - client = GitHubClient("token") - pages = [ - [repository_payload(f"repo-{index}") for index in range(100)], - [repository_payload("last")], - ] - monkeypatch.setattr(client, "request", lambda _path: pages.pop(0)) - assert len(client.list_repositories("ContextualWisdomLab")) == 101 - monkeypatch.setattr(client, "request", lambda _path: {"sha": "bad"}) - with pytest.raises(GitHubError, match="invalid default-branch SHA"): - client.default_branch_sha("ContextualWisdomLab/example", "release/v1") - - -def test_workflow_source_materialization_and_pagination( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Exact workflow source is decoded while unsafe source shapes remain unreadable.""" - client = GitHubClient("token") - page = [ - { - "id": index + 1, - "name": "Hourly Product Development", - "path": "" if index == 0 else "dynamic/x" if index == 1 else f".github/workflows/{index}.yml", - "state": "active", - } - for index in range(100) - ] - workflow_calls = 0 - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - nonlocal workflow_calls - del method, payload - if "actions/workflows" in path: - workflow_calls += 1 - return {"workflows": page if workflow_calls == 1 else []} - if "/contents/" in path: - index = int(path.split("/")[-1].split(".")[0]) - if index == 2: - data = b"on:\n workflow_dispatch:\n" - return { - "type": "file", - "size": len(data), - "sha": "good", - "encoding": "base64", - "content": base64.b64encode(data).decode(), - } - if index == 8: - raise GitHubError("forbidden") - variants: list[Any] = [ - None, - {"type": "dir", "size": 0, "encoding": "base64"}, - {"type": "file", "size": 1_048_577, "encoding": "base64"}, - {"type": "file", "size": 1, "encoding": "utf-8"}, - {"type": "file", "size": 1, "encoding": "base64", "content": "%%%"}, - {"type": "file", "size": 1, "encoding": "base64", "content": "/w=="}, - ] - return variants[(index - 3) % len(variants)] - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - records = client.list_workflows("ContextualWisdomLab/example", "a" * 40) - assert len(records) == 100 and workflow_calls == 2 - assert records[2].content_sha == "good" - assert sum(item.content is not None for item in records) == 1 - - -def test_run_and_pull_inventories_cover_live_fields_and_pages( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Live-run and pull inventories preserve exact identity across pages.""" - client = GitHubClient("token") - pull_calls = 0 - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - nonlocal pull_calls - del method, payload - if "actions/runs" in path: - status = path.split("status=")[1].split("&")[0] - page = int(path.split("&page=")[1].split("&")[0]) - if page > 1: - return {"workflow_runs": []} - return { - "workflow_runs": [{ - "id": len(status), - "name": "Hourly Product Development", - "path": ".github/workflows/hourly-product-development.yml", - "status": "" if status == "queued" else status, - "head_sha": "a" * 40, - }] - } - if "/pulls?" in path: - pull_calls += 1 - size = 100 if pull_calls == 1 else 1 - return [{ - "number": index + 1, - "draft": False, - "base": {"ref": "main"}, - "head": {"sha": f"{index + 1:040x}"}, - "updated_at": "2026-08-08T00:00:00Z", - } for index in range(size)] - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - runs = client.list_active_runs("ContextualWisdomLab/example") - assert len(runs) == 5 and runs[0].status == "queued" - assert len(client.list_open_pulls("ContextualWisdomLab/example")) == 101 - - -def test_snapshot_movement_and_dispatch_payloads(monkeypatch: pytest.MonkeyPatch) -> None: - """Snapshots reject movement and dispatches retain the reviewed bounded payloads.""" - client = GitHubClient("token") - shas = iter(("a" * 40, "b" * 40)) - monkeypatch.setattr(client, "default_branch_sha", lambda _repo, _branch: next(shas)) - monkeypatch.setattr(client, "list_workflows", lambda _repo, _ref: ()) - monkeypatch.setattr(client, "list_active_runs", lambda _repo: ()) - monkeypatch.setattr(client, "list_open_pulls", lambda _repo: ()) - with pytest.raises(SnapshotChanged): - client.snapshot("ContextualWisdomLab/example", "main") - - calls: list[tuple[str, str, Any]] = [] - - def capture(path: str, *, method: str = "GET", payload: Any = None) -> None: - calls.append((path, method, payload)) - - monkeypatch.setattr(client, "request", capture) - client.dispatch_review_repair("ContextualWisdomLab/example", "develop") - client.dispatch_product_workflow("ContextualWisdomLab/example", 91, "develop") - assert calls[0][2]["client_payload"] == { - "target_repository": "ContextualWisdomLab/example", - "base_branch": "develop", - "max_prs": "50", - "max_dispatches": "1", - "retry_hours": "1", - "dry_run": False, - } - assert calls[1][2] == {"ref": "develop"} - - -def test_complete_snapshot_materialization(monkeypatch: pytest.MonkeyPatch) -> None: - """One stable default head yields workflows, runs, and pull records together.""" - client = GitHubClient("token") - monkeypatch.setattr(client, "default_branch_sha", lambda _repo, _branch: "a" * 40) - monkeypatch.setattr(client, "list_workflows", lambda _repo, _ref: ()) - monkeypatch.setattr(client, "list_active_runs", lambda _repo: ()) - monkeypatch.setattr(client, "list_open_pulls", lambda _repo: ()) - result = client.snapshot("ContextualWisdomLab/example", "main") - assert result.default_sha == "a" * 40 - - -def test_default_branch_sha_normalizes_valid_hex(monkeypatch: pytest.MonkeyPatch) -> None: - """Valid exact branch identity is normalized before fingerprinting.""" - client = GitHubClient("token") - monkeypatch.setattr(client, "request", lambda _path: {"sha": "A" * 40}) - assert client.default_branch_sha("ContextualWisdomLab/example", "main") == "a" * 40 diff --git a/tests/test_organization_commercial_readiness_loop_import_contract.py b/tests/test_organization_commercial_readiness_loop_import_contract.py deleted file mode 100644 index 43c3c71ac..000000000 --- a/tests/test_organization_commercial_readiness_loop_import_contract.py +++ /dev/null @@ -1,20 +0,0 @@ -from pathlib import Path - - -REPO_ROOT = Path(__file__).resolve().parents[1] -QUALITY_WORKFLOW = ( - REPO_ROOT - / ".github" - / "workflows" - / "organization-commercial-readiness-loop-quality-ci.yml" -) - - -def test_quality_gate_uses_import_stable_test_support() -> None: - """Hosted and complete-suite collection must resolve the same helper module.""" - source = QUALITY_WORKFLOW.read_text(encoding="utf-8") - - assert "--import-mode=importlib" in source - assert '"organization_commercial_readiness_fixtures.py"' in source - assert "tests/organization_commercial_readiness_fixtures.py" not in source - assert "--include='scripts/ci/organization_commercial_readiness_loop.py' \\\n -m pytest" not in source diff --git a/tests/test_organization_commercial_readiness_loop_operational_failures.py b/tests/test_organization_commercial_readiness_loop_operational_failures.py deleted file mode 100644 index ae70d088d..000000000 --- a/tests/test_organization_commercial_readiness_loop_operational_failures.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - -import pytest - -from organization_commercial_readiness_fixtures import ( - FailingDispatchClient, - FakeClient, - pull, - repository_payload, - snapshot, -) -from scripts.ci.organization_commercial_readiness_loop import GitHubError, main - - -def test_cli_fails_when_every_selected_repository_inspection_fails( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """A fleet-wide inspection outage must make the scheduled job non-green.""" - monkeypatch.delenv("GITHUB_STEP_SUMMARY", raising=False) - client = FakeClient( - [repository_payload("broken")], - {"ContextualWisdomLab/broken": [GitHubError("forbidden")]}, - ) - - assert main([], client_factory=lambda: client) == 1 - - -def test_cli_fails_when_every_planned_dispatch_fails( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """A run that cannot start any selected work must make the job non-green.""" - monkeypatch.delenv("GITHUB_STEP_SUMMARY", raising=False) - review = snapshot("ContextualWisdomLab/review", pulls=(pull(1),)) - client = FailingDispatchClient( - [repository_payload("review")], - {review.full_name: [review, review]}, - ) - - assert main([], client_factory=lambda: client) == 1 diff --git a/tests/test_organization_commercial_readiness_loop_organization_scope.py b/tests/test_organization_commercial_readiness_loop_organization_scope.py deleted file mode 100644 index 5b20bfe5e..000000000 --- a/tests/test_organization_commercial_readiness_loop_organization_scope.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -import pytest - -from organization_commercial_readiness_fixtures import FakeClient -from scripts.ci.organization_commercial_readiness_loop import GitHubError, main, run_once - - -def test_runtime_rejects_a_foreign_organization_before_inventory() -> None: - """A variable org must never dispatch through the fixed CWL control plane.""" - client = FakeClient([], {}) - - with pytest.raises(GitHubError, match="ContextualWisdomLab"): - run_once(client, organization="OtherOrganization", rotation_seed=0) - - -def test_cli_rejects_a_well_formed_foreign_organization() -> None: - """A syntactically valid foreign org is still outside this scheduler's scope.""" - client = FakeClient([], {}) - - assert main( - ["--organization", "OtherOrganization"], client_factory=lambda: client - ) == 2 diff --git a/tests/test_organization_commercial_readiness_loop_policy.py b/tests/test_organization_commercial_readiness_loop_policy.py deleted file mode 100644 index 920f8072f..000000000 --- a/tests/test_organization_commercial_readiness_loop_policy.py +++ /dev/null @@ -1,177 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -from typing import Any - -from organization_commercial_readiness_fixtures import ( - manual_workflow, - pull, - snapshot, - workflow, -) -from scripts.ci.organization_commercial_readiness_loop import ( - ActionKind, - ActionResult, - RunRecord, - RunReport, - build_plan, - choose_rotating, - is_dedicated_writer_workflow, - is_live_writer_run, - is_manual_product_entrypoint, - repository_is_eligible, -) - -ROOT = Path(__file__).resolve().parents[1] - - -def test_static_and_live_writer_lease_policy() -> None: - """Only active high-signal writers, including unreadable ones, hold leases.""" - scheduled = workflow(content='on:\n schedule:\n - cron: "1 * * * *"\n') - disabled = workflow(state="disabled_manually", content=scheduled.content) - manual = workflow(content="on:\n workflow_dispatch:\n") - merge = workflow( - name="Required PR Review Merge Scheduler", - path=".github/workflows/pr-review-merge-scheduler.yml", - content='on:\n schedule:\n - cron: "*/15 * * * *"\n', - ) - assert is_dedicated_writer_workflow(scheduled) - assert is_dedicated_writer_workflow(workflow(content=None)) - assert not is_dedicated_writer_workflow(disabled) - assert not is_dedicated_writer_workflow(manual) - assert not is_dedicated_writer_workflow(merge) - - active = RunRecord(1, scheduled.name, scheduled.path, "in_progress", "a" * 40) - complete = RunRecord(2, scheduled.name, scheduled.path, "completed", "b" * 40) - assert is_live_writer_run(active) - assert not is_live_writer_run(complete) - - -def test_product_entrypoint_requires_manual_nvidia_opt_in() -> None: - """Product dispatch requires a marked, unscheduled, credential-isolated workflow.""" - safe = manual_workflow() - assert is_manual_product_entrypoint(safe) - assert not is_manual_product_entrypoint(workflow(state="disabled_manually", content="x")) - assert not is_manual_product_entrypoint(workflow(content=None)) - for changed in ( - (safe.content or "") + 'schedule:\n - cron: "1 * * * *"\n', - (safe.content or "") + "COPILOT_GITHUB_TOKEN: forbidden\n", - (safe.content or "").replace("# cwl-org-commercial-entrypoint: v1\n", ""), - (safe.content or "").replace("concurrency:\n", ""), - ): - assert not is_manual_product_entrypoint(workflow(content=changed)) - - -def test_repository_eligibility_is_owned_and_write_capable() -> None: - """Archived, forked, disabled, foreign, central, and read-only repos are excluded.""" - base: dict[str, Any] = { - "full_name": "ContextualWisdomLab/example", - "default_branch": "main", - "archived": False, - "disabled": False, - "fork": False, - "permissions": {"push": True}, - } - assert repository_is_eligible(base, "ContextualWisdomLab") - variants = ( - {**base, "archived": True}, - {**base, "disabled": True}, - {**base, "fork": True}, - {**base, "default_branch": None}, - {**base, "full_name": "Other/example"}, - {**base, "full_name": "ContextualWisdomLab/.github"}, - {**base, "permissions": {"pull": True}}, - ) - assert all(not repository_is_eligible(item, "ContextualWisdomLab") for item in variants) - - -def test_rotation_and_plan_are_bounded_and_dependency_safe() -> None: - """Review and development rotate independently without drafts, stacks, or leases.""" - assert choose_rotating(("a", "b", "c"), 1, 2) == ("b", "c") - assert choose_rotating(("a", "b", "c"), 2, 4) == ("c", "a", "b") - assert choose_rotating((), 1, 1) == () - assert choose_rotating(("a",), 1, 0) == () - - records = ( - snapshot("ContextualWisdomLab/review-a", pulls=(pull(1),)), - snapshot("ContextualWisdomLab/review-b", pulls=(pull(2),)), - snapshot("ContextualWisdomLab/product", workflows=(manual_workflow(),)), - snapshot("ContextualWisdomLab/draft", pulls=(pull(3, draft=True),)), - snapshot("ContextualWisdomLab/stack", pulls=(pull(4, base_ref="feature/base"),)), - snapshot( - "ContextualWisdomLab/leased", - workflows=(workflow(content='on:\n schedule:\n - cron: "1 * * * *"\n'),), - pulls=(pull(5),), - ), - ) - plan = build_plan(records, rotation_seed=1) - assert [(item.kind, item.repository) for item in plan] == [ - (ActionKind.REVIEW_REPAIR, "ContextualWisdomLab/review-b"), - (ActionKind.PRODUCT_DEVELOPMENT, "ContextualWisdomLab/product"), - ] - assert plan[1].workflow_id == 9 - - -def test_snapshot_fingerprint_ignores_api_order_only() -> None: - """Reordered workflow and PR lists retain one exact-state fingerprint.""" - a = snapshot( - "ContextualWisdomLab/example", - workflows=(workflow(workflow_id=2), workflow(workflow_id=1)), - pulls=(pull(2), pull(1)), - ) - b = snapshot( - "ContextualWisdomLab/example", - workflows=(workflow(workflow_id=1), workflow(workflow_id=2)), - pulls=(pull(1), pull(2)), - ) - assert a.fingerprint == b.fingerprint - - -def test_report_formats_actions_empty_state_and_errors() -> None: - """JSON and Markdown receipts preserve bounded action and failure evidence.""" - report = RunReport( - "ContextualWisdomLab", - 1, - ("ContextualWisdomLab/leased",), - (("ContextualWisdomLab/broken", "error|detail\nnext"),), - (ActionResult(ActionKind.REVIEW_REPAIR, "ContextualWisdomLab/a", "dry_run", "a|b"),), - True, - ) - assert '"dry_run": true' in report.to_json() - assert "a\\|b" in report.to_markdown() - empty = RunReport("ContextualWisdomLab", 0, (), (), (), False) - assert "No safe target" in empty.to_markdown() - - -def test_workflow_and_doctoring_contracts() -> None: - """Permanent files retain cadence, token, coverage, and realistic-scope controls.""" - workflow_source = ( - ROOT / ".github/workflows/organization-commercial-readiness-loop.yml" - ).read_text() - quality = ( - ROOT - / ".github/workflows/organization-commercial-readiness-loop-quality-ci.yml" - ).read_text() - doctoring = ( - ROOT / "docs/doctoring/organization-commercial-readiness-loop.md" - ).read_text() - assert 'cron: "7 * * * *"' in workflow_source - assert "cancel-in-progress: false" in workflow_source - assert 'MAX_REVIEW_DISPATCHES: "1"' in workflow_source - assert 'MAX_DEVELOPMENT_DISPATCHES: "1"' in workflow_source - assert "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in workflow_source - assert "OPENCODE_APPROVE_TOKEN" not in workflow_source - assert "workflow_dispatch:" not in workflow_source - assert "|| github.token" not in workflow_source - assert "NVIDIA_NIM_API_KEY" not in workflow_source - assert "COPILOT_GITHUB_TOKEN" not in workflow_source - assert "github.run_number" in workflow_source - assert "persist-credentials: false" in workflow_source - assert "--branch" in quality and "--fail-under=100" in quality - assert "--import-mode=importlib" in quality - assert "organization_commercial_readiness_fixtures.py" in quality - assert "github.event.pull_request.head.sha" in quality - assert "disabled workflow does not hold a lease" in doctoring - assert "manual-only, explicitly marked" in doctoring - assert "does not make every repository directly writable" in doctoring - assert "GITHUB_TOKEN" in doctoring and "APA 7" in doctoring diff --git a/tests/test_organization_commercial_readiness_loop_receipt_contract.py b/tests/test_organization_commercial_readiness_loop_receipt_contract.py deleted file mode 100644 index ce0956bba..000000000 --- a/tests/test_organization_commercial_readiness_loop_receipt_contract.py +++ /dev/null @@ -1,45 +0,0 @@ -from pathlib import Path - -from organization_commercial_readiness_fixtures import manual_workflow, workflow -from scripts.ci.organization_commercial_readiness_loop import ( - is_manual_product_entrypoint, -) - - -WORKFLOW_PATH = ( - Path(__file__).resolve().parents[1] - / ".github" - / "workflows" - / "organization-commercial-readiness-loop.yml" -) - - -def test_product_entrypoint_rejects_missing_model_key_or_manual_trigger() -> None: - """Both the NVIDIA model boundary and manual opt-in trigger are mandatory.""" - safe = manual_workflow() - without_nvidia = (safe.content or "").replace( - "NVIDIA_NIM_API_KEY", "OTHER_API_KEY" - ) - without_dispatch = (safe.content or "").replace( - "on:\n workflow_dispatch:\n", "on:\n push:\n" - ) - - assert not is_manual_product_entrypoint(workflow(content=without_nvidia)) - assert not is_manual_product_entrypoint(workflow(content=without_dispatch)) - - -def test_json_receipt_is_retained_as_an_immutable_short_lived_artifact() -> None: - """The machine-readable fleet receipt must outlive ephemeral runner storage.""" - source = WORKFLOW_PATH.read_text(encoding="utf-8") - - assert ( - "uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a" - in source - ) - assert "name: organization-commercial-readiness-${{ github.run_id }}-${{ github.run_attempt }}" in source - assert "path: ${{ runner.temp }}/organization-commercial-readiness-loop.json" in source - assert "if-no-files-found: error" in source - assert "retention-days: 3" in source - assert "results-receiver.actions.githubusercontent.com:443" in source - assert "*.actions.githubusercontent.com:443" in source - assert "*.blob.core.windows.net:443" in source diff --git a/tests/test_organization_commercial_readiness_loop_resource_limits.py b/tests/test_organization_commercial_readiness_loop_resource_limits.py deleted file mode 100644 index d90cad14b..000000000 --- a/tests/test_organization_commercial_readiness_loop_resource_limits.py +++ /dev/null @@ -1,121 +0,0 @@ -"""Resource-bound regressions for the organization readiness coordinator.""" - -from __future__ import annotations - -import base64 -from typing import Any - -import pytest - -from scripts.ci.organization_commercial_readiness_loop import GitHubClient, GitHubError - - -def _workflow(index: int) -> dict[str, Any]: - """Return one high-signal workflow metadata record.""" - - return { - "id": index + 1, - "name": f"Hourly Product Development {index}", - "path": f".github/workflows/product-development-{index}.yml", - "state": "active", - } - - -def test_workflow_metadata_count_is_bounded_per_repository( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """More than 1,000 workflow records fail closed before fleet memory grows.""" - - client = GitHubClient("token") - pages = [ - [ - { - "id": page * 100 + index + 1, - "name": "CI", - "path": f".github/workflows/ci-{page}-{index}.yml", - "state": "active", - } - for index in range(100) - ] - for page in range(10) - ] - pages.append( - [ - { - "id": 1001, - "name": "CI", - "path": ".github/workflows/ci-overflow.yml", - "state": "active", - } - ] - ) - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - del method, payload - if "actions/workflows" in path: - return {"workflows": pages.pop(0) if pages else []} - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - - with pytest.raises(GitHubError, match="workflow metadata limit"): - client.list_workflows("ContextualWisdomLab/example", "a" * 40) - - -def test_workflow_source_count_is_bounded_per_repository( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """More than 100 candidate sources fail closed before unbounded retention.""" - - client = GitHubClient("token") - pages = [[_workflow(index) for index in range(100)], [_workflow(100)]] - source = b"on:\n workflow_dispatch:\n" - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - del method, payload - if "actions/workflows" in path: - return {"workflows": pages.pop(0) if pages else []} - if "/contents/" in path: - return { - "type": "file", - "size": len(source), - "sha": "a" * 40, - "encoding": "base64", - "content": base64.b64encode(source).decode(), - } - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - - with pytest.raises(GitHubError, match="workflow source limit"): - client.list_workflows("ContextualWisdomLab/example", "a" * 40) - - -def test_workflow_source_bytes_are_bounded_per_repository( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Candidate source bytes above 10 MiB fail closed instead of exhausting memory.""" - - client = GitHubClient("token") - workflows = [_workflow(index) for index in range(11)] - source = b"x" * 1_000_000 - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - del method, payload - if "actions/workflows" in path: - current, workflows[:] = list(workflows), [] - return {"workflows": current} - if "/contents/" in path: - return { - "type": "file", - "size": len(source), - "sha": "b" * 40, - "encoding": "base64", - "content": base64.b64encode(source).decode(), - } - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - - with pytest.raises(GitHubError, match="workflow source byte limit"): - client.list_workflows("ContextualWisdomLab/example", "a" * 40) diff --git a/tests/test_organization_commercial_readiness_loop_run_pagination.py b/tests/test_organization_commercial_readiness_loop_run_pagination.py deleted file mode 100644 index fc16ea669..000000000 --- a/tests/test_organization_commercial_readiness_loop_run_pagination.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -from typing import Any - -import pytest - -from scripts.ci.organization_commercial_readiness_loop import GitHubClient - - -def test_active_writer_inventory_paginates_every_status( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """A writer beyond the first 100 active runs must still hold the lease.""" - client = GitHubClient("token") - requested_paths: list[str] = [] - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - del method, payload - requested_paths.append(path) - status = path.split("status=")[1].split("&")[0] - page = int(path.rsplit("page=", maxsplit=1)[1]) - if status == "queued" and page == 1: - return { - "workflow_runs": [ - { - "id": index + 1, - "name": "Ordinary CI", - "path": ".github/workflows/ci.yml", - "status": "queued", - "head_sha": "a" * 40, - } - for index in range(100) - ] - } - if status == "queued" and page == 2: - return { - "workflow_runs": [ - { - "id": 101, - "name": "Hourly Product Development", - "path": ".github/workflows/hourly-product-development.yml", - "status": "queued", - "head_sha": "b" * 40, - } - ] - } - return {"workflow_runs": []} - - monkeypatch.setattr(client, "request", fake) - - records = client.list_active_runs("ContextualWisdomLab/example") - - assert len(records) == 101 - assert records[-1].name == "Hourly Product Development" - assert any("status=queued&per_page=100&page=2" in path for path in requested_paths) diff --git a/tests/test_organization_commercial_readiness_loop_secret_scope.py b/tests/test_organization_commercial_readiness_loop_secret_scope.py deleted file mode 100644 index b47c2cadc..000000000 --- a/tests/test_organization_commercial_readiness_loop_secret_scope.py +++ /dev/null @@ -1,21 +0,0 @@ -from pathlib import Path - - -WORKFLOW_PATH = ( - Path(__file__).resolve().parents[1] - / ".github" - / "workflows" - / "organization-commercial-readiness-loop.yml" -) - - -def test_maintainer_token_is_scoped_only_to_the_dispatch_step() -> None: - """Third-party setup actions must never receive the cross-repository token.""" - source = WORKFLOW_PATH.read_text(encoding="utf-8") - before_dispatch, dispatch_step = source.split( - " - name: Coordinate one bounded fleet pass\n", maxsplit=1 - ) - - assert "PR_REVIEW_MERGE_TOKEN" not in before_dispatch - assert "GH_TOKEN:" not in before_dispatch - assert "env:\n GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in dispatch_step diff --git a/tests/test_organization_commercial_readiness_loop_workflow_source_scope.py b/tests/test_organization_commercial_readiness_loop_workflow_source_scope.py deleted file mode 100644 index 2cd3386ad..000000000 --- a/tests/test_organization_commercial_readiness_loop_workflow_source_scope.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -import base64 -from typing import Any - -import pytest - -from scripts.ci.organization_commercial_readiness_loop import GitHubClient - - -def test_workflow_source_fetch_is_limited_to_writer_candidates( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Ordinary CI workflows must not consume one contents request each.""" - client = GitHubClient("token") - content_paths: list[str] = [] - - def fake(path: str, *, method: str = "GET", payload: Any = None) -> Any: - del method, payload - if "actions/workflows" in path: - return { - "workflows": [ - { - "id": 1, - "name": "Ordinary CI", - "path": ".github/workflows/ci.yml", - "state": "active", - }, - { - "id": 2, - "name": "Hourly Product Development", - "path": ".github/workflows/hourly-product-development.yml", - "state": "active", - }, - ] - } - if "/contents/" in path: - content_paths.append(path) - data = b'on:\n schedule:\n - cron: "7 * * * *"\n' - return { - "type": "file", - "size": len(data), - "sha": "source-sha", - "encoding": "base64", - "content": base64.b64encode(data).decode(), - } - raise AssertionError(path) - - monkeypatch.setattr(client, "request", fake) - - records = client.list_workflows("ContextualWisdomLab/example", "a" * 40) - - assert records[0].content is None - assert records[0].content_sha == "" - assert records[1].content is not None - assert len(content_paths) == 1 - assert "hourly-product-development.yml" in content_paths[0] diff --git a/tests/test_organization_commercial_readiness_token_redaction.py b/tests/test_organization_commercial_readiness_token_redaction.py deleted file mode 100644 index 45fe26e6b..000000000 --- a/tests/test_organization_commercial_readiness_token_redaction.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Credential-redaction regressions for the organization coordinator. - -GitHub CLI diagnostics are repository-external text. A credential that crosses -the retained-suffix boundary, or appears in an endpoint string, must never be -partially or fully reflected in a workflow error. -""" - -from __future__ import annotations - -from typing import Any - -import pytest - -from scripts.ci.organization_commercial_readiness_loop import GitHubClient, GitHubError - - -def test_cli_error_redacts_token_before_bounding_output( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """A token crossing the final-900-character boundary leaves no suffix leak.""" - - token = "ghp_0123456789abcdefghijklmnopqrstuvwxyzAB" - raw_error = ("A" * 1000) + token + ("B" * 880) - - class Completed: - returncode = 1 - stdout = "" - stderr = raw_error - - def fake_run(*_args: Any, **_kwargs: Any) -> Completed: - return Completed() - - monkeypatch.setattr("subprocess.run", fake_run) - - with pytest.raises(GitHubError) as raised: - GitHubClient(token).request("/repos/ContextualWisdomLab/example") - - message = str(raised.value) - assert token not in message - assert token[-20:] not in message - assert len(message) < 1200 - - -def test_endpoint_diagnostic_redacts_exact_token_without_masking_context( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """Only the credential is removed when it appears in a diagnostic endpoint.""" - - token = "ghp_abcdefghijklmnopqrstuvwxyz0123456789AB" - - class Completed: - returncode = 1 - stdout = "" - stderr = "request rejected" - - monkeypatch.setattr("subprocess.run", lambda *_args, **_kwargs: Completed()) - - with pytest.raises(GitHubError) as raised: - GitHubClient(token).request(f"/repos/example/{token}/runs") - - message = str(raised.value) - assert token not in message - assert "repos/example" in message - assert "[REDACTED]" in message diff --git a/tests/test_originweave_hourly_review_caller.py b/tests/test_originweave_hourly_review_caller.py deleted file mode 100644 index 11b335378..000000000 --- a/tests/test_originweave_hourly_review_caller.py +++ /dev/null @@ -1,166 +0,0 @@ -"""Contract tests for OriginWeave's bounded hourly review-repair caller.""" - -from pathlib import Path - - -CALLER = Path(".github/workflows/originweave-hourly-review-repair.yml") -DOCTORING = Path("docs/doctoring/originweave-hourly-review-caller.md") -QUALITY_WORKFLOW = Path(".github/workflows/hourly-nvidia-nim-review-repair.yml") -SCHEDULER = Path(".github/workflows/pr-review-fix-scheduler.yml") - - -def _read(path: Path) -> str: - """Return one repository contract file as UTF-8 text.""" - return path.read_text(encoding="utf-8") - - -def _yaml_path_entries(block: str) -> set[str]: - """Return dashed YAML path entries from one trigger or compileall block.""" - entries: set[str] = set() - for raw_line in block.splitlines(): - stripped = raw_line.strip() - if stripped.startswith("- "): - entries.add(stripped[2:].strip()) - elif stripped.startswith("tests/") or stripped.startswith("scripts/"): - entries.add(stripped.rstrip(" \\")) - return entries - - -def _trigger_path_block(quality: str, trigger: str) -> str: - """Return the dashed path list under one named workflow trigger.""" - marker = f" {trigger}:\n paths:\n" - start = quality.index(marker) + len(marker) - lines: list[str] = [] - for line in quality[start:].splitlines(): - if line.startswith(" - "): - lines.append(line) - continue - if line.strip() == "": - continue - break - return "\n".join(lines) - - -def _compileall_block(quality: str) -> str: - """Return the compileall argument list from the focused quality job.""" - marker = "python -m compileall -q \\" - start = quality.index(marker) - remainder = quality[start:] - end = remainder.find("\n git ") - return remainder if end < 0 else remainder[:end] - - -def test_originweave_caller_is_hourly_bounded_and_non_cancelling() -> None: - """OriginWeave receives one realistic agent-browser repair without cancellation.""" - caller = _read(CALLER) - - assert 'cron: "10 * * * *"' in caller - assert "group: originweave-hourly-review-repair" in caller - assert "cancel-in-progress: false" in caller - assert "uses: ./.github/workflows/pr-review-fix-scheduler.yml" in caller - assert "target_repository: ContextualWisdomLab/OriginWeave" in caller - assert "base_branch: main" in caller - assert 'max_prs: "50"' in caller - assert 'max_dispatches: "1"' in caller - assert 'retry_hours: "2"' in caller - - -def test_originweave_caller_preserves_oidc_and_explicit_secret_scope() -> None: - """The queue scanner maps established credentials without model secrets.""" - caller = _read(CALLER) - workflow_scope, jobs_scope = caller.split("\njobs:\n", maxsplit=1) - - assert "\npermissions:\n contents: read\n" in workflow_scope - assert ( - "\n permissions:\n contents: read\n id-token: write\n" - in jobs_scope - ) - assert "PR_REVIEW_MERGE_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN }}" in caller - assert "OPENCODE_APPROVE_TOKEN: ${{ secrets.OPENCODE_APPROVE_TOKEN }}" in caller - assert "secrets: inherit" not in caller - assert "NVIDIA_NIM_API_KEY" not in caller - assert "COPILOT_GITHUB_TOKEN" not in caller - for forbidden in ( - "actions: write", - "contents: write", - "issues: write", - "pull-requests: write", - "statuses: write", - ): - assert forbidden not in caller - - -def test_originweave_target_is_not_hard_coded_in_shared_scheduler() -> None: - """Product identity remains in the thin caller rather than the engine.""" - assert "ContextualWisdomLab/OriginWeave" not in _read(SCHEDULER) - - -def test_originweave_doctoring_records_browser_activation_and_credentials() -> None: - """Operators retain target-allowlist, browser runtime, and approval prerequisites.""" - doctoring = _read(DOCTORING) - - for phrase in ( - "ContextualWisdomLab/OriginWeave", - "OPENCODE_REPOSITORY_DISPATCH_TARGETS", - "independent non-author approval", - "NVIDIA_NIM_API_KEY", - "COPILOT_GITHUB_TOKEN", - "id-token: write", - "two-hour same-head retry floor", - "root-cause analysis", - "remediation feasibility", - "protected-main operational acceptance", - "APA 7th references", - "ContextualWisdomLab/OriginWeave#175", - "ContextualWisdomLab/OriginWeave#173", - "ContextualWisdomLab/OriginWeave#168", - "ContextualWisdomLab/OriginWeave#166", - ): - assert phrase in doctoring - - -def test_path_block_helpers_keep_trigger_and_compileall_sets_disjoint() -> None: - """A path listed only under push or compileall must not satisfy pull_request.""" - quality = ( - "on:\n" - " pull_request:\n" - " paths:\n" - " - .github/workflows/originweave-hourly-review-repair.yml\n" - " push:\n" - " paths:\n" - " - docs/doctoring/originweave-hourly-review-caller.md\n" - " python -m compileall -q \\\n" - " tests/test_originweave_hourly_review_caller.py\n" - " git diff --check\n" - ) - - pull_request_paths = _yaml_path_entries(_trigger_path_block(quality, "pull_request")) - push_paths = _yaml_path_entries(_trigger_path_block(quality, "push")) - compileall_paths = _yaml_path_entries(_compileall_block(quality)) - - assert pull_request_paths == {".github/workflows/originweave-hourly-review-repair.yml"} - assert push_paths == {"docs/doctoring/originweave-hourly-review-caller.md"} - assert compileall_paths == {"tests/test_originweave_hourly_review_caller.py"} - assert "docs/doctoring/originweave-hourly-review-caller.md" not in pull_request_paths - assert ".github/workflows/originweave-hourly-review-repair.yml" not in compileall_paths - - -def test_focused_quality_workflow_tracks_originweave_contracts() -> None: - """Caller, test, and doctoring edits always rerun the focused gate.""" - quality = _read(QUALITY_WORKFLOW) - pull_request_paths = _yaml_path_entries(_trigger_path_block(quality, "pull_request")) - push_paths = _yaml_path_entries(_trigger_path_block(quality, "push")) - compileall_paths = _yaml_path_entries(_compileall_block(quality)) - caller = ".github/workflows/originweave-hourly-review-repair.yml" - doctoring = "docs/doctoring/originweave-hourly-review-caller.md" - contract = "tests/test_originweave_hourly_review_caller.py" - - assert caller in pull_request_paths - assert doctoring in pull_request_paths - assert contract in pull_request_paths - assert caller in push_paths - assert doctoring in push_paths - assert contract in push_paths - assert contract in compileall_paths - assert caller not in compileall_paths - assert doctoring not in compileall_paths diff --git a/tests/test_r_coverage_peer_gate.py b/tests/test_r_coverage_peer_gate.py index 594c90415..e77a80bca 100644 --- a/tests/test_r_coverage_peer_gate.py +++ b/tests/test_r_coverage_peer_gate.py @@ -56,24 +56,6 @@ def test_rejects_invalid_or_mixed_test_failures() -> None: ) -def test_skips_summary_regex_when_failure_marker_is_absent( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """The marker-absent cold path returns before summary regex evaluation.""" - - class ForbiddenSummaryPattern: - """Fail the test if the expensive summary scan is reached.""" - - @staticmethod - def findall(_text: str) -> list[str]: - """Reject any unexpected summary scan.""" - raise AssertionError("summary regex must not run without the failure marker") - - monkeypatch.setattr(gate, "FAIL_SUMMARY_RE", ForbiddenSummaryPattern()) - - assert not gate.classify_testthat_failure("x" * gate.MAX_LOG_BYTES, "aFIPC") - - def test_allows_only_declared_suggests_package_failures() -> None: """A peer-check deferral may include packageNotFound errors for declared Suggests.""" text = """\ @@ -240,9 +222,3 @@ def test_script_entrypoint_returns_cli_status( runpy.run_path(str(script), run_name="__main__") assert raised.value.code == 1 - - -def test_classify_testthat_failure_returns_false_no_summaries() -> None: - """A terminal failure marker without a summary remains non-authorizing.""" - text = "Error: Test failures something else missing package 'test'" - assert gate.classify_testthat_failure(text, "test") is False diff --git a/tests/test_sandboxed_web_e2e.py b/tests/test_sandboxed_web_e2e.py index 6e092c293..9ac865d25 100644 --- a/tests/test_sandboxed_web_e2e.py +++ b/tests/test_sandboxed_web_e2e.py @@ -114,6 +114,8 @@ def test_wait_helpers_and_service_cleanup_edges(monkeypatch, tmp_path): assert sandboxed_web_e2e.wait_for_url("http://127.0.0.1:1/", 1, exited_service) is False with pytest.raises(ValueError, match="URL must start with http:// or https://"): sandboxed_web_e2e.wait_for_url("file:///etc/passwd", 1, exited_service) + with pytest.raises(ValueError, match="URL must point to localhost or 127.0.0.1, got: http://example.com/ready"): + sandboxed_web_e2e.wait_for_url("http://example.com/ready", 1, exited_service) sandboxed_web_e2e.stop_service(exited_service) assert sandboxed_web_e2e.tail_text(tmp_path / "missing.log") == "" @@ -181,13 +183,13 @@ def fake_run(*args, **kwargs): assert service.command == "npm run dev" assert service.log_path == tmp_path / "backend.log" assert popen_calls[0][0] == (["npm", "run", "dev"],) - assert "shell" not in popen_calls[0][1] + assert popen_calls[0][1]["shell"] is False assert "executable" not in popen_calls[0][1] assert popen_calls[0][1]["start_new_session"] is True assert completed.returncode == 7 assert run_calls[0][0] == (["npm", "test"],) assert run_calls[0][1]["timeout"] == 5 - assert "shell" not in run_calls[0][1] + assert run_calls[0][1]["shell"] is False assert "executable" not in run_calls[0][1] diff --git a/tests/test_trusted_uv_download_contract.py b/tests/test_trusted_uv_download_contract.py index 380151db6..02f3c5961 100644 --- a/tests/test_trusted_uv_download_contract.py +++ b/tests/test_trusted_uv_download_contract.py @@ -9,7 +9,7 @@ _REPO_ROOT = Path(__file__).resolve().parents[1] _MATERIALIZER = _REPO_ROOT / "scripts" / "ci" / "materialize_base_python_requirements.py" _EXPECTED_URL = ( - "https://github.com/astral-sh/uv/releases/download/0.12.1/" + "https://releases.astral.sh/github/uv/releases/download/0.12.1/" "uv-x86_64-unknown-linux-gnu.tar.gz" ) _SEMGREP_DYNAMIC_URL_RULE = ( diff --git a/tests/test_uv_redirect_and_coverage_contract.py b/tests/test_uv_redirect_and_coverage_contract.py index bb83a9afc..0830624ef 100644 --- a/tests/test_uv_redirect_and_coverage_contract.py +++ b/tests/test_uv_redirect_and_coverage_contract.py @@ -17,16 +17,15 @@ @pytest.mark.parametrize( "unsafe_url", [ - "https://github.com:444/astral-sh/uv/releases/download/0.12.1/uv.tar.gz", - "https://github.com:not-a-port/astral-sh/uv/releases/download/0.12.1/uv.tar.gz", - "https://release-assets.githubusercontent.com:444/github-production-release-asset/1/file", + "https://releases.astral.sh:444/github/uv/releases/download/0.12.1/uv.tar.gz", + "https://releases.astral.sh:not-a-port/github/uv/releases/download/0.12.1/uv.tar.gz", ], ) def test_trusted_uv_download_rejects_nondefault_or_malformed_ports( monkeypatch: pytest.MonkeyPatch, unsafe_url: str, ) -> None: - """The pinned GitHub release origin cannot land on another or malformed port.""" + """The pinned Astral host cannot redirect to another or malformed service port.""" response = FakeHttpResponse(unsafe_url) monkeypatch.setattr( @@ -39,21 +38,14 @@ def test_trusted_uv_download_rejects_nondefault_or_malformed_ports( materializer._download_trusted_uv_archive() -@pytest.mark.parametrize( - "trusted_url", - [ - "https://github.com:443/astral-sh/uv/releases/download/0.12.1/uv-x86_64-unknown-linux-gnu.tar.gz", - "https://release-assets.githubusercontent.com:443/github-production-release-asset/1/file", - "https://objects.githubusercontent.com:443/github-production-release-asset/1/file", - ], -) def test_trusted_uv_download_accepts_explicit_default_https_port( monkeypatch: pytest.MonkeyPatch, - trusted_url: str, ) -> None: - """An explicit port 443 still denotes a fixed trusted HTTPS origin.""" + """An explicit port 443 still denotes the fixed trusted HTTPS origin.""" - response = FakeHttpResponse(trusted_url) + response = FakeHttpResponse( + "https://releases.astral.sh:443/github/uv/releases/download/0.12.1/uv.tar.gz" + ) monkeypatch.setattr( materializer.urllib.request, "urlopen", diff --git a/tests/test_uv_redirect_boundary.py b/tests/test_uv_redirect_boundary.py index c453070f7..fd98592e8 100644 --- a/tests/test_uv_redirect_boundary.py +++ b/tests/test_uv_redirect_boundary.py @@ -18,34 +18,12 @@ def clear_trusted_uv_opener_cache() -> Iterator[None]: materializer._install_trusted_uv_url_opener.cache_clear() -def test_trusted_uv_redirect_handler_allows_one_github_asset_hop() -> None: - """GitHub Releases may take one hop onto the official release-asset CDN.""" - handler = materializer._TrustedUvReleaseAssetRedirects() - original = urllib.request.Request(materializer.TRUSTED_UV_ARCHIVE_URL) - allowed = ( - "https://release-assets.githubusercontent.com/" - "github-production-release-asset/699532645/archive" - ) - - followed = handler.redirect_request( - original, - None, - 302, - "Found", - {}, - allowed, - ) - - assert followed is not None - assert followed.full_url == allowed - - def test_trusted_uv_redirect_handler_rejects_before_following() -> None: - """Non-allowlisted hops are rejected before urllib creates a target request.""" - handler = materializer._TrustedUvReleaseAssetRedirects() + """Every HTTP redirect is rejected before urllib creates a target request.""" + handler = materializer._RejectTrustedUvRedirects() original = urllib.request.Request(materializer.TRUSTED_UV_ARCHIVE_URL) - with pytest.raises(RuntimeError, match="redirected outside"): + with pytest.raises(RuntimeError, match="redirects are forbidden"): handler.redirect_request( original, None, @@ -56,104 +34,10 @@ def test_trusted_uv_redirect_handler_rejects_before_following() -> None: ) -def test_trusted_uv_redirect_handler_rejects_asset_host_follow_on() -> None: - """A second hop from the asset CDN cannot retarget the download.""" - handler = materializer._TrustedUvReleaseAssetRedirects() - current = urllib.request.Request( - "https://release-assets.githubusercontent.com/" - "github-production-release-asset/699532645/archive" - ) - - with pytest.raises(RuntimeError, match="redirected outside"): - handler.redirect_request( - current, - None, - 302, - "Found", - {}, - "https://objects.githubusercontent.com/other", - ) - - -def test_trusted_uv_redirect_handler_allows_legacy_objects_asset_hop() -> None: - """The previous GitHub release-asset hostname remains a valid first hop.""" - handler = materializer._TrustedUvReleaseAssetRedirects() - original = urllib.request.Request(materializer.TRUSTED_UV_ARCHIVE_URL) - allowed = "https://objects.githubusercontent.com/github-production-release-asset/1/file" - - followed = handler.redirect_request( - original, - None, - 302, - "Found", - {}, - allowed, - ) - - assert followed is not None - assert followed.full_url == allowed - - -def test_trusted_uv_redirect_handler_fails_closed_when_parent_drops_request( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """A parent handler that drops the follow-on request cannot open a new origin.""" - handler = materializer._TrustedUvReleaseAssetRedirects() - original = urllib.request.Request(materializer.TRUSTED_UV_ARCHIVE_URL) - allowed = ( - "https://release-assets.githubusercontent.com/" - "github-production-release-asset/699532645/archive" - ) - - monkeypatch.setattr( - urllib.request.HTTPRedirectHandler, - "redirect_request", - lambda *_args, **_kwargs: None, - ) - - with pytest.raises(RuntimeError, match="redirected outside"): - handler.redirect_request( - original, - None, - 302, - "Found", - {}, - allowed, - ) - - -@pytest.mark.parametrize( - "new_url", - [ - "https://user@release-assets.githubusercontent.com/archive", - "https://:secret@release-assets.githubusercontent.com/archive", - "https://release-assets.githubusercontent.com:444/archive", - "https://release-assets.githubusercontent.com:not-a-port/archive", - "http://release-assets.githubusercontent.com/archive", - ], -) -def test_trusted_uv_redirect_handler_rejects_unsafe_asset_locations( - new_url: str, -) -> None: - """Userinfo, non-HTTPS, and nondefault ports cannot become the asset origin.""" - handler = materializer._TrustedUvReleaseAssetRedirects() - original = urllib.request.Request(materializer.TRUSTED_UV_ARCHIVE_URL) - - with pytest.raises(RuntimeError, match="redirected outside"): - handler.redirect_request( - original, - None, - 302, - "Found", - {}, - new_url, - ) - - def test_trusted_uv_opener_is_cached_and_disables_ambient_proxies( monkeypatch: pytest.MonkeyPatch, ) -> None: - """The dedicated process installs one no-proxy GitHub-origin opener.""" + """The dedicated process installs one no-proxy, no-redirect opener.""" captured: dict[str, object] = {"builds": 0, "installs": 0} sentinel = object() @@ -180,4 +64,4 @@ def fake_install_opener(opener: object) -> None: assert len(handlers) == 2 assert isinstance(handlers[0], urllib.request.ProxyHandler) assert handlers[0].proxies == {} - assert isinstance(handlers[1], materializer._TrustedUvReleaseAssetRedirects) + assert isinstance(handlers[1], materializer._RejectTrustedUvRedirects)