hybrid_platforms_conductor 33.3.0 → 33.4.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 +6 -0
- data/README.md +31 -2
- data/docs/config_dsl.md +43 -0
- data/lib/hybrid_platforms_conductor/bitbucket.rb +134 -90
- data/lib/hybrid_platforms_conductor/common_config_dsl/bitbucket.rb +12 -44
- data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +9 -31
- data/lib/hybrid_platforms_conductor/confluence.rb +93 -88
- data/lib/hybrid_platforms_conductor/credentials.rb +112 -95
- data/lib/hybrid_platforms_conductor/deployer.rb +2 -2
- data/lib/hybrid_platforms_conductor/github.rb +39 -0
- data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +4 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/report/confluence.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +2 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +3 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +4 -1
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_conf.rb +6 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test/jenkins_ci_masters_ok.rb +6 -2
- data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +3 -1
- data/lib/hybrid_platforms_conductor/logger_helpers.rb +7 -1
- data/lib/hybrid_platforms_conductor/thycotic.rb +80 -75
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test.rb +6 -0
- data/spec/hybrid_platforms_conductor_test/api/credentials_spec.rb +247 -0
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/keepass_spec.rb +280 -319
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +2 -2
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/bitbucket_conf_spec.rb +49 -69
- data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +29 -39
- metadata +18 -2
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'octokit'
|
2
|
-
require 'hybrid_platforms_conductor/credentials'
|
3
|
-
|
4
1
|
module HybridPlatformsConductor
|
5
2
|
|
6
3
|
module CommonConfigDsl
|
@@ -8,12 +5,19 @@ module HybridPlatformsConductor
|
|
8
5
|
# Add common Github config DSL to declare known Github repositories
|
9
6
|
module Github
|
10
7
|
|
8
|
+
# List of Github repositories
|
9
|
+
# Array< Hash<Symbol, Object> >
|
10
|
+
# * *user* (String): User or organization name, storing repositories
|
11
|
+
# * *url* (String): URL to the Github API
|
12
|
+
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all
|
13
|
+
attr_reader :known_github_repos
|
14
|
+
|
11
15
|
# Initialize the DSL
|
12
16
|
def init_github
|
13
17
|
# List of Github repositories definitions
|
14
18
|
# Array< Hash<Symbol, Object> >
|
15
19
|
# Each definition is just mapping the signature of #github_repos
|
16
|
-
@
|
20
|
+
@known_github_repos = []
|
17
21
|
end
|
18
22
|
|
19
23
|
# Register new Github repositories
|
@@ -23,39 +27,13 @@ module HybridPlatformsConductor
|
|
23
27
|
# * *url* (String): URL to the Github API [default: 'https://api.github.com']
|
24
28
|
# * *repos* (Array<String> or Symbol): List of repository names from this project, or :all for all [default: :all]
|
25
29
|
def github_repos(user:, url: 'https://api.github.com', repos: :all)
|
26
|
-
@
|
30
|
+
@known_github_repos << {
|
27
31
|
url: url,
|
28
32
|
user: user,
|
29
33
|
repos: repos
|
30
34
|
}
|
31
35
|
end
|
32
36
|
|
33
|
-
# Iterate over each Github repository
|
34
|
-
#
|
35
|
-
# Parameters::
|
36
|
-
# * Proc: Code called for each Github repository:
|
37
|
-
# * Parameters::
|
38
|
-
# * *github* (Octokit::Client): The client instance accessing the Github API
|
39
|
-
# * *repo_info* (Hash<Symbol, Object>): The repository info:
|
40
|
-
# * *name* (String): Repository name.
|
41
|
-
# * *slug* (String): Repository slug.
|
42
|
-
def for_each_github_repo
|
43
|
-
@github_repos.each do |repo_info|
|
44
|
-
Octokit.configure do |c|
|
45
|
-
c.api_endpoint = repo_info[:url]
|
46
|
-
end
|
47
|
-
Credentials.with_credentials_for(:github, @logger, @logger_stderr, url: repo_info[:url]) do |_github_user, github_token|
|
48
|
-
client = Octokit::Client.new(access_token: github_token)
|
49
|
-
(repo_info[:repos] == :all ? client.repositories(repo_info[:user]).map { |repo| repo[:name] } : repo_info[:repos]).each do |name|
|
50
|
-
yield client, {
|
51
|
-
name: name,
|
52
|
-
slug: "#{repo_info[:user]}/#{name}"
|
53
|
-
}
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
37
|
end
|
60
38
|
|
61
39
|
end
|
@@ -7,111 +7,116 @@ require 'hybrid_platforms_conductor/credentials'
|
|
7
7
|
|
8
8
|
module HybridPlatformsConductor
|
9
9
|
|
10
|
-
#
|
11
|
-
|
10
|
+
# Mixin used to access Confluence API
|
11
|
+
module Confluence
|
12
12
|
|
13
|
-
include
|
13
|
+
include Credentials
|
14
14
|
|
15
15
|
# Provide a Confluence connector, and make sure the password is being cleaned when exiting.
|
16
16
|
#
|
17
17
|
# Parameters::
|
18
18
|
# * *confluence_url* (String): The Confluence URL
|
19
|
-
# * *logger* (Logger): Logger to be used
|
20
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr
|
21
19
|
# * Proc: Code called with the Confluence instance.
|
22
|
-
# * *confluence* (
|
23
|
-
def
|
24
|
-
|
25
|
-
yield
|
20
|
+
# * *confluence* (ConfluenceApi): The Confluence instance to use.
|
21
|
+
def with_confluence(confluence_url)
|
22
|
+
with_credentials_for(:confluence, resource: confluence_url) do |confluence_user, confluence_password|
|
23
|
+
yield ConfluenceApi.new(confluence_url, confluence_user, confluence_password, logger: @logger, logger_stderr: @logger_stderr)
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
|
-
#
|
30
|
-
|
31
|
-
# Parameters::
|
32
|
-
# * *confluence_url* (String): The Confluence URL
|
33
|
-
# * *confluence_user_name* (String): Confluence user name to be used when querying the API
|
34
|
-
# * *confluence_password* (String): Confluence password to be used when querying the API
|
35
|
-
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
36
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
37
|
-
def initialize(confluence_url, confluence_user_name, confluence_password, logger: Logger.new($stdout), logger_stderr: Logger.new($stderr))
|
38
|
-
init_loggers(logger, logger_stderr)
|
39
|
-
@confluence_url = confluence_url
|
40
|
-
@confluence_user_name = confluence_user_name
|
41
|
-
@confluence_password = confluence_password
|
42
|
-
end
|
27
|
+
# Provide an API access on Confluence
|
28
|
+
class ConfluenceApi
|
43
29
|
|
44
|
-
|
45
|
-
#
|
46
|
-
# Parameters::
|
47
|
-
# * *page_id* (String): Confluence page ID
|
48
|
-
# Result::
|
49
|
-
# * Nokogiri::HTML: Storage format content, as a Nokogiri object
|
50
|
-
def page_storage_format(page_id)
|
51
|
-
Nokogiri::HTML(call_api("plugins/viewstorage/viewpagestorage.action?pageId=#{page_id}").body)
|
52
|
-
end
|
30
|
+
include LoggerHelpers
|
53
31
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
32
|
+
# Constructor
|
33
|
+
#
|
34
|
+
# Parameters::
|
35
|
+
# * *confluence_url* (String): The Confluence URL
|
36
|
+
# * *confluence_user_name* (String): Confluence user name to be used when querying the API
|
37
|
+
# * *confluence_password* (String): Confluence password to be used when querying the API
|
38
|
+
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
39
|
+
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
40
|
+
def initialize(confluence_url, confluence_user_name, confluence_password, logger: Logger.new($stdout), logger_stderr: Logger.new($stderr))
|
41
|
+
init_loggers(logger, logger_stderr)
|
42
|
+
@confluence_url = confluence_url
|
43
|
+
@confluence_user_name = confluence_user_name
|
44
|
+
@confluence_password = confluence_password
|
45
|
+
end
|
63
46
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
version = info['version']['number'] + 1 if version.nil?
|
73
|
-
log_debug "Update Confluence page #{page_id}..."
|
74
|
-
call_api("rest/api/content/#{page_id}", :put) do |request|
|
75
|
-
request['Content-Type'] = 'application/json'
|
76
|
-
request.body = {
|
77
|
-
type: 'page',
|
78
|
-
title: info['title'],
|
79
|
-
body: {
|
80
|
-
storage: {
|
81
|
-
value: content,
|
82
|
-
representation: 'storage'
|
83
|
-
}
|
84
|
-
},
|
85
|
-
version: { number: version }
|
86
|
-
}.to_json
|
47
|
+
# Return a Confluence storage format content from a page ID
|
48
|
+
#
|
49
|
+
# Parameters::
|
50
|
+
# * *page_id* (String): Confluence page ID
|
51
|
+
# Result::
|
52
|
+
# * Nokogiri::HTML: Storage format content, as a Nokogiri object
|
53
|
+
def page_storage_format(page_id)
|
54
|
+
Nokogiri::HTML(call_api("plugins/viewstorage/viewpagestorage.action?pageId=#{page_id}").body)
|
87
55
|
end
|
88
|
-
end
|
89
56
|
|
90
|
-
|
57
|
+
# Return some info of a given page ID
|
58
|
+
#
|
59
|
+
# Parameters::
|
60
|
+
# * *page_id* (String): Confluence page ID
|
61
|
+
# Result::
|
62
|
+
# * Hash: Page information, as returned by the Confluence API
|
63
|
+
def page_info(page_id)
|
64
|
+
JSON.parse(call_api("rest/api/content/#{page_id}").body)
|
65
|
+
end
|
91
66
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
67
|
+
# Update a Confluence page to a new content.
|
68
|
+
#
|
69
|
+
# Parameters::
|
70
|
+
# * *page_id* (String): Confluence page ID
|
71
|
+
# * *content* (String): New content
|
72
|
+
# * *version* (String or nil): New version, or nil to automatically increase last existing version [default: nil]
|
73
|
+
def update_page(page_id, content, version: nil)
|
74
|
+
info = page_info(page_id)
|
75
|
+
version = info['version']['number'] + 1 if version.nil?
|
76
|
+
log_debug "Update Confluence page #{page_id}..."
|
77
|
+
call_api("rest/api/content/#{page_id}", :put) do |request|
|
78
|
+
request['Content-Type'] = 'application/json'
|
79
|
+
request.body = {
|
80
|
+
type: 'page',
|
81
|
+
title: info['title'],
|
82
|
+
body: {
|
83
|
+
storage: {
|
84
|
+
value: content,
|
85
|
+
representation: 'storage'
|
86
|
+
}
|
87
|
+
},
|
88
|
+
version: { number: version }
|
89
|
+
}.to_json
|
90
|
+
end
|
113
91
|
end
|
114
|
-
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Call the Confluence API for a given URL and HTTP verb.
|
96
|
+
# Provide a simple way to tweak the request with an optional proc.
|
97
|
+
# Automatically handles authentication, base URL and error handling.
|
98
|
+
#
|
99
|
+
# Parameters::
|
100
|
+
# * *api_path* (String): The API path to query
|
101
|
+
# * *http_method* (Symbol): HTTP method to be used to create the request [default = :get]
|
102
|
+
# * Proc: Optional code called to alter the request
|
103
|
+
# * Parameters::
|
104
|
+
# * *request* (Net::HTTPRequest): The request
|
105
|
+
# Result::
|
106
|
+
# * Net::HTTPResponse: The corresponding response
|
107
|
+
def call_api(api_path, http_method = :get)
|
108
|
+
response = nil
|
109
|
+
page_url = URI.parse("#{@confluence_url}/#{api_path}")
|
110
|
+
Net::HTTP.start(page_url.host, page_url.port, use_ssl: true) do |http|
|
111
|
+
request = Net::HTTP.const_get(http_method.to_s.capitalize.to_sym).new(page_url.request_uri)
|
112
|
+
request.basic_auth @confluence_user_name, @confluence_password
|
113
|
+
yield request if block_given?
|
114
|
+
response = http.request(request)
|
115
|
+
raise "Confluence page API request on #{page_url} returned an error: #{response.code}\n#{response.body}\n===== Request body =====\n#{request.body}" unless response.is_a?(Net::HTTPSuccess)
|
116
|
+
end
|
117
|
+
response
|
118
|
+
end
|
119
|
+
|
115
120
|
end
|
116
121
|
|
117
122
|
end
|
@@ -7,122 +7,139 @@ module HybridPlatformsConductor
|
|
7
7
|
# Give a secured and harmonized way to access credentials for a given service.
|
8
8
|
# It makes sure to remove passwords from memory for hardened security (this way if a vulnerability allows an attacker to dump the memory it won't get passwords).
|
9
9
|
# It gets credentials from the following sources:
|
10
|
+
# * Configuration
|
10
11
|
# * Environment variables
|
11
12
|
# * Netrc file
|
12
|
-
|
13
|
+
module Credentials
|
13
14
|
|
14
|
-
|
15
|
+
# Extend the Config DSL
|
16
|
+
module ConfigDSLExtension
|
17
|
+
|
18
|
+
# List of credentials. Each info has the following properties:
|
19
|
+
# * *credential_id* (Symbol): Credential ID this rule applies to
|
20
|
+
# * *resource* (Regexp): Resource filtering for this rule
|
21
|
+
# * *provider* (Proc): The code providing the credentials:
|
22
|
+
# * Parameters::
|
23
|
+
# * *resource* (String or nil): The resource for which we want credentials, or nil if none
|
24
|
+
# * *requester* (Proc): Code to be called to give credentials to:
|
25
|
+
# * Parameters::
|
26
|
+
# * *user* (String or nil): The user name, or nil if none
|
27
|
+
# * *password* (String or nil): The password, or nil if none
|
28
|
+
attr_reader :credentials
|
29
|
+
|
30
|
+
# Mixin initializer
|
31
|
+
def init_credentials_config
|
32
|
+
@credentials = []
|
33
|
+
end
|
34
|
+
|
35
|
+
# Define a credentials provider
|
36
|
+
#
|
37
|
+
# Parameters::
|
38
|
+
# * *credential_id* (Symbol): Credential ID this rule applies to
|
39
|
+
# * *resource* (String or Regexp): Resource filtering for this rule [default: /.*/]
|
40
|
+
# * *provider* (Proc): The code providing the credentials:
|
41
|
+
# * Parameters::
|
42
|
+
# * *resource* (String or nil): The resource for which we want credentials, or nil if none
|
43
|
+
# * *requester* (Proc): Code to be called to give credentials to:
|
44
|
+
# * Parameters::
|
45
|
+
# * *user* (String or nil): The user name, or nil if none
|
46
|
+
# * *password* (String or nil): The password, or nil if none
|
47
|
+
def credentials_for(credential_id, resource: /.*/, &provider)
|
48
|
+
@credentials << {
|
49
|
+
credential_id: credential_id,
|
50
|
+
resource: resource.is_a?(String) ? /^#{Regexp.escape(resource)}$/ : resource,
|
51
|
+
provider: provider
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
Config.extend_config_dsl_with ConfigDSLExtension, :init_credentials_config
|
15
58
|
|
16
59
|
# Get access to credentials and make sure they are wiped out from memory when client code ends.
|
17
60
|
# To ensure password safety, never store the password in a scope beyond the client code's Proc.
|
18
61
|
#
|
19
62
|
# Parameters::
|
20
63
|
# * *id* (Symbol): Credential ID
|
21
|
-
# * *
|
22
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr
|
23
|
-
# * *url* (String or nil): The URL for which we want the credentials, or nil if not associated to a URL [default: nil]
|
64
|
+
# * *resource* (String or nil): The resource for which we want the credentials, or nil if not associated to a resource [default: nil]
|
24
65
|
# * Proc: Client code called with credentials provided
|
25
66
|
# * Parameters::
|
26
67
|
# * *user* (String or nil): User name, or nil if none
|
27
68
|
# * *password* (String or nil): Password, or nil if none.
|
28
69
|
# !!! Never store this password in a scope broader than the client code itself !!!
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
yield credentials.user, credentials.password
|
33
|
-
ensure
|
34
|
-
credentials.clear_password
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Constructor
|
39
|
-
#
|
40
|
-
# Parameters::
|
41
|
-
# * *id* (Symbol): Credential ID
|
42
|
-
# * *url* (String or nil): The URL for which we want the credentials, or nil if not associated to a URL [default: nil]
|
43
|
-
# * *logger* (Logger): Logger to be used [default = Logger.new(STDOUT)]
|
44
|
-
# * *logger_stderr* (Logger): Logger to be used for stderr [default = Logger.new(STDERR)]
|
45
|
-
def initialize(id, url: nil, logger: Logger.new($stdout), logger_stderr: Logger.new($stderr))
|
46
|
-
init_loggers(logger, logger_stderr)
|
47
|
-
@id = id
|
48
|
-
@url = url
|
49
|
-
@user = nil
|
50
|
-
@password = nil
|
51
|
-
@retrieved = false
|
52
|
-
end
|
53
|
-
|
54
|
-
# Provide a helper to clear password from memory for security.
|
55
|
-
# To be used when the client knows it won't use the password anymore.
|
56
|
-
def clear_password
|
57
|
-
@password&.replace('gotyou!' * 100)
|
58
|
-
GC.start
|
59
|
-
end
|
60
|
-
|
61
|
-
# Get the associated user
|
62
|
-
#
|
63
|
-
# Result::
|
64
|
-
# * String or nil: The user name, or nil if none
|
65
|
-
def user
|
66
|
-
retrieve_credentials
|
67
|
-
@user
|
68
|
-
end
|
69
|
-
|
70
|
-
# Get the associated password
|
71
|
-
#
|
72
|
-
# Result::
|
73
|
-
# * String or nil: The password, or nil if none
|
74
|
-
def password
|
75
|
-
retrieve_credentials
|
76
|
-
@password
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
70
|
+
def with_credentials_for(id, resource: nil)
|
71
|
+
# Get the credentials provider
|
72
|
+
provider = nil
|
80
73
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
74
|
+
# Check configuration
|
75
|
+
# Take the last matching provider, this way we can define several providers for resources matched in a increasingly refined way.
|
76
|
+
@config.credentials.each do |credentials_info|
|
77
|
+
provider = credentials_info[:provider] if credentials_info[:credential_id] == id && (
|
78
|
+
(resource.nil? && credentials_info[:resource] == /.*/) || credentials_info[:resource] =~ resource
|
79
|
+
)
|
80
|
+
end
|
86
81
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
82
|
+
provider ||= proc do |requested_resource, requester|
|
83
|
+
# Check environment variables
|
84
|
+
user = ENV["hpc_user_for_#{id}"].dup
|
85
|
+
password = ENV["hpc_password_for_#{id}"].dup
|
86
|
+
if user.nil? || user.empty? || password.nil? || password.empty?
|
87
|
+
log_debug "[ Credentials for #{id} ] - Credentials not found from environment variables."
|
88
|
+
if requested_resource.nil?
|
89
|
+
log_debug "[ Credentials for #{id} ] - No resource associated to this credentials, so .netrc can't be used."
|
90
|
+
else
|
91
|
+
# Check Netrc
|
92
|
+
netrc = ::Netrc.read
|
93
|
+
begin
|
94
|
+
netrc_user, netrc_password = netrc[
|
95
|
+
begin
|
96
|
+
URI.parse(requested_resource).host.downcase
|
97
|
+
rescue URI::InvalidURIError
|
98
|
+
requested_resource
|
99
|
+
end
|
100
|
+
]
|
101
|
+
if netrc_user.nil?
|
102
|
+
log_debug "[ Credentials for #{id} ] - No credentials retrieved from .netrc."
|
103
|
+
# TODO: Add more credentials source if needed here
|
104
|
+
log_warn "[ Credentials for #{id} ] - Unable to get credentials for #{id} (Resource: #{requested_resource})."
|
105
|
+
else
|
106
|
+
user = netrc_user.dup
|
107
|
+
password = netrc_password.dup
|
108
|
+
log_debug "[ Credentials for #{id} ] - Credentials retrieved from .netrc using #{requested_resource}."
|
109
|
+
end
|
110
|
+
ensure
|
111
|
+
# Make sure the password does not stay in Netrc memory
|
112
|
+
# Wipe out any memory trace that might contain passwords in clear
|
113
|
+
netrc.instance_variable_get(:@data).each do |data_line|
|
114
|
+
data_line.each do |data_string|
|
115
|
+
data_string.replace('GotYou!!!' * 100)
|
116
|
+
end
|
114
117
|
end
|
118
|
+
# We do this assignment on purpose so that GC can remove sensitive data later
|
119
|
+
# rubocop:disable Lint/UselessAssignment
|
120
|
+
netrc = nil
|
121
|
+
# rubocop:enable Lint/UselessAssignment
|
115
122
|
end
|
116
|
-
# We don this assignment on purpose so that GC can remove sensitive data later
|
117
|
-
# rubocop:disable Lint/UselessAssignment
|
118
|
-
netrc = nil
|
119
|
-
# rubocop:enable Lint/UselessAssignment
|
120
123
|
end
|
124
|
+
else
|
125
|
+
log_debug "[ Credentials for #{id} ] - Credentials retrieved from environment variables."
|
121
126
|
end
|
122
|
-
|
123
|
-
|
127
|
+
GC.start
|
128
|
+
requester.call user, password
|
129
|
+
password&.replace('gotyou!' * 100)
|
130
|
+
GC.start
|
124
131
|
end
|
125
|
-
|
132
|
+
|
133
|
+
requester_called = false
|
134
|
+
provider.call(
|
135
|
+
resource,
|
136
|
+
proc do |user, password|
|
137
|
+
requester_called = true
|
138
|
+
yield user, password
|
139
|
+
end
|
140
|
+
)
|
141
|
+
|
142
|
+
raise "Requester not called by the credentials provider for #{id} (resource: #{resource}) - Please check the credentials_for code in your configuration." unless requester_called
|
126
143
|
end
|
127
144
|
|
128
145
|
end
|