Skip to content

security: require exact bytes for request stream accounting - #85

Draft
seonghobae wants to merge 15 commits into
mainfrom
security/exact-request-byte-chunks
Draft

security: require exact bytes for request stream accounting#85
seonghobae wants to merge 15 commits into
mainfrom
security/exact-request-byte-chunks

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Replacement and exact-tree binding

Supersedes closed draft #80 without transferring review or approval. Protected-main base and live protected-main tip remain 10d0c51daf2ad278d66f43be479df8cf6b08ba6d; current exact head is 8a1243feafd12f0faf67cc9fa12d53bd27181a14.

Security boundary

Outbound request-body accounting accepts only exact built-in bytes chunks before invoking length behavior or exposing data downstream. It preserves cumulative byte budgets, exact declared Content-Length, single-consumption semantics, exact authority/framing, TLS identity, proxy isolation, and timeout behavior.

When policy denial has already been decided, dependency-injected source cleanup is a narrow untrusted boundary:

  • ordinary synchronous and asynchronous cleanup exceptions are consumed;
  • dependency-controlled direct custom BaseException subclasses are consumed only inside policy-denial cleanup/setup so they cannot replace or become provenance for the generic denial;
  • KeyboardInterrupt, SystemExit, and GeneratorExit raised directly by cleanup are explicitly re-raised;
  • awaited async child exceptions, child self-cancellation, and non-awaitable cleanup returns are consumed;
  • cancellation directed at the outer request consumer while cleanup is awaited still propagates because the outer await cleanup is outside the BaseException catch;
  • ordinary caller-requested public cleanup semantics remain unchanged from the predecessor behavior.

The caller receives a fresh EgressNotAllowedError("egress URL is not allowed") with neither private context nor cause. No workflow, dependency, credential, permission, authority/TLS/proxy policy, public API, version, release/tag/publication path, or protected-ref behavior changes.

TDD evidence

The branch preserves its earlier exact-byte and async-cleanup RED/GREEN history. The latest direct-BaseException repair is independently test-first:

  1. test-only RED a0418869890fd146462237f9c347419f0cb70484 adds sync and async hostile cleanup sources that raise a custom direct BaseException, plus guards requiring KeyboardInterrupt, SystemExit, and GeneratorExit to propagate;
  2. exact RED CI run 31270939632 passed Ruff and package acceptance but failed the two new masking contracts across Python 3.10–3.13; Python 3.13 reported 2 failed, 763 passed, with the custom child error escaping at the synchronous self._stream.close() and asynchronous stream.aclose() boundaries;
  3. GREEN 8a1243feafd12f0faf67cc9fa12d53bd27181a14 introduces a dedicated synchronous policy-denial cleanup helper and narrows both sync/async BaseException catches to direct untrusted cleanup/setup, explicitly preserving interpreter control flow and keeping the outer async await outside the catch;
  4. exact GREEN CI run 31271043659 succeeds on Python 3.10, 3.11, 3.12, and 3.13 with package acceptance, Ruff, product-guard, and compileall all successful; Python 3.13 reports 765 passed, 1,637/1,637 production statements and 554/554 branches at 100%; request_body_safety.py is 97/97 statements and 32/32 branches;
  5. SAST Semgrep run 31271043648 succeeds on the same exact head.

The two same-head GitHub Code Quality suggestions to replace the narrow BaseException catches with Exception were disproven by the preceding exact RED: doing so deterministically restores the reproduced direct-child exception leak. They were documented as false positives and resolved only after the GREEN evidence proved both masking and control-flow preservation.

Standards and documentation

docs/research/request-body-resource-limits.md records RFC 9110, RFC 9112, CWE-400, CWE-444, Python asyncio semantics, and the HTTPX transport interface with APA 7th references. [Unreleased] records the same security boundary without a version bump.

Security-scan state

Security Scan run 31271043638 is aggregate green for executed jobs on exact head 8a1243feafd12f0faf67cc9fa12d53bd27181a14, including OSV, Trivy, and Scorecard. It is not complete dependency-review assurance: the dependency-review job concluded success while its actual Dependency review action step was skipped after only the support probe ran.

The separately governed control-plane sequence remains ContextualWisdomLab/.github#813 followed by refreshed/integrated .github#799. This EgressWeave loop does not mutate that repository. After the fail-closed central repair reaches protected main, this unchanged exact head requires a fresh organization Security Scan whose actual dependency-review action executes and succeeds.

Scope

Changed paths are exactly:

  • src/egressweave/request_body_safety.py
  • tests/test_request_stream_chunk_validation.py
  • tests/test_request_cleanup_base_exception.py
  • docs/research/request-body-resource-limits.md
  • CHANGELOG.md

Remaining merge gates

Keep this PR Draft. Do not merge or enable auto-merge until the central dependency-review repair is protected-main integrated, a fresh same-head dependency review actually executes successfully, exact-current-head automated review is complete with zero unresolved valid threads, a qualifying independent non-author formal APPROVED review exists, and branch protection/rulesets/every required check pass.

Queued, pending, skipped-required, cancelled, absent, neutral-required, predecessor-head, synthetic-merge, fail-open, rate-limited, or failed evidence is not acceptance. Do not release, publish, rebase, retarget, or weaken the trust boundary.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

동기·비동기 outbound request stream이 정확한 내장 bytes 청크만 허용하도록 변경되었습니다. 잘못된 청크는 EgressNotAllowedError로 거부하고 원본 스트림을 정리합니다. 비동기 정리 오류와 취소 동작을 검증하는 회귀 테스트와 문서가 추가되었습니다.

Changes

요청 스트림 보안 강화

Layer / File(s) Summary
정확한 bytes 검증과 동기 스트림 처리
src/egressweave/request_body_safety.py, tests/test_request_stream_chunk_validation.py, docs/research/request-body-resource-limits.md, CHANGELOG.md
동기 스트림은 len() 계산과 청크 전달 전에 type(chunk) is bytes를 확인합니다. bytes 하위 클래스, bytearray, 기타 객체를 거부하고 원본을 닫습니다. 유효한 바이트 예산과 Content-Length 처리는 유지됩니다.
비동기 거부 정리와 취소 처리
src/egressweave/request_body_safety.py, tests/test_request_stream_chunk_validation.py, docs/research/request-body-resource-limits.md
비동기 정책 거부 시 하위 스트림을 정리합니다. 정리 오류와 자식 스트림의 자기 취소는 일반 EgressNotAllowedError 뒤에 숨깁니다. 소비자 태스크 취소와 공개 aclose()의 취소 동작은 구분하여 검증합니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 정확한 bytes 검증, 오류 은닉, 스트림 정리, 기존 예산 및 Content-Length 동작 보존 요구를 구현했습니다.
Out of Scope Changes check ✅ Passed 변경은 요청 스트림 코드, 관련 테스트, 보안 문서, CHANGELOG.md로 제한되어 연결된 이슈 범위와 일치합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 요청 스트림 회계에 정확한 내장 bytes만 요구하는 주요 보안 변경사항을 명확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security/exact-request-byte-chunks

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only PR #85 at exact current head d89a82ae0fcb9d440404a3608824190d313aab1a against exact base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. This PR supersedes #80 without rewriting the tree; reviews do not transfer. Verify the exact-built-in-bytes request-stream boundary, synchronous/asynchronous malformed-source cleanup, hostile cleanup masking, byte-budget and exact Content-Length preservation, realistic regressions, RFC 9110/RFC 9112/CWE-400/CWE-444/HTTPX documentation, CHANGELOG entry, and absence of workflow/dependency/credential/publication/public-API changes. Treat only fresh PR-scoped exact-head checks as acceptance evidence.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Review only PR #85 exact head d89a82ae0fcb9d440404a3608824190d313aab1a against exact base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d; do not modify the branch. Independently inspect the exact-byte request-stream accounting boundary, malformed-source cleanup and hostile cleanup masking, preservation of byte budgets/declared Content-Length and existing authority/framing/TLS/proxy/timeout invariants, tests, standards-grounded documentation, and changelog. Fresh PR-scoped CI/SAST/Security Scan must be used; do not carry approval from #80.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

