diff --git a/Library/Homebrew/bundle/extensions/npm.rb b/Library/Homebrew/bundle/extensions/npm.rb index e3e686cc87f51..820ad8146d079 100644 --- a/Library/Homebrew/bundle/extensions/npm.rb +++ b/Library/Homebrew/bundle/extensions/npm.rb @@ -2,6 +2,7 @@ # frozen_string_literal: true require "bundle/extensions/extension" +require "language/node" module Homebrew module Bundle @@ -60,7 +61,7 @@ def install_package!(name, with: nil, verbose: false) npm = package_manager_executable! - Bundle.system(npm.to_s, "install", "-g", name, verbose:) + Bundle.system(npm.to_s, "install", *Language::Node.npm_install_security_args, "-g", name, verbose:) end sig { override.returns(T::Array[String]) } diff --git a/Library/Homebrew/language/node.rb b/Library/Homebrew/language/node.rb index 531ae3542a260..b707b4bd10a30 100644 --- a/Library/Homebrew/language/node.rb +++ b/Library/Homebrew/language/node.rb @@ -15,6 +15,18 @@ def self.npm_cache_config "cache=#{HOMEBREW_CACHE}/npm_cache" end + sig { params(ignore_scripts: T::Boolean).returns(T::Array[String]) } + def self.npm_install_security_args(ignore_scripts: true) + args = %W[ + --min-release-age=1 + --#{npm_cache_config} + ] + + args << "--ignore-scripts" if ignore_scripts + + args + end + sig { returns(String) } def self.pack_for_installation # Homebrew assumes the buildpath/testpath will always be disposable @@ -68,17 +80,15 @@ def self.std_npm_install_args(libexec, ignore_scripts: true) # npm install args for global style module format installed into libexec # Delay packages published in the last day so builds are less likely to # install a freshly compromised npm release or dependency. - args = %W[ + args = %w[ --loglevel=silly --global --build-from-source - --min-release-age=1 - --#{npm_cache_config} + ] + npm_install_security_args(ignore_scripts:) + %W[ --prefix=#{libexec} #{Dir.pwd}/#{pack} ] - args << "--ignore-scripts" if ignore_scripts args << "--unsafe-perm" if Process.uid.zero? args @@ -90,16 +100,10 @@ def self.local_npm_install_args(ignore_scripts: true) # npm install args for local style module format # Delay packages published in the last day so builds are less likely to # install a freshly compromised npm release or dependency. - args = %W[ + %w[ --loglevel=silly --build-from-source - --min-release-age=1 - --#{npm_cache_config} - ] - - args << "--ignore-scripts" if ignore_scripts - - args + ] + npm_install_security_args(ignore_scripts:) end # Mixin module for {Formula} adding shebang rewrite features. diff --git a/Library/Homebrew/test/bundle/npm_spec.rb b/Library/Homebrew/test/bundle/npm_spec.rb index 3bc553c7354c1..ba9cc264e1ed0 100644 --- a/Library/Homebrew/test/bundle/npm_spec.rb +++ b/Library/Homebrew/test/bundle/npm_spec.rb @@ -4,6 +4,7 @@ require "bundle" require "bundle/dsl" require "bundle/extensions/npm" +require "language/node" RSpec.describe Homebrew::Bundle::Npm do let(:klass) { Homebrew::Bundle::Npm } @@ -161,7 +162,16 @@ it "installs package" do expect(Homebrew::Bundle).to receive(:system) - .with("/opt/homebrew/bin/npm", "install", "-g", "vercel", verbose: false) + .with( + "/opt/homebrew/bin/npm", + "install", + "--min-release-age=1", + "--cache=#{HOMEBREW_CACHE}/npm_cache", + "--ignore-scripts", + "-g", + "vercel", + verbose: false, + ) .and_return(true) expect(klass.preinstall!("vercel")).to be(true) expect(klass.install!("vercel")).to be(true) diff --git a/Library/Homebrew/test/language/node_spec.rb b/Library/Homebrew/test/language/node_spec.rb index a566f53dfb0e2..d8ef53b3086a9 100644 --- a/Library/Homebrew/test/language/node_spec.rb +++ b/Library/Homebrew/test/language/node_spec.rb @@ -77,6 +77,16 @@ end end + describe "#npm_install_security_args" do + it "includes only npm install security arguments" do + expect(klass.npm_install_security_args).to eq([ + "--min-release-age=1", + "--cache=#{HOMEBREW_CACHE}/npm_cache", + "--ignore-scripts", + ]) + end + end + describe "#local_npm_install_args" do before do allow(klass).to receive(:setup_npm_environment)