authorgravatar for 93147993+hey-jj@users.noreply.github.comJJ <93147993+hey-jj@users.noreply.github.com> 2026-08-15 06:26:32-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-15 12:26:32+00:00
logdc0ff8f13eaa9753fdf0de60203c9e819f1cee27
tree22a9a62c9a4aa47190c1cf5fc2693b53bb8b5d27
parent160c76c6d1c5ab78441e21503cd10e7942b917f6
signature Signed by PGP key B5690EEEBB952194

fix(server): allow install scripts in npm-global provider updates (#5646)


2 files changed, 55 insertions(+), 4 deletions(-)

apps/server/src/provider/providerMaintenance.test.ts+44-3
...@@ -176,7 +176,8 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -176,7 +176,8 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
176 status: "behind_latest",176 status: "behind_latest",
177 currentVersion: "2.1.110",177 currentVersion: "2.1.110",
178 latestVersion: "2.1.117",178 latestVersion: "2.1.117",
179 updateCommand: "npm install -g @example/native-package-tool@latest",179 updateCommand:
180 "npm install -g --allow-scripts=@example/native-package-tool @example/native-package-tool@latest",
180 canUpdate: true,181 canUpdate: true,
181 message: "Install the update now or review provider settings.",182 message: "Install the update now or review provider settings.",
182 });183 });
...@@ -482,11 +483,17 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -482,11 +483,17 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
482 provider: driver("packageTool"),483 provider: driver("packageTool"),
483 packageName: "@example/package-tool",484 packageName: "@example/package-tool",
484 update: {485 update: {
485 command: "npm install -g @example/package-tool@latest",486 command:
487 "npm install -g --allow-scripts=@example/package-tool @example/package-tool@latest",
486488
487 executable: "npm",489 executable: "npm",
488490
489 args: ["install", "-g", "@example/package-tool@latest"],491 args: [
492 "install",
493 "-g",
494 "--allow-scripts=@example/package-tool",
495 "@example/package-tool@latest",
496 ],
490497
491 lockKey: "npm-global",498 lockKey: "npm-global",
492 },499 },
...@@ -541,6 +548,40 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {...@@ -541,6 +548,40 @@ it.layer(NodeServices.layer)("providerMaintenance", (it) => {
541 }),548 }),
542 );549 );
543550
551 it("allows the package's own install scripts in npm global updates", () => {
552 const claudeUpdate = makePackageManagedProviderMaintenanceResolver({
553 provider: driver("claudeAgent"),
554 npmPackageName: "@anthropic-ai/claude-code",
555 homebrewFormula: "claude-code",
556 nativeUpdate: {
557 executable: "claude",
558 args: ["update"],
559 lockKey: "claude-native",
560 isCommandPath: isNativeTestCommandPath("/.local/bin/claude"),
561 },
562 });
563
564 expect(claudeUpdate.resolve()).toEqual({
565 provider: driver("claudeAgent"),
566 packageName: "@anthropic-ai/claude-code",
567 update: {
568 command:
569 "npm install -g --allow-scripts=@anthropic-ai/claude-code @anthropic-ai/claude-code@latest",
570
571 executable: "npm",
572
573 args: [
574 "install",
575 "-g",
576 "--allow-scripts=@anthropic-ai/claude-code",
577 "@anthropic-ai/claude-code@latest",
578 ],
579
580 lockKey: "npm-global",
581 },
582 });
583 });
584
544 it("disables one-click updates for explicit custom binary paths it cannot safely map", () => {585 it("disables one-click updates for explicit custom binary paths it cannot safely map", () => {
545 expect(586 expect(
546 packageToolUpdate.resolve({587 packageToolUpdate.resolve({
apps/server/src/provider/providerMaintenance.ts+11-1
...@@ -137,7 +137,17 @@ function makeNpmGlobalProviderMaintenanceCapabilities(...@@ -137,7 +137,17 @@ function makeNpmGlobalProviderMaintenanceCapabilities(
137 provider: definition.provider,137 provider: definition.provider,
138 packageName: definition.npmPackageName,138 packageName: definition.npmPackageName,
139 updateExecutable: "npm",139 updateExecutable: "npm",
140 updateArgs: ["install", "-g", `${definition.npmPackageName}@latest`],140 // npm 12 blocks install scripts by default (empty allow-scripts allowlist)
141 // and still exits 0, so a package whose postinstall finishes the install
142 // (claude copies its native binary over a placeholder stub) is left broken
143 // while the update reports success. Allow this one package's scripts.
144 // Older npm warns about the unknown config and continues.
145 updateArgs: [
146 "install",
147 "-g",
148 `--allow-scripts=${definition.npmPackageName}`,
149 `${definition.npmPackageName}@latest`,
150 ],
141 updateLockKey: "npm-global",151 updateLockKey: "npm-global",
142 });152 });
143}153}