@seonghobae I will review only PR #85 against base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d and head d89a82ae0fcb9d440404a3608824190d313aab1a.

I will verify the exact built-in bytes boundary, sync and async cleanup, cleanup-failure masking, byte-budget and Content-Length accounting, regressions, required documentation, the CHANGELOG entry, and prohibited change categories. I will treat only fresh PR-scoped exact-head checks as acceptance evidence.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Perform a read-only review of exact current head d89a82ae0fcb9d440404a3608824190d313aab1a against exact base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d for PR #85. Do not modify files, refs, PR state, or review-agent credentials.

Independently verify that synchronous and asynchronous request-stream wrappers require exact built-in bytes before any overridable length protocol or downstream delivery; malformed values and bytes subclasses are withheld; source close/aclose is attempted; hostile cleanup failures cannot replace or become the context/cause of the stable generic denial; valid exact-byte cumulative budgets, exact Content-Length, single-consumption, authority, framing, TLS, proxy, and timeout semantics are preserved; changed paths remain limited to request-body validation, focused tests, directly relevant standards/operator guidance, and CHANGELOG; and APA 7 references accurately trace RFC 9110, RFC 9112, CWE-400, CWE-444, and the HTTPX transport contract. Exact-head CI 31147833467, SAST 31147833447, and Security Scan 31147833496 succeeded; Python 3.13 ran 749 tests with 1,620 statements and 554 branches at 100%. Anchor any formal outcome to this PR and exact head; do not transfer approval from closed #80 and do not merge, release, or publish.

@coderabbitai review

Review only exact head d89a82ae0fcb9d440404a3608824190d313aab1a on PR #85. Prior commit status or any analysis attached to closed #80 is historical context, not current PR approval. Focus on exact-type checking before len, sync/async parity, cleanup/provenance erasure, preserved valid-stream behavior, realistic tests, documentation accuracy, scope, and CHANGELOG. Do not report success for another PR or head.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='d89a82ae0fcb9d440404a3608824190d313aab1a'

echo '== Commit identity and ancestry =='
git rev-parse HEAD
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
git merge-base --is-ancestor "$base" "$head" && echo 'base is an ancestor of head'
git diff --stat "$base" "$head"
git diff --name-status "$base" "$head"

echo '== Relevant changed-code symbols =='
changed_files="$(git diff --name-only "$base" "$head")"
printf '%s\n' "$changed_files" | while IFS= read -r f; do
  case "$f" in
    *.py)
      echo "--- AST outline: $f"
      ast-grep outline "$f" --items all || true
      ;;
  esac
done

echo '== Exact-type checks, length calls, cleanup, and denial paths in changed Python files =='
printf '%s\n' "$changed_files" | while IFS= read -r f; do
  case "$f" in
    *.py)
      echo "--- $f"
      rg -n -C 5 -e 'type\s*\([^)]*\)\s+is\s+bytes' -e '\blen\s*\(' \
        -e '\b(close|aclose)\s*\(' -e '\b(raise|from None)\b' "$f" || true
      ;;
  esac
done

echo '== Complete changed-file patch =='
git diff --find-renames --find-copies --unified=80 "$base" "$head" -- $changed_files

echo '== PR `#85` metadata, head, checks, and reviews =='
gh pr view 85 --repo ContextualWisdomLab/EgressWeave \
  --json number,state,baseRefOid,headRefOid,headRefName,isDraft,mergeStateStatus,reviews,statusCheckRollup,url

Length of output: 70436


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Wrapper construction and surrounding transport logic =='
rg -n -C 12 -e '_BoundedSyncRequestStream\s*\(' -e '_BoundedAsyncRequestStream\s*\(' src tests

echo '== Request safety, authority, framing, TLS, proxy, and timeout references =='
rg -n -C 4 \
  -e '_enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length|transfer-encoding|framing' \
  -e 'proxy|trust_env|follow_redirects' \
  -e 'sni_hostname|TLS|ssl_context|verify' \
  -e 'timeout|Timeout' \
  -e '_iteration_started|single-consumption|single consumption' \
  src tests

echo '== Existing request-body tests and their focused assertions =='
fd -t f -e py . tests | sort | while IFS= read -r f; do
  if rg -q -e 'request_body_safety|request.bytes|max_request_bytes|Content-Length|_Bounded.*RequestStream' "$f"; then
    echo "--- $f"
    ast-grep outline "$f" --items all
    rg -n -C 3 -e 'max_request_bytes|Content-Length|_Bounded.*RequestStream|EgressNotAllowedError' "$f"
  fi
done

echo '== New regression test: exact exception provenance and malformed values =='
sed -n '1,220p' tests/test_request_stream_chunk_validation.py

echo '== Files modified by each commit in the PR-only range =='
git log --format='commit %H%n%s' --name-status \
  10d0c51daf2ad278d66f43be479df8cf6b08ba6d..d89a82ae0fcb9d440404a3608824190d313aab1a

Length of output: 135734


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '== Synchronous and asynchronous wrapper installation =='
rg -n -C 24 '_Bounded(Sync|Async)RequestStream\s*\(' \
  src/egressweave/sync_transport.py src/egressweave/transport.py

echo '== Request-target validation order and pool dispatch methods =='
ast-grep outline src/egressweave/sync_transport.py --items all --match 'handle|verify|close'
ast-grep outline src/egressweave/transport.py --items all --match 'handle|verify|close'
rg -n -C 18 \
  -e 'def handle_request\s*\(' -e 'async def handle_async_request\s*\(' \
  -e '_verify_request_target\s*\(' -e '_build_safe_request_headers\s*\(' \
  -e '_enforce_request_header_limits\s*\(' -e 'handle_request\s*\(' \
  -e 'handle_async_request\s*\(' \
  src/egressweave/sync_transport.py src/egressweave/transport.py

