dependabot-common 0.325.1 → 0.326.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba085c2069cfc7b9437a7cbc49c548cf314245c119f8a1f298e3fba5de59fb7c
4
- data.tar.gz: ad59447a4ce03bfacae2a04e9b2880fbfba0ce7ac825187c80e0b783949fc3fb
3
+ metadata.gz: 3695212089e3d38adf8800ef559aa7a5b7810bbb858cbcb7da59dd892e70dbb7
4
+ data.tar.gz: f85bfcb72c316ce232598fe58ccbf26bb7f567feb7ead474cb9e90bcf83d4948
5
5
  SHA512:
6
- metadata.gz: af5bc9099d1ebe204df3dd481a2f777d4debf52dde8a6eafcd4d4ecb1df0fc95ad02639f833aeaa76ba459b469df05ffcac44eed70a61996b3ee8956eda7196d
7
- data.tar.gz: 6bf1193f09e83ed48a5505c3fb60a0855db365ab12c13f9a8b81e868aea8a1f664d74c8a2b8284f9a4f7e72135f3b41cec62dddab78042e08fa61f340f96091d
6
+ metadata.gz: 4f60dee3b855b61b43f618b76d9a96f72861f25f2a986ae29e87e65ab19aa6a49c0023390878c1550070acc44d98d861e4acbb26a1f9f006f1c061fb81b09ecb
7
+ data.tar.gz: 41d051c22efaf95ac33638d3fa17b4e6068845c87bbe643f980dac94d99c3bd842b34006a0e9d7a37b3780bc43970d9e371319382124d0803688a5e499b7a126
@@ -34,14 +34,15 @@ module Dependabot
34
34
  end
35
35
  def update_config(package_manager, directory: nil, target_branch: nil)
36
36
  dir = directory || "/"
37
- package_ecosystem = PACKAGE_MANAGER_LOOKUP.invert.fetch(package_manager)
37
+ package_ecosystem = REVERSE_PACKAGE_MANAGER_LOOKUP.fetch(package_manager, "dummy")
38
38
  cfg = updates.find do |u|
39
39
  u[:"package-ecosystem"] == package_ecosystem && u[:directory] == dir &&
40
40
  (target_branch.nil? || u[:"target-branch"] == target_branch)
41
41
  end
42
42
  UpdateConfig.new(
43
43
  ignore_conditions: ignore_conditions(cfg),
44
- commit_message_options: commit_message_options(cfg)
44
+ commit_message_options: commit_message_options(cfg),
45
+ exclude_paths: exclude_paths(cfg)
45
46
  )
46
47
  end
47
48
 
@@ -86,6 +87,11 @@ module Dependabot
86
87
  "vcpkg" => "vcpkg"
87
88
  }.freeze, T::Hash[String, String])
88
89
 
90
+ REVERSE_PACKAGE_MANAGER_LOOKUP = T.let(
91
+ PACKAGE_MANAGER_LOOKUP.invert.freeze,
92
+ T::Hash[String, String]
93
+ )
94
+
89
95
  sig { params(cfg: T.nilable(T::Hash[Symbol, T.untyped])).returns(T::Array[IgnoreCondition]) }
90
96
  def ignore_conditions(cfg)
91
97
  ignores = cfg&.dig(:ignore) || []
@@ -109,6 +115,11 @@ module Dependabot
109
115
  include: commit_message[:include]
110
116
  )
111
117
  end
118
+
119
+ sig { params(cfg: T.nilable(T::Hash[Symbol, T.untyped])).returns(T::Array[String]) }
120
+ def exclude_paths(cfg)
121
+ Array(cfg&.dig(:"exclude-paths") || [])
122
+ end
112
123
  end
113
124
  end
114
125
  end
@@ -16,15 +16,20 @@ module Dependabot
16
16
  sig { returns(T::Array[IgnoreCondition]) }
17
17
  attr_reader :ignore_conditions
18
18
 
19
+ sig { returns(T.nilable(T::Array[String])) }
20
+ attr_reader :exclude_paths
21
+
19
22
  sig do
20
23
  params(
21
24
  ignore_conditions: T.nilable(T::Array[IgnoreCondition]),
22
- commit_message_options: T.nilable(CommitMessageOptions)
25
+ commit_message_options: T.nilable(CommitMessageOptions),
26
+ exclude_paths: T.nilable(T::Array[String])
23
27
  ).void
