on_container 0.0.7 → 0.0.12

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
- SHA1:
3
- metadata.gz: 49a6b84a56344cf0119b822fd9f12277bb66fe70
4
- data.tar.gz: 6676d161e20a802d3f75c765e04bfd6b0969972c
2
+ SHA256:
3
+ metadata.gz: cc7ffb417b7d418f2415df1cd5c6cbd0325d78e576e71a701010bd44ead098f6
4
+ data.tar.gz: 260e06a5fa81789bc977cac9b02c8e092100a0896d9eccc4c4f88423592a1f9d
5
5
  SHA512:
6
- metadata.gz: 9aa5a059a7ba11f6f658c08d32ead851ab667ad3c894f5442cd795febc3c8e6c9e65f1e8d126708a6a2a0702d18661e043a600768522caadc8cf90ae119f0c90
7
- data.tar.gz: 6916cb665fa674c90a43634f2cf5bce4632c105c862f44caf8b08200b486440f305fc9f2ca01af4220ba59e87ef15b43969072b900e0c198f290c336ff341580
6
+ metadata.gz: 9e54869d4ec1c390a555731ac199ece8b804098eece937321123e48884d0b7fa0dff418147f97e811b4e05fb23517f433bf622b08fc4f4941d04801fa31f8570
7
+ data.tar.gz: 410eb4b5c14a632600ecccade83dcca9764965085dfa95177976365bc762516ac36e8d6ec70cdd51925d9204c19652afe80c50887774b67ffbe0990c9edeb18b
data/README.md CHANGED
@@ -52,7 +52,7 @@ end if command_requires_setup?
52
52
  execute_given_or_default_command
53
53
  ```
54
54
 
55
- ### Loading secrets into environment variables, and inserting credentials into URL environment variables
55
+ ### Loading secrets into environment variables
56
56
 
57
57
  When using Docker Swarm, the secrets are loaded as files mounted into the container's filesystem.
58
58
 
@@ -65,11 +65,58 @@ For our Rails example app, we added the following line to the `config/boot.rb` f
65
65
 
66
66
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
67
67
 
68
- require 'on_container/load_env_secrets' # Load secrets injected by Kubernetes/Swarm
69
-
70
68
  require 'bundler/setup' # Set up gems listed in the Gemfile.
71
69
  require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
70
+
71
+ # Load swarm/gcp secrets to ENV:
72
+ require 'on_container/load_env_secrets'
73
+ ```
74
+
75
+ #### Loading Google Cloud Secret Manager secrets into ENV
76
+
77
+ If you require loading YAML data stored at [Google Cloud Secret Manager](https://cloud.google.com/secret-manager),
78
+ you will require the following steps:
79
+
80
+ 1. Install the `google-cloud-secret_manager` gem
81
+
82
+ On your gemfile:
83
+
84
+ ```ruby
85
+ # Read secrets from Google Cloud Secret Manager
86
+ gem 'google-cloud-secret_manager', '~> 1.0'
87
+ ```
88
+
89
+ 2. Require it at `config/boot.rb`
90
+
91
+ On `config/boot`, right before requiring `on_container/load_env_secrets`:
92
+
93
+ ```ruby
94
+ # Require Google Cloud Secret Manager to enable 'on_container/load_env_secrets'
95
+ # loading secrets from GCP to ENV:
96
+ require 'google/cloud/secret_manager'
97
+
98
+ # Load swarm/gcp secrets to ENV:
99
+ require 'on_container/load_env_secrets'
100
+ ```
101
+
102
+ 3. Make sure your app has google cloud credentials configured, and have access
103
+ to the secrets your'e planning to use.
104
+
105
+ 4. Configure any number of environment variables ending with
106
+ `_GOOGLE_CLOUD_SECRET`, each containing the secret you want to load. In the
107
+ following example, the command to deploy an image into Google Cloud Run:
108
+
109
+ ```bash
110
+ gcloud run deploy my-demo-app \
111
+ --platform "managed" \
112
+ --region us-central1 \
113
+ --allow-unauthenticated \
114
+ --set-env-vars A_GOOGLE_CLOUD_SECRET=my-super-secret \
115
+ --set-env-vars ANOTHER_GOOGLE_CLOUD_SECRET=project/another-project/secrets/another-secret/versions/1 \
116
+ --service-account=my-demo-service-account@google-cloud \
117
+ --image gcr.io/my-demo-project/my-demo-app:latest
72
118
  ```
119
+ #### Inserting credentials into URL environment variables
73
120
 
74
121
  The `on_container/load_env_secrets` also merges any credential available in environment variables into any matching
75
122
  `_URL` environment variable. For example, consider the following environment variables:
@@ -96,7 +143,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
96
143
 
97
144
  ## Contributing
98
145
 
99
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/on_container. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/on_container/blob/master/CODE_OF_CONDUCT.md).
146
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/on_container. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/on_container/blob/main/CODE_OF_CONDUCT.md).
100
147
 