echo '== Arbitrary malformed-object and exception-provenance tests =='
sed -n '1,110p' tests/test_request_body_chunk_types.py
rg -n -C 4 -e '__cause__|__context__|from None|private request stream' \
  tests/test_request_body_cleanup.py tests/test_request_stream_chunk_validation.py \
  src/egressweave/request_body_safety.py

echo '== Current PR `#85` check summary and approvals =='
gh pr view 85 --repo ContextualWisdomLab/EgressWeave \
  --json headRefOid,reviews,statusCheckRollup,mergeStateStatus \
  --jq '{head: .headRefOid, mergeStateStatus, reviews, checks: [.statusCheckRollup[] | {name, workflowName, status, conclusion, detailsUrl}]}'

Length of output: 52948


🤖 web_search executed:

Verify the canonical publication metadata and relevant content for RFC 9110 and RFC 9112, CWE-400, CWE-444, and the HTTPX transport API. Confirm whether the documentation references in EgressWeave use accurate APA 7 authors, organization, title, publication year, DOI or URL, and access-date convention.

Length of output: 17876


@seonghobae I reviewed only PR #85 at head d89a82ae0fcb9d440404a3608824190d313aab1a against base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d.

I found one security issue.

  • High — Mask BaseException cleanup failures at the untrusted-stream boundary.
    src/egressweave/request_body_safety.py, Line 125 and Line 178 use suppress(Exception). A caller-controlled close() or aclose() method can raise a custom BaseException subclass. That exception escapes and replaces the required generic EgressNotAllowedError. It can also expose private source behavior. The same issue affects malformed chunks, budget overruns, declared-length mismatches, and repeated iteration. If the policy requires hostile cleanup failures to remain behind the generic denial boundary, catch BaseException only around the untrusted cleanup call. Add synchronous and asynchronous regressions that raise a custom BaseException subclass and assert the resulting EgressNotAllowedError has no cause or context.

Other review results:

  • Both request-stream wrappers use type(chunk) is bytes before len(chunk) and before downstream delivery.
  • The synchronous and asynchronous transport paths install the wrappers after authority, target, TLS identity, timeout, header, framing, and declared-length checks. They install the wrappers immediately before pool dispatch.
  • Existing and new tests cover valid exact-byte streams, cumulative budgets, exact Content-Length, single consumption, framing, authority, TLS, proxy isolation, and timeout behavior.
  • The changed paths are limited to the intended source, tests, operator guidance, and changelog.
  • The RFC 9110 and RFC 9112 citations use the correct authors, 2022 date, IETF publisher, and DOI format. The documentation includes the requested CWE and HTTPX references.
  • CHANGELOG.md includes one [Unreleased] Security entry.
  • Fresh PR-scoped acceptance is incomplete. strix remains in progress, coverage-evidence is queued, the PR has no reviews, and the merge state is BLOCKED. I did not use checks from PR #80 as approval evidence.
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review only exact current head d89a82ae0fcb9d440404a3608824190d313aab1a. Treat #80 as superseded historical context and do not transfer its review state. Verify exact built-in-byte enforcement precedes len() and downstream delivery on both sync/async paths, malformed-source cleanup and exception-provenance behavior, valid-byte and exact Content-Length compatibility, the four-file scope, public docstrings, APA 7 standards traceability, CHANGELOG, and the absence of workflow/dependency/credential/public-API changes.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 10 minutes and 2 seconds before sending another message.

@seonghobae
seonghobae marked this pull request as draft August 7, 2026 05:27

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Review exact current head d89a82ae0fcb9d440404a3608824190d313aab1a against exact base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d only. Verify exact built-in bytes validation precedes request-body accounting/delivery, malformed and over-budget cleanup remains fail-closed and non-leaking, valid Content-Length/single-consumption semantics are preserved, tests/docs/CHANGELOG are accurate, and no unrelated DNS/TLS/proxy/workflow/release behavior changed. Do not reuse closed #80 review evidence.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Perform a read-only exact-head review of d89a82ae0fcb9d440404a3608824190d313aab1a against 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. Do not modify files, refs, PR state, credentials, or permissions. Verify sync/async exact-byte request-stream validation, byte/declared-length accounting, hostile cleanup masking, stable generic denial, tests and standards documentation. Anchor any outcome to this replacement PR and exact head only.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='d89a82ae0fcb9d440404a3608824190d313aab1a'
repo='ContextualWisdomLab/EgressWeave'

echo '== Exact commit identity =='
printf 'checked-out: '; git rev-parse HEAD
git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"
git merge-base --is-ancestor "$base" "$head"
printf 'base: '; git rev-parse "$base"
printf 'head: '; git rev-parse "$head"

echo '== Changed paths =='
git diff --name-status "$base" "$head"
echo '== Diff stat =='
git diff --stat "$base" "$head"

echo '== Changed Python outlines =='
git diff --name-only "$base" "$head" -- '*.py' | while IFS= read -r path; do
  echo "--- $path"
  ast-grep outline "$path" --items all || true
done

echo '== Request-body implementation: exact-type checks, accounting, cleanup, and raises =='
if test -f src/egressweave/request_body_safety.py; then
  nl -ba src/egressweave/request_body_safety.py | sed -n '1,260p'
fi

echo '== Focused changed tests =='
git diff --name-only "$base" "$head" -- 'tests/*.py' | while IFS= read -r path; do
  echo "--- $path"
  nl -ba "$path" | sed -n '1,320p'
done

echo '== Documentation and CHANGELOG patch =='
git diff --unified=60 "$base" "$head" -- \
  'CHANGELOG.md' '*.md' '*.rst' '*.txt'

echo '== Complete code patch for changed production Python =='
git diff --unified=80 "$base" "$head" -- 'src/**/*.py' 'src/*.py'

echo '== PR `#85` exact head, checks, and reviews =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,headSha,detailsUrl}]}'

Length of output: 4429


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='d89a82ae0fcb9d440404a3608824190d313aab1a'
repo='ContextualWisdomLab/EgressWeave'

echo '== request_body_safety.py at exact head =='
sed -n '1,280p' src/egressweave/request_body_safety.py

echo '== Focused regression tests at exact head =='
sed -n '1,360p' tests/test_request_stream_chunk_validation.py

echo '== Exact production-file patch =='
git diff --unified=100 "$base" "$head" -- src/egressweave/request_body_safety.py

echo '== Exact test-file patch =='
git diff --unified=100 "$base" "$head" -- tests/test_request_stream_chunk_validation.py

echo '== CHANGELOG patch =='
git diff --unified=100 "$base" "$head" -- CHANGELOG.md

echo '== Documentation patch =='
git diff --unified=100 "$base" "$head" -- docs/research/request-body-resource-limits.md

