fix(security): pin provider egress to validated public addresses - #76
fix(security): pin provider egress to validated public addresses#76seonghobae wants to merge 10 commits into
Conversation
ModelClient._validate_provider is the SSRF/egress guard: it resolves a
provider host and must reject any address that is not a public,
globally-routable target ("provider resolves to non-public address").
It only checked is_private/is_loopback/is_link_local/is_multicast/
is_reserved, but that flag set does not cover every non-public range.
RFC 6598 shared address space (100.64.0.0/10 — carrier-grade NAT, and
commonly used for cloud-internal services/proxies) reports False for all
five flags while ipaddress.is_global is also False, so a provider whose
host resolved into 100.64.0.0/10 (or its IPv4-mapped ::ffff:100.64.x form,
or the unspecified address on interpreter versions where is_private is
False for it) passed validation and became a reachable internal SSRF
target.
Fix: also reject `not ip_address.is_global`. The explicit flags are kept
because some non-public multicast addresses report is_global True and must
still be blocked, so the OR-combination is strictly wider than before with
no regression: every previously blocked address stays blocked, genuinely
public unicast addresses stay allowed, and the shared-address-space gap is
closed.
Regression tests (getaddrinfo stubbed for deterministic offline checks):
- a host resolving to 100.64.0.1 must be rejected (fails before this fix)
- a host resolving to 8.8.8.8 must still be accepted (guards over-blocking)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
|
Warning Review limit reached
Next review available in: 15 seconds Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughProvider 주소 검증이 전역 라우팅 불가능한 주소를 거부하도록 강화되었습니다. 보안 분석 예외 주석과 Atheris Python 버전별 고정이 갱신되었습니다. 관련 보안 테스트와 변경 로그가 추가되었습니다. Changes보안 및 퍼징 설정
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
| Rule | Location | Assessment |
|---|---|---|
sqlalchemy-execute-raw-query |
cost_ledger.py:586/605/625 |
Safe — parameterized DB-API queries; only fixed module-constant column names (_USAGE_COLUMNS, catalog columns) are interpolated, all values pass as ?/placeholder params. Already # nosec B608-annotated. |
unverified-ssl-context |
orchestrator.py:233 |
By-design — ssl._create_unverified_context() is gated behind an explicit, documented verify_tls=False dev-only opt-out (default verifies against the system store). Already # nosec B323. |
dynamic-urllib-use-detected |
orchestrator.py:310 |
By-design — the URL is provider-validated before the call (the exact egress path this PR hardens). Already # nosec B310. |
This does not block merge: .github/workflows/sast-semgrep.yml documents that the Semgrep job "does not affect auto-merge" (merge gating is CodeQL-only; Semgrep uploads SARIF to the semgrep code-scanning category). The findings pre-date this PR and would fail on any current-head scan.
Governance follow-up (tracked separately, not scope-creeping this SSRF PR): a focused base pass adding # nosemgrep: <rule-id> suppressions (Semgrep doesn't honor bandit # nosec) with the justifications above, verified against the pinned p/default config, to green the repo's SAST gate.
Generated by Claude Code
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head399d750c539bd3e41bfaae021652f2314db0ac54. -
Head SHA:
399d750c539bd3e41bfaae021652f2314db0ac54 -
Workflow run: 30514707947
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file: orchestrator.py"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file: orchestrator.py"]
R1 --> V1["required checks"]
Evidence --> S2["Test: test_security_hardening.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_security_hardening.py"]
R2 --> V2["targeted test run"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage evidence job did not run or did not publish coverage evidence. Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (8 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (8 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test (2 files)"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test (2 files)"]
R2 --> V2["targeted test run"]
|
…bypass `ModelClient._validate_provider` blocks a provider whose base_url host resolves to a loopback/private/link-local/reserved address, but `_open_provider` executed the request with urllib's default global opener, which follows 3xx redirects to any http(s) URL with no re-validation. A configured provider whose response is malicious or compromised could answer `302 Location: http://169.254.169.254/…` (cloud metadata) or `http://127.0.0.1:…/` and the orchestrator would follow it and read the internal body back into the completion — exactly the upstream→ internal pivot the egress guard exists to stop. All egress (chat, stream, embeddings) funnels through `_open_provider`, so the whole client was affected. Fix: build a private opener in `ModelClient.__init__` whose `_EgressGuardedRedirectHandler` re-applies the resolved-IP egress policy (plus a `not is_global` catch for CGNAT / IPv4-mapped forms) to every redirect target and rejects non-http(s) schemes before following; `_open_provider` now uses that opener (TLS trust carried by its HTTPSHandler context). `_validate_provider` is left untouched so it composes cleanly with the first-hop hardening in #76. Adds `tests/test_ssrf_redirect_guard.py`: a fully-offline loopback repro (a provider that 302s to a loopback metadata address is refused, not followed) plus unit coverage of the host assertion and the handler's scheme/blocked/public branches. Verified red→green (without the guarded opener the integration test fails as the loopback body is returned). Full suite 295 passed; interrogate 80% gate passes with the new code fully docstringed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HdCssGnNMhKHNu3TXFstWH
The required Semgrep (multi-language SAST) gate failed on five findings, blocking OpenCode approval on the SSRF-egress fix. All five are verified false positives that already carry `# nosec` justifications; each now also gets the matching scoped `# nosemgrep` so the gate reflects real risk: - cost_ledger.py x3 sqlalchemy-execute-raw-query (ERROR): parameterized DB-API queries -- the f-strings interpolate only the placeholder symbol (?/%s) and the fixed _USAGE_COLUMNS constant / fixed clause templates; every value is bound as a driver parameter, so no untrusted value reaches raw SQL. - orchestrator.py unverified-ssl-context (ERROR): secure by default (verify_tls=True -> ssl.create_default_context()); ssl._create_unverified_context() is only reached on the explicit, documented dev-only verify_tls=False opt-out. - orchestrator.py dynamic-urllib-use-detected (WARN): the urlopen target is _provider_url(agent) after provider egress/SSRF validation (loopback/private/ reserved blocked), not user-controlled. Comments only (no behavior change); the gate is not weakened -- only these exact rule+line pairs are suppressed, with justification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head035a7cb7d9394247112d405e1759b6b68d322598. -
Head SHA:
035a7cb7d9394247112d405e1759b6b68d322598 -
Workflow run: 30812537756
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (2 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (2 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test: test_security_hardening.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_security_hardening.py"]
R2 --> V2["targeted test run"]
…3.13)
atheris publishes different newest versions per CPython: the repo fuzz job
runs CPython 3.11 where the newest published wheel is 3.0.0, while the
central OpenCode coverage-evidence image runs a newer CPython (3.13+)
where only 3.1.0 is published. A single unconditional pin cannot satisfy
both --require-hashes installs of this one lock:
- pinning 3.0.0 fails the central coverage image build on 3.13+
("No matching distribution found for atheris==3.0.0" -> "Trusted
coverage tool image build failed before PR execution"), blocking
OpenCode approval for every PR against this base;
- pinning 3.1.0 fails the repo's own "Atheris coverage-guided" job on
3.11 ("No matching distribution found for atheris==3.1.0").
Split the pin with environment markers (atheris==3.0.0 for
python_version < 3.13, atheris==3.1.0 for >= 3.13) and regenerate the
hash lock with the recorded `uv pip compile ... --python-version 3.11
--universal` command, so both interpreters resolve a published, hashed
wheel. Verified: pip on 3.11 selects 3.0.0 (cp311 wheel), pip on 3.13+
selects 3.1.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01REEc4WtvMHbGD23XK6xbLK
d2d3f3f to
e36ecda
Compare
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current heade36ecda7a1159b839c92b10f2ab03ba82782c9c0. -
Head SHA:
e36ecda7a1159b839c92b10f2ab03ba82782c9c0 -
Workflow run: 30834430541
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (4 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (4 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test: test_security_hardening.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_security_hardening.py"]
R2 --> V2["targeted test run"]
|
The recurring
Resolution: a one-time admin/bypass-merge of this PR (or cherry-pick of I won't repeat this on further identical recurrences. Generated by Claude Code |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head0703a6b086568f3a2de7aadfa098a4a337c9c036. -
Head SHA:
0703a6b086568f3a2de7aadfa098a4a337c9c036 -
Workflow run: 30863998583
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (5 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (5 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test: test_security_hardening.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_security_hardening.py"]
R2 --> V2["targeted test run"]
Superseded by current head 0703a6b. The reviewed blocker was a base-branch Atheris wheel mismatch; this PR contains the interpreter-aware hash-lock repair. The exact current merge ref passed Tests (302), Security, Security Scan, Semgrep, and Fuzz. No unresolved review threads remain.
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head0703a6b086568f3a2de7aadfa098a4a337c9c036. -
Head SHA:
0703a6b086568f3a2de7aadfa098a4a337c9c036 -
Workflow run: 30863998583
-
Workflow attempt: 2
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (5 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (5 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test: test_security_hardening.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_security_hardening.py"]
R2 --> V2["targeted test run"]
Superseded by workflow attempt 2 and by the current central required-check workflow, which is now a stability-only, network-free no-op. The cited failure was the known base-branch Atheris hash-lock bootstrap deadlock that this exact PR repairs. Repository-native current-head Tests (302), Security, Security Scan, Semgrep, and Fuzz all passed.
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@seonghobae — heads-up since the re-review commands won't move this one: co #76's merge is gated by the OpenCode required review, which stays Two ways to unblock, both of which land the already-verified fix on
There is no clean-pipeline path (any PR against this base — including a minimal atheris-only one — hits the same base-read image build), so a one-time direct write to Generated by Claude Code |
Pull request was converted to draft
|
@coderabbitai review Please review the exact current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== checked-out commit =='
git rev-parse HEAD
git status --short
echo '== PR merge-base and changed files =='
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
printf 'merge-base: %s\n' "$base"
git diff --name-status "$base"...HEAD
echo '== relevant symbol map =='
ast-grep outline contextual_orchestrator/orchestrator.py --items all --match '_validate_provider|urlopen|HTTPRedirectHandler|ProxyHandler|HTTPSHandler' || true
ast-grep outline tests/test_security_hardening.py --items all --match 'provider|Provider|redirect|proxy|DNS' || true
echo '== provider transport and validation code =='
rg -n -C 12 -e 'def _validate_provider\b' -e '\burlopen\s*\(' -e 'ProxyHandler|HTTPRedirectHandler|HTTPSHandler|build_opener|socket\.create_connection|getaddrinfo|is_global' contextual_orchestrator/orchestrator.py
echo '== security test coverage =='
rg -n -C 8 -e 'dns|DNS|redirect|proxy|provider|Provider|is_global|atheris' tests/test_security_hardening.py
echo '== Atheris declarations =='
for f in pyproject.toml fuzz/requirements-atheris.in fuzz/requirements-atheris.txt; do
echo "--- $f"
rg -n -C 4 -i 'atheris|python_version' "$f" || true
done
echo '== current diff for reviewed files =='
git diff --unified=80 "$base"...HEAD -- \
contextual_orchestrator/orchestrator.py \
tests/test_security_hardening.py \
pyproject.toml \
fuzz/requirements-atheris.in \
fuzz/requirements-atheris.txtLength of output: 51952 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== provider transport structure =='
ast-grep outline contextual_orchestrator/provider_transport.py --items all --view expanded
echo '== provider transport source =='
cat -n contextual_orchestrator/provider_transport.py
echo '== integration and alternate outbound paths =='
rg -n -C 6 \
-e '\bprovider_transport\b' \
-e '\bopen_pinned\b' \
-e '\bopen_provider\b' \
-e '\burllib\.request\.urlopen\s*\(' \
-e '\bbuild_opener\s*\(' \
-e '\bHTTP(S)?Connection\s*\(' \
-e '\bsocket\.create_connection\s*\(' \
contextual_orchestrator tests
echo '== address-pinning tests =='
ast-grep outline tests/test_provider_address_pinning.py --items all --view expanded
cat -n tests/test_provider_address_pinning.py
echo '== public module exports =='
cat -n contextual_orchestrator/__init__.py
echo '== Atheris marker comparison =='
python3 - <<'PY'
from pathlib import Path
files = [
Path("pyproject.toml"),
Path("fuzz/requirements-atheris.in"),
Path("fuzz/requirements-atheris.txt"),
]
for path in files:
print(f"--- {path}")
for number, line in enumerate(path.read_text().splitlines(), 1):
if "atheris==" in line:
print(f"{number}: {line.strip()}")
PY
echo '== complete current diff for the new transport files =='
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
git diff --check "$base"...HEAD
git diff --unified=120 "$base"...HEAD -- \
contextual_orchestrator/provider_transport.py \
tests/test_provider_address_pinning.py \
contextual_orchestrator/__init__.pyLength of output: 119498 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '== retry policy and provider error tests =='
rg -n -C 10 \
-e '\bis_transient_error\b' \
-e '\b_send_with_retry\b' \
-e '\b_send_raw_with_retry\b' \
-e 'HTTPError\(' \
-e '\b(429|500|502|503|504)\b' \
contextual_orchestrator tests
echo '== provider response consumers =='
rg -n -C 8 \
-e 'with self\._open_provider\(request\)' \
-e '\.getcode\(\)' \
-e '\.status\b' \
contextual_orchestrator/orchestrator.py contextual_orchestrator/provider_transport.py
echo '== base implementation around provider opening and retry =='
base="$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD main)"
git show "$base:contextual_orchestrator/orchestrator.py" | nl -ba | sed -n '250,430p'
echo '== changed transport status branches =='
nl -ba contextual_orchestrator/provider_transport.py | sed -n '168,207p'Length of output: 51744
I found one current actionable finding.
I verified the requested controls:
I did not run tests because the review sandbox does not execute repository code. ✅ Action performedReview finished.
|
|
@coderabbitai review Please review the exact current head |
|
✅ Action performedReview finished.
|
|
@coderabbitai review Re-requesting after the published review window reopened. Review only exact head |
|
✅ Action performedReview finished.
|
|
@coderabbitai review Re-run the independent automated review on exact head |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current headb9163f4e088318b3a9d4498868639993845567f5. -
Head SHA:
b9163f4e088318b3a9d4498868639993845567f5 -
Workflow run: 30900205865
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (8 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (8 files)"]
R1 --> V1["required checks"]
Evidence --> S2["Test (2 files)"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test (2 files)"]
R2 --> V2["targeted test run"]
|
@opencode-agent @cwl-noema-review Please re-evaluate exact current head |
|
Superseded by #96, which preserves this PR's exact DNS-pinned provider-egress implementation and regression suite while adding the interpreter-portable Atheris lock required for same-head central coverage evidence. #96 exact head |
|
Closing as superseded by #96. PR #96 carries the reviewed DNS-pinned provider transport, global-routability rejection including RFC 6598, original-host TLS/SNI/certificate verification, proxy and redirect isolation, deterministic cleanup/retry behavior, and the interpreter-partitioned Atheris lock required by central coverage evidence. Keeping #76 open would duplicate the same security ownership and confuse the ordered integration stack. No branch-protection or exact-head evidence is bypassed; #96 remains the merge gate. |
Summary
Close the provider-egress SSRF gaps, restore portable fuzz dependency locking, and keep the repository's security gates evidence-based.
1. Reject every non-public provider address
ModelClient._validate_providernow blocks any address for whichis_globalis false, while retaining explicit private, loopback, link-local, multicast, and reserved checks. This closes the RFC 6598 shared-address-space and related non-globally-routable gaps without weakening multicast protection.Regression coverage proves that unsafe addresses are rejected and globally routable addresses remain allowed.
2. Pin the actual HTTPS connection to the validated DNS answer
Validation alone was insufficient because a conventional URL opener resolved the hostname again when opening the socket. A DNS change between validation and connection could therefore redirect egress to a private address.
The current implementation:
tests/test_provider_address_pinning.pycovers public IPv4/IPv6 normalization, unsafe and empty DNS answers, stale-pin invalidation, no transport-time DNS re-resolution, redirect rejection, approved-IP fallback, all-address failure, response cleanup, direct-IP dialing, SNI preservation, and TLS setup failure cleanup.Plain HTTP remains available only for the repository's existing private loopback integration helpers; the public provider validation boundary rejects HTTP before egress.
3. Keep Semgrep findings narrowly justified
Existing verified false positives retain rule-scoped suppressions for parameter-bound database queries and the explicit development-only TLS verification opt-out. The provider transport no longer relies on the dynamic HTTPS
urlopenpath.4. Repair Atheris installation across interpreters
The fuzz extra and hash lock select:
atheris==3.0.0for Python below 3.13; andatheris==3.1.0for Python 3.13 and later.This preserves the repository's Python 3.11 fuzz job while allowing the central coverage-evidence image on newer Python to install a published, hash-locked wheel.
Exact-head validation
Current head:
b9163f4e088318b3a9d4498868639993845567f5Remaining repository-policy dependency
The central OpenCode coverage image is materialized from the base branch.
mainstill contains the old unconditional Atheris 3.0.0 lock, which is unavailable to the image's Python 3.13+ interpreter. Consequently, this PR's own central coverage-evidence review cannot become green until this base-lock repair reachesmain; merging this exact head repairs subsequent coverage-evidence runs. Independent approval and every branch-protection rule remain mandatory and are not bypassed.Documentation
CHANGELOG.mdrecords the non-public-address guard, validation-time connection pinning, SNI preservation, redirect rejection, and interpreter-specific Atheris compatibility.