101
148
 
102
149
  ## License
@@ -105,4 +152,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
105
152
 
106
153
  ## Code of Conduct
107
154
 
108
- Everyone interacting in the OnContainer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/on_container/blob/master/CODE_OF_CONDUCT.md).
155
+ Everyone interacting in the OnContainer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/on_container/blob/main/CODE_OF_CONDUCT.md).
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnContainer
4
+ module Common
5
+ module Performable
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def perform!(*args, **kargs)
12
+ new(*args, **kargs).perform!
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'on_container/common/performable'
4
+
5
+ module OnContainer
6
+ module Common
7
+ module SafePerformable
8
+ def self.included(base)
9
+ base.include OnContainer::Common::Performable
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ def perform(*args, **kargs)
14
+ perform!(*args, **kargs)
15
+ rescue
16
+ false
17
+ end
18
+
19
+ module ClassMethods
20
+ def perform(*args, **kargs)
21
+ new(*args, **kargs).perform
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,50 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Reads the specified secret paths (i.e. Docker Secrets) into environment
4
- # variables:
5
-
6
- require 'active_support'
7
- require 'active_support/core_ext/object'
8
-
9
- # Process only a known list of env vars that can filled by reading a file (i.e.
10
- # a docker secret):
11
- Dir["#{ENV.fetch('SECRETS_PATH', '/run/secrets/')}*"].each do |secret_filepath|
12
- next unless File.file?(secret_filepath)
13
-
14
- secret_envvarname = File.basename(secret_filepath, '.*').upcase
15
-
16
- # Skip if variable is already set - already-set variables have precedence over
17
- # the secret files:
18
- next if ENV.key?(secret_envvarname) && ENV[secret_envvarname].present?
19
-
20
- ENV[secret_envvarname] = File.read(secret_filepath).strip
21
- end
22
-
23
- # For each *_URL environment variable where there's also a *_(USER|USERNAME) or
24
- # *_(PASS|PASSWORD), update the URL environment variable with the given
25
- # credentials. For example:
3
+ # This script achieves a list of secret loading & processing:
26
4
  #
27
- # DATABASE_URL: postgres://postgres:5432/demo_production
28
- # DATABASE_USERNAME: lalito
29
- # DATABASE_PASSWORD: lepass
5
+ # 1. Loads secrets from Google Cloud Secret Manager to ENV, if configured.
6
+ # 2. Reads files in a configured Folder, and loads them into ENV variables.
7
+ # 3. Processes "*_URL" env vars, adding their respective "*_USER" and "*_PASS".
30
8
  #
31
- # Results in the following updated DATABASE_URL:
32
- # DATABASE_URL = postgres://lalito:lepass@postgres:5432/demo_production
33
- require 'uri' if (url_keys = ENV.keys.select { |key| key =~ /_URL/ }).any?
34
-
35
- url_keys.each do |url_key|
36
- credential_pattern_string = url_key.gsub('_URL', '_(USER(NAME)?|PASS(WORD)?)')
37
- credential_pattern = Regexp.new "\\A#{credential_pattern_string}\\z"
38
- credential_keys = ENV.keys.select { |key| key =~ credential_pattern }
39
- next unless credential_keys.any?
40
-
41
- uri = URI(ENV[url_key])
42
- username = URI.encode_www_form_component ENV[credential_keys.detect { |key| key =~ /USER/ }]
43
- password = URI.encode_www_form_component ENV[credential_keys.detect { |key| key =~ /PASS/ }]
44
-
45
- uri.user = username if username
46
- uri.password = password if password
47
- ENV[url_key] = uri.to_s
48
- end
9
+ # - See https://github.com/IcaliaLabs/on-container-for-ruby#loading-secrets-into-environment-variables
49
10
 
