dependabot-core 0.76.11 → 0.77.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5a81bf12f28897fd225b92b4e37e0476b0896fcc58685457173f696f3010c44
4
- data.tar.gz: b30ff79c7eb025531e5d559270f7f13b06d4a0fd099f478a3019a9ad9fa2fe63
3
+ metadata.gz: 643315e66fbeb494837f087852166010e52b5c24daf7ff8c459bbf660b0d4d63
4
+ data.tar.gz: cfff2982eda91bc92af1e374d0a7071610ef4d9ace6024185ebffc1c28cc01b5
5
5
  SHA512:
6
- metadata.gz: b1379cee6737a8d68f06463024c9793f1db3ffc0750af144e358e717ae8fab08febb492c7ff4638bd8b74980d257cf7ca50d901be33f51e757409dc5ee68c8cc
7
- data.tar.gz: 527956ec32bea4528e5868d2168cd9ac5c23331783a8da287393a00b7a669dee2a8cfdb91066bbd315deb93dd23b623c0f4461e2ff177d2eda1bfb33ca7e2f4f
6
+ metadata.gz: e5436d554912bd92166d5580fd7737fad37b69feb0a7acef0d5fe1f3e3c465ce62ea03580486a0ddd3a5ca1dd3e3dee8f3e7d65743f34a3e25089b3af98b1b3d
7
+ data.tar.gz: 0deffbebb24d5c99233a0522305fb911e9111bd466bf2f7aa54f4494cd917e4c9c8f34ba4ae4c11c29d1879bdb4b1e905a46b1397903f4a40f858c120a23d077
@@ -1,3 +1,7 @@
1
+ ## v0.77.0, 7 December 2018
2
+
3
+ - Move Docker support to a separate gem
4
+
1
5
  ## v0.76.11, 7 December 2018
2
6
 
3
7
  - Python: Ignore dependencies that we had to insert a version for
@@ -7,7 +7,6 @@ require "dependabot/file_fetchers/java/maven"
7
7
  require "dependabot/file_fetchers/java/gradle"
8
8
  require "dependabot/file_fetchers/php/composer"
9
9
  require "dependabot/file_fetchers/git/submodules"
10
- require "dependabot/file_fetchers/docker/docker"
11
10
  require "dependabot/file_fetchers/elixir/hex"
12
11
  require "dependabot/file_fetchers/rust/cargo"
13
12
  require "dependabot/file_fetchers/dotnet/nuget"
@@ -25,7 +24,6 @@ module Dependabot
25
24
  "pip" => FileFetchers::Python::Pip,
26
25
  "composer" => FileFetchers::Php::Composer,
27
26
  "submodules" => FileFetchers::Git::Submodules,
28
- "docker" => FileFetchers::Docker::Docker,
29
27
  "hex" => FileFetchers::Elixir::Hex,
30
28
  "cargo" => FileFetchers::Rust::Cargo,
31
29
  "nuget" => FileFetchers::Dotnet::Nuget,
@@ -7,7 +7,6 @@ require "dependabot/file_parsers/java/maven"
7
7
  require "dependabot/file_parsers/java/gradle"
8
8
  require "dependabot/file_parsers/php/composer"
9
9
  require "dependabot/file_parsers/git/submodules"
10
- require "dependabot/file_parsers/docker/docker"
11
10
  require "dependabot/file_parsers/elixir/hex"
12
11
  require "dependabot/file_parsers/rust/cargo"
13
12
  require "dependabot/file_parsers/dotnet/nuget"
@@ -25,7 +24,6 @@ module Dependabot
25
24
  "pip" => FileParsers::Python::Pip,
26
25
  "composer" => FileParsers::Php::Composer,
27
26
  "submodules" => FileParsers::Git::Submodules,
28
- "docker" => FileParsers::Docker::Docker,
29
27
  "hex" => FileParsers::Elixir::Hex,
30
28
  "cargo" => FileParsers::Rust::Cargo,
31
29
  "nuget" => FileParsers::Dotnet::Nuget,
@@ -7,7 +7,6 @@ require "dependabot/file_updaters/java/maven"
7
7
  require "dependabot/file_updaters/java/gradle"
8
8
  require "dependabot/file_updaters/php/composer"
9
9
  require "dependabot/file_updaters/git/submodules"
