Skip to content

probe: tolerate expected non-zero exits #5

probe: tolerate expected non-zero exits

probe: tolerate expected non-zero exits #5

Workflow file for this run

name: bughunt-pip
on:
push:
branches: ['bughunt/pip/**']
permissions:
contents: read
jobs:
probe:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python: ['3.8', '3.13']
pip: ['20.3.4', 'latest']
runs-on: ${{ matrix.os }}
timeout-minutes: 45
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- run: rustup show
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
with:
save-if: false
- run: cargo build --release -p socket-patch-cli
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: ${{ matrix.python }}
- name: probe
run: |
set +e -x
W="$RUNNER_TEMP/w"; mkdir -p "$W"; cd "$W"
BIN="$GITHUB_WORKSPACE/target/release/socket-patch"; [ -f "$BIN.exe" ] && BIN="$BIN.exe"
python -m venv pv
if [ -d pv/Scripts ]; then PY=pv/Scripts/python; else PY=pv/bin/python; fi
if [ "${{ matrix.pip }}" = latest ]; then $PY -m pip install -q -U pip; else $PY -m pip install -q "pip==${{ matrix.pip }}"; fi
$PY -m pip --version
$PY -m pip download -q six==1.16.0 --no-deps -d dl
cat > mock.py <<'PYEOF'
import base64, hashlib, json, re, sys, zipfile, io
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
PORT=int(sys.argv[1]) if len(sys.argv)>1 else 8765
ORG="test-org"; PURL="pkg:pypi/six@1.16.0"; UUID="5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"
TOKEN="11111111-2222-4333-8444-555555555555"; WHEEL="six-1.16.0-py2.py3-none-any.whl"
GHSA="GHSA-real-pypi-0001"; CVE="CVE-2026-7201"
orig=zipfile.ZipFile("dl/"+WHEEL).read("six.py")
patched=orig+b"\n# SOCKET-PATCHED\nSOCKET_PATCHED = 1\n"
def d(b): return base64.urlsafe_b64encode(hashlib.sha256(b).digest()).rstrip(b"=").decode()
meta=b"Metadata-Version: 2.1\nName: six\nVersion: 1.16.0\nSummary: x\n"
wh=b"Wheel-Version: 1.0\nGenerator: t\nRoot-Is-Purelib: true\nTag: py2-none-any\nTag: py3-none-any\n"
mem=[("six.py",patched),("six-1.16.0.dist-info/METADATA",meta),("six-1.16.0.dist-info/WHEEL",wh)]
rec="".join(f"{n},sha256={d(b)},{len(b)}\n" for n,b in mem)+"six-1.16.0.dist-info/RECORD,,\n"
buf=io.BytesIO(); z=zipfile.ZipFile(buf,"w")
for n,b in mem+[("six-1.16.0.dist-info/RECORD",rec.encode())]: z.writestr(n,b)
z.close(); wheel=buf.getvalue()
sha256=hashlib.sha256(wheel).hexdigest(); sha512="sha512-"+base64.b64encode(hashlib.sha512(wheel).digest()).decode()
def g(b): return hashlib.sha256(b"blob %d\0"%len(b)+b).hexdigest()
BASE=f"http://127.0.0.1:{PORT}"
APATH=f"/patch/pypi/six/1.16.0/{TOKEN}/{UUID}/{WHEEL}"
view={"uuid":UUID,"purl":PURL,"publishedAt":"Fri, 27 Mar 2026 00:00:00 GMT","files":{"six.py":{"beforeHash":g(orig),"afterHash":g(patched),"blobContent":base64.b64encode(patched).decode()}},
"vulnerabilities":{GHSA:{"cves":[CVE],"summary":"s","severity":"high","description":"d"}},"description":"x","license":"MIT","tier":"free"}
class H(BaseHTTPRequestHandler):
def log_message(self,*a): sys.stderr.write("REQ "+self.command+" "+self.path+"\n")
def j(self,o):
b=json.dumps(o).encode(); self.send_response(200); self.send_header("content-type","application/json"); self.send_header("content-length",str(len(b))); self.end_headers(); self.wfile.write(b)
def do_HEAD(self):
p=self.path.split("?")[0]
if p==APATH: self.send_response(200); self.send_header("content-length",str(len(wheel))); self.end_headers()
else: self.send_response(404); self.end_headers()
def do_GET(self):
p=self.path.split("?")[0]
if p==APATH:
self.send_response(200); self.send_header("content-type","application/octet-stream"); self.send_header("content-length",str(len(wheel))); self.end_headers(); self.wfile.write(wheel)
elif p.endswith("/patches/view/"+UUID) or p=="/patch/view/"+UUID: self.j(view)
elif re.match(f"^/v0/orgs/{ORG}/patches/by-package/.+$",p):
self.j({"patches":[{"uuid":UUID,"purl":PURL,"publishedAt":"2026-03-27T00:00:00Z","description":"x","license":"MIT","tier":"free","vulnerabilities":{}}],"canAccessPaidPatches":False})
else: self.send_response(404); self.end_headers()
def do_POST(self):
n=int(self.headers.get("content-length",0)); body=self.rfile.read(n)
p=self.path.split("?")[0]
if p.endswith("/patches/batch"):
want=PURL in body.decode(errors="replace")
self.j({"packages":[{"purl":PURL,"patches":[{"uuid":UUID,"purl":PURL,"tier":"free","cveIds":[CVE],"ghsaIds":[GHSA],"severity":"high","title":"t"}]}] if want else [],"canAccessPaidPatches":False})
elif p.endswith("/patches/package"):
u=BASE+APATH
self.j({"results":{UUID:{"status":"granted","url":u,"purl":PURL,"artifacts":[{"kind":"tarball","url":u,"integrity":{"sha256":sha256,"sha512":sha512}}],"registryOverride":None}}})
else: self.send_response(404); self.end_headers()
print("wheel sha256",sha256,flush=True)
ThreadingHTTPServer(("127.0.0.1",PORT),H).serve_forever()
PYEOF
python mock.py 8765 > mock.log 2>&1 &
sleep 3; cat mock.log
export NO_PROXY=127.0.0.1 SOCKET_TELEMETRY_DISABLED=1 SOCKET_NO_CONFIG=1
A="--api-url http://127.0.0.1:8765 --api-token fake --org test-org --patch-server-url http://127.0.0.1:8765"
echo "#### A: hosted scan then rollback / remove / vendored takeover of a one-line requirements.txt"
for sub in rollback remove takeover; do
rm -rf "a-$sub"; mkdir "a-$sub"; cd "a-$sub"; printf 'six==1.16.0\n' > requirements.txt
"$BIN" scan $A --cwd . > /dev/null 2>&1
case $sub in
rollback) "$BIN" rollback --yes $A --cwd . > out.txt 2>&1; rc=$? ;;
remove) "$BIN" remove pkg:pypi/six@1.16.0 --yes $A --cwd . > out.txt 2>&1; rc=$? ;;
takeover) "$BIN" scan --mode vendored $A --cwd . > out.txt 2>&1; rc=$? ;;
esac
grep -q 'not derivable' out.txt && v=REFUSED || v=OK
echo "RESULT A-$sub rc=$rc $v :: $(head -c 70 requirements.txt)"
cd ..
done
echo "#### B: lockfile-only checkout, pin only in -r include"
for layout in root include; do for mode in hosted vendored; do
d="b-$layout-$mode"; rm -rf "$d"; mkdir -p "$d/requirements"; cd "$d"
if [ $layout = root ]; then printf 'six==1.16.0\n' > requirements.txt; else printf -- '-r requirements/base.txt\n' > requirements.txt; printf 'six==1.16.0\n' > requirements/base.txt; fi
"$BIN" scan --mode $mode --json $A --cwd . > out.json 2> err.txt; rc=$?
n=$(cat requirements.txt requirements/base.txt 2>/dev/null | grep -c '@ http\|\.whl')
lo=$(python -c "import json;print(json.load(open('out.json')).get('lockfileOnlyPackages'))")
../$PY -m pip install -q --no-cache-dir --target tgt -r requirements.txt > pip.txt 2>&1
if grep -q SOCKET_PATCHED tgt/six.py 2>/dev/null; then pat=PATCHED; elif [ -f tgt/six.py ]; then pat=UNPATCHED; else pat="FAIL $(grep -m1 ERROR pip.txt)"; fi
echo "RESULT B-$layout-$mode rc=$rc lockfileOnly=$lo rewritten=$n install=$pat"
cd ..
done; done