24
28
  end
25
- def initialize(ignore_conditions: nil, commit_message_options: nil)
29
+ def initialize(ignore_conditions: nil, commit_message_options: nil, exclude_paths: nil)
26
30
  @ignore_conditions = T.let(ignore_conditions || [], T::Array[IgnoreCondition])
27
31
  @commit_message_options = commit_message_options
32
+ @exclude_paths = exclude_paths
28
33
  end
29
34
 
30
35
  sig { params(dependency: Dependency, security_updates_only: T::Boolean).returns(T::Array[String]) }
@@ -102,12 +102,13 @@ module Dependabot
102
102
  directory: T.nilable(String),
103
103
  subdependency_metadata: T.nilable(T::Array[T::Hash[T.any(Symbol, String), String]]),
104
104
  removed: T::Boolean,
105
- metadata: T.nilable(T::Hash[T.any(Symbol, String), String])
105
+ metadata: T.nilable(T::Hash[T.any(Symbol, String), String]),
106
+ direct_relationship: T::Boolean
106
107
  ).void
107
108
  end
108
109
  def initialize(name:, requirements:, package_manager:, version: nil,
109
110
  previous_version: nil, previous_requirements: nil, directory: nil,
110
- subdependency_metadata: [], removed: false, metadata: {})
111
+ subdependency_metadata: [], removed: false, metadata: {}, direct_relationship: false)
111
112
  @name = name
112
113
  @version = T.let(
113
114
  case version
@@ -134,6 +135,7 @@ module Dependabot
134
135
  end
135
136
  @removed = removed
136
137
  @metadata = T.let(symbolize_keys(metadata || {}), T::Hash[Symbol, T.untyped])
138
+ @direct_relationship = direct_relationship
137
139
 
138
140
  check_values
139
141
  end
@@ -145,6 +147,12 @@ module Dependabot
145
147
  requirements.any?
146
148
  end
147
149
 
150
+ # used to support lockfile parsing/DependencySubmission
151
+ sig { returns(T::Boolean) }
152
+ def direct?
153
+ top_level? || @direct_relationship
154
+ end
155
+
148
156
  sig { returns(T::Boolean) }
149
157
  def removed?
150
158
  @removed
@@ -28,6 +28,14 @@ module Dependabot
28
28
  sig { returns(T::Boolean) }
29
29
  attr_accessor :vendored_file
30
30
 
31
+ # Dependency file priority is used to determine which files are relevant when generating a dependency graph for the
32
+ # project - only the highest priority files will be graphed for each directory.
33
+ #
34
+ # This allows us to default to treating all dependency files as relevant unless the ecosystem's file parser tells
35
+ # us otherwise, for example indicating that a Gemfile.lock fully supersedes its peered Gemfile.
36
+ sig { returns(Integer) }
37
+ attr_accessor :priority
38
+
31
39
  sig { returns(T.nilable(String)) }
32
40
  attr_accessor :symlink_target
33
41
 
@@ -40,6 +48,9 @@ module Dependabot
40
48
  sig { returns(T.nilable(String)) }
41
49
  attr_accessor :mode
42
50
 
51
+ sig { returns(T::Set[T.untyped]) }
52
+ attr_accessor :dependencies
53
+
43
54
  class ContentEncoding
44
55
  UTF_8 = "utf-8"
45
56
  BASE64 = "base64"
@@ -75,14 +86,15 @@ module Dependabot
75
86
  content_encoding: String,
76
87
  deleted: T::Boolean,
77
88
  operation: String,
78
- mode: T.nilable(String)
89
+ mode: T.nilable(String),
90
+ priority: Integer
79
91
  )
80
92
  .void
81
93
  end
82
94
  def initialize(name:, content:, directory: "/", type: "file",
83
95
  support_file: false, vendored_file: false, symlink_target: nil,
84
96
  content_encoding: ContentEncoding::UTF_8, deleted: false,
85
- operation: Operation::UPDATE, mode: nil)
97
+ operation: Operation::UPDATE, mode: nil, priority: 0)
86
98
  @name = name
87
99
  @content = content