echo '== Related existing behavior and test definitions =='
rg -n -C 8 \
  -e 'class _Bounded(Sync|Async)RequestStream' \
  -e 'def _enforce_declared_request_size' \
  -e 'async def test_.*(request|stream|content)' \
  -e 'def test_.*(request|stream|content)' \
  -e 'Content-Length|content-length|single.?consumption|single.?use' \
  src tests

echo '== Current PR metadata, checks, and reviews =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 194342


@seonghobae I reviewed only PR #85 at head d89a82ae0fcb9d440404a3608824190d313aab1a against base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d.

I found one High-severity issue.

  • High — Mask direct BaseException cleanup failures at the untrusted stream boundary.
    src/egressweave/request_body_safety.py, Line 125 and Line 178 use suppress(Exception). A caller-controlled close() or aclose() can raise a custom direct subclass of BaseException. That exception escapes before the wrapper raises EgressNotAllowedError. It replaces the stable denial and can expose source-specific behavior. Catch BaseException only around the untrusted cleanup call. Add synchronous and asynchronous tests that raise a custom BaseException subclass. Assert that the result is EgressNotAllowedError with both __cause__ and __context__ set to None.

Other results:

  • Both wrappers require type(chunk) is bytes before len(chunk) and before downstream delivery.
  • The new tests reject a lying bytes subclass, a length-raising bytes subclass, and bytearray in both paths.
  • Existing tests cover valid exact-byte streams, cumulative byte budgets, exact Content-Length, declared-length overrun and truncation, and single consumption.
  • The diff has the requested four-file scope. It has no DNS, TLS, proxy, workflow, dependency, credential, release, or public-API changes.
  • The documentation includes RFC 9110, RFC 9112, CWE-400, CWE-444, and HTTPX references. The cleanup-masking statements are not accurate until the BaseException case is handled.
  • CHANGELOG.md has one [Unreleased] Security entry. Its cleanup-masking claim has the same limitation.
  • PR #85 is open and clean at the requested head. The listed PR checks are successful. The PR has no reviews. I did not use #80 as review evidence.
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae marked this pull request as ready for review August 7, 2026 07:40

Copy link
Copy Markdown
Contributor Author

@coderabbitai review
@opencode-agent @cwl-noema-review Please perform a read-only review of exact current head d89a82ae0fcb9d440404a3608824190d313aab1a against protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. Treat predecessor-head evidence as stale. Verify the bounded request-stream byte-accounting hardening, tests, coverage evidence, documentation, and unchanged workflow/credential/publication boundary. Do not modify refs or merge state.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='d89a82ae0fcb9d440404a3608824190d313aab1a'
repo='ContextualWisdomLab/EgressWeave'

echo '== Commit identity and ancestry =='
printf 'checked-out: '; git rev-parse HEAD
printf 'base: '; git rev-parse "$base"
printf 'head: '; git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base-is-ancestor: yes'

echo '== Changed paths and stat =='
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"

echo '== Production implementation at requested head =='
git show "$head:src/egressweave/request_body_safety.py" | nl -ba | sed -n '1,280p'

echo '== Production patch =='
git diff --unified=100 "$base" "$head" -- src/egressweave/request_body_safety.py

echo '== Focused test outlines and patch =='
for path in \
  tests/test_request_stream_chunk_validation.py \
  tests/test_request_body_cleanup.py \
  tests/test_request_body_chunk_types.py
do
  if git cat-file -e "$head:$path" 2>/dev/null; then
    echo "--- $path"
    git show "$head:$path" | nl -ba | sed -n '1,420p'
  fi
done
git diff --unified=100 "$base" "$head" -- tests

echo '== Documentation and CHANGELOG patches =='
git diff --unified=100 "$base" "$head" -- CHANGELOG.md docs

echo '== Wrapper installation and related existing invariants =='
rg -n -C 8 \
  -e '_BoundedSyncRequestStream\s*\(' \
  -e '_BoundedAsyncRequestStream\s*\(' \
  -e '_enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length' \
  -e '_iteration_started' \
  src tests

echo '== PR metadata and fresh check evidence =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 2986


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='d89a82ae0fcb9d440404a3608824190d313aab1a'
repo='ContextualWisdomLab/EgressWeave'

echo '== Production implementation at requested head =='
git show "$head:src/egressweave/request_body_safety.py" | cat -n | sed -n '1,280p'

echo '== Production patch =='
git diff --unified=100 "$base" "$head" -- src/egressweave/request_body_safety.py

echo '== Focused test file at requested head =='
git show "$head:tests/test_request_stream_chunk_validation.py" | cat -n | sed -n '1,420p'

echo '== All test changes =='
git diff --unified=100 "$base" "$head" -- tests

echo '== Documentation and CHANGELOG changes =='
git diff --unified=100 "$base" "$head" -- CHANGELOG.md docs/research/request-body-resource-limits.md

echo '== Wrapper installation and related invariants =='
rg -n -C 10 \
  -e '_BoundedSyncRequestStream\s*\(' \
  -e '_BoundedAsyncRequestStream\s*\(' \
  -e '_enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length' \
  -e '_iteration_started' \
  src tests

echo '== PR metadata and status checks =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 150804


@seonghobae I reviewed only PR #85 at d89a82ae0fcb9d440404a3608824190d313aab1a against 10d0c51daf2ad278d66f43be479df8cf6b08ba6d.

I found one High-severity issue.

  • High — Mask direct BaseException failures from untrusted cleanup.
    src/egressweave/request_body_safety.py, Line 125 and Line 178 use suppress(Exception). A caller-controlled close() or aclose() can raise a direct subclass of BaseException. That exception escapes before EgressNotAllowedError is raised. It can replace the stable denial and expose source-specific behavior. Catch BaseException only around the untrusted cleanup call. Add sync and async regressions that raise a direct BaseException subclass. Assert that the result is EgressNotAllowedError with __cause__ is None and __context__ is None.

Other results:

  • Both bounded request-stream wrappers use type(chunk) is bytes before len(chunk) and before downstream delivery.
  • The new tests reject a lying bytes subclass, a length-raising bytes subclass, and bytearray in both paths.
  • Existing tests cover valid exact-byte streams, cumulative byte budgets, exact Content-Length, declared-length overrun and truncation, and single consumption.
  • The diff is limited to four paths: request-body validation, focused tests, relevant operator guidance, and CHANGELOG.md.
  • The diff contains no workflow, dependency, credential, publication, DNS, TLS, proxy, or public-API changes.
  • The documentation includes RFC 9110, RFC 9112, CWE-400, CWE-444, and HTTPX references. Its cleanup-masking claim is not accurate for direct BaseException cleanup failures.
  • CHANGELOG.md contains one [Unreleased] Security entry. Its cleanup-masking claim has the same limitation.
  • PR #85 is open and has the requested base and head. The PR status rollup lists successful PR-scoped CI, SAST, Security Scan, and coverage-evidence checks. The PR has no reviews. I did not use closed PR #80 as review evidence.
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@cwl-noema-review @opencode-agent Please perform a read-only formal review of PR #85 at exact head d89a82ae0fcb9d440404a3608824190d313aab1a against exact protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. Treat closed #80 and predecessor-head evidence as historical only. Verify exact-built-in-bytes request-stream validation before len()/delivery, exact Content-Length and cumulative budget accounting, malformed-source cleanup and provenance masking, unchanged authority/TLS/proxy/public API behavior, and the four-file bounded scope. CI/SAST are green on this exact head; the pre-repair aggregate Security Scan is not complete dependency-review assurance until the central fail-closed repair reaches protected main and this unchanged head is rerun. If acceptable, submit a qualifying formal non-author review; otherwise report only exact-current-head actionable findings. Do not modify refs, settings, credentials, merge state, or branch protection.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Apply a bounded test-first fix only to exact current head d89a82ae0fcb9d440404a3608824190d313aab1a on branch security/exact-request-byte-chunks; stop without writing if the live head differs.

