mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(guards): refuse a .npmrc beside a portal manifest, like bunfig.toml
Bun reads .npmrc too, so a registry line beside a borrowed portal's manifest fetches every dependency from a server the portal's author picked - the same door bunfig.toml opens, which the installer and guard check 3 already refuse. Both now reject either file. The #718 integration test, which pointed Bun at its offline registry through a .npmrc, passes the registry through NPM_CONFIG_REGISTRY instead; it still proves the hook stays off, because the hooked package only exists on that server. Follows GHSA-wq7j-x5jq-pjrw; this case is ours, not the report's. Guard tests for the workspaces and bunfig.toml refusals, which the previous commit added without them, come along. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
0bcfd75e60
commit
83c788d779
9 files changed
+67
-28
No files matched your search
@@ -83,6 +83,13 @@ class InstallPortalClis(unittest.TestCase):
|
||||
(cli / "bunfig.toml").write_text('[install]\nregistry = "https://registry.example"\n', encoding="utf-8")
|
||||
self.assertIn("bunfig.toml", unsafe_reason(cli))
|
||||
|
||||
def test_npmrc_is_unsafe(self):
|
||||
# Bun reads .npmrc too: a registry line beside the manifest fetches
|
||||
# every dependency from a server the portal's author picked.
|
||||
cli = self.add_cli("x")
|
||||
(cli / ".npmrc").write_text("registry=https://registry.example/\n", encoding="utf-8")
|
||||
self.assertIn(".npmrc", unsafe_reason(cli))
|
||||
|
||||
def test_bun_install_never_runs_lifecycle_scripts(self):
|
||||
# #718: --ignore-scripts on every install, so a dependency's hook stays
|
||||
# off whatever the Bun release's default trust list says.
|
||||
|
||||
@@ -72,10 +72,12 @@ class DependencyHooks(unittest.TestCase):
|
||||
(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")
|
||||
# The registry goes in through the environment: a .npmrc beside
|
||||
# the manifest is one of the things the installer now refuses.
|
||||
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")}
|
||||
"BUN_INSTALL_CACHE_DIR": str(root / "cache"),
|
||||
"NPM_CONFIG_REGISTRY": f"http://127.0.0.1:{server.server_port}/"}
|
||||
if "SYSTEMROOT" in os.environ:
|
||||
env["SYSTEMROOT"] = os.environ["SYSTEMROOT"]
|
||||
proc = subprocess.run([sys.executable, str(tools / "install_portal_clis.py")],
|
||||
|
||||
@@ -874,6 +874,30 @@ class ManifestGuardTests(GuardRepoFixture):
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertIn("trustedDependencies", result.stdout)
|
||||
|
||||
# GHSA-wq7j-x5jq-pjrw: the other doors into `bun install`. Workspace
|
||||
# packages carry scripts this check never reads; a config file beside the
|
||||
# manifest (bunfig.toml, .npmrc) can point every dependency at another
|
||||
# registry. The installer refuses the same things.
|
||||
def test_workspaces_fails(self):
|
||||
self.write_manifest({"name": "example-cli", "workspaces": ["packages/*"]})
|
||||
result = run_guards(self.root)
|
||||
self.assertEqual(result.returncode, 1)
|
||||
self.assertIn("workspaces", result.stdout)
|
||||
|
||||
def test_install_config_file_beside_manifest_fails(self):
|
||||
for name, body in (("bunfig.toml", '[install]\nregistry = "https://registry.example/"\n'),
|
||||
(".npmrc", "registry=https://registry.example/\n")):
|
||||
with self.subTest(file=name):
|
||||
config = self.manifest.parent / name
|
||||
config.write_text(body, encoding="utf-8")
|
||||
try:
|
||||
result = run_guards(self.root)
|
||||
finally:
|
||||
config.unlink()
|
||||
self.assertEqual(result.returncode, 1, result.stdout)
|
||||
self.assertIn(name, result.stdout)
|
||||
self.assertIn("example-search/cli/" + name, result.stdout.replace("\\", "/"))
|
||||
|
||||
def test_malformed_manifest_shape_fails_cleanly(self):
|
||||
for data, message in [
|
||||
([], "top-level JSON value must be an object"),
|
||||
|
||||
Reference in new issue
Block a user