test: stop aiming I12 transport tests at recycled ports - #124
Merged
Conversation
wiremock's process-wide pool binds 127.0.0.1:0 for the process lifetime. The I12 transport-error tests bound an ephemeral 127.0.0.1 port, dropped the listener, and connected at the freed address expecting ECONNREFUSED. Under load that port can belong to a newly created pooled listener: unwrap_err panics on another test's corpus, .expect(1) over-counts a foreign request, or — worst — the I12 test goes green without sanitizing a transport error at all. Point those tests at 127.0.0.2:1 instead. That address is still loopback (127.0.0.0/8) so the kernel refuses immediately (or returns ENETUNREACH), and a pooled listener binds only 127.0.0.1 so it can never occupy it. A bounded probe refuses to return an address that accepted or timed out; the client call itself is capped at 2s so a proxy/routing hang cannot become the 30s client timeout; and the assertion requires reqwest's "error sending request" so an empty or HTTP-status error cannot pass a bare !contains(KEY). A mutation that retargets the helper at 127.0.0.1 fails the helper. I12 is unchanged: the key still must not appear in Display or Debug of a real transport error. Closes #115
127.0.0.2 is extra loopback on Linux but is not aliased on macOS, so the I12 probe hung until timeout on rust-macos. Switch to 127.0.0.1:1: a privileged port both OSes refuse immediately if nothing is listening, and that a non-root wiremock 127.0.0.1:0 pool cannot occupy. The helper now asserts the port stays privileged so a bind-then-drop of an ephemeral port still fails.
2 tasks
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.
What
Stop the I12 transport-error tests from connecting to an ephemeral
127.0.0.1port that has been freed back to the OS.wiremock 0.6 binds
127.0.0.1:0and keeps those listeners in a process-wide pool for the process lifetime. The five I12 sites bound an ephemeral port, dropped the listener, and fired a request at the freed address expectingECONNREFUSED. Under load that port can belong to a newly created pooled listener (~1–4 failures per 300 stress runs; independently reproduced in #93):unwrap_err()panics onOkcarrying another test's corpus.expect(1)over-counts a foreign requestapi_key_absent_from_transport_error_i12goes green without sanitizing a transport error at allAll five sites now connect to
127.0.0.2:1— still loopback (127.0.0.0/8), so the kernel refuses immediately (or returnsENETUNREACHif the extra address is not configured). A pooled listener binds only127.0.0.1and can never occupy that address.crates/bugwarden-core/tests/guard_wiremock.rs—get_bugs/whoami/valid_loginI12 testscrates/bugwarden/tests/preflight_wiremock.rs— preflight whoami I12crates/bugwarden/tests/tools_wiremock.rs— MCP-visible whoami I12crates/bugwarden/tests/common/mod.rsfor the two server binariesA bounded TCP probe refuses to return an address that accepted or timed out. The client call itself is capped at 2s so a proxy/routing hang cannot become the 30s client timeout. The assertion requires reqwest's
error sending request(Display and Debug) so an empty or HTTP-status error cannot pass a bare!contains(KEY). A mutation that retargets the helper at127.0.0.1fails the helper.Why
#93 / #112 only stopped asserting on
[0]of a polluted recording. The bind-then-drop(listener)hazard remained at every I12 site, including a silent coverage loss on a security invariant.Invariants
I12 is unchanged: the Bugzilla API key must not appear in a real transport-level error. Fail-closed behavior is untouched. No production code changed except adding the
timefeature to bugwarden-core's tokio dev-dependency so the tests can bound the connect.Adversarial review (pre-PR)
127.0.0.1:0inguard_wiremock,preflight_wiremock, ortools_wiremock.assert_ne!(ip, 127.0.0.1)kills a bind-then-drop mutation.error sending request), not a timeout-with-empty-text.Accepted findings (fixed before this PR): URL/probe drift; a 127.0.0.1 mutation that would still pass; missing hang budget; duplicated helper across the two server test binaries.
Rejected: capturing the warn-log in
tools_wiremockto assert the internalized whoami error text. That test's contract is the client-visible surface (I2 uniform denial). The transport error is already asserted in the three core tests and the preflight test.Verification
cargo fmt --checkcargo clippy --workspace --all-targets -- -D warningscargo clippy -p bugwarden --features gen --all-targets -- -D warningscargo test --workspace --all-targets --lockedcargo deny checkCloses #115