10
- require "dependabot/file_updaters/docker/docker"
11
10
  require "dependabot/file_updaters/elixir/hex"
12
11
  require "dependabot/file_updaters/rust/cargo"
13
12
  require "dependabot/file_updaters/dotnet/nuget"
@@ -25,7 +24,6 @@ module Dependabot
25
24
  "pip" => FileUpdaters::Python::Pip,
26
25
  "composer" => FileUpdaters::Php::Composer,
27
26
  "submodules" => FileUpdaters::Git::Submodules,
28
- "docker" => FileUpdaters::Docker::Docker,
29
27
  "hex" => FileUpdaters::Elixir::Hex,
30
28
  "cargo" => FileUpdaters::Rust::Cargo,
31
29
  "nuget" => FileUpdaters::Dotnet::Nuget,
@@ -6,7 +6,6 @@ require "dependabot/metadata_finders/java_script/npm_and_yarn"
6
6
  require "dependabot/metadata_finders/java/maven"
7
7
  require "dependabot/metadata_finders/php/composer"
8
8
  require "dependabot/metadata_finders/git/submodules"
9
- require "dependabot/metadata_finders/docker/docker"
10
9
  require "dependabot/metadata_finders/elixir/hex"
11
10
  require "dependabot/metadata_finders/rust/cargo"
12
11
  require "dependabot/metadata_finders/dotnet/nuget"
@@ -23,7 +22,6 @@ module Dependabot
23
22
  "pip" => MetadataFinders::Python::Pip,
24
23
  "composer" => MetadataFinders::Php::Composer,
25
24
  "submodules" => MetadataFinders::Git::Submodules,
26
- "docker" => MetadataFinders::Docker::Docker,
27
25
  "hex" => MetadataFinders::Elixir::Hex,
28
26
  "cargo" => MetadataFinders::Rust::Cargo,
29
27
  "nuget" => MetadataFinders::Dotnet::Nuget,
@@ -7,7 +7,6 @@ require "dependabot/update_checkers/java/maven"
7
7
  require "dependabot/update_checkers/java/gradle"
8
8
  require "dependabot/update_checkers/php/composer"
9
9
  require "dependabot/update_checkers/git/submodules"
10
- require "dependabot/update_checkers/docker/docker"
11
10
  require "dependabot/update_checkers/elixir/hex"
12
11
  require "dependabot/update_checkers/rust/cargo"
13
12
  require "dependabot/update_checkers/dotnet/nuget"
@@ -25,7 +24,6 @@ module Dependabot
25
24
  "pip" => UpdateCheckers::Python::Pip,
26
25
  "composer" => UpdateCheckers::Php::Composer,
27
26
  "submodules" => UpdateCheckers::Git::Submodules,
28
- "docker" => UpdateCheckers::Docker::Docker,
29
27
  "hex" => UpdateCheckers::Elixir::Hex,
30
28
  "cargo" => UpdateCheckers::Rust::Cargo,
31
29
  "nuget" => UpdateCheckers::Dotnet::Nuget,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dependabot
4
- VERSION = "0.76.11"
4
+ VERSION = "0.77.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.76.11
4
+ version: 0.77.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -380,7 +380,6 @@ files:
380
380
  - lib/dependabot/file_fetchers.rb
381
381
  - lib/dependabot/file_fetchers/README.md
382
382
  - lib/dependabot/file_fetchers/base.rb
383
- - lib/dependabot/file_fetchers/docker/docker.rb
384
383
  - lib/dependabot/file_fetchers/dotnet/nuget.rb
385
384
  - lib/dependabot/file_fetchers/dotnet/nuget/import_paths_finder.rb
386
385
  - lib/dependabot/file_fetchers/dotnet/nuget/sln_project_paths_finder.rb
@@ -405,7 +404,6 @@ files:
405
404
  - lib/dependabot/file_parsers/README.md
406
405
  - lib/dependabot/file_parsers/base.rb
407
406
  - lib/dependabot/file_parsers/base/dependency_set.rb
408
- - lib/dependabot/file_parsers/docker/docker.rb
409
407
  - lib/dependabot/file_parsers/dotnet/nuget.rb
410
408
  - lib/dependabot/file_parsers/dotnet/nuget/packages_config_parser.rb
411
409
  - lib/dependabot/file_parsers/dotnet/nuget/project_file_parser.rb
