on_container 0.0.6 → 0.0.11
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 +5 -5
- data/README.md +114 -3
- data/lib/on_container/common/performable.rb +17 -0
- data/lib/on_container/common/safe_performable.rb +26 -0
- data/lib/on_container/dev/active_record_ops.rb +1 -9
- data/lib/on_container/load_env_secrets.rb +17 -9
- data/lib/on_container/secrets/google_cloud/env_loader.rb +37 -0
- data/lib/on_container/secrets/google_cloud/fetcher.rb +62 -0
- data/lib/on_container/secrets/google_cloud/service_base.rb +19 -0
- data/lib/on_container/version.rb +1 -1
- data/on_container.gemspec +2 -2
- metadata +12 -15
- data/lib/on_container/step_down_from_root.rb +0 -55
- data/spec/on_container_spec.rb +0 -5
- data/spec/spec_helper.rb +0 -14
- data/spec/step_down_from_root_spec.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 819d1f5a057f277e3b816eedd99435c9816b6d1ec6ff2e79e2d90798b5b74648
|
4
|
+
data.tar.gz: 163f0552ec15c2b0199934ec81313d8708877339e20504c427f270e228ecc94b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16c10e11aa18e20cd8fb02ee53018f5477c1ec661ef6c43329b6c0a74814d0bb7b00f785c9966f2006670e0c73858c36d719ff5177ece9b35fb54fbc33743808
|
7
|
+
data.tar.gz: 900379b6246d9d44f301a81213e965feec8cb1235bd514fc9235b3e5fd5dc97b5f91399f25b18ac7efd0596e9a15e878766f85726e98040b30a688e80f0519db
|
data/README.md
CHANGED
@@ -22,7 +22,118 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
### Development Routines & Docker Entrypoint Scripts
|
26
|
+
|
27
|
+
We use some routines included in this gem to create compelling development entrypoint scripts for docker development containers.
|
28
|
+
|
29
|
+
In this example, we'll be using the `on_container/dev/rails` routine bundle to create our dev entrypoint:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
#!/usr/bin/env ruby
|
33
|
+
|
34
|
+
# frozen_string_literal: true
|
35
|
+
|
36
|
+
require 'on_container/dev/rails'
|
37
|
+
|
38
|
+
set_given_or_default_command
|
39
|
+
|
40
|
+
# `on_setup_lock_acquired` prevents multiple app containers from running
|
41
|
+
# the setup process concurrently:
|
42
|
+
on_setup_lock_acquired do
|
43
|
+
ensure_project_gems_are_installed
|
44
|
+
ensure_project_node_packages_are_installed
|
45
|
+
|
46
|
+
wait_for_service_to_accept_connections 'tcp://postgres:5432'
|
47
|
+
setup_activerecord_database unless activerecord_database_ready?
|
48
|
+
|
49
|
+
remove_rails_pidfile if rails_server?
|
50
|
+
end if command_requires_setup?
|
51
|
+
|
52
|
+
execute_given_or_default_command
|
53
|
+
```
|
54
|
+
|
55
|
+
### Loading secrets into environment variables
|
56
|
+
|
57
|
+
When using Docker Swarm, the secrets are loaded as files mounted into the container's filesystem.
|
58
|
+
|
59
|
+
The `on_container/load_env_secrets` runs a couple of routines that reads these files into environment variables.
|
60
|
+
|
61
|
+
For our Rails example app, we added the following line to the `config/boot.rb` file:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# frozen_string_literal: true
|
65
|
+
|
66
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
67
|
+
|
68
|
+
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
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
|
118
|
+
```
|
119
|
+
#### Inserting credentials into URL environment variables
|
120
|
+
|
121
|
+
The `on_container/load_env_secrets` also merges any credential available in environment variables into any matching
|
122
|
+
`_URL` environment variable. For example, consider the following environment variables:
|
123
|
+
|
124
|
+
```shell
|
125
|
+
DATABASE_URL=postgres://postgres:5432/?encoding=unicode
|
126
|
+
DATABASE_USER=postgres
|
127
|
+
DATABASE_PASS=3x4mpl3P455w0rd
|
128
|
+
```
|
129
|
+
|
130
|
+
The routine will merge `DATABASE_USER` and `DATABASE_PASS` into `DATABASE_URL`:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
puts ENV['DATABASE_URL']
|
134
|
+
> postgres://postgres:3x4mpl3P455w0rd@postgres:5432/?encoding=unicode
|
135
|
+
```
|
136
|
+
|
26
137
|
|
27
138
|
## Development
|
28
139
|
|
@@ -32,7 +143,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
143
|
|
33
144
|
## Contributing
|
34
145
|
|
35
|
-
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/
|
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).
|
36
147
|
|
37
148
|
|
38
149
|
## License
|
@@ -41,4 +152,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
41
152
|
|
42
153
|
## Code of Conduct
|
43
154
|
|
44
|
-
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/
|
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
|
@@ -26,15 +26,7 @@ module OnContainer
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def establish_activerecord_database_connection
|
29
|
-
unless defined?(ActiveRecord)
|
30
|
-
require 'rubygems'
|
31
|
-
require 'bundler'
|
32
|
-
|
33
|
-
Bundler.setup(:default)
|
34
|
-
|
35
|
-
require 'active_record'
|
36
|
-
end
|
37
|
-
|
29
|
+
require 'active_record' unless defined?(ActiveRecord)
|
38
30
|
ActiveRecord::Base.establish_connection activerecord_config
|
39
31
|
ActiveRecord::Base.connection_pool.with_connection { |connection| }
|
40
32
|
end
|
@@ -6,12 +6,16 @@
|
|
6
6
|
require 'active_support'
|
7
7
|
require 'active_support/core_ext/object'
|
8
8
|
|
9
|
+
# Load secrets from Google Cloud Secret Manager to ENV, if any:
|
10
|
+
require 'on_container/secrets/google_cloud/env_loader'
|
11
|
+
OnContainer::Secrets::GoogleCloud::EnvLoader.perform!
|
12
|
+
|
9
13
|
# Process only a known list of env vars that can filled by reading a file (i.e.
|
10
14
|
# a docker secret):
|
11
|
-
Dir["#{ENV.fetch('SECRETS_PATH', '/run/secrets
|
12
|
-
|
13
|
-
|
14
|
-
secret_envvarname =
|
15
|
+
Dir["#{ENV.fetch('SECRETS_PATH', '/run/secrets')}/**/*"].map do |path|
|
16
|
+
Pathname.new(path)
|
17
|
+
end.select(&:file?).each do |secret_filepath|
|
18
|
+
secret_envvarname = secret_filepath.basename('.*').to_s.upcase
|
15
19
|
|
16
20
|
# Skip if variable is already set - already-set variables have precedence over
|
17
21
|
# the secret files:
|
@@ -39,12 +43,16 @@ url_keys.each do |url_key|
|
|
39
43
|
next unless credential_keys.any?
|
40
44
|
|
41
45
|
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
46
|
|
45
|
-
|
46
|
-
|
47
|
+
credential_keys.each do |credential_key|
|
48
|
+
credential_value = URI.encode_www_form_component ENV[credential_key]
|
49
|
+
case credential_key
|
50
|
+
when /USER/ then uri.user = credential_value
|
51
|
+
when /PASS/ then uri.password = credential_value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
47
55
|
ENV[url_key] = uri.to_s
|
48
56
|
end
|
49
57
|
|
50
|
-
# STDERR.puts ENV.inspect
|
58
|
+
# STDERR.puts ENV.inspect
|
@@ -0,0 +1,37 @@
|
|
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 secret_manager?
|
22
|
+
defined?(Google::Cloud::SecretManager) == 'constant'
|
23
|
+
end
|
24
|
+
|
25
|
+
def perform!
|
26
|
+
return unless env_keys? && secret_manager?
|
27
|
+
|
28
|
+
env_keys.each do |key|
|
29
|
+
ENV.merge! Fetcher.perform! ENV[key], client: client
|
30
|
+
end
|
31
|
+
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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
|
data/lib/on_container/version.rb
CHANGED
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/
|
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,5 @@ 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
|
27
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
28
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: on_container
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roberto Quintanilla
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
description: A small collection of scripts and routines to help ruby development within
|
28
28
|
containers
|
29
29
|
email:
|
@@ -38,6 +38,8 @@ files:
|
|
38
38
|
- README.md
|
39
39
|
- Rakefile
|
40
40
|
- lib/on_container.rb
|
41
|
+
- lib/on_container/common/performable.rb
|
42
|
+
- lib/on_container/common/safe_performable.rb
|
41
43
|
- lib/on_container/dev/active_record_ops.rb
|
42
44
|
- lib/on_container/dev/bundler_ops.rb
|
43
45
|
- lib/on_container/dev/container_command_ops.rb
|
@@ -47,12 +49,11 @@ files:
|
|
47
49
|
- lib/on_container/dev/setup_ops.rb
|
48
50
|
- lib/on_container/load_env_secrets.rb
|
49
51
|
- lib/on_container/ops/service_connection_checks.rb
|
50
|
-
- lib/on_container/
|
52
|
+
- lib/on_container/secrets/google_cloud/env_loader.rb
|
53
|
+
- lib/on_container/secrets/google_cloud/fetcher.rb
|
54
|
+
- lib/on_container/secrets/google_cloud/service_base.rb
|
51
55
|
- lib/on_container/version.rb
|
52
56
|
- on_container.gemspec
|
53
|
-
- spec/on_container_spec.rb
|
54
|
-
- spec/spec_helper.rb
|
55
|
-
- spec/step_down_from_root_spec.rb
|
56
57
|
homepage: https://github.com/IcaliaLabs/on-container-for-ruby
|
57
58
|
licenses:
|
58
59
|
- MIT
|
@@ -60,7 +61,7 @@ metadata:
|
|
60
61
|
allowed_push_host: https://rubygems.org
|
61
62
|
homepage_uri: https://github.com/IcaliaLabs/on-container-for-ruby
|
62
63
|
source_code_uri: https://github.com/IcaliaLabs/on-container-for-ruby
|
63
|
-
changelog_uri: https://github.com/IcaliaLabs/on-container-for-ruby/blob/
|
64
|
+
changelog_uri: https://github.com/IcaliaLabs/on-container-for-ruby/blob/main/CHANGELOG.md
|
64
65
|
post_install_message:
|
65
66
|
rdoc_options: []
|
66
67
|
require_paths:
|
@@ -76,13 +77,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
77
|
- !ruby/object:Gem::Version
|
77
78
|
version: '0'
|
78
79
|
requirements: []
|
79
|
-
|
80
|
-
rubygems_version: 2.5.2.3
|
80
|
+
rubygems_version: 3.1.4
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
83
|
summary: A small collection of scripts and routines to help ruby development within
|
84
84
|
containers
|
85
|
-
test_files:
|
86
|
-
- spec/on_container_spec.rb
|
87
|
-
- spec/spec_helper.rb
|
88
|
-
- spec/step_down_from_root_spec.rb
|
85
|
+
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
|
data/spec/on_container_spec.rb
DELETED
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
|