Repository navigation
row 130 E5a: every framed connector dial honours the proxy environment, as 1.5.5 did - #804
Open
MattJackson wants to merge 14 commits into
Open
MattJackson wants to merge 14 commits into
MattJackson wants to merge 14 commits into
Conversation
…t, as 1.5.5 did ARCHITECT ruling 2026-10-12: the kernel engine's proxy behaviour moves into the connector unchanged, so every dial through the connector honours HTTPS_PROXY / HTTP_PROXY / ALL_PROXY / NO_PROXY exactly as 1.5.5's reqwest clients did. The connector and the transport plugins had no proxy support, so every dial already on the connector (the door planes, oidc, cimd) went direct past a configured proxy. - busbar-core-connector/src/proxy.rs: the engine's decision moved verbatim (busbar-kernel egress/engine/mod.rs `mod tunnel`): scheme-scoped slots with the ALL_PROXY fallback, uppercase before lowercase, NO_PROXY's full rule set (host, domain suffix, IP literal, CIDR), Basic Proxy-Authorization from userinfo, an https:// proxy and a garbage value refused without echoing the password; the CONNECT request bytes and the 2xx / 8 KiB answer rule of the engine's connect_handshake. - compose.rs: a dial through a proxy connects to the proxy, writes the CONNECT request before anything else, reads the proxy's head raw (under the 10 s CONNECT bound), then runs the secure layer (the target's name and certificate) and the framer over the tunnel. Bytes after the head are the target's. - lib.rs: Connector::proxying; a FRAMED dial (never a carrier carried as itself, as 1.5.5's drivers never used a proxy) not pinned `within` an address set, to a host the scheme's slot has a proxy for and NO_PROXY does not exclude, is judged in two steps: the target (its name arm, and its own resolution when it resolves here; a name that does not resolve here goes to the proxy, the engine's tunnelled arm), then the proxy's address with reach (a private proxy admitted, cloud metadata never). process::build reads the environment once; a set value that does not parse refuses the boot, as the engine's install did. - Tests (src/tests/proxy_tests.rs): the engine's semantics rows ported (precedence, garbage, NO_PROXY suffix and IP/CIDR matrix, scheme scoping, password redaction, the answer rule), and end to end through Connector::open: a framed dial to a name only the proxy resolves writes exactly `CONNECT upstream.test:8080 HTTP/1.1`, `Host`, the Basic credential, and its exchange rides the tunnel; RED arms: a 407 refuses the exchange; a NO_PROXY host and a raw-stream need dial direct and the proxy is never asked; with no proxy a name nothing resolves is refused.
promote into
|
| gate | row | detail |
|---|---|---|
| secret-hygiene | secret-hygiene:check3-message |
1 violation(s) (BLOCKING, #53; SECRET_GATE_REPORT_ONLY=1 is the report-only escape): crates/busbar-core-connector/src/proxy.rs:397 secret-subject-parameter (target) — wrap each secret VALUE in busbar_ |
| kind-isolation | kind-isolation:law0 |
6 hit(s) off the [[law0]] ceilings, 4 finding(s) over 14 neutral crate(s): law0-rise busbar × instance:secret 37 hit(s) against a ceiling of 35: this landing grew a neutral crate's instance vocabulary |
| kind-isolation | kind-isolation:law0-base |
1 hit(s) grown over the merge-base 62fdbdf, 1 cell(s): law0-grown busbar-core-connector × transport 68 -> 69 hit(s) over the same cell at the merge-base 62fdbdf (its '[[law0]]' row 68 there): this b |
| kind-isolation-ship | kind-isolation:law0 |
6 hit(s) off the [[law0]] ceilings, 4 finding(s) over 14 neutral crate(s): law0-rise busbar × instance:secret 37 hit(s) against a ceiling of 35: this landing grew a neutral crate's instance vocabulary |
| kind-isolation-ship | kind-isolation:law0-base |
1 hit(s) grown over the merge-base 62fdbdf, 1 cell(s): law0-grown busbar-core-connector × transport 68 -> 69 hit(s) over the same cell at the merge-base 62fdbdf (its '[[law0]]' row 68 there): this b |
Denied because (20)
- shard 1/4: gate:kind-isolation row kind-isolation:law0-base: red now, not red at base
- shard 1/4: gate:kind-isolation-ship row kind-isolation:law0-base: red now, not red at base
- shard 1/4: gate:secret-hygiene: green at base, red now (secret-hygiene:check3-message)
- shard 1/4: gate:kind-isolation row kind-isolation:law0: figure rose 5 -> 6
- shard 1/4: gate:kind-isolation-ship row kind-isolation:law0: figure rose 5 -> 6
- shard 2/4: gate:kind-isolation row kind-isolation:law0-base: red now, not red at base
- shard 2/4: gate:kind-isolation-ship row kind-isolation:law0-base: red now, not red at base
- shard 2/4: gate:secret-hygiene: green at base, red now (secret-hygiene:check3-message)
- shard 2/4: gate:kind-isolation row kind-isolation:law0: figure rose 5 -> 6
- shard 2/4: gate:kind-isolation-ship row kind-isolation:law0: figure rose 5 -> 6
- shard 3/4: gate:kind-isolation row kind-isolation:law0-base: red now, not red at base
- shard 3/4: gate:kind-isolation-ship row kind-isolation:law0-base: red now, not red at base
- shard 3/4: gate:secret-hygiene: green at base, red now (secret-hygiene:check3-message)
- shard 3/4: gate:kind-isolation row kind-isolation:law0: figure rose 5 -> 6
- shard 3/4: gate:kind-isolation-ship row kind-isolation:law0: figure rose 5 -> 6
- shard 4/4: gate:kind-isolation row kind-isolation:law0-base: red now, not red at base
- shard 4/4: gate:kind-isolation-ship row kind-isolation:law0-base: red now, not red at base
- shard 4/4: gate:secret-hygiene: green at base, red now (secret-hygiene:check3-message)
- shard 4/4: gate:kind-isolation row kind-isolation:law0: figure rose 5 -> 6
- shard 4/4: gate:kind-isolation-ship row kind-isolation:law0: figure rose 5 -> 6
Judged against base 62fdbdf3b: 3 new red, 2 worse, 3 standing (excused).
New reds: gate:kind-isolation row kind-isolation:law0-base: red now, not red at base, gate:kind-isolation-ship row kind-isolation:law0-base: red now, not red at base, gate:secret-hygiene: green at base, red now (secret-hygiene:check3-message)
Already red on predev, not this PR's: 8
| gate | row | detail |
|---|---|---|
| construction | one-pick-site |
3 production call site(s) of 'pick_among(' (ceiling 2): crates/busbar-kernel-egress/src/walk.rs:298; crates/busbar-llm/src/engine/exhaustion/fallback.rs:120; crates/busbar-llm/src/engine/pipeline.rs:8 |
| kind-isolation | kind-isolation:deps |
3 finding(s), 93 shipped edge instance(s) over 30 class(es), 93 declaration(s); 56 '[[dep]]' row(s), 0 question(s): unlisted-dep-edge legacy -> plane busbar-llm -> busbar-plane-llm is a shipped edge w |
| kind-isolation-ship | kind-isolation:deps |
10 finding(s) over 93 shipped edge(s): ship-edge kernel -> hooks busbar-kernel -> busbar-hook-ranking is 'not-allowed': the architecture grants no kernel -> hooks edge, and the ship criterion is the a |
| kind-isolation-ship | kind-isolation:test-deps |
8 finding(s) over 32 test edge(s): ship-edge cleanliness -> export busbar-core-admin -> busbar-export-prometheus is 'not-allowed': the architecture grants no cleanliness -> export edge, and the ship c |
| kind-isolation-ship | kind-isolation:faces |
2 finding(s) over 40 crate(s): foreign-entry crates/busbar busbar is kind 'root' and implements 'Transport' 1 time(s) in shipped source — the entry face of kind 'transport'. A trait implementation is |
| kind-isolation-ship | kind-isolation:legacy-drain |
3 finding(s): transitional-live qa/kind-isolation.toml 'busbar-a2a -> busbar-core-admin' (legacy drain: the retiring A2A engine's tests drive the admin surface that drained into the cleanliness tier) |
| ship-ready | ship-ready:ship-twin |
'kind-isolation-ship' is not green: kind-isolation:deps (a dependency the architecture does not grant is still in the graph); kind-isolation:test-deps (a dependency the architecture does not grant is |
| structure-lint | structure-lint:plane-dup:unledgered |
22 finding(s): PLANE-DUPLICATE (module): 'config.rs' — a2a:crates/busbar-a2a/src/a2a/config.rs decisions:crates/busbar-plane-decisions/src/config.rs voice:crates/busbar-voice/src/config.rs (the ledger |
tests passed: 0, failed: 0. Run: https://github.com/GetBusbar/busbar/actions/runs/38312118329 . Artifact verdict-73ab28a2a33a4993ddf6ae53010ecbd8f6b5ee3c (failures.json, junit.xml, raw.log; 90 days).
…d parameter secret-hygiene check 3 read connect_answer's `authority` parameter as a secret subject: the CONNECT target is `target` throughout (ProxySpec::endpoint for the proxy's own host:port). The kind-isolation law0 scan read the verbatim engine word for the proxy's choice as the decisions plane's bare id: it is `choice` here. Three comments say socket instead of naming a carrier.
MattJackson
added a commit
that referenced
this pull request
Oct 12, 2026
… the one connector The kernel's last dial of its own, preflight::plugin_fetch_downloader (the engine on a cold one-shot posture), is deleted. The root downloads every plugins.fetch artifact through the process's one connector (BUSBAR-1.6.0.md §3 stage 3c, "fetch plugins through the connector"): crates/busbar/src/root/plugin_fetch.rs declares a provider-class need per URL scheme under the root's own identity (NeedId 1 and 2; 0 is the authorization server's) and sends one GET, so the connector's one guard judges and pins the address, the proxy environment applies (#804), and the http door writes the request with the client defaults 1.5.5's Client::new().get() sent: `accept: */*` before `host`. That is the oracle cell egress.fetch|plugins|url, known-red as egress-plugin-fetch-accept; its mark stays until ModernCI shows the cell green. What stays the download's own moves verbatim: https for a public host and plaintext only for a loopback or private one, the cloud-metadata denylist extended by security.blocked_metadata_hosts, no redirect followed, a declared Content-Length over the cap refused before a body byte and the body counted against the cap, every refusal in 1.5.5's words, and the dedicated thread with its own current-thread runtime. The kernel's PluginsFetch row now hands the root the operator's denylist instead of a downloader; the kernel test build's stand-in refuses every download (it has no connector). Tests: the kernel's two downloader tests move to root/tests/plugin_fetch.rs, driven over a connector of the build's linked doors against scripted loopback far ends (an honest and an absent Content-Length over the cap, a within-cap body byte for byte, a redirect refused in its 1.5.5 words), plus the wire row (exactly `GET <path>`, `accept: */*`, `host`) and a pre-check RED row.
# Conflicts: # crates/busbar-core-connector/src/compose.rs # crates/busbar-core-connector/src/lib.rs
…he kernel engine takes its choice ARCHITECT ruling 2026-10-12 (a move, not a copy): proxy environment parsing (the variables, the scheme rule, the credential) lives in busbar-core-connector only. The kernel engine's own parser (parse_proxy, the environment read, the precedence resolve, the redaction) is deleted with its suite's rows, which the connector's suite holds. - busbar-contract proxy_route: the shared shape, ProxyHop (endpoint and credential, Debug redacted) and ProxyChoice (the secured and plain slots and the exemption list, with curl's rule set, moved verbatim), naming no transport. - busbar-core-connector proxy: the parser fills ProxyChoice; Connector::proxy hands it out. - busbar-kernel egress engine: install_proxy(choice) replaces install_proxy_tunnel_if_configured; the root installs the connector's choice right after the connector is installed; busbar-llm no longer reads the environment at its runtime build.
…on, the per-dial choice names no plane, a CONNECT refusal names its addr; law0 rows settle at the merged tree's measure - busbar-contract ProxyHop::auth() -> proxy_authorization(): a contract-exported `auth` identifier is masked tree-wide by kind-isolation's contract_identifiers, which hid every `auth-header`/`busbar-auth-*` hit outside the contract (busbar x auth 49 -> 21, kernel x auth 50 -> 31, plugin-loader x auth 5 -> 0 were that mask, not a drain). - proxy_route.rs: "The per-dial decision:" read as a `decision:` section key (contract x plane +1); reworded. - proxy.rs connect_answer: the refused-CONNECT message interpolated a `target` parameter beside the word "proxy" (secret-hygiene check 3); the parameter is the `host:port` addr it always was. - qa/kind-isolation.toml: kernel x plane 1132 -> 1128, kernel x auth 50 -> 49 (drains with the tunnel the engine gave up); kernel x transport 284 -> 278 and core-connector x transport 68 -> 69, a ruled net-flat MOVE of the `"http"` proxy-scheme check, reason on both rows.
MattJackson
added a commit
that referenced
this pull request
Oct 13, 2026
…nto lane-egress-e6-plugin-fetch Both sides carry the same E5a commits (e56e48f, 73ab28a, 3587dab), so every shared row takes #804's side rather than theirs + ours - base, which would count E5a twice: - busbar-core-connector x transport: O == T == 69 (the one ruled MOVE of the "http" proxy-scheme check) -> theirs, count and cite. - busbar-kernel x transport: O == T == 278 -> theirs (cite: 5 drained + 1 moved, both E5a; this branch's E6 download move is net 0 on the row, as its gates measured 278 over a 284 base). - busbar-kernel x plane: theirs 1128 (predev 1132 - E5a's 4); ours 1137 was E5a's same -4 over the older 1141, so T + O - B would drain it twice. - busbar x auth 21 -> 49, busbar-kernel x auth 31 -> 49, busbar-plugin-loader x auth 0 -> 5: this branch's lowered values measured the mask #804 removes (busbar-contract exported a bare `auth` accessor, which kind-isolation's contract_identifiers masks tree-wide). With ProxyHop::proxy_authorization the rows read predev's 49 and 5, and kernel x auth 49 is the one real drain (the `auth header` comment that left with the engine's proxy-parse test). E6's diff adds or removes no auth-vocabulary text. - proxy_route.rs doc and proxy.rs connect_answer: #804's text (the `addr` parameter keeps the 1.5.5 refusal wording, so proxy_tests.rs takes #804's expectation).
…a miscount busbar-contract exports a `header` identifier, and kind-isolation's contract_identifiers masks every whole-token `header` outside the contract, so the engine test's "the auth header is prebuilt Basic" comment was never an `auth-header` hit. Its deletion drained nothing: the row keeps predev's count and cite (gates measured 50 on #805's 979c4b1, which carries this change).
qa/kind-isolation.toml busbar-kernel x transport: base 284, ours 278 (E5a: -5 drained, -1 ruled MOVE to busbar-core-connector), theirs 267 (#741's -17 listener MOVE to the root): different changes, so theirs + ours - base = 261, predev's cite kept with E5a's clause renumbered 267 -> 261.
qa/kind-isolation.toml busbar-kernel x transport: base 267, ours 261 (E5a: -5 drained, -1 ruled MOVE to busbar-core-connector), theirs 266 (#532: auth/token.rs's "http" check deleted, a different hit): theirs + ours - base = 260, predev's cite kept with E5a's clause renumbered 266 -> 260.
qa/kind-isolation.toml busbar-kernel x plane: base 1132, ours 1128 (E5a's proxy-tunnel drain: two `llm engine` prose mentions, the `decision:` doc key, the `installed decision` assert message), theirs 1128 (#674: the ask-state seal's `crate::mcp::roots` links and `\x6dcp` domains). O == T, but these are two different drains of equal size, not one change carried twice, so theirs + ours - base = 1124, predev's cite kept with E5a's clause renumbered 1128 -> 1124.
qa/kind-isolation.toml busbar-kernel x plane: base 1128, ours 1124 (E5a's proxy-tunnel drain), theirs 1122 (E2's net_guard deletion): different drains, so theirs + ours - base = 1118, predev's cite kept with E5a's clause renumbered 1122 -> 1118. The kernel no-socket pin (#796) stays exact on the merged tree.
Collaborator
Author
|
row 155 B2 (#974) edits crates/busbar-kernel/src/proxy/mod.rs at fn auth_failure_status_and_kind and the tail of fn ingress_error; disjoint from this PR's hunks. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
/status row 130 (E5a), per the ARCHITECT ruling of 2026-10-12. The engine's proxy behaviour moves into the connector unchanged, so every dial through the connector honours
HTTPS_PROXY/HTTP_PROXY/ALL_PROXY/NO_PROXYexactly as 1.5.5's reqwest clients did. This keeps 1.5.5 behaviour, so no owner signature is needed.Why. Neither the connector nor the transport plugins supported a proxy. Every dial already on the connector (the door planes, oidc, cimd) went straight to its target and ignored a configured proxy. This also unblocks E6 (the plugins.fetch download through the connector) and E5 (deleting the engine pool).
What moves.
busbar-core-connector/src/proxy.rsis the kernel engine'smod tunneldecision, moved verbatim:ALL_PROXYfallback, uppercase variable names read before lowercase;NO_PROXYwith reqwest's full rule set (host, domain suffix, IP literal, CIDR);Proxy-Authorization: Basicbuilt from the proxy URL's userinfo;https://proxy and a garbage value both refuse the boot, and the refusal never echoes the password;Where it runs.
compose.rs: a dial through a proxy connects to the proxy and writes the CONNECT request first. It reads the proxy's answer raw, under the engine's 10 s CONNECT bound. Only then do the secure layer (the target's name and certificate) and the framer run, over the tunnel.lib.rs(Connector::proxying): the proxy applies to a framed dial that is not pinned to an address set. The scheme's slot must name a proxy andNO_PROXYmust not exclude the host.process::buildreads the environment once at boot.Tests (
src/tests/proxy_tests.rs):NO_PROXYsuffix and IP/CIDR matrix, scheme scoping, password redaction, and the answer rule.Connector::open: a framed dial to a name only the proxy resolves writes exactlyCONNECT upstream.test:8080 HTTP/1.1,Hostand the Basic credential, and its exchange then rides the tunnel.NO_PROXYhost and a raw-stream need both dial direct, and the proxy is never asked;Proof: ModernCI only (owner rule 2026-10-12, no M3 builds).
#780 also touches
lib.rs, so whichever lands second rebases. Rows 104 and 105 are untouched.