@@ -164,7 +164,20 @@ def run_yarn_berry_updater(path, lockfile_name)
164164 "up -R #{ dependency . name } #{ Helpers . yarn_berry_args } " . strip ,
165165 fingerprint : "up -R <dependency_name> #{ Helpers . yarn_berry_args } " . strip
166166 )
167- { lockfile_name => File . read ( lockfile_name ) }
167+
168+ updated_content = File . read ( lockfile_name )
169+ if yarn_update_was_noop? ( updated_content )
170+ begin
171+ NativeHelpers . run_yarn_audit_fix_command
172+ rescue SharedHelpers ::HelperSubprocessFailed
173+ Dependabot . logger . info (
174+ "yarn npm audit --fix failed or partially fixed — continuing with any changes made"
175+ )
176+ end
177+ updated_content = File . read ( lockfile_name )
178+ end
179+
180+ { lockfile_name => updated_content }
168181 end
169182 end
170183 end
@@ -177,7 +190,24 @@ def run_pnpm_updater(path, lockfile_name)
177190 "update #{ dependency . name } --lockfile-only" ,
178191 fingerprint : "update <dependency_name> --lockfile-only"
179192 )
180- { lockfile_name => File . read ( lockfile_name ) }
193+
194+ updated_content = File . read ( lockfile_name )
195+ if pnpm_update_was_noop? ( updated_content )
196+ begin
197+ NativeHelpers . run_pnpm_audit_fix_command
198+ Helpers . run_pnpm_command (
199+ "install --lockfile-only" ,
200+ fingerprint : "install --lockfile-only"
201+ )
202+ rescue SharedHelpers ::HelperSubprocessFailed
203+ Dependabot . logger . info (
204+ "pnpm audit --fix failed or partially fixed — continuing with any changes made"
205+ )
206+ end
207+ updated_content = File . read ( lockfile_name )
208+ end
209+
210+ { lockfile_name => updated_content }
181211 end
182212 end
183213 end
@@ -188,11 +218,51 @@ def run_npm_updater(path, lockfile_name)
188218 Dir . chdir ( path ) do
189219 NativeHelpers . run_npm8_subdependency_update_command ( [ dependency . name ] )
190220
191- { lockfile_name => File . read ( lockfile_name ) }
221+ updated_content = File . read ( lockfile_name )
222+ if npm_update_was_noop? ( updated_content )
223+ # `npm update` is a no-op for transitive dependencies not in
224+ # any package.json (common in workspace repos). Fall back to
225+ # `npm audit fix` which can resolve these in the lockfile.
226+ # npm audit fix exits non-zero when vulnerabilities remain, so
227+ # we rescue and use whatever lockfile changes it managed to make.
228+ begin
229+ NativeHelpers . run_npm_audit_fix_command
230+ rescue SharedHelpers ::HelperSubprocessFailed
231+ Dependabot . logger . info ( "npm audit fix failed or partially fixed — continuing with any changes made" )
232+ end
233+ updated_content = File . read ( lockfile_name )
234+ end
235+
236+ { lockfile_name => updated_content }
192237 end
193238 end
194239 end
195240
241+ sig { params ( updated_content : String ) . returns ( T ::Boolean ) }
242+ def npm_update_was_noop? ( updated_content )
243+ parsed = JSON . parse ( updated_content )
244+ packages = parsed . fetch ( "packages" , { } )
245+
246+ packages . any? do |path , details |
247+ next false unless path . end_with? ( "/#{ dependency . name } " ) ||
248+ path == "node_modules/#{ dependency . name } "
249+
250+ details [ "version" ] == dependency . version
251+ end
252+ end
253+
254+ sig { params ( updated_content : String ) . returns ( T ::Boolean ) }
255+ def yarn_update_was_noop? ( updated_content )
256+ updated_content . include? ( "\" #{ dependency . name } @" ) &&
257+ updated_content . include? ( "version: #{ dependency . version } " )
258+ end
259+
260+ sig { params ( updated_content : String ) . returns ( T ::Boolean ) }
261+ def pnpm_update_was_noop? ( updated_content )
262+ updated_content . include? ( "'#{ dependency . name } @#{ dependency . version } '" ) ||
263+ updated_content . include? ( "/#{ dependency . name } @#{ dependency . version } " )
264+ end
265+
196266 sig { params ( path : String , lockfile_name : String ) . returns ( T ::Hash [ String , String ] ) }
197267 def run_npm6_updater ( path , lockfile_name )
198268 SharedHelpers . with_git_configured ( credentials : credentials ) do
0 commit comments