50
- # STDERR.puts ENV.inspect
11
+ require 'on_container/secrets/env_loader'
12
+ OnContainer::Secrets::EnvLoader.perform!
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'on_container/common/safe_performable'
4
+ require 'on_container/secrets/google_cloud/env_loader'
5
+ require 'on_container/secrets/mounted_files/env_loader'
6
+ require 'on_container/secrets/url_variable_processor'
7
+
8
+ module OnContainer
9
+ module Secrets
10
+ #= EnvLoader
11
+ #
12
+ # Reads the specified secret paths (i.e. Docker Secrets) into environment
13
+ # variables:
14
+ class EnvLoader
15
+ include OnContainer::Common::SafePerformable
16
+
17
+ def perform!
18
+ load_secrets_from_google_cloud if google_cloud_secrets?
19
+ load_secrets_from_mounted_files
20
+ process_url_variables
21
+ true
22
+ end
23
+
24
+ private
25
+
26
+ def google_cloud_secrets?
27
+ OnContainer::Secrets::GoogleCloud::EnvLoader.secret_manager?
28
+ end
29
+
30
+ def load_secrets_from_google_cloud
31
+ OnContainer::Secrets::GoogleCloud::EnvLoader.perform!
32
+ end
33
+
34
+ def load_secrets_from_mounted_files
35
+ OnContainer::Secrets::MountedFiles::EnvLoader.perform!
36
+ end
37
+
38
+ def process_url_variables
39
+ OnContainer::Secrets::UrlVariableProcessor.perform!
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "on_container/secrets/google_cloud/fetcher"
4
+
5
+ module OnContainer
6
+ module Secrets
7
+ module GoogleCloud
8
+ class EnvLoader < ServiceBase
9
+ ENV_KEY_SUFIX = '_GOOGLE_CLOUD_SECRET'
10
+
11
+ def env_keys
12
+ @env_keys ||= ENV.keys.select do |key|
13
+ key.end_with?(ENV_KEY_SUFIX)
14
+ end.sort
15
+ end
16
+
17
+ def env_keys?
18
+ env_keys.any?
19
+ end
20
+
21
+ def self.secret_manager?
22
+ defined?(Google::Cloud::SecretManager) == 'constant'
23
+ end
24
+
25
+ def secret_manager?
26
+ self.class.secret_manager?
27
+ end
28
+
29
+ def perform!
30
+ return unless env_keys? && secret_manager?
31
+
32
+ env_keys.each do |key|
33
+ ENV.merge! Fetcher.perform! ENV[key], client: client
34
+ end
35
+
36
+ true
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'on_container/secrets/google_cloud/service_base'
5
+
6
+ module OnContainer
7
+ module Secrets
8
+ module GoogleCloud
9
+ class Fetcher < ServiceBase
10
+ PROJECT_PATTERN = %r{\Aprojects\/(\w+)\/.*}.freeze
11
+ SECRET_NAME_PATTERN = %r{secrets\/([\w-]+)\/?}.freeze
12
+ SECRET_VERSION_PATTERN = %r{versions\/(\d+|latest)\z}.freeze
13
+
14
+ attr_reader :project, :secret_name, :secret_version
15
+
16
+ def initialize(given_key, client: nil)
17
+ @client = client
18
+ @project = extract_project given_key
19
+ @secret_version = extract_secret_version given_key
20
+ @secret_name = extract_secret_name given_key
21
+ end
22
+
23
+ def perform!
24
+ # Build the resource name of the secret version.
25
+ name = client.secret_version_path project: @project,
26
+ secret: @secret_name,
27
+ secret_version: @secret_version
28
+
29
+ version = client.access_secret_version name: name
30
+
31
+ YAML.load version.payload.data
32
+ end
33
+
34
+ protected
35
+
36
+ def default_project
37
+ ENV['GOOGLE_CLOUD_PROJECT']
38
+ end
39
+
40
+ def extract_project(given_key)
41
+ match = given_key.match(PROJECT_PATTERN)
42
+ return default_project unless match
43
+
44
+ match.captures.first
45
+ end
46
+
47
+ def extract_secret_version(given_key)
48
+ match = given_key.match(SECRET_VERSION_PATTERN)
49
+ return 'latest' unless match
50
+
51
+ match.captures.first
52
+ end
53
+
54
+ def extract_secret_name(given_key)
55
+ given_key
56
+ .sub("projects/#{@project}/secrets/", '')
57
+ .sub("/versions/#{@secret_version}", '')
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "on_container/common/safe_performable"
4
+
5
+ module OnContainer
6
+ module Secrets
7
+ module GoogleCloud
8
+ class ServiceBase
9
+ include OnContainer::Common::SafePerformable
10
+
11
+ attr_reader :client
12
+
13
+ def client
14
+ @client ||= Google::Cloud::SecretManager.secret_manager_service
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/core_ext/object'
5
+ require 'on_container/common/safe_performable'
6
+
7
+ module OnContainer
8
+ module Secrets
9
+ module MountedFiles
10
+ class EnvLoader
11
+ include OnContainer::Common::SafePerformable
12
+
13
+ def perform!
14
+ setup_secrets_path
15
+ scan_secrets_path_for_files
16
+ load_secret_files_to_env_vars
17
+ end
18
+
19
+ def secrets_path
20
+ @secrets_path ||= ENV.fetch('SECRETS_PATH', '/run/secrets')
21
+ end
22
+
23
+ def secret_mounted_file_paths
24
+ @secret_mounted_file_paths ||= Dir["#{secrets_path}/**/*"]
25
+ .map { |path| Pathname.new(path) }
26
+ .select(&:file?)
27
+ end
28
+
29
+ private
30
+
31
+ alias setup_secrets_path secrets_path
32
+ alias scan_secrets_path_for_files secret_mounted_file_paths
33
+
34
+ def load_secret_files_to_env_vars
35
+ return if @already_loaded
36
+
37
+ secret_mounted_file_paths
38
+ .each { |file_path| load_secret_file_to_env_var(file_path) }
39
+
40
+ @already_loaded = true
41
+ end
42
+
43
+ def load_secret_file_to_env_var(file_path)
44
+ env_var_name = file_path.basename('.*').to_s.upcase
45
+
46
+ # Skip if variable is already set - already-set variables have
47
+ # precedence over the secret files:
48
+ return if ENV.key?(env_var_name) && ENV[env_var_name].present?
49
+
50
+ contents = file_path.read.strip
51
+
52
+ # TODO: Do not load if content has null bytes
53
+ ENV[env_var_name] = file_path.read.strip
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'on_container/common/safe_performable'
4
+
5
+ module OnContainer
6
+ module Secrets
7
+ #= UrlVariableProcessor
8
+ #
9
+ # For each *_URL environment variable where there's also a *_(USER|USERNAME)
10
+ # or *_(PASS|PASSWORD), updates the URL environment variable with the given
11
+ # credentials. For example:
12
+ #
13
+ # DATABASE_URL: postgres://postgres:5432/demo_production
14
+ # DATABASE_USERNAME: lalito
15
+ # DATABASE_PASSWORD: lepass
16
+ #
17
+ # Results in the following updated DATABASE_URL:
18
+ # DATABASE_URL = postgres://lalito:lepass@postgres:5432/demo_production
19
+ class UrlVariableProcessor
20
+ include OnContainer::Common::SafePerformable
21
+
22
+ def perform!
23
+ require_uri_module if url_keys?
24
+ process_credential_keys
25
+ end
26
+
27
+ def url_keys
28
+ @url_keys ||= ENV.keys.select { |key| key =~ /_URL/ }
29
+ end
30
+
31
+ def url_keys?
32
+ url_keys.any?
33
+ end
34
+
35
+ private
36
+
37
+ def process_credential_keys
38
+ url_keys.each { |url_key| process_credential_keys_for(url_key) }
39
+ end
40
+
41
+ def require_uri_module
42
+ require 'uri'
43
+ end
44
+
45
+ def credential_keys_for(url_key)
46
+ credential_pattern_string = url_key
47
+ .gsub('_URL', '_(USER(NAME)?|PASS(WORD)?)')
48
+
49
+ credential_pattern = Regexp.new "\\A#{credential_pattern_string}\\z"
50
+ ENV.keys.select { |key| key =~ credential_pattern }
51
+ end
52
+
53
+ def process_credential_keys_for(url_key)
54
+ return unless (credential_keys = credential_keys_for(url_key)).any?
55
+
56
+ uri = URI(ENV[url_key])
57
+
58
+ # Reverse sorting will place "*_USER" before "*_PASS":
59
+ credential_keys.sort.reverse.each do |credential_key|
60
+ credential_value = URI.encode_www_form_component ENV[credential_key]
61
+ case credential_key
62
+ when /USER/ then uri.user = credential_value
63
+ when /PASS/ then uri.password = credential_value
64
+ end
65
+ end
66
+
67
+ ENV[url_key] = uri.to_s
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnContainer
4
- VERSION = '0.0.7'
4
+ VERSION = '0.0.12'
5
5
  end
