You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
socket.yml ignorePackages / packages and scan --package don't PEP 503-normalise PyPI names, so ignorePackages: ["typing_extensions"] is silently ignored and the package is patched anyway #910
[agent] Found by the scheduled pip / requirements.txt bug-hunt routine (ledger #309).
Summary
The policy package matcher (package_spec_matches) compares PyPI names by lowercasing them only. Every PyPI purl socket-patch builds is PEP 503-canonical (canonicalize_pypi_name: _ / . / - runs become -). So a spec written the way the name appears in requirements.txt, on PyPI's project page or in import (typing_extensions, zope.interface, ruamel.yaml, pkg:pypi/typing_extensions) never matches pkg:pypi/typing-extensions@4.12.2.
Impact:
Exclusion fails open.patches.ignorePackages: ["typing_extensions"] is dropped silently. The hosted scan rewrites requirements.txt to the Socket build and exits 0. policy.filtered[] is empty and there is no warning, so a team that opted a package out of patching still has it patched.
Allowlist and --package fail closed, also silently.patches.packages: ["typing_extensions"] and scan --package typing_extensions select nothing (policy_package_not_listed / nothing redirected), with no hint that the spelling is the cause.
Any PyPI project whose name contains _ or . is affected (typing_extensions, zope.interface, ruamel.yaml, jaraco., backports., …). The matcher is shared by every PyPI package manager. I found and verified it with pip / requirements.txt.
The patch API is a local mock that serves one free patch for pkg:pypi/typing-extensions@4.12.2 (batch, by-package, package grant and the patched wheel), the same shape as crates/socket-patch-cli/tests/hosted_superseding_pypi.rs.
policy.filtered: []; the package is handed to apply
You can see the same thing at unit level: package_spec_matches("typing_extensions", "pkg:pypi/typing-extensions@4.12.2") returns false.
Expected vs actual
Expected: CLI_CONTRACT.md ("Package specs are exactly --package's: a name … or a purl … names compare case-insensitively"). The matcher's own doc comment gives the reason: "PyPI, NuGet and Composer names are case-insensitive". PyPI names are equivalent under PEP 503 normalisation, not just case folding: pip treats typing_extensions, typing-extensions and Typing.Extensions as one project. The "Narrowing never removes … trust boundary" section says a policy only ever removes candidates, so a valid exclusion that silently stops excluding is a policy bypass.
Actual: only the exact canonical - spelling matches. Every other spelling is dropped without a socket_yml_* warning.
OS × version
OS
pip / Python
Reproduces
Linux
pip 26.0 + 24.0 / CPython 3.11
yes (hosted and agent policy evaluation)
macOS / Windows
—
not probed. The matcher is pure string logic with no OS branch, so I expect the same result
This isn't a regression: socket.yml and --package are new in v5 (unreleased; the latest tag is v4.0.0).
Suspect code
crates/socket-patch-core/src/policy/mod.rs:744-779 (package_spec_matches): to_lowercase() only. For a pkg:pypi/ purl it should compare canonicalize_pypi_name of both the spec name and the purl name, for both the bare-name and the purl-spec branches.
The same function backs scan --package (crates/socket-patch-cli/src/commands/scan/mod.rs:1913) and get's policy_bypassed check.
[agent] Found by the scheduled pip / requirements.txt bug-hunt routine (ledger #309).
Summary
The policy package matcher (
package_spec_matches) compares PyPI names by lowercasing them only. Every PyPI purl socket-patch builds is PEP 503-canonical (canonicalize_pypi_name:_/./-runs become-). So a spec written the way the name appears inrequirements.txt, on PyPI's project page or inimport(typing_extensions,zope.interface,ruamel.yaml,pkg:pypi/typing_extensions) never matchespkg:pypi/typing-extensions@4.12.2.Impact:
patches.ignorePackages: ["typing_extensions"]is dropped silently. The hosted scan rewritesrequirements.txtto the Socket build and exits 0.policy.filtered[]is empty and there is no warning, so a team that opted a package out of patching still has it patched.--packagefail closed, also silently.patches.packages: ["typing_extensions"]andscan --package typing_extensionsselect nothing (policy_package_not_listed/ nothing redirected), with no hint that the spelling is the cause._or.is affected (typing_extensions, zope.interface, ruamel.yaml, jaraco., backports., …). The matcher is shared by every PyPI package manager. I found and verified it with pip / requirements.txt.Repro (main
9c43dfc, Linux, pip 26.0 / 24.0, CPython 3.11)The patch API is a local mock that serves one free patch for
pkg:pypi/typing-extensions@4.12.2(batch,by-package,packagegrant and the patched wheel), the same shape ascrates/socket-patch-cli/tests/hosted_superseding_pypi.rs.Results for each spec spelling (fresh project each time; reproduced twice):
typing-extensionsignorePackagespolicy_package_ignored), file untouched ✅typing_extensionsignorePackagesTyping_ExtensionsignorePackagestyping.extensionsignorePackagespkg:pypi/typing_extensionsignorePackagestyping_extensionspackages(allowlist)policy_package_not_listed❌typing_extensionsscan --packagetyping-extensionsscan --packagetyping_extensionsignorePackages,--mode agentpolicy.filtered: []; the package is handed to applyYou can see the same thing at unit level:
package_spec_matches("typing_extensions", "pkg:pypi/typing-extensions@4.12.2")returnsfalse.Expected vs actual
--package's: a name … or a purl … names compare case-insensitively"). The matcher's own doc comment gives the reason: "PyPI, NuGet and Composer names are case-insensitive". PyPI names are equivalent under PEP 503 normalisation, not just case folding: pip treatstyping_extensions,typing-extensionsandTyping.Extensionsas one project. The "Narrowing never removes … trust boundary" section says a policy only ever removes candidates, so a valid exclusion that silently stops excluding is a policy bypass.-spelling matches. Every other spelling is dropped without asocket_yml_*warning.OS × version
This isn't a regression: socket.yml and
--packageare new in v5 (unreleased; the latest tag is v4.0.0).Suspect code
crates/socket-patch-core/src/policy/mod.rs:744-779(package_spec_matches):to_lowercase()only. For apkg:pypi/purl it should comparecanonicalize_pypi_nameof both the spec name and the purl name, for both the bare-name and the purl-spec branches.scan --package(crates/socket-patch-cli/src/commands/scan/mod.rs:1913) andget'spolicy_bypassedcheck.canonicalize_pypi_nameinto a PyPI name module would make it reachable frompolicy).