@@ -435,7 +433,6 @@ files:
435
433
  - lib/dependabot/file_updaters.rb
436
434
  - lib/dependabot/file_updaters/README.md
437
435
  - lib/dependabot/file_updaters/base.rb
438
- - lib/dependabot/file_updaters/docker/docker.rb
439
436
  - lib/dependabot/file_updaters/dotnet/nuget.rb
440
437
  - lib/dependabot/file_updaters/dotnet/nuget/packages_config_declaration_finder.rb
441
438
  - lib/dependabot/file_updaters/dotnet/nuget/project_file_declaration_finder.rb
@@ -499,7 +496,6 @@ files:
499
496
  - lib/dependabot/metadata_finders/base/changelog_pruner.rb
500
497
  - lib/dependabot/metadata_finders/base/commits_finder.rb
501
498
  - lib/dependabot/metadata_finders/base/release_finder.rb
502
- - lib/dependabot/metadata_finders/docker/docker.rb
503
499
  - lib/dependabot/metadata_finders/dotnet/nuget.rb
504
500
  - lib/dependabot/metadata_finders/elixir/hex.rb
505
501
  - lib/dependabot/metadata_finders/elm/elm_package.rb
@@ -525,7 +521,6 @@ files:
525
521
  - lib/dependabot/update_checkers.rb
526
522
  - lib/dependabot/update_checkers/README.md
527
523
  - lib/dependabot/update_checkers/base.rb
528
- - lib/dependabot/update_checkers/docker/docker.rb
529
524
  - lib/dependabot/update_checkers/dotnet/nuget.rb
530
525
  - lib/dependabot/update_checkers/dotnet/nuget/property_updater.rb
531
526
  - lib/dependabot/update_checkers/dotnet/nuget/repository_finder.rb
@@ -583,7 +578,6 @@ files:
583
578
  - lib/dependabot/update_checkers/rust/cargo/requirements_updater.rb
584
579
  - lib/dependabot/update_checkers/rust/cargo/version_resolver.rb
585
580
  - lib/dependabot/utils.rb
586
- - lib/dependabot/utils/docker/credentials_finder.rb
587
581
  - lib/dependabot/utils/dotnet/requirement.rb
588
582
  - lib/dependabot/utils/dotnet/version.rb
589
583
  - lib/dependabot/utils/elixir/requirement.rb
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/file_fetchers/base"
4
-
5
- module Dependabot
6
- module FileFetchers
7
- module Docker
8
- class Docker < Dependabot::FileFetchers::Base
9
- def self.required_files_in?(filenames)
10
- filenames.any? { |f| f.match?(/dockerfile/i) }
11
- end
12
-
13
- def self.required_files_message
14
- "Repo must contain a Dockerfile."
15
- end
16
-
17
- private
18
-
19
- def fetch_files
20
- fetched_files = []
21
- fetched_files += dockerfiles
22
-
23
- return fetched_files if fetched_files.any?
24
-
25
- raise(
26
- Dependabot::DependencyFileNotFound,
27
- File.join(directory, "Dockerfile")
28
- )
29
- end
30
-
31
- def dockerfiles
32
- @dockerfiles ||=
33
- repo_contents(raise_errors: false).
34
- select { |f| f.type == "file" && f.name.match?(/dockerfile/i) }.
35
- map { |f| fetch_file_from_host(f.name) }
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,164 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "docker_registry2"
4
-
5
- require "dependabot/dependency"
6
- require "dependabot/file_parsers/base"
7
- require "dependabot/errors"
8
- require "dependabot/utils/docker/credentials_finder"
9
-
10
- module Dependabot
11
- module FileParsers
12
- module Docker
13
- class Docker < Dependabot::FileParsers::Base
14
- require "dependabot/file_parsers/base/dependency_set"
15
-
16
- # Detials of Docker regular expressions is at
17
- # https://github.com/docker/distribution/blob/master/reference/regexp.go
18
- DOMAIN_COMPONENT =
19
- /(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/.freeze
20
- DOMAIN = /(?:#{DOMAIN_COMPONENT}(?:\.#{DOMAIN_COMPONENT})+)/.freeze
21
- REGISTRY = /(?<registry>#{DOMAIN}(?::[0-9]+)?)/.freeze
22
-
23
- NAME_COMPONENT = /(?:[a-z0-9]+(?:(?:[._]|__|[-]*)[a-z0-9]+)*)/.freeze
24
- IMAGE = %r{(?<image>#{NAME_COMPONENT}(?:/#{NAME_COMPONENT})*)}.freeze
25
-
26
- FROM = /[Ff][Rr][Oo][Mm]/.freeze
27
- TAG = /:(?<tag>[\w][\w.-]{0,127})/.freeze
28
- DIGEST = /@(?<digest>[^\s]+)/.freeze
29
- NAME = /\s+AS\s+(?<name>[a-zA-Z0-9_-]+)/.freeze
30
- FROM_LINE =
31
- %r{^#{FROM}\s+(#{REGISTRY}/)?#{IMAGE}#{TAG}?#{DIGEST}?#{NAME}?}.freeze
32
-
33
- AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+).amazonaws\.com/.freeze
34
-
35
- def parse
36
- dependency_set = DependencySet.new
37
-
38
- dockerfiles.each do |dockerfile|
39
- dockerfile.content.each_line do |line|
40
- next unless FROM_LINE.match?(line)
41
-
42
- parsed_from_line = FROM_LINE.match(line).named_captures
43
-
44
- version = version_from(parsed_from_line)
45
- next unless version
46
-
47
- dependency_set << Dependency.new(
48
- name: parsed_from_line.fetch("image"),
49
- version: version,
50
- package_manager: "docker",
51
- requirements: [
52
- requirement: nil,
53
- groups: [],
54
- file: dockerfile.name,
55
- source: source_from(parsed_from_line)
56
- ]
57
- )
58
- end
59
- end
60
-
61
- dependency_set.dependencies
62
- end
63
-
64
- private
65
-
66
- def dockerfiles
67
- # The Docker file fetcher only fetches Dockerfiles, so no need to
68
- # filter here
69
- dependency_files
70
- end
71
-
72
- def version_from(parsed_from_line)
73
- return parsed_from_line.fetch("tag") if parsed_from_line.fetch("tag")
74
-
75
- version_from_digest(
76
- registry: parsed_from_line.fetch("registry"),
77
- image: parsed_from_line.fetch("image"),
78
- digest: parsed_from_line.fetch("digest")
79
- )
80
- end
81
-
82
- def source_from(parsed_from_line)
83
- source = {}
84
-
85
- if parsed_from_line.fetch("registry")
86
- source[:registry] = parsed_from_line.fetch("registry")
87
- end
88
-
89
- if parsed_from_line.fetch("tag")
90
- source[:tag] = parsed_from_line.fetch("tag")
91
- end
92
-
93
- if parsed_from_line.fetch("digest")
94
- source[:digest] = parsed_from_line.fetch("digest")
95
- end
96
-
97
- source
98
- end
99
-
100
- def version_from_digest(registry:, image:, digest:)
101
- return unless digest
102
-
103
- repo = docker_repo_name(image, registry)
104
- registry_client = docker_registry_client(registry)
105
- registry_client.tags(repo).fetch("tags").find do |tag|
106
- digest == registry_client.digest(repo, tag)
107
- rescue DockerRegistry2::NotFound
108
- # Shouldn't happen, but it does. Example of existing tag with
109
- # no manifest is "library/python", "2-windowsservercore".
110
- false
111
- end
112
- rescue DockerRegistry2::RegistryAuthenticationException,
113
- RestClient::Forbidden
114
- raise if standard_registry?(registry)
115
-
116
- raise PrivateSourceAuthenticationFailure, registry
117
- end
118
-
119
- def docker_repo_name(image, registry)
120
- return image unless standard_registry?(registry)
121
- return image unless image.split("/").count < 2
122
-
123
- "library/#{image}"
124
- end
125
-
126
- def docker_registry_client(registry)
127
- if registry
128
- credentials = registry_credentials(registry)
129
-
130
- DockerRegistry2::Registry.new(
131
- "https://#{registry}",
132
- user: credentials&.fetch("username"),
133
- password: credentials&.fetch("password")
134
- )
135
- else
136
- DockerRegistry2::Registry.new("https://registry.hub.docker.com")
137
- end
138
- end
139
-
140
- def registry_credentials(registry_url)
141
- credentials_finder.credentials_for_registry(registry_url)
142
- end
143
-
144
- def credentials_finder
145
- @credentials_finder ||=
146
- Utils::Docker::CredentialsFinder.new(credentials)
147
- end
148
-
149
- def standard_registry?(registry)
150
- return true if registry.nil?
151
-
152
- registry == "registry.hub.docker.com"
153
- end
154
-
155
- def check_required_files
156
- # Just check if there are any files at all.
157
- return if dependency_files.any?
158
-
159
- raise "No Dockerfile!"
160
- end
161
- end
162
- end
163
- end
164
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/file_updaters/base"
4
- require "dependabot/errors"
5
-
6
- module Dependabot
7
- module FileUpdaters
8
- module Docker
9
- class Docker < Dependabot::FileUpdaters::Base
10
- FROM_REGEX = /[Ff][Rr][Oo][Mm]/.freeze
11
-
12
- def self.updated_files_regex
13
- [/dockerfile/]
14
- end
15
-
16
- def updated_dependency_files
17
- updated_files = []
18
-
19
- dependency_files.each do |file|
20
- next unless requirement_changed?(file, dependency)
21
-
22
- updated_files <<
23
- updated_file(
24
- file: file,
25
- content: updated_dockerfile_content(file)
26
- )
27
- end
28
-
29
- updated_files.reject! { |f| dependency_files.include?(f) }
30
- raise "No files changed!" if updated_files.none?
31
-
32
- updated_files
33
- end
34
-
35
- private
36
-
37
- def dependency
38
- # Dockerfiles will only ever be updating a single dependency
39
- dependencies.first
40
- end
41
-
42
- def check_required_files
43
- # Just check if there are any files at all.
44
- return if dependency_files.any?
45
-
46
- raise "No Dockerfile!"
47
- end
48
-
49
- def updated_dockerfile_content(file)
50
- updated_content =
51
- if specified_with_digest?(file)
52
- update_digest_and_tag(file)
53
- else
54
- update_tag(file)
55
- end
56
-
57
- raise "Expected content to change!" if updated_content == file.content
58
-
59
- updated_content
60
- end
61
-
62
- def update_digest_and_tag(file)
63
- old_declaration_regex = /^#{FROM_REGEX}\s+.*@#{old_digest(file)}/
64
-
65
- file.content.gsub(old_declaration_regex) do |old_dec|
66
- old_dec.
67
- gsub("@#{old_digest(file)}", "@#{new_digest(file)}").
68
- gsub(":#{dependency.previous_version}",
69
- ":#{dependency.version}")
70
- end
71
- end
72
-
73
- def update_tag(file)
74
- return unless old_tag(file)
75
-
76
- old_declaration =
77
- if private_registry_url(file) then "#{private_registry_url(file)}/"
78
- else ""
79
- end
80
- old_declaration += "#{dependency.name}:#{old_tag(file)}"
81
- escaped_declaration = Regexp.escape(old_declaration)
82
-
83
- old_declaration_regex = /^#{FROM_REGEX}\s+#{escaped_declaration}/
84
-
85
- file.content.gsub(old_declaration_regex) do |old_dec|
86
- old_dec.gsub(":#{old_tag(file)}", ":#{new_tag(file)}")
87
- end
88
- end
89
-
90
- def specified_with_digest?(file)
91
- dependency.
92
- requirements.
93
- find { |r| r[:file] == file.name }.
94
- fetch(:source)[:digest]
95
- end
96
-
97
- def new_digest(file)
98
- return unless specified_with_digest?(file)
99
-
100
- dependency.requirements.
101
- find { |r| r[:file] == file.name }.
102
- fetch(:source).fetch(:digest)
103
- end
104
-
105
- def old_digest(file)
106
- return unless specified_with_digest?(file)
107
-
108
- dependency.previous_requirements.
109
- find { |r| r[:file] == file.name }.
110
- fetch(:source).fetch(:digest)
111
- end
112
-
113
- def new_tag(file)
114
- dependency.requirements.
115
- find { |r| r[:file] == file.name }.
116
- fetch(:source)[:tag]
117
- end
118
-
119
- def old_tag(file)
120
- dependency.previous_requirements.
121
- find { |r| r[:file] == file.name }.
122
- fetch(:source)[:tag]
123
- end
124
-
125
- def private_registry_url(file)
126
- dependency.requirements.
127
- find { |r| r[:file] == file.name }.
128
- fetch(:source)[:registry]
129
- end
130
- end
131
- end
132
- end
133
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/metadata_finders/base"
4
-
5
- module Dependabot
6
- module MetadataFinders
7
- module Docker
8
- class Docker < Dependabot::MetadataFinders::Base
9
- private
10
-
11
- def look_up_source
12
- # TODO: Find a way to add links to PRs
13
- nil
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,290 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "docker_registry2"
4
-
5
- require "dependabot/update_checkers/base"
6
- require "dependabot/errors"
7
- require "dependabot/utils/docker/credentials_finder"
8
-
9
- module Dependabot
10
- module UpdateCheckers
11
- module Docker
12
- class Docker < Dependabot::UpdateCheckers::Base
13
- VERSION_REGEX = /(?<version>[0-9]+(?:\.[a-zA-Z0-9]+)*)/.freeze
14
- VERSION_WITH_SUFFIX =
15
- /^#{VERSION_REGEX}(?<affix>-[a-z0-9.\-]+)?$/.freeze
16
- VERSION_WITH_PREFIX =
17
- /^(?<affix>[a-z0-9.\-]+-)?#{VERSION_REGEX}$/.freeze
18
- NAME_WITH_VERSION =
19
- /#{VERSION_WITH_PREFIX}|#{VERSION_WITH_SUFFIX}/.freeze
20
-
21
- def latest_version
22
- @latest_version ||= fetch_latest_version
23
- end
24
-
25
- def latest_resolvable_version
26
- # Resolvability isn't an issue for Docker containers.
27
- latest_version
28
- end
29
-
30
- def latest_resolvable_version_with_no_unlock
31
- # No concept of "unlocking" for Docker containers
32
- dependency.version
33
- end
34
-
35
- def updated_requirements
36
- dependency.requirements.map do |req|
37
- updated_source = req.fetch(:source).dup
38
- updated_source[:digest] = updated_digest if req[:source][:digest]
39
- updated_source[:tag] = latest_version if req[:source][:tag]
40
-
41
- req.merge(source: updated_source)
42
- end
43
- end
44
-
45
- private
46
-
47
- def latest_version_resolvable_with_full_unlock?
48
- # Full unlock checks aren't relevant for Dockerfiles
49
- false
50
- end
51
-
52
- def updated_dependencies_after_full_unlock
53
- raise NotImplementedError
54
- end
55
-
56
- def version_can_update?(*)
57
- !version_up_to_date?
58
- end
59
-
60
- def version_up_to_date?
61
- # If the tag isn't up-to-date then we can definitely update
62
- return false if version_tag_up_to_date? == false
63
-
64
- # Otherwise, if the Dockerfile specifies a digest check that that is
65
- # up-to-date
66
- digest_up_to_date?
67
- end
68
-
69
- def version_tag_up_to_date?
70
- return unless dependency.version.match?(NAME_WITH_VERSION)
71
-
72
- old_v = numeric_version_from(dependency.version)
73
- latest_v = numeric_version_from(latest_version)
74
-
75
- return true if version_class.new(latest_v) <= version_class.new(old_v)
76
-
77
- # Check the precision of the potentially higher tag is the same as the
78
- # one it would replace. In the event that it's not the same, check the
79
- # digests are also unequal. Avoids 'updating' ruby-2 -> ruby-2.5.1
80
- return false if old_v.split(".").count == latest_v.split(".").count
81
-
82
- digest_of(dependency.version) == digest_of(latest_version)
83
- end
84
-
85
- def digest_up_to_date?
86
- dependency.requirements.all? do |req|
87
- next true unless req.fetch(:source)[:digest]
88
-
89
- req.fetch(:source).fetch(:digest) == digest_of(dependency.version)
90
- end
91
- end
92
-
93
- # Note: It's important that this *always* returns a version (even if
94
- # it's the existing one) as it is what we later check the digest of.
95
- def fetch_latest_version
96
- unless dependency.version.match?(NAME_WITH_VERSION)
97
- return dependency.version
98
- end
99
-
100
- # Prune out any downgrade tags before checking for pre-releases
101
- # (which requires a call to the registry for each tag, so can be slow)
102
- candidate_tags = comparable_tags_from_registry
103
- non_downgrade_tags = remove_version_downgrades(candidate_tags)
104
- candidate_tags = non_downgrade_tags if non_downgrade_tags.any?
105
-
106
- wants_prerelease = prerelease?(dependency.version)
107
- candidate_tags =
108
- candidate_tags.
109
- reject { |tag| prerelease?(tag) && !wants_prerelease }.
110
- reject do |tag|
111
- version = version_class.new(numeric_version_from(tag))
112
- ignore_reqs.any? { |r| r.satisfied_by?(version) }
113
- end
114
-
115
- latest_tag =
116
- candidate_tags.
117
- max_by { |tag| version_class.new(numeric_version_from(tag)) }
118
-
119
- latest_tag || dependency.version
120
- end
121
-
122
- def comparable_tags_from_registry
123
- original_affix = affix_of(dependency.version)
124
-
125
- tags_from_registry.
126
- select { |tag| tag.match?(NAME_WITH_VERSION) }.
127
- select { |tag| affix_of(tag) == original_affix }.
128
- reject { |tag| commit_sha_suffix?(tag) }
129
- end
130
-
131
- def remove_version_downgrades(candidate_tags)
132
- candidate_tags.select do |tag|
133
- version_class.new(numeric_version_from(tag)) >=
134
- version_class.new(numeric_version_from(dependency.version))
135
- end
136
- end
137
-
138
- def commit_sha_suffix?(tag)
139
- # Some people suffix their versions with commit SHAs. Dependabot
140
- # can't order on those but will try to, so instead we should exclude
141
- # them (unless there's a `latest` version pushed to the registry, in
142
- # which case we'll use that to find the latest version)
143
- return false unless tag.match?(/(^|\-)[0-9a-f]{7,}$/)
144
-
145
- !tag.match?(/(^|\-)20[0-1]\d{5}$/)
146
- end
147
-
148
- def version_of_latest_tag
149
- return unless latest_digest
150
-
151
- tags_from_registry.
152
- select { |tag| canonical_version?(tag) }.
153
- select { |t| digest_of(t) == latest_digest }.
154
- map { |t| version_class.new(numeric_version_from(t)) }.
155
- max
156
- end
157
-
158
- def canonical_version?(tag)
159
- return false unless numeric_version_from(tag)
160
- return true if tag == numeric_version_from(tag)
161
-
162
- # .NET tags are suffixed with -sdk. There may be other cases we need
163
- # to consider in future, too.
164
- tag == numeric_version_from(tag) + "-sdk"
165
- end
166
-
167
- def updated_digest
168
- @updated_digest ||=
169
- begin
170
- docker_registry_client.digest(docker_repo_name, latest_version)
171
- rescue RestClient::Exceptions::Timeout
172
- attempt ||= 1
173
- attempt += 1
174
- raise if attempt > 3
175
-
176
- retry
177
- end
178
- rescue DockerRegistry2::RegistryAuthenticationException,
179
- RestClient::Forbidden
180
- raise PrivateSourceAuthenticationFailure, registry_hostname
181
- end
182
-
183
- def tags_from_registry
184
- @tags_from_registry ||=
185
- begin
186
- docker_registry_client.tags(docker_repo_name).fetch("tags")
187
- rescue RestClient::Exceptions::Timeout
188
- attempt ||= 1
189
- attempt += 1
190
- raise if attempt > 3
191
-
192
- retry
193
- end
194
- rescue DockerRegistry2::RegistryAuthenticationException,
195
- RestClient::Forbidden
196
- raise PrivateSourceAuthenticationFailure, registry_hostname
197
- end
198
-
199
- def latest_digest
200
- return unless tags_from_registry.include?("latest")
201
-
202
- digest_of("latest")
203
- end
204
-
205
- def digest_of(tag)
206
- @digests ||= {}
207
- return @digests[tag] if @digests.key?(tag)
208
-
209
- @digests[tag] =
210
- begin
211
- docker_registry_client.digest(docker_repo_name, tag)
212
- rescue *transient_docker_errors => e
213
- attempt ||= 1
214
- attempt += 1
215
- return if attempt > 3 && e.is_a?(DockerRegistry2::NotFound)
216
- raise if attempt > 3
217
-
218
- retry
219
- end
220
- end
221
-
222
- def transient_docker_errors
223
- [RestClient::Exceptions::Timeout, DockerRegistry2::NotFound]
224
- end
225
-
226
- def affix_of(tag)
227
- tag.match(NAME_WITH_VERSION).named_captures.fetch("affix")
228
- end
229
-
230
- def prerelease?(tag)
231
- return true if numeric_version_from(tag).match?(/[a-zA-Z]/)
232
-
233
- # If we're dealing with a numeric version we can compare it against
234
- # the digest for the `latest` tag.
235
- return false unless numeric_version_from(tag)
236
- return false unless latest_digest
237
- return false unless version_of_latest_tag
238
-
239
- version_class.new(numeric_version_from(tag)) > version_of_latest_tag
240
- end
241
-
242
- def numeric_version_from(tag)
243
- return unless tag.match?(NAME_WITH_VERSION)
244
-
245
- tag.match(NAME_WITH_VERSION).named_captures.fetch("version")
246
- end
247
-
248
- def registry_hostname
249
- dependency.requirements.first[:source][:registry] ||
250
- "registry.hub.docker.com"
251
- end
252
-
253
- def using_dockerhub?
254
- registry_hostname == "registry.hub.docker.com"
255
- end
256
-
257
- def registry_credentials
258
- credentials_finder.credentials_for_registry(registry_hostname)
259
- end
260
-
261
- def credentials_finder
262
- @credentials_finder ||=
263
- Utils::Docker::CredentialsFinder.new(credentials)
264
- end
265
-
266
- def docker_repo_name
267
- return dependency.name unless using_dockerhub?
268
- return dependency.name unless dependency.name.split("/").count < 2
269
-
270
- "library/#{dependency.name}"
271
- end
272
-
273
- def docker_registry_client
274
- @docker_registry_client ||=
275
- DockerRegistry2::Registry.new(
276
- "https://#{registry_hostname}",
277
- user: registry_credentials&.fetch("username"),
278
- password: registry_credentials&.fetch("password")
279
- )
280
- end
281
-
282
- def ignore_reqs
283
- # Note: we use Gem::Requirement here because ignore conditions will
284
- # be passed as Ruby ranges
285
- ignored_versions.map { |req| Gem::Requirement.new(req.split(",")) }
286
- end
287
- end
288
- end
289
- end
290
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "aws-sdk-ecr"
4
- require "base64"
5
-
6
- require "dependabot/errors"
7
-
8
- module Dependabot
9
- module Utils
10
- module Docker
11
- class CredentialsFinder
12
- AWS_ECR_URL = /dkr\.ecr\.(?<region>[^.]+).amazonaws\.com/.freeze
13
-
14
- def initialize(credentials)
15
- @credentials = credentials
16
- end
17
-
18
- def credentials_for_registry(registry_hostname)
19
- registry_details =
20
- credentials.
21
- select { |cred| cred["type"] == "docker_registry" }.
22
- find { |cred| cred.fetch("registry") == registry_hostname }
23
- return unless registry_details
24
- return registry_details unless registry_hostname.match?(AWS_ECR_URL)
25
-
26
- build_aws_credentials(registry_details)
27
- end
28
-
29
- private
30
-
31
- attr_reader :credentials
32
-
33
- def build_aws_credentials(registry_details)
34
- # If credentials have been generated from AWS we can just return them
35
- return registry_details if registry_details.fetch("username") == "AWS"
36
-
37
- # Otherwise, we need to use the provided Access Key ID and secret to
38
- # generate a temporary username and password
39
- aws_credentials = Aws::Credentials.new(
40
- registry_details.fetch("username"),
41
- registry_details.fetch("password")
42
- )
43
-
44
- registry_hostname = registry_details.fetch("registry")
45
- region = registry_hostname.match(AWS_ECR_URL).
46
- named_captures.fetch("region")
47
-
48
- @authorization_tokens ||= {}
49
- @authorization_tokens[registry_hostname] ||=
50
- Aws::ECR::Client.new(region: region, credentials: aws_credentials).
51
- get_authorization_token.authorization_data.first.
52
- authorization_token
53
-
54
- username, password =
55
- Base64.decode64(@authorization_tokens[registry_hostname]).split(":")
56
-
57
- registry_details.merge("username" => username, "password" => password)
58
- rescue Aws::Errors::MissingCredentialsError,
59
- Aws::ECR::Errors::UnrecognizedClientException
60
- raise PrivateSourceAuthenticationFailure, registry_hostname
61
- end
62
- end
63
- end
64
- end
65
- end