A current valid asynchronous cleanup gap remains in src/egressweave/request_body_safety.py: _BoundedAsyncRequestStream.aclose() uses suppress(Exception), but Python 3.13 asyncio.CancelledError directly subclasses BaseException. When a request chunk is malformed, exceeds the policy budget or declared length, ends short of an exact declaration, or a second iteration is refused, a dependency-injected source whose aclose() self-cancels can therefore replace the already-established generic EgressNotAllowedError with child cancellation and violate this PR's documented non-leaking denial boundary.

Use strict RED → GREEN:

  1. First add focused async regressions in tests/test_request_stream_chunk_validation.py covering at minimum a malformed non-exact-byte chunk and an over-budget exact-byte chunk whose source aclose() raises asyncio.CancelledError. Assert cleanup was attempted and the caller still receives exactly EgressNotAllowedError("egress URL is not allowed") with __context__ is None and __cause__ is None.
  2. Add a deterministic regression that cancels the outer request-consumer task while it is awaiting a blocking source cleanup and assert that external cancellation still propagates. Ordinary caller-requested stream.aclose() must retain its existing best-effort contract.
  3. Record the policy-path regressions failing against unmodified production code.
  4. Make the minimal production repair by obtaining the dependency-injected cleanup awaitable safely and observing it through asyncio.gather(..., return_exceptions=True) or an equivalently narrow helper. Consume call-time cleanup errors, awaited cleanup errors, and child self-cancellation, but do not broadly suppress cancellation directed at the outer consumer.
  5. Update only the directly governing request-body documentation/changelog if the child-cancellation distinction is not already accurate.

Run python -m pytest tests/test_request_stream_chunk_validation.py -q, the complete suite with exactly 100% production statement/branch coverage, Ruff, compileall, package acceptance, and exact-head hosted CI. Do not alter .github, workflows, dependencies, credentials, permissions, authority/TLS/proxy policy, public API, version, release/tag/publication behavior, merge state, or branch protection; do not merge, rebase, retarget, auto-merge, publish, or release.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review
@cwl-noema-review @opencode-agent Review PR #85 at exact current head ef6b1805700193bcaf739d7282df478ed948ac7f against exact protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d only. Treat all predecessor-head evidence as stale. This head preserves the exact-built-in-bytes request-stream boundary and adds a policy-denial-only async cleanup path that consumes an injected child stream's cleanup exception/self-cancellation while preserving cancellation directed at the consuming coordinator; explicit caller-requested aclose() semantics remain unchanged. Immutable RED head 527ec6cdedec891455b97c3df5aaa4599ad354be failed CI 31174208322 exactly because child CancelledError escaped on malformed and over-budget chunks. Exact current CI 31174484107 is green across Python 3.10–3.13 plus package acceptance and the 100% coverage gate. SAST/Security are still queued and are not acceptance; even a pre-central-repair aggregate Security success is not complete dependency-review assurance. If acceptable, submit a qualifying formal non-author review; otherwise report only exact-current-head actionable findings. Read-only: do not modify refs, settings, credentials, merge state, or branch protection.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 17 minutes and 58 seconds before sending another message.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/egressweave/request_body_safety.py`:
- Around line 130-143: Update _close_async_request_after_policy_denial so
invoking stream.aclose() and awaiting asyncio.gather are both inside the
protected cleanup path; suppress synchronous exceptions and non-awaitable return
failures rather than replacing EgressNotAllowedError, while re-raising only
cancellation directed at the awaiting consumer. Add a regression test covering
aclose returning a non-awaitable value and verifying the policy-denial error
remains observable.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a26e7bfe-f7da-4c63-baf5-eef033c84262

📥 Commits

Reviewing files that changed from the base of the PR and between 10d0c51 and 7493893.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/research/request-body-resource-limits.md
  • src/egressweave/request_body_safety.py
  • tests/test_request_stream_chunk_validation.py

Comment thread src/egressweave/request_body_safety.py

Copy link
Copy Markdown
Contributor Author

@coderabbitai review
@cwl-noema-review @opencode-agent Review PR #85 at exact current head 4d94034be7b2e89a8401eb117e1302e52e82b961 against exact protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d only. Treat predecessor-head evidence as stale. Immutable RED 5c485ec3217f855376bc8d9cd50d0c05ffc6b33d failed exact CI 31175150880 because a dependency-injected async request stream could raise synchronously from aclose() and replace the stable policy denial. This GREEN head adds only the production call-time cleanup guard while preserving child awaited exception/self-cancellation masking, coordinator cancellation propagation, exact built-in bytes and Content-Length accounting, and explicit caller-requested aclose() cancellation behavior. Exact-head CI 31175465704 is green; SAST/Security remain queued and are not success, and pre-central-repair aggregate Security remains incomplete dependency-review assurance. If acceptable, submit a qualifying formal non-author review; otherwise report only exact-current-head actionable findings. Read-only: do not modify refs, settings, credentials, merge state, or branch protection.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Rate Limit Exceeded

@seonghobae have exceeded the limit for the number of chat messages per hour. Please wait 4 minutes and 29 seconds before sending another message.

Comment thread tests/test_request_stream_chunk_validation.py Fixed

Copy link
Copy Markdown
Contributor Author

@opencode-agent Repair only the test-fixture lint blocker on exact current head e75242fe658fdafbfe00d9569baa35a5bfb5636d of branch security/exact-request-byte-chunks; stop without writing if the live head differs.

Hosted RED run 31176283938 checked out the exact head and package acceptance passed, but Ruff stopped before pytest because _NonAwaitableCleanupAsyncRequestStream.aclose() explicitly uses return None, triggering RET501 and PLR1711. Modify only tests/test_request_stream_chunk_validation.py: remove that explicit return None line. Falling off the synchronous method still deterministically returns non-awaitable None, which is the intended hostile fixture.