data/on_container.gemspec CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = spec.homepage
19
- spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/master/CHANGELOG.md"
19
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
20
20
 
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.files = `git ls-files -- lib/* *.md *.gemspec *.txt Rakefile`.split("\n")
@@ -24,5 +24,6 @@ Gem::Specification.new do |spec|
24
24
  spec.bindir = 'exe'
25
25
  spec.require_paths = ['lib']
26
26
 
27
- spec.add_development_dependency 'bundler', '~> 1.17'
27
+ spec.add_runtime_dependency 'activesupport', '>= 4'
28
+ spec.add_development_dependency 'bundler', '~> 2.1'
28
29
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: on_container
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roberto Quintanilla
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-28 00:00:00.000000000 Z
11
+ date: 2021-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1.17'
33
+ version: '2.1'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1.17'
40
+ version: '2.1'
27
41
  description: A small collection of scripts and routines to help ruby development within
28
42
  containers
29
43
  email:
@@ -38,6 +52,8 @@ files:
38
52
  - README.md
39
53
  - Rakefile
40
54
  - lib/on_container.rb
55
+ - lib/on_container/common/performable.rb
56
+ - lib/on_container/common/safe_performable.rb
41
57
  - lib/on_container/dev/active_record_ops.rb
42
58
  - lib/on_container/dev/bundler_ops.rb
