envameleon 0.1.0 → 0.3.0

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
2
  SHA256:
3
- metadata.gz: 71067c7187ac66066961bb5ae52346bdfa7dd72a11b7506b25f728ac4c81a64d
4
- data.tar.gz: d1dc5952b9fb0c501750c0655d905792b9bafe45a31c9a21af7f5ffe0b58cbdf
3
+ metadata.gz: a494de9062b6ee90d21cb2f3d95560ab4d7816a244e65fb3a7397fc9783583eb
4
+ data.tar.gz: 763a80b9220b29341d71b42b1df2a36e72e0491e9cea5567a7dc268698a8bcc4
5
5
  SHA512:
6
- metadata.gz: b6492dd83fabd4f3d3e261bb4fcfa4fc16ee15c9d0c6f688b282b5a089dc4fff3512480904c32800ef6c9c7115e9c4d739f24ac2195587458b1a9d832feab392
7
- data.tar.gz: c98a6dd250a633190cd3326a8f425d62902023e8855982db5430c33b7844a22a9e21e29586b221326a3070345910c84f5a8916ca5879f9149aa2cf1f76b62fef
6
+ metadata.gz: 7e2d6d9d3ffff7090e09b710949827047b2a9e1a404707e2a45f03f498be5c8147a3378b747ee191ed2eccd120d6b14e6f408490f5dbeded6522b5300aa5d0eb
7
+ data.tar.gz: eb1903816fdeab2c866ef09561adef82676ba89f9d4e6a375420315358fb8483bc385fb1033a483130e2f8166328bf46b09f8fb291e59288aa94dbadb1b77afb
data/README.md CHANGED
@@ -19,6 +19,7 @@
19
19
 
