mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(installer): disable dependency hooks explicitly across Bun versions
This commit is contained in:
1 parent
4f2083bfbd
commit
2b8803f777
2 files changed
+98
-1
No files matched your search
@@ -0,0 +1,94 @@
|
||||
"""Real Bun install against an offline npm registry: dependency hooks stay off.
|
||||
|
||||
The fixture has the same ordinary npm dependency shape as esbuild, whose
|
||||
postinstall Bun 1.2 runs by default. It writes only a local marker. No public
|
||||
registry, credentials or lifecycle-script runner is mocked.
|
||||
"""
|
||||
import base64
|
||||
import hashlib
|
||||
import http.server
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
from tempfile import TemporaryDirectory
|
||||
import threading
|
||||
import unittest
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
BUN = os.environ.get("TEST_BUN") or shutil.which("bun")
|
||||
|
||||
|
||||
@unittest.skipUnless(BUN, "requires Bun for the offline package-manager integration")
|
||||
class DependencyHooks(unittest.TestCase):
|
||||
def test_installing_dependency_does_not_execute_its_hook(self):
|
||||
package = {"name": "esbuild", "version": "0.25.0", "scripts": {"postinstall": "bun run hook.js"}}
|
||||
archive = io.BytesIO()
|
||||
with tarfile.open(fileobj=archive, mode="w:gz") as tar:
|
||||
for name, data in {
|
||||
"package.json": json.dumps(package).encode(),
|
||||
"hook.js": b'await Bun.write("hook-ran.txt", "ran");',
|
||||
}.items():
|
||||
entry = tarfile.TarInfo("package/" + name)
|
||||
entry.size = len(data)
|
||||
tar.addfile(entry, io.BytesIO(data))
|
||||
blob = archive.getvalue()
|
||||
|
||||
class Registry(http.server.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
if self.path.endswith(".tgz"):
|
||||
body = blob
|
||||
else:
|
||||
metadata = {**package, "dist": {
|
||||
"tarball": f"http://127.0.0.1:{self.server.server_port}/esbuild.tgz",
|
||||
"integrity": "sha512-" + base64.b64encode(hashlib.sha512(blob).digest()).decode(),
|
||||
}}
|
||||
body = json.dumps({"name": "esbuild", "dist-tags": {"latest": "0.25.0"},
|
||||
"versions": {"0.25.0": metadata}}).encode()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Registry)
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
try:
|
||||
with TemporaryDirectory() as directory:
|
||||
root = Path(directory)
|
||||
tools = root / "tools"
|
||||
tools.mkdir()
|
||||
for name in ("install_portal_clis.py", "security_guards.py"):
|
||||
shutil.copyfile(ROOT / "tools" / name, tools / name)
|
||||
cli = root / ".agents/skills/example-search/cli"
|
||||
cli.mkdir(parents=True)
|
||||
(cli / "package.json").write_text(json.dumps({
|
||||
"name": "example-search", "private": True, "dependencies": {"esbuild": "0.25.0"},
|
||||
}), encoding="utf-8")
|
||||
(cli / ".npmrc").write_text(f"registry=http://127.0.0.1:{server.server_port}/\n", encoding="utf-8")
|
||||
env = {"PATH": str(Path(BUN).absolute().parent) + os.pathsep + os.defpath,
|
||||
"HOME": str(root), "TMPDIR": str(root), "TEMP": str(root), "TMP": str(root),
|
||||
"BUN_INSTALL_CACHE_DIR": str(root / "cache")}
|
||||
if "SYSTEMROOT" in os.environ:
|
||||
env["SYSTEMROOT"] = os.environ["SYSTEMROOT"]
|
||||
proc = subprocess.run([sys.executable, str(tools / "install_portal_clis.py")],
|
||||
env=env, capture_output=True, text=True, timeout=30)
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
dependency = cli / "node_modules/esbuild"
|
||||
self.assertTrue((dependency / "hook.js").is_file(), "the dependency was actually installed")
|
||||
self.assertFalse((dependency / "hook-ran.txt").exists(), "the dependency install hook ran")
|
||||
finally:
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
thread.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -18,6 +18,9 @@ skipped and reported instead of installed: those are the hooks that run code
|
||||
during `bun install`, and tools/security_guards.py forbids them in-tree. A
|
||||
borrowed portal that carries one gets read by a human before it runs.
|
||||
|
||||
Every install also passes --ignore-scripts, including on older Bun releases
|
||||
that run a built-in list of dependency hooks without trustedDependencies.
|
||||
|
||||
Each CLI installs independently; one failure does not stop the rest. Exit 0
|
||||
when every CLI installed, 1 when bun is missing, a manifest was skipped, or an
|
||||
install failed.
|
||||
@@ -72,7 +75,7 @@ def install(cli_dirs: list[Path], bun: str, dry_run: bool, root: Path = ROOT, ru
|
||||
print(f"would install {name}")
|
||||
continue
|
||||
print(f"installing {name}", flush=True)
|
||||
if run([bun, "install"], cwd=cli_dir).returncode != 0:
|
||||
if run([bun, "install", "--ignore-scripts"], cwd=cli_dir).returncode != 0:
|
||||
print(f"FAIL {name}: bun install exited non-zero")
|
||||
failures.append(name)
|
||||
if failures:
|
||||
|
||||
Reference in new issue
Block a user