43
59
  - lib/on_container/dev/container_command_ops.rb
@@ -47,12 +63,14 @@ files:
47
63
  - lib/on_container/dev/setup_ops.rb
48
64
  - lib/on_container/load_env_secrets.rb
49
65
  - lib/on_container/ops/service_connection_checks.rb
50
- - lib/on_container/step_down_from_root.rb
66
+ - lib/on_container/secrets/env_loader.rb
67
+ - lib/on_container/secrets/google_cloud/env_loader.rb
68
+ - lib/on_container/secrets/google_cloud/fetcher.rb
69
+ - lib/on_container/secrets/google_cloud/service_base.rb
70
+ - lib/on_container/secrets/mounted_files/env_loader.rb
71
+ - lib/on_container/secrets/url_variable_processor.rb
51
72
  - lib/on_container/version.rb
52
73
  - on_container.gemspec
53
- - spec/on_container_spec.rb
54
- - spec/spec_helper.rb
55
- - spec/step_down_from_root_spec.rb
56
74
  homepage: https://github.com/IcaliaLabs/on-container-for-ruby
57
75
  licenses:
58
76
  - MIT
@@ -60,7 +78,7 @@ metadata:
60
78
  allowed_push_host: https://rubygems.org
61
79
  homepage_uri: https://github.com/IcaliaLabs/on-container-for-ruby
62
80
  source_code_uri: https://github.com/IcaliaLabs/on-container-for-ruby
63
- changelog_uri: https://github.com/IcaliaLabs/on-container-for-ruby/blob/master/CHANGELOG.md
81
+ changelog_uri: https://github.com/IcaliaLabs/on-container-for-ruby/blob/main/CHANGELOG.md
64
82
  post_install_message:
65
83
  rdoc_options: []
66
84
  require_paths:
@@ -76,13 +94,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
94
  - !ruby/object:Gem::Version
77
95
  version: '0'
78
96
  requirements: []
79
- rubyforge_project:
80
- rubygems_version: 2.5.2.3
97
+ rubygems_version: 3.1.4
81
98
  signing_key:
82
99
  specification_version: 4
83
100
  summary: A small collection of scripts and routines to help ruby development within
84
101
  containers