Do not modify production code yet. Run Ruff and python -m pytest tests/test_request_stream_chunk_validation.py -q; preserve and report the expected focused failure showing that the current helper lets asyncio.gather(None, ...) replace the generic policy denial. Change no other line, dependency, workflow, documentation, public API, release state, or branch metadata. Do not merge, rebase, retarget, auto-merge, publish, or release.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review exact current head 270b5ce84b93cdc10e417990e86da0622c9ff16f against protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. Review only; predecessor-head conclusions are stale.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Read-only review exact current head 270b5ce84b93cdc10e417990e86da0622c9ff16f only. Verify exact-byte request accounting and policy-denial cleanup for call-time, awaited, child-cancelled, and non-awaitable outcomes while outer cancellation propagates. Do not modify repository state.

Copy link
Copy Markdown
Contributor Author

@cwl-noema-review Read-only review exact current head 270b5ce84b93cdc10e417990e86da0622c9ff16f only. Verify current-head code, tests, and trust-boundary evidence; return source-backed findings or an exact-head verdict.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='270b5ce84b93cdc10e417990e86da0622c9ff16f'
repo='ContextualWisdomLab/EgressWeave'

echo '== Commit identity and ancestry =='
printf 'checked-out: '; git rev-parse HEAD
printf 'base: '; git rev-parse "$base"
printf 'head: '; git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base-is-ancestor: yes'

echo '== Exact changed paths =='
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"

echo '== Request-body safety structure =='
ast-grep outline src/egressweave/request_body_safety.py --items all

echo '== Current request-body implementation =='
git show "$head:src/egressweave/request_body_safety.py" | nl -ba | sed -n '1,300p'

echo '== Focused regression test structure and content =='
ast-grep outline tests/test_request_stream_chunk_validation.py --items all
git show "$head:tests/test_request_stream_chunk_validation.py" | nl -ba | sed -n '1,500p'

echo '== Exact production and test patches =='
git diff --unified=100 "$base" "$head" -- \
  src/egressweave/request_body_safety.py \
  tests/test_request_stream_chunk_validation.py

echo '== Documentation and changelog patches =='
git diff --unified=100 "$base" "$head" -- \
  docs/research/request-body-resource-limits.md \
  CHANGELOG.md

echo '== Wrapper installation and preserved request invariants =='
rg -n -C 10 \
  -e '_BoundedSyncRequestStream\s*\(' \
  -e '_BoundedAsyncRequestStream\s*\(' \
  -e '_enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length' \
  -e '_iteration_started' \
  src tests

echo '== PR current head, check rollup, and reviews =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 3647


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='270b5ce84b93cdc10e417990e86da0622c9ff16f'
repo='ContextualWisdomLab/EgressWeave'

echo '== Current request-body implementation =='
git show "$head:src/egressweave/request_body_safety.py" | cat -n | sed -n '1,300p'

echo '== Focused regression test file =='
git show "$head:tests/test_request_stream_chunk_validation.py" | cat -n | sed -n '1,520p'

echo '== Exact production patch =='
git diff --unified=100 "$base" "$head" -- src/egressweave/request_body_safety.py

echo '== Exact focused-test patch =='
git diff --unified=100 "$base" "$head" -- tests/test_request_stream_chunk_validation.py

echo '== Documentation and changelog patches =='
git diff --unified=100 "$base" "$head" -- \
  docs/research/request-body-resource-limits.md \
  CHANGELOG.md

echo '== Wrapper installation and preserved request invariants =='
rg -n -C 10 \
  -e '_BoundedSyncRequestStream\s*\(' \
  -e '_BoundedAsyncRequestStream\s*\(' \
  -e '_enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length' \
  -e '_iteration_started' \
  src tests

echo '== PR current head, check rollup, and reviews =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 169678


@seonghobae I reviewed only PR #85 at 270b5ce84b93cdc10e417990e86da0622c9ff16f against 10d0c51daf2ad278d66f43be479df8cf6b08ba6d.

I found one actionable security issue.

  • High — Mask direct BaseException failures from policy-denial cleanup.
    In src/egressweave/request_body_safety.py, Line 126 suppresses only Exception around synchronous close(). Lines 142-146 catch only Exception and asyncio.CancelledError when calling asynchronous aclose() and creating the cleanup gather. A dependency-injected stream can raise a direct custom subclass of BaseException. That failure escapes and replaces the required EgressNotAllowedError("egress URL is not allowed").
    Catch BaseException only at these untrusted policy-denial cleanup invocation boundaries. Do not catch around await cleanup, because cancellation directed at the consuming coordinator must still propagate. Add synchronous and asynchronous regressions that raise a direct custom BaseException. Assert that the result is the generic denial with __context__ is None and __cause__ is None.

Other results:

  • Both request-stream wrappers require type(chunk) is bytes before length accounting and downstream delivery.
  • The async helper handles ordinary call-time exceptions, non-awaitable returns, awaited child failures, and child asyncio.CancelledError.
  • The regression tests preserve outer consumer cancellation and explicit stream.aclose() cancellation behavior.
  • Existing tests cover cumulative budgets, exact Content-Length, declared-length overrun and truncation, and single consumption.
  • The diff is limited to the intended four paths. It has no workflow, dependency, credential, publication, DNS, TLS, proxy, or public-API changes.
  • The documentation and changelog cleanup-masking claims are not accurate for direct BaseException cleanup failures.
  • Exact-head CI, package acceptance, coverage evidence, Semgrep, dependency review, OSV, Trivy, Scorecard, and CodeQL are successful. strix remains in progress. The PR merge state is BLOCKED.
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review Perform a read-only formal review of PR #85 at exact head 270b5ce84b93cdc10e417990e86da0622c9ff16f against exact protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. CI 31177449526 and SAST 31177449531 are complete and successful; Security Scan 31177449530 remains incomplete dependency-review assurance until the external central .github#813 → #799 repair integrates and a fresh scan actually executes dependency review. Existing CodeRabbit/GitHub Code Quality findings are addressed/resolved. Review exact built-in-byte enforcement, cumulative and declared-length accounting, malformed/over-budget cleanup, non-awaitable async cleanup, provenance erasure, outer-consumer cancellation propagation, docs, and realistic regressions. If acceptable, submit a qualifying exact-head formal APPROVED review while preserving the central repaired dependency-review scan as an independent merge prerequisite; otherwise submit only still-valid exact-head REQUEST_CHANGES. Do not modify refs, settings, credentials, merge state, branch protection, workflows, dependencies, authority/TLS/proxy policy, or publication behavior, and do not transfer predecessor-head evidence.

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review Perform a read-only formal review of PR #85 at exact unchanged head 270b5ce84b93cdc10e417990e86da0622c9ff16f against exact protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. Treat predecessor-head evidence as stale. Current CodeRabbit and GitHub Code Quality findings are addressed/resolved; exact-head CI 31177449526 and SAST 31177449531 are green with 100% production statement/branch coverage. The aggregate Security Scan remains incomplete assurance until the separately governed .github#813 → #799 repair reaches protected main and a fresh dependency-review action actually executes successfully. Review exact-built-in-byte request accounting, declared-length/resource limits, dependency-injected cleanup failure masking, non-awaitable cleanup handling, outer-consumer cancellation propagation, and preserved authority/framing/TLS/proxy semantics. If acceptable, submit a qualifying exact-head formal APPROVED review while preserving the central security prerequisite; otherwise submit only current-head path-specific findings. Do not modify refs, settings, credentials, merge state, branch protection, or publication behavior.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review
@opencode-agent @cwl-noema-review Review exact current head 270b5ce84b93cdc10e417990e86da0622c9ff16f against protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d only. Recheck exact built-in request bytes, cumulative/declared-length accounting, malformed and over-budget cleanup, non-awaitable async cleanup handling, provenance erasure, and outer cancellation propagation. Existing inline findings are resolved/outdated; do not transfer predecessor-head evidence. Read-only; submit formal exact-head review evidence or new actionable path-specific findings.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='270b5ce84b93cdc10e417990e86da0622c9ff16f'
repo='ContextualWisdomLab/EgressWeave'

