Repository navigation
bughunt(yarn-classic): probe offline mirror + git-sourced deps on mac… #1
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
| name: bughunt yarn-classic probe | |
| on: | |
| push: | |
| branches: ['bughunt/yarn-classic/**'] | |
| permissions: | |
| contents: read | |
| jobs: | |
| probe: | |
| name: probe ${{ matrix.os }} yarn ${{ matrix.yarn }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| yarn: ['1.10.1', '1.22.22'] | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Install Rust | |
| run: rustup show | |
| - name: Setup Node.js | |
| uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | |
| with: | |
| node-version: '24.x' | |
| - name: Build socket-patch | |
| run: cargo build -p socket-patch-cli | |
| - name: Probe (offline mirror + git-sourced dep) | |
| env: | |
| COREPACK_ENABLE_DOWNLOAD_PROMPT: '0' | |
| YARN_V: ${{ matrix.yarn }} | |
| run: | | |
| cat > "$RUNNER_TEMP/probe.sh" <<'PROBE_EOF' | |
| #!/usr/bin/env bash | |
| # probe.sh SP_BIN YARN_VERSION — prints RESULT lines | |
| set -u | |
| SP=$1; V=$2; W=$(pwd)/probe-work; rm -rf "$W"; mkdir -p "$W"; cd "$W" | |
| export COREPACK_ENABLE_DOWNLOAD_PROMPT=0 | |
| PY=python3; command -v python3 >/dev/null && python3 -c 1 2>/dev/null || PY=python | |
| PORT=18555; API=http://127.0.0.1:$PORT | |
| winpath() { if command -v cygpath >/dev/null; then cygpath -m "$1"; else echo "$1"; fi; } | |
| Y() { corepack yarn@$V "$@"; } | |
| sp() { "$SP" "$@" --api-url $API --org test-org --api-token fake; } | |
| marker() { if [ -f "$1" ] && head -c 22 "$1" | grep -q SOCKET-PATCHED; then echo PATCHED; elif [ -f "$1" ]; then echo UNPATCHED; else echo MISSING; fi; } | |
| fresh() { rm -rf "$2"; mkdir -p "$2"; (cd "$1" && tar cf - --exclude=node_modules --exclude=.c . ) | (cd "$2" && tar xf -); } | |
| # --- patched left-pad tarball + mock API --- | |
| mkdir pk && (cd pk && npm pack left-pad@1.3.0 --silent >/dev/null) | |
| cat > mk.py <<'PY' | |
| import tarfile,io,hashlib,base64,json,sys | |
| src=tarfile.open("pk/left-pad-1.3.0.tgz"); buf=io.BytesIO(); dst=tarfile.open(fileobj=buf,mode="w:gz") | |
| for m in src.getmembers(): | |
| if not m.isfile(): continue | |
| d=src.extractfile(m).read(); rel=m.name.split("/",1)[1] | |
| if rel=="index.js": b=d; d=b"/* SOCKET-PATCHED */\n"+d; a=d | |
| t=tarfile.TarInfo("package/"+rel); t.mode=0o644; t.mtime=0; t.size=len(d); dst.addfile(t,io.BytesIO(d)) | |
| dst.close(); tgz=buf.getvalue(); open("pk/patched.tgz","wb").write(tgz) | |
| g=lambda d: hashlib.sha256(b"blob %d\0"%len(d)+d).hexdigest() | |
| json.dump({"org":"test-org","pkgs":[{"name":"left-pad","version":"1.3.0","uuid":"7c8d9e0f-1a2b-4c3d-8e4f-5a6b7c8d9e0f","tgz":"pk/patched.tgz","sha1":hashlib.sha1(tgz).hexdigest(),"sri":"sha512-"+base64.b64encode(hashlib.sha512(tgz).digest()).decode(),"files":{"package/index.js":{"before":g(b),"after":g(a),"blob":base64.b64encode(a).decode()}}}]},open("cfg.json","w")) | |
| PY | |
| $PY mk.py | |
| cat > mock.py <<'PY' | |
| #!/usr/bin/env python3 | |
| """Hold-open mock Socket patch API. Usage: mock.py PORT CONFIG.json | |
| CONFIG: {"org":"test-org","token":"...","pkgs":[{"name","version","uuid","tgz","files":{"package/index.js":{"before":hex,"after":hex}}, "sha1","sri"}]}""" | |
| import json, sys, os, re, urllib.parse | |
| from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler | |
| PORT=int(sys.argv[1]); CFG=json.load(open(sys.argv[2])) | |
| ORG=CFG["org"]; TOKEN=CFG.get("token","33333333-3333-4333-8333-333333333333") | |
| LOG=open(sys.argv[2]+".log","a",buffering=1) | |
| def purl(p): | |
| n=p["name"] | |
| pass | |
| return f"pkg:npm/{n}@{p['version']}" | |
| def hurl(p): | |
| return f"http://127.0.0.1:{PORT}/patch/npm/{p['name']}/{p['version']}/{TOKEN}/{p['uuid']}/{p['name'].split('/')[-1]}-{p['version']}.tgz" | |
| class H(BaseHTTPRequestHandler): | |
| def log_message(self,*a): pass | |
| def send(self,obj,code=200,raw=None): | |
| b=raw if raw is not None else json.dumps(obj).encode() | |
| self.send_response(code); self.send_header("Content-Length",str(len(b))) | |
| self.send_header("Content-Type","application/octet-stream" if raw is not None else "application/json"); self.end_headers(); self.wfile.write(b) | |
| def body(self): | |
| n=int(self.headers.get("Content-Length") or 0); return self.rfile.read(n).decode() if n else "" | |
| def summary(self,p): | |
| return {"uuid":p["uuid"],"purl":purl(p),"tier":"free","cveIds":[],"ghsaIds":["GHSA-x-"+p["uuid"][:4]],"severity":"high","title":"fixture "+p["name"], | |
| "publishedAt":"2026-01-01T00:00:00Z","description":"x","license":"MIT","vulnerabilities":{}} | |
| def do_POST(self): | |
| b=self.body(); LOG.write(f"POST {self.path} {b[:300]}\n") | |
| if self.path.endswith("/patches/batch"): | |
| pk=[{"purl":purl(p),"patches":[self.summary(p)]} for p in CFG["pkgs"] if purl(p) in urllib.parse.unquote(b) or purl(p) in b] | |
| return self.send({"packages":pk,"canAccessPaidPatches":False}) | |
| if self.path.endswith("/patches/package"): | |
| res={} | |
| for p in CFG["pkgs"]: | |
| if p["uuid"] in b: | |
| u=hurl(p); res[p["uuid"]]={"status":"granted","url":u,"purl":purl(p),"artifacts":[{"kind":"tarball","url":u,"integrity":{"sha512":p["sri"],"sha1":p["sha1"]}}],"registryOverride":None} | |
| return self.send({"results":res}) | |
| self.send({"error":"nf"},404) | |
| def do_GET(self): | |
| LOG.write(f"GET {self.path}\n") | |
| m=re.search(r"/patches/by-package/(.+)$",self.path) | |
| if m: | |
| q=urllib.parse.unquote(m.group(1)) | |
| return self.send({"patches":[self.summary(p) for p in CFG["pkgs"] if purl(p)==q or urllib.parse.unquote(purl(p))==q],"canAccessPaidPatches":False}) | |
| m=re.search(r"/patches/view/([0-9a-f-]+)$",self.path) | |
| if m: | |
| for p in CFG["pkgs"]: | |
| if p["uuid"]==m.group(1): | |
| files={k:{"beforeHash":v["before"],"afterHash":v["after"],**({"blobContent":v["blob"]} if "blob" in v else {})} for k,v in p["files"].items()} | |
| return self.send({"uuid":p["uuid"],"purl":purl(p),"publishedAt":"2026-01-01T00:00:00Z","files":files, | |
| "vulnerabilities":{"GHSA-x-"+p["uuid"][:4]:{"cves":["CVE-2026-1"],"summary":"s","severity":"high","description":"d"}},"description":"x","license":"MIT","tier":"free"}) | |
| if self.path.startswith("/patch/"): | |
| for p in CFG["pkgs"]: | |
| if p["uuid"] in self.path: | |
| return self.send(None,raw=open(p["tgz"],"rb").read()) | |
| # blob fetch | |
| self.send({"error":"nf"},404) | |
| ThreadingHTTPServer(("127.0.0.1",PORT),H).serve_forever() | |
| PY | |
| $PY mock.py $PORT cfg.json > mock.out 2>&1 & | |
| MOCKPID=$!; sleep 2 | |
| result() { echo "RESULT os=${RUNNER_OS:-local} yarn=$V $*"; } | |
| # --- case 1: hosted + yarn-offline-mirror --- | |
| P=$W/mir; mkdir -p $P; echo '{"name":"b","version":"1.0.0","private":true,"dependencies":{"left-pad":"1.3.0"}}' > $P/package.json | |
| printf 'yarn-offline-mirror "./mirror"\n' > $P/.yarnrc | |
| (cd $P && YARN_CACHE_FOLDER=$P/.c Y install --no-progress >/dev/null 2>&1) | |
| fresh $P $W/mirctl; (cd $W/mirctl && YARN_CACHE_FOLDER=$W/cc0 Y install --frozen-lockfile --no-progress >/dev/null 2>&1); result "case=mirror-control(no-socket-patch) rc=$? $(marker $W/mirctl/node_modules/left-pad/index.js)" | |
| sp scan --mode hosted --json --yes --cwd "$(winpath $P)" > $W/mirscan.json 2>/dev/null; result "case=mirror-hosted-scan rc=$? $(tr -d '\n' < $W/mirscan.json | grep -o '"redirected": *[0-9]*' | head -1) warnings=$(grep -o '"code": *"[a-z_]*"' $W/mirscan.json | tr -d ' \n')" | |
| for mode in "" "--offline"; do fresh $P $W/mirf; (cd $W/mirf && YARN_CACHE_FOLDER=$W/cc$RANDOM Y install --frozen-lockfile $mode --no-progress > $W/mirf.log 2>&1); rc=$?; result "case=mirror-hosted-fresh-install${mode} rc=$rc $(marker $W/mirf/node_modules/left-pad/index.js) err=$(grep -o 'Integrity check failed\|offline mode' $W/mirf.log | head -1 | tr ' ' _)"; done | |
| # --- case 2: git-sourced dep, hosted & vendored --- | |
| G=$W/lpgit; mkdir -p $G; tar xzf pk/left-pad-1.3.0.tgz -C $G --strip-components=1; (cd $G && git init -q && git add -A && git -c user.email=a@b -c user.name=a commit -qm v && git tag v1.3.0) | |
| for m in hosted vendored; do | |
| P=$W/git-$m; mkdir -p $P; echo "{\"name\":\"g\",\"version\":\"1.0.0\",\"private\":true,\"dependencies\":{\"left-pad\":\"git+file:///$(winpath $G | sed 's#^/##')#v1.3.0\"}}" > $P/package.json | |
| (cd $P && YARN_CACHE_FOLDER=$P/.c Y install --no-progress > $P/../i-$m.log 2>&1) || result "case=git-$m fixture-install-failed $(tail -1 $P/../i-$m.log)" | |
| extra=""; [ $m = vendored ] && extra="--detached --vendor-source build" | |
| sp scan --mode $m $extra --json --yes --cwd "$(winpath $P)" --vex "$(winpath $W/v-$m.json)" > $W/g-$m.json 2>/dev/null; result "case=git-$m-scan rc=$? status=$(grep -o '"status": *"[a-z_]*"' $W/g-$m.json | head -1 | tr -d ' ') inrun-vex=$(grep -o '"not_affected"' $W/v-$m.json | head -1)" | |
| fresh $P $W/gf-$m; (cd $W/gf-$m && YARN_CACHE_FOLDER=$W/gc$RANDOM Y install --frozen-lockfile --no-progress > $W/gf-$m.log 2>&1); rc=$?; result "case=git-$m-fresh-install rc=$rc $(marker $W/gf-$m/node_modules/left-pad/index.js) err=$(grep -m1 '^error' $W/gf-$m.log | cut -c1-80 | tr ' ' _)" | |
| done | |
| kill $MOCKPID 2>/dev/null | |
| PROBE_EOF | |
| BIN="$PWD/target/debug/socket-patch"; [ -f "$BIN.exe" ] && BIN="$BIN.exe" | |
| cd "$RUNNER_TEMP" && bash probe.sh "$BIN" "$YARN_V" 2>&1 | tee probe.log | grep RESULT || true | |
| echo '--- mock log ---'; cat probe-work/cfg.json.log 2>/dev/null | cut -c1-200 | tail -20 |