85
- test_files:
86
- - spec/on_container_spec.rb
87
- - spec/spec_helper.rb
88
- - spec/step_down_from_root_spec.rb
102
+ test_files: []
@@ -1,55 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'etc'
4
-
5
- module OnContainer
6
- class StepDownFromRoot
7
- attr_reader :curent_user, :target_user
8
-
9
- def initialize
10
- @curent_user = Etc.getpwuid
11
- end
12
-
13
- def target_user
14
- @target_user ||= Etc.getpwuid(developer_uid)
15
- end
16
-
17
- def perform
18
- return unless root_user?
19
- return warn_no_developer_uid unless developer_uid?
20
-
21
- switch_to_developer_user
22
- end
23
-
24
- def root_user?
25
- curent_user.name == 'root'
26
- end
27
-
28
- def developer_uid?
29
- developer_uid > 0
30
- end
31
-
32
- def developer_uid
33
- @developer_uid ||= ENV.fetch('DEVELOPER_UID', '').to_i
34
- end
35
-
36
- protected
37
-
38
- def switch_to_developer_user
39
- target_user_name = target_user.name
40
- puts "Switching from 'root' user to '#{target_user_name}'..."
41
- Kernel.exec 'su-exec', target_user_name, $0, *$*
42
- end
43
-
44
- def warn_no_developer_uid
45
- puts "The 'DEVELOPER_UID' environment variable is not set... " \
46
- 'still running as root!'
47
- end
48
-
49
- def self.perform
50
- new.perform
51
- end
52
- end
53
- end
54
-
55
- OnContainer::StepDownFromRoot.perform
@@ -1,5 +0,0 @@
1
- RSpec.describe OnContainer do
2
- it "has a version number" do
3
- expect(OnContainer::VERSION).not_to be nil
4
- end
5
- end
data/spec/spec_helper.rb DELETED
@@ -1,14 +0,0 @@
1
- require "bundler/setup"
2
- require "on_container"
3
-
4
- RSpec.configure do |config|
5
- # Enable flags like --only-failures and --next-failure
6
- config.example_status_persistence_file_path = ".rspec_status"
7
-
8
- # Disable RSpec exposing methods globally on `Module` and `main`
9
- config.disable_monkey_patching!
10
-
11
- config.expect_with :rspec do |c|
12
- c.syntax = :expect
13
- end
14
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'on_container/step_down_from_root'
4
-
5
- RSpec.describe OnContainer::StepDownFromRoot do
6
- let(:root_user) do
7
- instance_double "struct Etc::Passwd",
8
- name: 'root',
9
- passwd: 'x',
10
- uid: 0,
11
- gid: 0,
12
- gecos: 'root',
13
- dir: '/root',
14
- shell: '/bin/bash'
15
- end
16
-
17
- let(:developer_user) do
18
- instance_double "struct Etc::Passwd",
19
- name: 'developer',
20
- passwd: 'x',
21
- uid: 1000,
22
- gid: 1000,
23
- gecos: 'Developer User,,,',
24
- dir: '/usr/src',
25
- shell: '/bin/bash'
26
- end
27
-
28
- let(:example_current_user) { root_user }
29
- let(:example_target_user) { developer_user }
30
- let(:example_developer_uid) { '1000' }
31
-
32
- before do
33
- allow(ENV).to receive(:fetch).with('DEVELOPER_UID', '') { example_developer_uid }
34
- allow(Etc).to receive(:getpwuid) { example_current_user }
35
- allow(Etc).to receive(:getpwuid).with(example_target_user.uid) { example_target_user }
36
- allow(Kernel).to receive(:exec).with('su-exec', example_target_user.name, any_args)
37
- end
38
-
39
- describe '#perform' do
40
- it 'changes to the target user' do
41
- subject.perform
42
- expect(Kernel).to have_received(:exec).with 'su-exec', example_target_user.name, any_args
43
- end
44
-
45
- context 'without a developer uid' do
46
- let(:example_developer_uid) { '' }
47
-
48
- example 'does not change the current user' do
49
- subject.perform
50
- expect(Kernel).not_to have_received(:exec)
51
- end
52
- end
53
-
54
- context 'when not as root' do
55
- let(:example_current_user) { developer_user }
56
-
57
- example 'does not change the current user' do
58
- subject.perform
59
- expect(Kernel).not_to have_received(:exec)
60
- end
61
- end
62
- end
63
- end