Skip to content

bughunt uv probe: requirements lane on 3 OS #10

bughunt uv probe: requirements lane on 3 OS

bughunt uv probe: requirements lane on 3 OS #10

Workflow file for this run

name: bughunt uv probe
on:
push:
branches: ["bughunt/uv/**"]
permissions:
contents: read
jobs:
probe:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 45
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
- name: Build CLI
run: cargo build --release -p socket-patch-cli
- name: Write probe files
run: |
mkdir -p "$RUNNER_TEMP/mock" "$RUNNER_TEMP/work"
cat > "$RUNNER_TEMP/mock/mock.py" <<'PYEOF'
#!/usr/bin/env python3
"""Local mock of the Socket patch API serving one patched pypi package (six 1.16.0)."""
import base64, hashlib, io, json, os, re, sys, zipfile
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
HERE = os.path.dirname(os.path.abspath(__file__))
PORT = int(os.environ.get("MOCK_PORT", "18080"))
ORG = "test-org"
UUID = "0f6e7c1a-1111-4222-8333-444455556666"
TOKEN = "11111111-2222-4333-8444-555555555555"
SUFFIX = b"\n# SOCKET-PATCHED\nSOCKET_PATCHED = 1\n"
NAME, VER = "six", "1.16.0"
PURL = f"pkg:pypi/{NAME}@{VER}"
LEAF = f"{NAME}-{VER}-py2.py3-none-any.whl"
LOG = os.path.join(HERE, "requests.log")
def git_sha256(b):
return hashlib.sha256(b"blob %d\0" % len(b) + b).hexdigest()
def build():
src = zipfile.ZipFile(os.path.join(HERE, LEAF))
members = []
dist = f"{NAME}-{VER}.dist-info"
for info in src.infolist():
if info.filename == f"{dist}/RECORD":
continue
data = src.read(info.filename)
if info.filename == "six.py":
orig = data
data = data + SUFFIX
members.append((info.filename, data))
rec = ""
for n, d in members:
dig = base64.urlsafe_b64encode(hashlib.sha256(d).digest()).rstrip(b"=").decode()
rec += f"{n},sha256={dig},{len(d)}\n"
rec += f"{dist}/RECORD,,\n"
members.append((f"{dist}/RECORD", rec.encode()))
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as z:
for n, d in members:
zi = zipfile.ZipInfo(n, date_time=(2020, 1, 1, 0, 0, 0)); zi.compress_type = zipfile.ZIP_DEFLATED
z.writestr(zi, d)
return orig, orig + SUFFIX, buf.getvalue()
ORIG, PATCHED, WHEEL = build()
SHA = hashlib.sha256(WHEEL).hexdigest()
BASE = f"http://127.0.0.1:{PORT}"
ART_PATH = f"/patch/pypi/{NAME}/{VER}/{TOKEN}/{UUID}/{LEAF}"
ART = BASE + ART_PATH
VIEW = {
"uuid": UUID, "purl": PURL, "publishedAt": "Fri, 27 Mar 2026 00:00:00 GMT",
"files": {"six.py": {"beforeHash": git_sha256(ORIG), "afterHash": git_sha256(PATCHED),
"blobContent": base64.b64encode(PATCHED).decode()}},
"vulnerabilities": {"GHSA-uvbu-ildv-ex01": {"cves": ["CVE-2026-7101"], "summary": "s",
"severity": "high", "description": "d"}},
"description": "uv bughunt patch", "license": "MIT", "tier": "free",
}
class H(BaseHTTPRequestHandler):
def log_message(self, *a):
pass
def send(self, code, body, ctype="application/json"):
if not isinstance(body, bytes):
body = json.dumps(body).encode()
self.send_response(code)
self.send_header("Content-Type", ctype)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def route(self):
with open(LOG, "a") as f:
f.write(f"{self.command} {self.path}\n")
p = self.path.split("?")[0]
n = int(self.headers.get("Content-Length") or 0)
body = self.rfile.read(n) if n else b""
if p == ART_PATH:
if self.command == "HEAD":
self.send_response(200); self.send_header("Content-Length", str(len(WHEEL))); self.end_headers(); return
return self.send(200, WHEEL, "application/octet-stream")
if re.fullmatch(rf"/v0/orgs/{ORG}/patches/batch", p) or p.endswith("/patch/batch"):
try:
comps = json.loads(body or b"{}").get("components", [])
except Exception:
comps = []
purls = [c.get("purl", "") for c in comps] if comps else [PURL]
if not any(pu.lower().startswith(f"pkg:pypi/{NAME}@{VER}") for pu in purls):
return self.send(200, {"packages": [], "canAccessPaidPatches": False})
return self.send(200, {"packages": [{"purl": PURL, "patches": [{
"uuid": UUID, "purl": PURL, "tier": "free", "cveIds": ["CVE-2026-7101"],
"ghsaIds": ["GHSA-uvbu-ildv-ex01"], "severity": "HIGH", "title": "uv bughunt"}]}],
"canAccessPaidPatches": False})
if "/patches/by-package/" in p or "/patch/by-package/" in p:
return self.send(200, {"patches": [{"uuid": UUID, "purl": PURL,
"publishedAt": "2026-09-01T00:00:00Z", "description": "uv bughunt",
"license": "MIT", "tier": "free", "vulnerabilities": {}}],
"canAccessPaidPatches": False})
if p.endswith("/patches/package") or p.endswith("/patch/package"):
return self.send(200, {"results": {UUID: {"status": "granted", "url": ART, "purl": PURL,
"artifacts": [{"kind": "tarball", "url": ART, "integrity": {"sha256": SHA, "sha512": "sha512-" + base64.b64encode(hashlib.sha512(WHEEL).digest()).decode()}}],
"registryOverride": None}}})
if p.endswith(f"/view/{UUID}"):
return self.send(200, VIEW)
if "/blob/" in p:
h = p.rsplit("/", 1)[1]
if h == git_sha256(PATCHED):
return self.send(200, PATCHED, "application/octet-stream")
if h == git_sha256(ORIG):
return self.send(200, ORIG, "application/octet-stream")
return self.send(404, {"error": "not found", "path": p})
do_GET = route
do_POST = route
do_HEAD = route
if __name__ == "__main__":
print(json.dumps({"art": ART, "sha": SHA, "patched_py_sha": hashlib.sha256(PATCHED).hexdigest(),
"orig_py_sha": hashlib.sha256(ORIG).hexdigest()}), flush=True)
ThreadingHTTPServer(("127.0.0.1", PORT), H).serve_forever()
PYEOF
cat > "$RUNNER_TEMP/repro.sh" <<'SHEOF'
#!/usr/bin/env bash
# usage: repro.sh <uv-binary> <workdir> <hosted|vendored> <lf|crlf>
set -u
UVB=$1; D=$2; MODE=$3; EOL=$4; mkdir -p "$D" && cd "$D" || exit 1
W=$(pwd -W 2>/dev/null || pwd)
PY() { if [ -x .venv/Scripts/python.exe ]; then .venv/Scripts/python.exe "$@"; else .venv/bin/python "$@"; fi; }
ORC() { PY -c "import six; print('PATCHED' if getattr(six, 'SOCKET_PATCHED', 0) else 'PRISTINE')" 2>&1 | tail -1; }
printf 'six==1.16.0\nidna==3.7\n' > requirements.in
"$UVB" pip compile -q --generate-hashes requirements.in -o requirements.txt || { echo "compile failed"; exit 0; }
if [ "$EOL" = crlf ]; then python -c "import sys;p='requirements.txt';b=open(p,'rb').read().replace(b'\r\n',b'\n').replace(b'\n',b'\r\n');open(p,'wb').write(b)"; fi
cp requirements.txt orig.txt
"$UVB" venv -q .venv; VIRTUAL_ENV="$W/.venv" "$UVB" pip sync -q requirements.txt
$SP scan --mode $MODE --json --yes $API > scan.json 2>scan.err; rc=$?
python -c "import json;d=json.load(open('scan.json'));r=d.get('redirect') or {};v=d.get('vendor') or {};print('scan rc=$rc',d.get('status'),r.get('redirected'),[w['code'] for w in r.get('warnings',[])],[(e['action'],e.get('errorCode')) for e in v.get('events',[])])" || cat scan.err
grep -n "six\|socket" requirements.txt | head -3
rm -rf .venv; "$UVB" venv -q .venv
VIRTUAL_ENV="$W/.venv" UV_CACHE_DIR="$W/cache1" "$UVB" pip sync --require-hashes requirements.txt 2>&1 | grep -iE "error|six" | head -3
echo "fresh install after $MODE scan: $(ORC)"
if [ $MODE = hosted ]; then $SP rollback --json --yes $API > rb.json 2>/dev/null; else $SP vendor --revert --json --yes $API > rb.json 2>/dev/null; fi
python -c "import json;d=json.load(open('rb.json'));print('unwind',d['status'],str(d.get('hosted') or d.get('events'))[:300],d.get('warnings'))"
cmp -s orig.txt requirements.txt && echo "unwind BYTE-IDENTICAL" || { echo "unwind DRIFT"; diff orig.txt requirements.txt | head -6; }
VIRTUAL_ENV="$W/.venv" "$UVB" pip sync requirements.txt 2>&1 | tail -1
echo "after unwind + uv pip sync: $(ORC)"
SHEOF
python -m pip download --no-deps six==1.16.0 -d "$RUNNER_TEMP/mock"
- name: Run probe
run: |
python "$RUNNER_TEMP/mock/mock.py" > "$RUNNER_TEMP/mock.out" 2>&1 &
sleep 3; cat "$RUNNER_TEMP/mock.out"
export SP="$PWD/target/release/socket-patch"; [ -f "$SP.exe" ] && SP="$SP.exe"
export API="--api-url http://127.0.0.1:18080 --api-token fake-token --org test-org --patch-server-url http://127.0.0.1:18080"
export SOCKET_TELEMETRY_DISABLED=1 SOCKET_NO_CONFIG=1
for v in 0.1.44 0.5.31 0.12.21; do
python -m venv "$RUNNER_TEMP/uv-$v"
if [ -d "$RUNNER_TEMP/uv-$v/Scripts" ]; then B="$RUNNER_TEMP/uv-$v/Scripts"; else B="$RUNNER_TEMP/uv-$v/bin"; fi
"$B/python" -m pip install -q "uv==$v"
UVB="$B/uv"; [ -f "$UVB.exe" ] && UVB="$UVB.exe"
echo "### RESULT uv $v on ${{ matrix.os }}"
for m in hosted vendored; do for e in lf crlf; do
echo "### CELL uv $v ${{ matrix.os }} $m $e"
bash "$RUNNER_TEMP/repro.sh" "$UVB" "$RUNNER_TEMP/work/r-$v-$m-$e" $m $e || true
done; done
done