envameleon 0.2.0-aarch64-linux-gnu
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +279 -0
- data/lib/envameleon/3.2/envameleon.so +0 -0
- data/lib/envameleon/3.3/envameleon.so +0 -0
- data/lib/envameleon/3.4/envameleon.so +0 -0
- data/lib/envameleon/4.0/envameleon.so +0 -0
- data/lib/envameleon.rb +30 -0
- metadata +108 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b7d40e81075e5e8642eaeabeb6e6459ed8f9a266821cada6be9347533ecab268
|
|
4
|
+
data.tar.gz: bfdfb779361822d8500d54bb3d0b89dd60116ba8142f358c06fe2239c4f7bdb7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1d6d822af0df80cc318e33c1b87fee0db5d956b54be5447c72f4b859804aed2ad8c6377319b3c02b65abc4e72d4a0e732ff2802c7f3046562985b547890fbbcf
|
|
7
|
+
data.tar.gz: a4c5935307019a145399231e5bbfc0bc3857d1f8ab08dc337f0cc262e41c5a00c483731ad3a97066af812e27749b9bb0faf96c4abe609bd40998e1c433d0d567
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dmytro Shteflyuk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
<a id="readme-top"></a>
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<img src="assets/envameleon.png" alt="ENVameleon — Leave no ENVidence." width="800">
|
|
5
|
+
|
|
6
|
+
<h1>ENVameleon</h1>
|
|
7
|
+
<p><strong>Leave no ENVidence.</strong></p>
|
|
8
|
+
<p>Hide the first process environment shown by Linux without changing Ruby's <code>ENV</code>.</p>
|
|
9
|
+
<p>
|
|
10
|
+
<a href="#about">About</a> ·
|
|
11
|
+
<a href="#getting-started">Get started</a> ·
|
|
12
|
+
<a href="#usage">Usage</a> ·
|
|
13
|
+
<a href="#how-it-works">How it works</a> ·
|
|
14
|
+
<a href="#development">Development</a>
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
- [About](#about)
|
|
21
|
+
- [Getting Started](#getting-started)
|
|
22
|
+
- [Native Gems](#native-gems)
|
|
23
|
+
- [Usage](#usage)
|
|
24
|
+
- [How It Works](#how-it-works)
|
|
25
|
+
- [Process Inheritance](#process-inheritance)
|
|
26
|
+
- [Security Limits](#security-limits)
|
|
27
|
+
- [Development](#development)
|
|
28
|
+
- [License](#license)
|
|
29
|
+
|
|
30
|
+
## About
|
|
31
|
+
|
|
32
|
+
Linux exposes the environment passed at process start through
|
|
33
|
+
`/proc/self/environ`. ENVameleon lets a Ruby process mask, scrub, or drop that
|
|
34
|
+
view after boot. Ruby's live `ENV` stays intact.
|
|
35
|
+
|
|
36
|
+
### Why this matters
|
|
37
|
+
|
|
38
|
+
Suppose your app keeps its credentials in an encrypted file. Your container
|
|
39
|
+
runner passes the unlock key through the process environment. The encrypted
|
|
40
|
+
file may seem safe even if an attacker can read any file that the app can
|
|
41
|
+
access.
|
|
42
|
+
|
|
43
|
+
Guess again. Linux also exposes `/proc/self/environ` as a file. It may hold the
|
|
44
|
+
unlock key passed at process launch. An attacker who reads both files can
|
|
45
|
+
decrypt the credentials, recover a session signing key, and forge sessions.
|
|
46
|
+
|
|
47
|
+
ENVameleon removes this copy of the key from the proc view after app boot.
|
|
48
|
+
|
|
49
|
+
The gem has no runtime dependencies. Loading it does not change anything. Your
|
|
50
|
+
app chooses when to call one of its three methods.
|
|
51
|
+
|
|
52
|
+
## Getting Started
|
|
53
|
+
|
|
54
|
+
### Requirements
|
|
55
|
+
|
|
56
|
+
- CRuby 3.2 or newer
|
|
57
|
+
- Linux for changes to `/proc/self/environ`
|
|
58
|
+
- The Linux `CAP_SYS_RESOURCE` right only for `ENV.drop_proc_data`
|
|
59
|
+
|
|
60
|
+
On macOS and Windows, all three methods are safe no-ops.
|
|
61
|
+
|
|
62
|
+
### Installation
|
|
63
|
+
|
|
64
|
+
Install the gem:
|
|
65
|
+
|
|
66
|
+
```console
|
|
67
|
+
gem install envameleon
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or add it to your `Gemfile`:
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
gem "envameleon"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then load it:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
require "envameleon"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
[Back to top](#readme-top).
|
|
83
|
+
|
|
84
|
+
## Native Gems
|
|
85
|
+
|
|
86
|
+
ENVameleon publishes precompiled native gems for its supported CRuby minors on:
|
|
87
|
+
|
|
88
|
+
- GNU/Linux and musl Linux on x86-64 and AArch64
|
|
89
|
+
|
|
90
|
+
The macOS and Windows gems contain the documented pure-Ruby no-ops. There is no
|
|
91
|
+
native code to compile on those systems. Linux is split into `-linux-gnu` and
|
|
92
|
+
`-linux-musl` gems so a glibc binary is never mistaken for a musl binary. These
|
|
93
|
+
native gems require RubyGems 3.3.22 or newer; musl users should use Bundler
|
|
94
|
+
2.5.6 or newer.
|
|
95
|
+
|
|
96
|
+
Each precompiled Linux gem contains a separate binary for every supported Ruby
|
|
97
|
+
minor and has no extension build hook. When Linux runs a newer Ruby API,
|
|
98
|
+
RubyGems or Bundler selects the generic source gem instead. That gem runs
|
|
99
|
+
`extconf.rb` and requires a C compiler, Make, and the Ruby headers. macOS and
|
|
100
|
+
Windows continue to select their compiler-free no-op gems. If neither a native
|
|
101
|
+
nor source fallback applies on Linux, `require "envameleon"` fails closed
|
|
102
|
+
instead of silently exposing the process environment.
|
|
103
|
+
|
|
104
|
+
Every GitHub release includes the gems and `SHA256SUMS`. Release gems also have
|
|
105
|
+
GitHub build-provenance attestations, which can be checked with:
|
|
106
|
+
|
|
107
|
+
```console
|
|
108
|
+
gh attestation verify envameleon-0.2.0-x86_64-linux-gnu.gem --repo kpumuk/envameleon
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
[Back to top](#readme-top).
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
require "envameleon"
|
|
117
|
+
|
|
118
|
+
ENV.mask_proc_data
|
|
119
|
+
# SECRET=example becomes SECRET=e*****e in /proc/self/environ
|
|
120
|
+
|
|
121
|
+
ENV.scrub_proc_data
|
|
122
|
+
# /proc/self/environ now holds only NUL bytes
|
|
123
|
+
|
|
124
|
+
ENV.drop_proc_data
|
|
125
|
+
# /proc/self/environ is now zero bytes long
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
| Method | Result in `/proc/self/environ` | File length | Permissions |
|
|
129
|
+
| --- | --- | --- | --- |
|
|
130
|
+
| `ENV.mask_proc_data` | Names plus the first and last value byte | Unchanged | None |
|
|
131
|
+
| `ENV.scrub_proc_data` | NUL bytes | Unchanged | None |
|
|
132
|
+
| `ENV.drop_proc_data` | Empty | Zero | `CAP_SYS_RESOURCE` |
|
|
133
|
+
|
|
134
|
+
Choose the least power you need.
|
|
135
|
+
|
|
136
|
+
> [!IMPORTANT]
|
|
137
|
+
> `ENV.drop_proc_data` requires `CAP_SYS_RESOURCE` on Linux. Without it, the
|
|
138
|
+
> method raises `Errno::EPERM`.
|
|
139
|
+
|
|
140
|
+
Masking works on raw bytes, not characters. It replaces all value bytes except
|
|
141
|
+
the first and last with `*`. Values shorter than three bytes stay unchanged.
|
|
142
|
+
|
|
143
|
+
[Back to top](#readme-top).
|
|
144
|
+
|
|
145
|
+
## How It Works
|
|
146
|
+
|
|
147
|
+
CRuby moves its active environment during startup. Linux still keeps the old
|
|
148
|
+
range used by `/proc/self/environ`. ENVameleon reads that range from
|
|
149
|
+
`/proc/self/stat`.
|
|
150
|
+
|
|
151
|
+
Masking and scrubbing first check that Ruby no longer uses the old range. They
|
|
152
|
+
then change those bytes in place. If Ruby still uses any of them, the method
|
|
153
|
+
raises an error and changes nothing.
|
|
154
|
+
|
|
155
|
+
Dropping uses `PR_SET_MM_ENV_END` to move the end of the kernel's view to its
|
|
156
|
+
start. This makes `/proc/self/environ` truly zero-length. Linux requires the
|
|
157
|
+
`CAP_SYS_RESOURCE` right for that call.
|
|
158
|
+
|
|
159
|
+
## Process Inheritance
|
|
160
|
+
|
|
161
|
+
Call a method before `fork` and each child inherits the changed proc view. Ruby
|
|
162
|
+
`ENV` remains available in the parent and children. The test suite checks this
|
|
163
|
+
with a second fork for all three methods.
|
|
164
|
+
|
|
165
|
+
`spawn`, `system`, and `exec` are different. They give the new program a fresh
|
|
166
|
+
proc environment. That program must load ENVameleon and call a method itself.
|
|
167
|
+
|
|
168
|
+
### Forking servers
|
|
169
|
+
|
|
170
|
+
You may call a method in the parent before it forks. You may also call it from a
|
|
171
|
+
worker boot hook. These examples use scrubbing, which needs no extra right.
|
|
172
|
+
|
|
173
|
+
#### Unicorn
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
require "envameleon"
|
|
177
|
+
|
|
178
|
+
after_fork do |_server, _worker|
|
|
179
|
+
ENV.scrub_proc_data
|
|
180
|
+
end
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Puma
|
|
184
|
+
|
|
185
|
+
Use `before_worker_boot` for cluster workers. In single mode, call the method
|
|
186
|
+
during app boot.
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
require "envameleon"
|
|
190
|
+
|
|
191
|
+
before_worker_boot do
|
|
192
|
+
ENV.scrub_proc_data
|
|
193
|
+
end
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Sidekiq
|
|
197
|
+
|
|
198
|
+
Standard Sidekiq uses threads. Its startup hook runs before work begins. Sidekiq
|
|
199
|
+
Enterprise Swarm runs the hook in each child.
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
require "envameleon"
|
|
203
|
+
|
|
204
|
+
Sidekiq.configure_server do |config|
|
|
205
|
+
config.on(:startup) { ENV.scrub_proc_data }
|
|
206
|
+
end
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### Karafka
|
|
210
|
+
|
|
211
|
+
The `app.running` event runs in the server process. In Swarm mode, it runs in
|
|
212
|
+
each forked node.
|
|
213
|
+
|
|
214
|
+
```ruby
|
|
215
|
+
require "envameleon"
|
|
216
|
+
|
|
217
|
+
Karafka::App.monitor.subscribe("app.running") do
|
|
218
|
+
ENV.scrub_proc_data
|
|
219
|
+
end
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
If a child calls `ENV.drop_proc_data`, it must still have the needed Linux right.
|
|
223
|
+
|
|
224
|
+
[Back to top](#readme-top).
|
|
225
|
+
|
|
226
|
+
## Security Limits
|
|
227
|
+
|
|
228
|
+
> [!WARNING]
|
|
229
|
+
> **`CAP_SYS_RESOURCE` grants broad powers outside ENVameleon.**
|
|
230
|
+
>
|
|
231
|
+
> `ENV.drop_proc_data` needs this Linux capability. Grant it only if you accept
|
|
232
|
+
> its wider access. Masking and scrubbing do not need it.
|
|
233
|
+
|
|
234
|
+
ENVameleon changes only what `/proc/self/environ` shows. It does not erase every
|
|
235
|
+
copy of a secret. It gives no protection from memory disclosure, debuggers, or
|
|
236
|
+
core dumps.
|
|
237
|
+
|
|
238
|
+
Dropping leaves the old bytes in memory. Masking keeps variable names and the
|
|
239
|
+
outer bytes of each value. Short values remain fully visible. Scrubbing
|
|
240
|
+
overwrites the old proc range, but a secret may still exist elsewhere.
|
|
241
|
+
|
|
242
|
+
[Back to top](#readme-top).
|
|
243
|
+
|
|
244
|
+
## Development
|
|
245
|
+
|
|
246
|
+
Install the checksum-locked development bundle and run the `test/unit` suite.
|
|
247
|
+
The test task compiles the extension on Linux and exercises the pure-Ruby no-ops
|
|
248
|
+
elsewhere:
|
|
249
|
+
|
|
250
|
+
```console
|
|
251
|
+
bundle install
|
|
252
|
+
bundle exec rake test
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
On Linux, the drop test runs when `CAP_SYS_RESOURCE` is available. Otherwise,
|
|
256
|
+
that one test is omitted.
|
|
257
|
+
|
|
258
|
+
Build the macOS and Windows no-op gems and the Linux source fallback with:
|
|
259
|
+
|
|
260
|
+
```console
|
|
261
|
+
bundle exec rake gem
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Native builds run inside the versioned image selected by the
|
|
265
|
+
checksum-locked `rake-compiler-dock` gem. The image installs the exact Bundler
|
|
266
|
+
version recorded in `Gemfile.lock`; Bundler then validates its own locked
|
|
267
|
+
checksum and installs every other dependency from the prepared local cache:
|
|
268
|
+
|
|
269
|
+
```console
|
|
270
|
+
bundle cache --all-platforms
|
|
271
|
+
bundle exec rake gem:x86_64-linux-gnu
|
|
272
|
+
ruby .github/scripts/verify_native_gem.rb pkg/envameleon-0.2.0-x86_64-linux-gnu.gem x86_64-linux-gnu
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## License
|
|
276
|
+
|
|
277
|
+
Distributed under the MIT License. See `LICENSE.txt`.
|
|
278
|
+
|
|
279
|
+
[Back to top](#readme-top).
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/envameleon.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
ruby_api_version = RUBY_VERSION[/\A\d+\.\d+/]
|
|
6
|
+
native_extension = File.expand_path(
|
|
7
|
+
"envameleon/#{ruby_api_version}/envameleon.#{RbConfig::CONFIG.fetch("DLEXT")}",
|
|
8
|
+
__dir__
|
|
9
|
+
)
|
|
10
|
+
development_extension = File.expand_path(
|
|
11
|
+
"envameleon/envameleon.#{RbConfig::CONFIG.fetch("DLEXT")}",
|
|
12
|
+
__dir__
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if RbConfig::CONFIG.fetch("host_os").include?("linux")
|
|
16
|
+
extension = [native_extension, development_extension].find { |path| File.file?(path) }
|
|
17
|
+
if extension
|
|
18
|
+
require extension
|
|
19
|
+
else
|
|
20
|
+
begin
|
|
21
|
+
require "envameleon/envameleon"
|
|
22
|
+
rescue LoadError => error
|
|
23
|
+
raise unless error.path == "envameleon/envameleon"
|
|
24
|
+
|
|
25
|
+
raise LoadError, "ENVameleon has no native extension for Ruby #{ruby_api_version} on #{RUBY_PLATFORM}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
require_relative "envameleon/noop"
|
|
30
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: envameleon
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.0
|
|
5
|
+
platform: aarch64-linux-gnu
|
|
6
|
+
authors:
|
|
7
|
+
- Dmytro Shteflyuk
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.2'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.2'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: rake-compiler
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.3.1
|
|
33
|
+
type: :development
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 1.3.1
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: rake-compiler-dock
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.12'
|
|
47
|
+
type: :development
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '1.12'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: test-unit
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '3.7'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.7'
|
|
68
|
+
description: Scrub, mask, or drop Linux's /proc/self/environ view without changing
|
|
69
|
+
Ruby's ENV.
|
|
70
|
+
executables: []
|
|
71
|
+
extensions: []
|
|
72
|
+
extra_rdoc_files: []
|
|
73
|
+
files:
|
|
74
|
+
- LICENSE.txt
|
|
75
|
+
- README.md
|
|
76
|
+
- lib/envameleon.rb
|
|
77
|
+
- lib/envameleon/3.2/envameleon.so
|
|
78
|
+
- lib/envameleon/3.3/envameleon.so
|
|
79
|
+
- lib/envameleon/3.4/envameleon.so
|
|
80
|
+
- lib/envameleon/4.0/envameleon.so
|
|
81
|
+
homepage: https://github.com/kpumuk/envameleon
|
|
82
|
+
licenses:
|
|
83
|
+
- MIT
|
|
84
|
+
metadata:
|
|
85
|
+
bug_tracker_uri: https://github.com/kpumuk/envameleon/issues
|
|
86
|
+
rubygems_mfa_required: 'true'
|
|
87
|
+
source_code_uri: https://github.com/kpumuk/envameleon
|
|
88
|
+
rdoc_options: []
|
|
89
|
+
require_paths:
|
|
90
|
+
- lib
|
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '3.2'
|
|
96
|
+
- - "<"
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: 4.1.0.dev
|
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 3.3.22
|
|
104
|
+
requirements: []
|
|
105
|
+
rubygems_version: 4.0.6
|
|
106
|
+
specification_version: 4
|
|
107
|
+
summary: Leave no ENVidence.
|
|
108
|
+
test_files: []
|