Two detectors scanned a narrower population than they claimed: the shim gate saw only test_*.py, and the netblock's three open egress routes were six (#1598, #1584) - #1642
Merged
Conversation
Comment on lines
+568
to
+569
| 'while [ $# -gt 0 ]; do case "$1" in -*) shift ;; *) break ;; esac; done' | ||
| '\nif [ "$1" = "status" ]; then exit 128; fi\n', |
| call() | ||
| except _netblock.OutboundBlocked: | ||
| raise | ||
| except OSError: |
| return orig_methods["connect"](self, address) | ||
| _refuse("an outbound connect", address) | ||
|
|
||
| def _connect_ex(self: socket.socket, address: Any) -> Any: |
| return orig_methods["connect_ex"](self, address) | ||
| _refuse("an outbound connect_ex", address) | ||
|
|
||
| def _sendto(self: socket.socket, *args: Any) -> Any: |
Comment on lines
+289
to
+290
| def _sendmsg(self: socket.socket, buffers: Any, ancdata: Any = (), | ||
| flags: int = 0, address: Any = None) -> Any: |
…1598, #1584) #1598 -- the `$1`-shim gate scanned `tests/test_*.py`, so a shim in `_gitshim.py`, `_git_decline.py`, `conftest.py` or `tests/fixtures/` returned the same clean zero. It now reads every Python module under `tests/`, recursively. The widened population produces exactly one hit, `_gitshim.py`'s `while`/`shift` dispatcher, which is the correct implementation of the pattern and is exempted by its shape rather than its filename -- `$1` inside a loop that consumes arguments has no position to slide to, the same grammar argument #1412 used for an option at `$1`. Naming the file would have re-created the allowlist #1412 deleted. The module-level POSIX `pytestmark` also came off, onto the five tests that actually run a `/bin/sh` shim: it was skipping the class gate and every rule test on Windows, all of them pure AST and regex work. #1584 -- the suite-wide netblock documented its blind spot as one thing and six in-process egress routes stayed open behind the sentence. `connect_ex`, `sendto`, `gethostbyname`, `gethostbyname_ex`, `gethostbyaddr` and `getnameinfo` all left an armed context, and `gethostbyname` came back with a live-resolved address. All are refused now, with `sendmsg`. The fix is not the longer list: `_netblock.ROUTES` / `SOCKET_ROUTES` classify every callable `socket` and `socket.socket` expose, a new one arrives red, and the four routes no in-process patch can reach are named in `BEYOND_THE_PROCESS` rather than counted as blocked. Co-Authored-By: Max <noreply>
…en-out list The reviewer's finding, and it would have reddened every Windows leg rather than a socket test: `block_outbound` computed `_MODULE_PATCHES` / `_METHOD_PATCHES` with a `hasattr` filter -- precisely because Windows has no `socket.socket.sendmsg` -- and then iterated a hardcoded four-name tuple anyway. `monkeypatch.setattr` with `raising=True` on an absent attribute raises `AttributeError` out of an autouse fixture, so every test in the suite. Pinned by a test that shortens the derived tuple and asserts the untouched method stayed untouched; against the previous loop that assertion is False. `delattr` cannot simulate the platform here -- `socket.socket.sendmsg` is inherited from `_socket.socket` -- which is why the pin is on the tuple. Also the reviewer's second finding: a line in `test_transport_seam_enforced_1341.py` still named `connect`/`getaddrinfo` as the whole boundary, one paragraph above the rewritten disclosure. That is the #1584 defect reproduced next to its own fix. Co-Authored-By: Max <noreply>
fdaviddpt
force-pushed
the
fix/1598-1584
branch
from
August 13, 2026 22:30
c869f62 to
bbbf838
Compare
…ws-only route was classified nowhere (#1584) `socket.socket.ioctl` exists under `MS_WINDOWS` only. The register's population is `dir(socket.socket)` on the running interpreter -- right for a name a later Python grows, blind by construction to a name another platform has -- so it was in neither register, invisible to every POSIX author and every POSIX leg, and red on all four Windows legs one PR after the register shipped. Classified `OPEN`, not `PATCHED`. `WSAIoctl` addresses no peer, but `SIO_RCVALL` puts the interface into promiscuous receive, and the traffic that then arrives at `recv` carries no destination for a destination-refusing guard to check -- indistinguishable there from the loopback bytes the suite is entitled to. It is not patched rather than not patchable: refusing it means deciding per control code on a platform nobody who maintains this file can run, and a guess would be coverage claimed rather than had. `BEYOND_THE_PROCESS` stays at four; `ioctl` is inside the process, it is a route this guard declines, which is what `OPEN` is for. `OPEN_ROUTES`' header claimed all its entries were the connected-descriptor shape; `ioctl` is a second shape and says so rather than being filed under it. One name is not the fix, though -- a register that learns one platform-only name per release is the sentence it replaced. `PLATFORM_ONLY` states the `MS_WINDOWS` names (`ioctl`, `share`, `fromshare`) and a parametrised test asserts each is classified and present exactly on its own platform: absent here, present on the Windows legs. Only win32 is listed, and deliberately -- the macOS and Linux populations are derived green on every PR, so they are observed; Windows was the one platform no green leg had ever agreed with. Windows claims here are reasoned from CPython's `Modules/socketmodule.c`, not observed: this was written on macOS. The presence half of the new test is what converts them, on the leg that can. Adjacent, same file: `test_the_register_only_classifies_names_that_exist` checked `ROUTES` against the interpreter and left `SOCKET_ROUTES` unchecked, so a method name no Python has could sit there and read as coverage -- the same half-derived population as the defect this file exists for. Widened; verified non-vacuous by injecting a bogus name (`['wsarecvmsg']` reported, `[]` as shipped). RED before the fix, matching the Windows legs: test_every_platform_only_route_is_classified[ioctl] AssertionError: ioctl Co-Authored-By: Max <noreply>
This was referenced Aug 14, 2026
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.
Two detectors whose population was narrower than their claim, so each zero read as "clean" when it meant "I did not look there". Both re-derived, and both counts in the issues were wrong in the direction that matters.
#1598 — the shim gate scanned only
tests/test_*.pyWidening the scan over the 21 previously unscanned modules found exactly one hit,
_gitshim.py:38, as filed. But the issue omittedtests/fixtures/— three real modules — so the fix isrglob, notglob._modules_scanned()is now every*.pyundertests/recursively minus__pycache__, with hits reported asrelative_to(root).as_posix().The exemption is a grammar answer, not a filename allowlist:
_shifts_through_argvrequires every$1-test position to sit inside awhile|until|for … donespan containingshift, consistent with #1412.The judgment call: the one pre-existing site is the correct implementation, so no register was needed — shape over marker, because a marker is a self-declaration anybody can write above a broken shim.
GREEN:
47 passed in 5.49s#1584 — the issue said three open egress routes. It is six.
gethostbyname_ex,getnameinfoandgethostbyaddrwere open and unnamed:All six refused now, plus
sendmsg. Loopback and AF_UNIX stay open by design.The judgment call: not a longer list.
_netblock.ROUTES/SOCKET_ROUTESclassify every callablesocketandsocket.socketexpose asPATCHED/VIA/LOCAL/INERT/OPEN, with the population derived fromdir(socket)at test time — so a name CPython grows arrives red rather than silently unblocked.OPENcarries a reason, andBEYOND_THE_PROCESSnames the four uncoverable routes instead of counting them blocked.Prose corrected at all three live sites (
conftest.py,docs/contributing.md,test_transport_seam_enforced_1341.py).CHANGELOG.md:180deliberately left — it is a historical release record.RED
16 failed, 3 passed→ GREEN19 passed, then179 passedacross the netblock/hashnode/seam/shim suites.The reviewer caught a Windows-wide outage before CI could
_netblock.py:322— the patch loop hardcoded("connect","connect_ex","sendto","sendmsg")while_METHOD_PATCHESwashasattr-filtered directly above. Windows has nosocket.socket.sendmsg, andmonkeypatch.setattr(raising=True)on an absent attribute raisesAttributeErrorout of an autouse fixture — every test, every Windows leg. Fixed; the loop iterates the derived tuples.The pin proved red against the old loop (
hardcoded loop -> sendmsg is original: False). Notedelattrcannot simulate the platform —socket.socket.sendmsgis inherited from_socket.socket— so the pin shortens the derived tuple instead.Two more accepted: a stale sentence one paragraph above the rewritten disclosure, and a docstring claiming patches == register while the loop had drifted.
Adjacent, fixed
tests/test_git_shim_subcommand_1206.pycarried a module-levelpytestmark = skipif(os.name == "nt"), which was skipping the class gate and every pure-AST rule test on Windows. Scoped to the five tests that actually run/bin/sh; the AST tests now run there.Suite
Full suite twice in disposable clones:
12898 passed, 97 skipped. Two failures, neither from this diff —test_no_cli_at_all_is_not_an_absence_either(fails identically on parentd2a48e7fin a clean clone in isolation; filed separately) andtest_a_minified_file_does_not_hang_the_diagnostic(passes in isolation on both sides; timing). Windows unverified locally — CI is the authority.Closes #1598
Closes #1584