Repository navigation
[P1][Gateway] Preserve Content-Encoding with representation bytes #447
Description
Finding
Fresh review of Draft #441's bounded gateway mediation found a representation-integrity gap in the proposed allowlist: Content-Type was preserved but Content-Encoding was not admitted on either request or response. The generic proxy forwards representation bytes unchanged. With the active reqwest feature set (default-features = false, rustls-tls, multipart, json, stream; no automatic gzip/brotli/deflate decoder), a coded representation such as Content-Encoding: gzip therefore crossed the gateway as coded bytes after its decoding metadata had been removed.
RFC 9110 §8.1 defines representation data as Content-Encoding(Content-Type(data)); §8.4 defines Content-Encoding as representation metadata and requires a sender that applies codings to generate the field in coding order. It explicitly distinguishes Content-Encoding from hop-by-hop Transfer-Encoding. Dropping Content-Encoding while retaining coded bytes changes the representation contract and can cause downstream misinterpretation, corrupt buyer payloads, or shift content inspection to an unintended decoding layer.
Wardnet owns this generic gateway mediation/evidence boundary. This issue does not authorize transport-destination logic from EgressWeave, sandbox isolation from quarantine-sandbox-runtime, LLM routing from contextual-orchestrator, or AppGuardrail policy duplication.
Required RED
Use a real loopback buyer path, not a unit-only HeaderMap fixture:
- request: send non-identity coded bytes with
Content-Type: application/jsonandContent-Encoding: gzip; prove the upstream receives the same representation bytes and ordered content-coding metadata; - response: return coded bytes with
Content-Type: application/jsonandContent-Encoding: gzip; prove the buyer receives the same bytes and coding metadata; - prove
Transfer-Encoding,Connection, framing/authority fields and credentials remain stripped/owned by the HTTP stacks rather than broadening the allowlist; - preserve legal ordered Content-Encoding list semantics instead of treating it as a singleton; malformed/unrepresentable metadata must fail closed at the same request/response boundary as fix(gateway): enforce bounded HTTP header mediation #441.
The RED remained test-only in #448 while #441 stayed the sole production mediation writer.
Executed semantic RED — 2026-09-24
Historical exact 26c5de512899d8e91fb7f64b48c1d8e77e36a814 did not establish semantic RED because CI 35820987427, rust job 107052573207, stopped at inherited/base cargo fmt --check before Test and Clippy. The later restacked predecessor a208450ec0206ec4f65725a9fb54de41eb18ed66 likewise did not reach semantic execution. CI 35893375073 on exact 44c03a0fe83b7199ebad43cff0e009646f7554f1 acquired a hosted runner but stopped only at the fixture's rustfmt layout.
Formatter-only exact #448 head 8a254028faf4db0485ba8710945c2781a876fbed then executed CI 35917178809, rust job 107371632198. cargo fmt --check and all 151 existing library unit tests passed before the real loopback buyer-path assertions ran. Both intended cases failed semantically against unchanged production mediation:
- request path: coded bytes reached the upstream but
Content-Encoding: gzipwas absent (left: None,right: Some("gzip")); - response path: coded bytes reached the buyer but
Content-Encoding: gzipwas absent (left: None,right: Some("gzip")).
This is the valid #447 RED and authorized the bounded repair only in sole production writer #441.
Minimum causal repair in #441
The minimum repair first reached #441 exact 16a0d0807692203dabc83823793dcefef087c661 and is now carried unchanged in integrated #441 head cd3c5985fd6317ab80c888fe1e37786f94d780e8:
- add
content-encodingto the bounded request/response mediation allowlists; - preserve legal ordered multiplicity (for example
gzip,br) rather than treating Content-Encoding as a singleton; - retain dynamic
Connectionnomination stripping, includingConnection: ... content-encoding; - keep credentials, authority/framing fields,
Transfer-Encodingand other hop-by-hop fields excluded; - do not enable automatic decompression;
- do not acquire EgressWeave destination/DNS/peer/redirect/proxy/TLS/resource authority.
Owned unit contracts in #441 cover ordered gzip, br multiplicity in both directions and dynamic nomination stripping.
Current verification state — refreshed 2026-09-24
#448 adopted repaired parent #441@16a0d0807692203dabc83823793dcefef087c661 non-force through ordinary restack PR #449. Exact child 30b52cae32b7022237c552aa6224ebd7d9dfb632 retained only tests/gateway_content_encoding.rs as its effective child delta.
Fresh exact-child CI 35941616793 completed SUCCESS on the unchanged head, and fresh review/thread inventory was empty. #448 was marked Ready and normally merged into #441 with fixed expected-head protection as two-parent merge cd3c5985fd6317ab80c888fe1e37786f94d780e8. No force update, destructive rebase, self/model approval, gate weakening or bypass was used.
#441 is now exact cd3c5985fd6317ab80c888fe1e37786f94d780e8, based exactly on #435 11e7fabfca76e0051fa883905228a0dbe472f4df. Fresh exact-head CI 35962640235 and Fuzz 35962640233 are queued. Predecessor GREEN is not promoted to this new head. Keep #447 open until the effective source/test/doc delta reaches protected main through #441/#435 or a verified complete successor.
Exact-head acceptance
Formatting, locked workspace tests, strict Clippy, Fuzz/security/SAST/CodeQL governance as applicable, owned-production statement/branch/edge/public-rustdoc evidence, realistic async buyer-path performance, zero valid unresolved findings/threads, and fresh parent/protected-base compatibility are required on one unchanged candidate lineage. No force update, destructive rebase, self/model approval, gate weakening, mutable sibling dependency, source copy, blind rerun, predecessor-result promotion, or routine bypass.
Traceability
- Parent mediation lane: fix(gateway): enforce bounded HTTP header mediation #441
- Response-singleton test child: test(gateway): reject ambiguous singleton responses #446
- Content-Encoding test-only child: test(gateway): preserve coded representation metadata #448
- Non-force parent-adoption PR: chore(stack): adopt repaired gateway parent into #448 #449
- RFC 9110 §§5.2-5.3, 8.1, 8.4: https://www.rfc-editor.org/rfc/rfc9110.html#section-8.4
- Cargo transport features:
Cargo.tomlon the active Wardnet source lineage
Activity
seonghobae commentedon Sep 23, 2026
Fresh source-parent adoption/status update: canonical mediation parent #441 is now exact
68fc8ed6e6b9644d3406f0bf0c31113e7c1b76e0, a normal source/docs head after the successful bounded-header synthesis. Test-only child #448 adopted that complete parent non-force through ordinary two-parent mergea208450ec0206ec4f65725a9fb54de41eb18ed66; GitHub reports the child mechanically mergeable and its effective delta remains onlytests/gateway_content_encoding.rs.Fresh exact-child CI
35865632473is currently queued, so the earlier format-only run remains non-semantic and Content-Encoding RED is still not established. Keep #448 test-only. Only an executed real-loopback request/response failure may authorize #441 to preserve legal orderedContent-Encodingalongside byte-identical coded representation data. No transparent-decompression shortcut, production change in the child, runner-selector churn, blind rerun, central-workflow copy, or bypass is justified while the exact run is merely queued.seonghobae commentedon Sep 24, 2026
Current semantic evidence supersedes the queued snapshot above.
Exact test-only #448 head
8a254028faf4db0485ba8710945c2781a876fbedexecuted on hosted CI35917178809, rust job107371632198.cargo fmt --checkand all 151 existing library unit tests passed before the real loopback buyer-path fixture ran. Both intended representation assertions then failed semantically against unchanged production mediation:Content-Encoding: gzipwas absent (left: None,right: Some("gzip"));Content-Encoding: gzipwas absent (left: None,right: Some("gzip")).This is the valid #447 RED and authorizes the bounded repair only in sole production writer #441.
#441 has applied the minimum causal source change at exact
16a0d0807692203dabc83823793dcefef087c661: addcontent-encodingto request/response mediation allowlists, preserve legal ordered multiplicity, retain dynamicConnectionnomination stripping, and do not enable automatic decompression or any EgressWeave transport authority. Unit contracts cover orderedgzip,brvalues in both directions and nomination stripping.#448 adopted that repaired parent non-force through ordinary two-parent restack PR #449; current child exact head is
30b52cae32b7022237c552aa6224ebd7d9dfb632, base exactly#441@16a0d080..., with effective delta still onlytests/gateway_content_encoding.rs. Fresh exact-child CI35941616793and exact-parent CI/Fuzz are queued. No GREEN is claimed until those unchanged exact heads execute successfully. Do not blind-rerun or promote predecessor evidence.