echo '== Exact commit identity and ancestry =='
printf 'checked-out: '; git rev-parse HEAD
printf 'base: '; git rev-parse "$base"
printf 'head: '; git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base-is-ancestor: yes'

echo '== Exact changed paths =='
git diff --name-status "$base" "$head"
git diff --stat "$base" "$head"

echo '== Request-body implementation at exact head =='
git show "$head:src/egressweave/request_body_safety.py" | cat -n | sed -n '1,330p'

echo '== Focused regression tests at exact head =='
git show "$head:tests/test_request_stream_chunk_validation.py" | cat -n | sed -n '1,560p'

echo '== Exact source and test diffs =='
git diff --unified=100 "$base" "$head" -- \
  src/egressweave/request_body_safety.py \
  tests/test_request_stream_chunk_validation.py

echo '== Documentation and changelog diffs =='
git diff --unified=80 "$base" "$head" -- \
  docs/research/request-body-resource-limits.md \
  CHANGELOG.md

echo '== Wrapper construction and declared-length enforcement =='
rg -n -C 10 \
  -e '_BoundedSyncRequestStream\s*\(' \
  -e '_BoundedAsyncRequestStream\s*\(' \
  -e 'def _enforce_declared_request_size\s*\(' \
  -e 'Content-Length|content-length' \
  -e '_iteration_started' \
  src tests

echo '== Current PR metadata, reviews, and checks =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

Length of output: 164811


@seonghobae I reviewed PR #85 at exact head 270b5ce84b93cdc10e417990e86da0622c9ff16f against base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d.

I found one current-head security issue.

  • High — Mask direct BaseException cleanup failures on policy-denial paths.
    In src/egressweave/request_body_safety.py, Line 126 suppresses only Exception around sync close(). Lines 142-146 catch only Exception and asyncio.CancelledError when async policy-denial cleanup calls aclose() and creates asyncio.gather(...). An injected stream can raise a direct custom subclass of BaseException from either cleanup call. That exception escapes before EgressNotAllowedError("egress URL is not allowed") is raised. It also exposes source-specific behavior.

    Catch BaseException only around the untrusted cleanup invocation and asyncio.gather(...) construction. Do not catch around await cleanup. This preserves cancellation directed at the consuming coordinator. Add sync and async regressions with a direct custom BaseException. Assert source cleanup was attempted and that the result is EgressNotAllowedError with __cause__ is None and __context__ is None.

Other exact-head results:

  • Both wrappers require type(chunk) is bytes before len(chunk) and downstream delivery.
  • The wrappers preserve cumulative byte budgets, declared-length overrun rejection, short-body rejection, and single-consumption behavior.
  • Async policy-denial cleanup handles ordinary call-time errors, non-awaitable results, awaited child exceptions, and child asyncio.CancelledError.
  • The focused test preserves cancellation directed at the consuming coordinator.
  • Explicit caller-requested aclose() still propagates child cancellation.
  • The diff is limited to the intended four paths. It has no workflow, dependency, credential, publication, authority, TLS, proxy, or public API changes.
  • CI, coverage, package acceptance, CodeQL, Semgrep, OSV, dependency review, Trivy, Scorecard, and Strix report success for this head. The PR is CLEAN.

The documentation and changelog cleanup-masking claims remain inaccurate until direct BaseException cleanup failures are masked.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@coderabbitai approve

Formal exact-head approval request for PR #85 at 270b5ce84b93cdc10e417990e86da0622c9ff16f against protected base 10d0c51daf2ad278d66f43be479df8cf6b08ba6d. The valid async-cleanup finding is addressed/resolved, the latest Code Quality finding is resolved/outdated, exact-head CI/SAST are green, and no unresolved review thread remains. Preserve the separately governed central fail-closed dependency-review repair and fresh post-repair Security Scan as independent merge prerequisites; the current aggregate Security Scan is not complete dependency-review assurance. Approve only if the current exact-head four-file request-resource hardening is acceptable; otherwise return only current-head actionable findings.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='270b5ce84b93cdc10e417990e86da0622c9ff16f'
repo='ContextualWisdomLab/EgressWeave'

echo '== Commit identity and ancestry =='
printf 'checked-out: '; git rev-parse HEAD
printf 'base: '; git rev-parse "$base"
printf 'head: '; git rev-parse "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base-is-ancestor: yes'

echo '== Changed paths =='
git diff --name-status "$base" "$head"

echo '== Request-body safety implementation at exact head =='
git show "$head:src/egressweave/request_body_safety.py" | nl -ba | sed -n '1,280p'

echo '== Focused cleanup regressions at exact head =='
git show "$head:tests/test_request_stream_chunk_validation.py" | nl -ba | sed -n '1,560p'

echo '== Exact source and test diff =='
git diff --unified=100 "$base" "$head" -- \
  src/egressweave/request_body_safety.py \
  tests/test_request_stream_chunk_validation.py

echo '== Documentation and changelog diff =='
git diff --unified=80 "$base" "$head" -- \
  docs/research/request-body-resource-limits.md \
  CHANGELOG.md

echo '== PR head, checks, reviews, and review threads =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

gh api graphql -F owner='ContextualWisdomLab' -F name='EgressWeave' -F number=85 -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes { isResolved isOutdated comments(first: 1) { nodes { author { login } body path } } }
      }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] |
  select((.isResolved | not) and (.isOutdated | not)) |
  {author: .comments.nodes[0].author.login, path: .comments.nodes[0].path, body: .comments.nodes[0].body}]'

Length of output: 2835


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='10d0c51daf2ad278d66f43be479df8cf6b08ba6d'
head='270b5ce84b93cdc10e417990e86da0622c9ff16f'
repo='ContextualWisdomLab/EgressWeave'

echo '== Request-body safety implementation at exact head =='
git show "$head:src/egressweave/request_body_safety.py" | cat -n | sed -n '1,280p'

echo '== Focused cleanup regressions at exact head =='
git show "$head:tests/test_request_stream_chunk_validation.py" | cat -n | sed -n '1,560p'