20
20
  - [About](#about)
21
21
  - [Getting Started](#getting-started)
22
+ - [Native Gems](#native-gems)
22
23
  - [Usage](#usage)
23
24
  - [How It Works](#how-it-works)
24
25
  - [Process Inheritance](#process-inheritance)
@@ -56,7 +57,7 @@ app chooses when to call one of its three methods.
56
57
  - Linux for changes to `/proc/self/environ`
57
58
  - The Linux `CAP_SYS_RESOURCE` right only for `ENV.drop_proc_data`
58
59
 
59
- On other systems, all three methods are safe no-ops.
60
+ On macOS and Windows, all three methods are safe no-ops.
60
61
 
61
62
  ### Installation
62
63
 
@@ -80,6 +81,35 @@ require "envameleon"
80
81
 
81
82
  [Back to top](#readme-top).
82
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
+
83
113
  ## Usage
84
114
 
85
115
  ```ruby
@@ -213,21 +243,34 @@ overwrites the old proc range, but a secret may still exist elsewhere.
213
243
 
214
244
  ## Development
215
245
 
216
- Build the native extension and run the `test/unit` suite:
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:
217
249
 
218
250
  ```console
219
- ruby -Cext/envameleon extconf.rb
220
- make -C ext/envameleon
221
- ruby -Ilib -Iext test/test_envameleon.rb
251
+ bundle install
252
+ bundle exec rake test
253
+ bundle exec rake standard
222
254
  ```
223
255
 
224
256
  On Linux, the drop test runs when `CAP_SYS_RESOURCE` is available. Otherwise,
225
257
  that one test is omitted.
226
258
 
227
- Build the gem with:
259
+ Build the macOS and Windows no-op gems and the Linux source fallback with:
260
+
261
+ ```console
262
+ bundle exec rake gem
263
+ ```
264
+
265
+ Native builds run inside the versioned image selected by the
266
+ checksum-locked `rake-compiler-dock` gem. The image installs the exact Bundler
267
+ version recorded in `Gemfile.lock`; Bundler then validates its own locked
268
+ checksum and installs every other dependency from the prepared local cache:
228
269
 
229
270
  ```console
230
- gem build envameleon.gemspec
271
+ bundle cache --all-platforms
272
+ bundle exec rake gem:x86_64-linux-gnu
273
+ ruby .github/scripts/verify_native_gem.rb pkg/envameleon-0.2.0-x86_64-linux-gnu.gem x86_64-linux-gnu
231
274
  ```
232
275
 
233
276
  ## License
@@ -7,7 +7,6 @@
7
7
  #include <stdlib.h>
8
8
  #include <string.h>
9
9
  #include <sys/prctl.h>
10
- #include <linux/prctl.h>
11
10
 
12
11
  static void
13
12
  read_env_range(unsigned long *env_start, unsigned long *env_end)
@@ -16,22 +15,26 @@ read_env_range(unsigned long *env_start, unsigned long *env_end)
16
15
  char *field;
17
16
  char *end;
18
17
  FILE *file = fopen("/proc/self/stat", "r");
18
+ int error = 0;
19
19
  int number;
20
+ size_t length;
20
21
 
21
22
  if (file == NULL)
22
23
  rb_sys_fail("fopen(/proc/self/stat)");
23
24
 
24
- if (fgets(stat, sizeof(stat), file) == NULL) {
25
- int error = errno;
26
- fclose(file);
27
- if (error != 0) {
28
- errno = error;
29
- rb_sys_fail("fgets(/proc/self/stat)");
30
- }
31
- rb_raise(rb_eRuntimeError, "empty /proc/self/stat");
32
- }
25
+ length = fread(stat, 1, sizeof(stat), file);
26
+ if (ferror(file))
27
+ error = errno == 0 ? EIO : errno;
33
28
  fclose(file);
34
29
 
30
+ if (error != 0)
31
+ rb_syserr_fail(error, "fread(/proc/self/stat)");
32
+ if (length == sizeof(stat))
33
+ rb_raise(rb_eRuntimeError, "/proc/self/stat is too large");
34
+ if (length == 0)
35
+ rb_raise(rb_eRuntimeError, "empty /proc/self/stat");
36
+ stat[length] = '\0';
37
+
35
38
  field = strrchr(stat, ')');
36
39
  if (field == NULL || field[1] != ' ')
37
40
  rb_raise(rb_eRuntimeError, "invalid /proc/self/stat");
@@ -98,16 +101,15 @@ mask_proc_data(VALUE environment)
98
101
  size_t remaining = (char *)env_end - entry;
99
102
  char *terminator = memchr(entry, '\0', remaining);
100
103
  char *equals;
101
- char *value;
102
- size_t value_length;
103
104
 
104
105
  if (terminator == NULL)
105
106
  rb_raise(rb_eRuntimeError, "invalid environment data");
106
107
 
107
108
  equals = memchr(entry, '=', terminator - entry);
108
109
  if (equals != NULL) {
109
- value = equals + 1;
110
- value_length = terminator - value;
110
+ char *value = equals + 1;
111
+ size_t value_length = terminator - value;
112
+
111
113
  if (value_length > 2)
112
114
  memset(value + 1, '*', value_length - 2);
113
115
  }
@@ -154,7 +156,7 @@ drop_proc_data(VALUE environment)
154
156
  }
155
157
  #endif
156
158
 
157
- void
159
+ RUBY_FUNC_EXPORTED void
158
160
  Init_envameleon(void)
159
161
  {
160
162
  ID environment_id = rb_intern2("ENV", 3);
@@ -2,4 +2,24 @@
2
2
 
3
3
  require "mkmf"
4
4
 
5
+ append_cflags %w[
6
+ -Wall
7
+ -Wextra
8
+ -Wformat=2
9
+ -Werror=format-security
10
+ -Werror=implicit-function-declaration
11
+ -fstack-protector-strong
12
+ -fvisibility=hidden
13
+ ]
14
+
15
+ if RUBY_PLATFORM.include?("linux")
16
+ append_cflags "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3"
17
+
18
+ append_ldflags %w[
19
+ -Wl,-z,noexecstack
20
+ -Wl,-z,now
21
+ -Wl,-z,relro
22
+ ]
23
+ end
24
+
5
25
  create_makefile("envameleon/envameleon")
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV.define_singleton_method(:scrub_proc_data) { nil }
4
+ ENV.define_singleton_method(:mask_proc_data) { nil }
5
+ ENV.define_singleton_method(:drop_proc_data) { nil }
data/lib/envameleon.rb CHANGED
@@ -1,7 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ENVameleon
4
- VERSION = "0.1.0"
5
- end
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
+ )
6
14
 
7
- require "envameleon/envameleon"
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 CHANGED
@@ -1,14 +1,84 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: envameleon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmytro Shteflyuk
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies: []
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: standard
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.56'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.56'
68
+ - !ruby/object:Gem::Dependency
69
+ name: test-unit
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.7'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.7'
12
82
  description: Scrub, mask, or drop Linux's /proc/self/environ view without changing
13
83
  Ruby's ENV.
14
84
  executables: []
@@ -18,13 +88,17 @@ extra_rdoc_files: []
18
88
  files:
19
89
  - LICENSE.txt
20
90
  - README.md
21
- - assets/envameleon.png
22
91
  - ext/envameleon/envameleon.c
23
92
  - ext/envameleon/extconf.rb
24
93
  - lib/envameleon.rb
94
+ - lib/envameleon/noop.rb
95
+ homepage: https://github.com/kpumuk/envameleon
25
96
  licenses:
26
97
  - MIT
27
- metadata: {}
98
+ metadata:
99
+ bug_tracker_uri: https://github.com/kpumuk/envameleon/issues
100
+ rubygems_mfa_required: 'true'
101
+ source_code_uri: https://github.com/kpumuk/envameleon
28
102
  rdoc_options: []
29
103
  require_paths:
30
104
  - lib
@@ -32,14 +106,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
32
106
  requirements:
33
107
  - - ">="
34
108
  - !ruby/object:Gem::Version
35
- version: '3.2'
109
+ version: 3.2.0
36
110
  required_rubygems_version: !ruby/object:Gem::Requirement
37
111
  requirements:
38
112
  - - ">="
39
113
  - !ruby/object:Gem::Version
40
114
  version: '0'
41
115
  requirements: []
42
- rubygems_version: 3.6.9
116
+ rubygems_version: 4.0.16
43
117
  specification_version: 4
44
118
  summary: Leave no ENVidence.
45
119
  test_files: []
Binary file