88
100
  @directory = T.let(clean_directory(directory), String)
@@ -92,6 +104,8 @@ module Dependabot
92
104
  @content_encoding = content_encoding
93
105
  @operation = operation
94
106
  @mode = mode
107
+ @dependencies = T.let(Set.new, T::Set[T.untyped])
108
+ @priority = priority
95
109
  raise ArgumentError, "Invalid Git mode: #{mode}" if mode && !VALID_MODES.include?(mode)
96
110
 
97
111
  # Make deleted override the operation. Deleted is kept when operation
@@ -100,14 +100,16 @@ module Dependabot
100
100
  source: Dependabot::Source,
101
101
  credentials: T::Array[Dependabot::Credential],
102
102
  repo_contents_path: T.nilable(String),
103
- options: T::Hash[String, String]
103
+ options: T::Hash[String, String],
104
+ update_config: T.nilable(Dependabot::Config::UpdateConfig)
104
105
  )
105
106
  .void
106
107
  end
107
- def initialize(source:, credentials:, repo_contents_path: nil, options: {})
108
+ def initialize(source:, credentials:, repo_contents_path: nil, options: {}, update_config: nil)
108
109
  @source = source
109
110
  @credentials = credentials
110
111
  @repo_contents_path = repo_contents_path
112
+ @exclude_paths = T.let(update_config&.exclude_paths || [], T::Array[String])
111
113
  @linked_paths = T.let({}, T::Hash[T.untyped, T.untyped])
112
114
  @submodules = T.let([], T::Array[T.untyped])
113
115
  @options = options
@@ -115,6 +117,13 @@ module Dependabot
115
117
  @files = T.let([], T::Array[DependencyFile])
116
118
  end
117
119
 
120
+ # rubocop:disable Style/TrivialAccessors
121
+ sig { params(excludes: T::Array[String]).void }
122
+ def exclude_paths=(excludes)
123
+ @exclude_paths = excludes
124
+ end
125
+ # rubocop:enable Style/TrivialAccessors
126
+
118
127
  sig { returns(String) }
119
128
  def repo
120
129
  source.repo
@@ -453,14 +462,18 @@ module Dependabot
453
462
  params(path: String, fetch_submodules: T::Boolean, raise_errors: T::Boolean)
454
463
  .returns(T::Array[OpenStruct])
455
464
  end
456
- def _fetch_repo_contents(path, fetch_submodules: false,
457
- raise_errors: true)
465
+ def _fetch_repo_contents(path, fetch_submodules: false, raise_errors: true) # rubocop:disable Metrics/PerceivedComplexity
458
466
  path = path.gsub(" ", "%20")
459
467
  provider, repo, tmp_path, commit =
460
468
  _full_specification_for(path, fetch_submodules: fetch_submodules)
461
469
  .values_at(:provider, :repo, :path, :commit)
462
470
 
463
- _fetch_repo_contents_fully_specified(provider, repo, tmp_path, commit)
471
+ entries = _fetch_repo_contents_fully_specified(provider, repo, tmp_path, commit)
472
+ if Dependabot::Experiments.enabled?(:enable_exclude_paths_subdirectory_manifest_files)
473
+ filter_excluded(entries)
474
+ else
475
+ entries
476
+ end
464
477
  rescue *CLIENT_NOT_FOUND_ERRORS
465
478
  raise Dependabot::DirectoryNotFound, directory if path == directory.gsub(%r{^/*}, "")
466
479
 
@@ -522,7 +535,7 @@ module Dependabot
522
535
  repo_path = File.join(clone_repo_contents, relative_path)
523
536
  return [] unless Dir.exist?(repo_path)
524
537
 
525
- Dir.entries(repo_path).sort.filter_map do |name|
538
+ entries = Dir.entries(repo_path).sort.filter_map do |name|
526
539
  next if name == "." || name == ".."
527
540
 
528
541
  absolute_path = File.join(repo_path, name)
@@ -541,6 +554,66 @@ module Dependabot
541
554
  size: 0 # NOTE: added for parity with github contents API
542
555
  )
543
556
  end
557
+ if Dependabot::Experiments.enabled?(:enable_exclude_paths_subdirectory_manifest_files)
558
+ filter_excluded(entries)
559
+ else
560
+ entries
561
+ end
562
+ end
563
+
564
+ # Filters out any entries whose paths match one of the exclude_paths globs.
565
+ sig { params(entries: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
566
+ def filter_excluded(entries) # rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/AbcSize
567
+ Dependabot.logger.info("DEBUG filter_excluded: entries=#{entries.length}, exclude_paths=#{@exclude_paths.inspect}") # rubocop:disable Layout/LineLength
568
+
569
+ return entries if @exclude_paths.empty?
570
+
571
+ filtered_entries = entries.reject do |entry|
572
+ full_entry_path = entry.path
573
+ Dependabot.logger.info("DEBUG: Checking entry path: #{full_entry_path}")
574
+
575
+ @exclude_paths.any? do |exclude_pattern|
576
+ Dependabot.logger.info("DEBUG: Testing pattern: #{exclude_pattern} against path: #{full_entry_path}")
577
+
578
+ # case 1: exact match
579
+ exclude_exact = full_entry_path == exclude_pattern
580
+
581
+ # case 2: Directory prefix matching: check if path is inside an excluded directory
582
+ exclude_deeper = full_entry_path.start_with?("#{exclude_pattern}#{File::SEPARATOR}",
583
+ "#{exclude_pattern}/")
584
+
585
+ # case 3: Explicit recursive (patterns that end with /**)
586
+ exclude_recursive = false
587
+ if exclude_pattern.end_with?("/**")
588
+ base_pattern = exclude_pattern[0...-3]
589
+ exclude_recursive = full_entry_path == base_pattern ||
590
+ full_entry_path.start_with?("#{base_pattern}/") ||
591
+ full_entry_path.start_with?("#{base_pattern}#{File::SEPARATOR}")
592
+ end
593
+
594
+ # case 4: Glob pattern matching with enhanced flags
595
+ # Use multiple fnmatch attempts with different flag combinations
596
+ fnmatch_flags = [
597
+ File::FNM_EXTGLOB,
598
+ File::FNM_EXTGLOB | File::FNM_PATHNAME,
599
+ File::FNM_EXTGLOB | File::FNM_PATHNAME | File::FNM_DOTMATCH,
600
+ File::FNM_PATHNAME
601
+ ]
602
+ exclude_fnmatch_paths = fnmatch_flags.any? do |flag|
603
+ File.fnmatch?(exclude_pattern, full_entry_path, flag)
604
+ end
605
+
606
+ result = exclude_exact || exclude_deeper || exclude_recursive || exclude_fnmatch_paths
607
+ Dependabot.logger.info("DEBUG: Pattern #{exclude_pattern} vs #{full_entry_path} -> #{result ? 'EXCLUDED' : 'INCLUDED'}") # rubocop:disable Layout/LineLength
608
+ result
609
+ end
610
+ end
611
+
612
+ Dependabot.logger.info("DEBUG filter_excluded: Filtered from #{entries.length} to #{filtered_entries.length} entries") # rubocop:disable Layout/LineLength
613
+ filtered_entries
614
+ rescue StandardError => e
615
+ Dependabot.logger.warn("Error while filtering exclude paths patterns: #{e.message}")
616
+ entries
544
617
  end
545
618
 
546
619
  sig { params(file: Sawyer::Resource).returns(OpenStruct) }
@@ -56,7 +56,7 @@ module Dependabot
56
56
  sig { params(package_manager: String).void }
57
57
  def self.validate_package_manager!(package_manager)
58
58
  # Official package manager
59
- return if Config::File::PACKAGE_MANAGER_LOOKUP.invert.key?(package_manager)
59
+ return if Config::File::REVERSE_PACKAGE_MANAGER_LOOKUP.key?(package_manager)
60
60
 
61
61
  # Used by specs
62
62
  return if package_manager == "dummy" || package_manager == "silent"
data/lib/dependabot.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
5
- VERSION = "0.325.1"
5
+ VERSION = "0.326.1"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.325.1
4
+ version: 0.326.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -625,7 +625,7 @@ licenses:
625
625
  - MIT
626
626
  metadata:
627
627
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
628
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.325.1
628
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.326.1
629
629
  rdoc_options: []
630
630
  require_paths:
631
631
  - lib