echo '== Cleanup call sites and exact-type checks =='
git show "$head:src/egressweave/request_body_safety.py" |
  grep -n -E 'type\(chunk\) is bytes|close\(|aclose\(|BaseException|CancelledError|gather|from None|EgressNotAllowedError' || true

echo '== Exact source and test diff =='
git diff --unified=100 "$base" "$head" -- \
  src/egressweave/request_body_safety.py \
  tests/test_request_stream_chunk_validation.py

echo '== Documentation and changelog diff =='
git diff --unified=80 "$base" "$head" -- \
  docs/research/request-body-resource-limits.md \
  CHANGELOG.md

echo '== PR head, checks, reviews =='
gh pr view 85 --repo "$repo" \
  --json number,state,baseRefOid,headRefOid,mergeStateStatus,reviews,statusCheckRollup,url \
  --jq '{number,state,url,base: .baseRefOid,head: .headRefOid,mergeStateStatus,reviews,checks: [.statusCheckRollup[] | {name,workflowName,status,conclusion,detailsUrl}]}'

echo '== Unresolved, current review threads =='
gh api graphql -F owner='ContextualWisdomLab' -F name='EgressWeave' -F number=85 -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes { isResolved isOutdated comments(first: 1) { nodes { author { login } body path } } }
      }
    }
  }
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] |
  select((.isResolved | not) and (.isOutdated | not)) |
  {author: .comments.nodes[0].author.login, path: .comments.nodes[0].path, body: .comments.nodes[0].body}]'

Length of output: 86416


@seonghobae I cannot approve PR #85 at 270b5ce84b93cdc10e417990e86da0622c9ff16f.

One current-head security finding remains.

  • High — Policy-denial cleanup does not mask direct BaseException failures.
    In src/egressweave/request_body_safety.py, Line 126 suppresses only Exception around close(). Lines 142-146 catch only Exception and asyncio.CancelledError around aclose() and asyncio.gather(...) construction. An injected source can raise a direct custom subclass of BaseException from either call. That exception escapes before the wrapper raises EgressNotAllowedError("egress URL is not allowed"). It can expose source behavior and replace the stable denial.

    Catch BaseException only around the untrusted cleanup invocation and asyncio.gather(...) construction. Do not catch it around await cleanup. This preserves cancellation directed at the consuming coordinator. Add synchronous and asynchronous regressions that raise a direct custom BaseException. Assert that cleanup was attempted and that the result is EgressNotAllowedError with __context__ is None and __cause__ is None.

The exact head has the requested four-file scope. The exact-built-in-bytes check occurs before len() and downstream delivery. The focused tests cover ordinary cleanup exceptions, non-awaitable cleanup, child cancellation, and coordinator cancellation. CI and SAST checks report success. There are no unresolved current review threads.

The central dependency-review repair and a fresh post-repair Security Scan remain independent merge prerequisites.


✏️ Learnings added
Learnt from: seonghobae
URL: https://github.com/ContextualWisdomLab/EgressWeave/pull/85

Timestamp: 2026-08-08T00:09:53.926Z
Learning: For EgressWeave PR `#85`, successful aggregate Security Scan results do not provide complete dependency-review assurance until the separately governed central fail-closed dependency-review repair is integrated into protected main and a fresh Security Scan executes dependency review on the unchanged PR head.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@opencode-agent Apply one bounded test-first security fix only if PR #85 still has exact head 270b5ce84b93cdc10e417990e86da0622c9ff16f on branch security/exact-request-byte-chunks; reread the live head immediately before every write and stop without writing if it differs.

Current exact-head CodeRabbit review found a valid remaining trust-boundary defect: policy-denial cleanup suppresses ordinary Exception (and the async helper specially handles child CancelledError) but a dependency-injected close() / direct aclose() invocation can raise a custom direct subclass of BaseException, replacing the stable EgressNotAllowedError and leaking backend-specific behavior.

Use strict RED→GREEN and keep the existing four-path ownership boundary:

  1. RED commit first: add deterministic sync and async regressions in tests/test_request_stream_chunk_validation.py using a custom direct BaseException subclass raised synchronously by the injected source cleanup call. Exercise at least one malformed/non-exact-byte policy denial in each path; assert cleanup was attempted and the outward result remains exactly EgressNotAllowedError("egress URL is not allowed") with __context__ is None and __cause__ is None. Preserve existing non-awaitable, child-self-cancellation, outer-consumer-cancellation, over-budget, declared-length, and single-consumption regressions.
  2. Record the focused tests failing against unchanged production code.
  3. GREEN commit: in src/egressweave/request_body_safety.py, catch BaseException only around direct untrusted policy-denial cleanup invocation/setup (stream.close() and the stream.aclose() + gather-construction setup). Do not catch around the outer await cleanup; cancellation directed at the consuming task must continue to propagate. Do not broaden suppression into ordinary caller-requested close/aclose semantics.
  4. Run focused tests, Ruff, complete Python suite with exactly 100% production statement/branch coverage, public-docstring gate, compileall, product guard, wheel/sdist package acceptance, then allow exact-head hosted CI/SAST/Security/review to rerun. Update existing research guidance / [Unreleased] entry only if necessary to make the already-stated cleanup-masking contract exact; do not create unrelated docs churn.

Do not touch .github, workflows, dependencies, credentials, permissions, DNS/TLS/proxy/authority policy, public API shape, version, release/tag/publication behavior, base branch, merge state, or reviewer identities. Do not merge, auto-merge, rebase, retarget, publish, or release. After any new head, predecessor-head reviews/checks are stale and must not be reused.

@seonghobae
seonghobae marked this pull request as draft August 8, 2026 13:10
Comment thread src/egressweave/request_body_safety.py
Comment thread src/egressweave/request_body_safety.py

Copy link
Copy Markdown
Contributor Author

Exact-head review disposition for 8a1243feafd12f0faf67cc9fa12d53bd27181a14: the two new GitHub Code Quality suggestions to replace the narrowly scoped BaseException cleanup catches with Exception are disproven by the TDD evidence and would reintroduce the reproduced security defect. On test-only RED head a0418869890fd146462237f9c347419f0cb70484, CI 31270939632 failed exactly two policy-denial regressions because a dependency-controlled direct custom BaseException escaped sync and async cleanup setup and replaced EgressNotAllowedError; Python 3.13 reported 2 failed, 763 passed. The GREEN implementation catches BaseException only at the direct untrusted cleanup/setup boundary, explicitly re-raises KeyboardInterrupt, SystemExit, and GeneratorExit, and leaves the outer async await cleanup outside the catch so coordinator cancellation propagates. Exact-head CI 31271043659 now passes Python 3.10–3.13; Python 3.13 reports 765 passed, with 1637/1637 production statements and 554/554 branches at 100%, plus Ruff, compileall, product-guard, and package acceptance. Therefore those two static findings are false positives for this intentionally narrowed trust boundary, not actionable source defects.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant