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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/dependabot/file_fetchers.rb +0 -2
- data/lib/dependabot/file_parsers.rb +0 -2
- data/lib/dependabot/file_updaters.rb +0 -2
- data/lib/dependabot/metadata_finders.rb +0 -2
- data/lib/dependabot/update_checkers.rb +0 -2
- data/lib/dependabot/version.rb +1 -1
- metadata +1 -7
- data/lib/dependabot/file_fetchers/docker/docker.rb +0 -40
- data/lib/dependabot/file_parsers/docker/docker.rb +0 -164
- data/lib/dependabot/file_updaters/docker/docker.rb +0 -133
- data/lib/dependabot/metadata_finders/docker/docker.rb +0 -18
- data/lib/dependabot/update_checkers/docker/docker.rb +0 -290
- data/lib/dependabot/utils/docker/credentials_finder.rb +0 -65
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 643315e66fbeb494837f087852166010e52b5c24daf7ff8c459bbf660b0d4d63
|
4
|
+
data.tar.gz: cfff2982eda91bc92af1e374d0a7071610ef4d9ace6024185ebffc1c28cc01b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5436d554912bd92166d5580fd7737fad37b69feb0a7acef0d5fe1f3e3c465ce62ea03580486a0ddd3a5ca1dd3e3dee8f3e7d65743f34a3e25089b3af98b1b3d
|
7
|
+
data.tar.gz: 0deffbebb24d5c99233a0522305fb911e9111bd466bf2f7aa54f4494cd917e4c9c8f34ba4ae4c11c29d1879bdb4b1e905a46b1397903f4a40f858c120a23d077
|
data/CHANGELOG.md
CHANGED
@@ -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,
|
data/lib/dependabot/version.rb
CHANGED
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.
|
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
|