opdotenv 1.0.1 → 1.0.3

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: 010e15bce13dd6d38d5c1d05871fe4a395cda0b9a68e0057045aec4f0bed6a15
4
- data.tar.gz: 46bf2e43e4b2df72bf1fbb739751dc170e16262a306b6a2373f1098571e00457
3
+ metadata.gz: dd66207d97fd6cf74fe9eaf05dcd22e43b05dd68af9995dcc5348be00fd465ae
4
+ data.tar.gz: 78f719f95dcd42edbdde3e00ed0be0ca9be5ef470055e0a6e49623f3599fd566
5
5
  SHA512:
6
- metadata.gz: 9334e5fc25e01fee0fd7d9ffda74e8df98e598a6275a8ea740790e3dbabde7614eb17bc2f4afddeb37bb29ce10b65f94e63475e46e9f64552fc9699aa6309ffa
7
- data.tar.gz: 57d4a520a562d583e8fff85e3d9bf3944429d3442339dbbf44e75731a5f5abad819029606179d8667627836aa730b8424eac3fe21f39ddf81060e0bf36f44e12
6
+ metadata.gz: 4ba1fbc82986e6a20c8302c21bf27e0c61a3ba4703379dc0a9966d115d0101c8383497a7eea4a14cbce010eff8a94d273f98a6da1c5c01810773d2dc70c6400a
7
+ data.tar.gz: f695a8cf1a6e7e1f3c2daba02609366618b82f66162c45a4f64912e50dae71313dfab2cc0cd276dfae8409f43ba6895707a3a85b9447eaea4af00653bebd82e6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.0.3 (2025-11-07)
4
+
5
+ - Fix exit code handling in OpClient by using Open3.capture2e instead of IO.popen for reliable process status
6
+ - Improve load_all_fields to filter out empty keys and only include fields from 1Password items
7
+ - Strip whitespace from field labels and treat empty labels (after stripping) as nil
8
+ - Filter out fields with empty or whitespace-only values
9
+
10
+ ## 1.0.2 (2025-11-05)
11
+
12
+ - Enhance error handling and security measures across the codebase
13
+ - Improved error logging to avoid leaking sensitive information (uses exception class names instead of messages)
14
+ - Enhanced API error handling with generic messages for server errors to prevent sensitive data exposure
15
+ - Updated CLI output to clarify that secrets may be displayed intentionally for command-line usage
16
+ - Update Rails appraisals: remove support for Rails 6.0, 7.0, 7.1, 8.0; maintain support for Rails 6.1, 7.2, 8.1
17
+
3
18
  ## 1.0.1 (2025-11-05)
4
19
 
5
20
  - Add configurable op CLI path support
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # opdotenv
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/opdotenv.svg?v=1.0.0)](https://badge.fury.io/rb/opdotenv) [![Test Status](https://github.com/amkisko/opdotenv.rb/actions/workflows/ci.yml/badge.svg)](https://github.com/amkisko/opdotenv.rb/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/amkisko/opdotenv.rb/graph/badge.svg?token=U4FMVZGO8R)](https://codecov.io/gh/amkisko/opdotenv.rb)
3
+ [![Gem Version](https://badge.fury.io/rb/opdotenv.svg?v=1.0.3)](https://badge.fury.io/rb/opdotenv) [![Test Status](https://github.com/amkisko/opdotenv.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/opdotenv.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/opdotenv.rb/graph/badge.svg?token=U4FMVZGO8R)](https://codecov.io/gh/amkisko/opdotenv.rb)
4
4
 
5
5
  Load environment variables from 1Password using the `op` CLI or 1Password Connect Server API. Supports dotenv, JSON, and YAML formats.
6
6
 
7
7
  Sponsored by [Kisko Labs](https://www.kiskolabs.com).
8
8
 
9
9
  <a href="https://www.kiskolabs.com">
10
- <img src="https://brand.kiskolabs.com/images/logos/Kisko_Logo_Black_Horizontal-7249a361.svg" width="200" style="display: block; background: white; border-radius: 10px;" />
10
+ <img src="kisko.svg" width="200" alt="Sponsored by Kisko Labs" />
11
11
  </a>
12
12
 
13
13
  ## Installation
data/bin/opdotenv CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
3
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
4
  require "opdotenv"
@@ -15,6 +14,8 @@ when "read"
15
14
  end.parse!(ARGV)
16
15
  abort("--path required") unless path
17
16
  data = Opdotenv::Loader.load(path)
17
+ # Note: This CLI intentionally outputs secrets to stdout for CLI usage
18
+ # This is expected behavior for the command-line tool
18
19
  puts Opdotenv::Exporter.serialize_by_format(data, :dotenv)
19
20
  when "export"
20
21
  path = file = nil
@@ -118,8 +118,8 @@ begin
118
118
  rescue => e
119
119
  # Only warn if debugging is enabled, as this is expected when Anyway Config isn't used
120
120
  if ENV["OPDOTENV_DEBUG"] == "true"
121
- warn "[opdotenv] Failed to register Anyway loader: #{e.message}"
122
- warn "[opdotenv] Error details: #{e.class}: #{e.message}"
121
+ # Avoid leaking exception messages
122
+ warn "[opdotenv] Failed to register Anyway loader: #{e.class}"
123
123
  warn "[opdotenv] Backtrace: #{e.backtrace.first(3).join("\n")}" if e.backtrace
124
124
  end
125
125
  end
@@ -261,17 +261,24 @@ module Opdotenv
261
261
  when 404
262
262
  raise ConnectApiError, "Not found: #{path}"
263
263
  when 500..599
264
- raise ConnectApiError, "API error (#{code}): #{extract_error_message(response)}"
264
+ raise ConnectApiError, "API error (#{code}): Server error"
265
265
  else
266
- raise ConnectApiError, "API error (#{code}): #{extract_error_message(response)}"
266
+ # Extract safe error message without leaking response body
267
+ safe_message = extract_safe_error_message(response)
268
+ raise ConnectApiError, "API error (#{code}): #{safe_message}"
267
269
  end
268
270
  end
269
271
 
270
- def extract_error_message(response)
272
+ def extract_safe_error_message(response)
273
+ # Only extract structured error messages from JSON responses
274
+ # Never include raw response body to avoid leaking secrets
275
+
271
276
  parsed = JSON.parse(response.body)
272
- parsed["message"] || parsed["error"] || response.body
277
+ # Only return known safe fields that are typically error messages
278
+ parsed["message"] || parsed["error"] || "Request failed"
273
279
  rescue JSON::ParserError
274
- response.body
280
+ # For non-JSON responses, return generic message to avoid leaking body
281
+ "Request failed"
275
282
  end
276
283
 
277
284
  def validate_url(url)
@@ -25,11 +25,23 @@ module Opdotenv
25
25
  raw_json = client.item_get(item, vault: vault)
26
26
  item_hash = parse_json_safe(raw_json)
27
27
 
28
+ # Only process fields from the 1Password item, filter out empty values
28
29
  item_hash["fields"]&.each_with_object({}) do |field, env_data|
29
- label = field["label"] || field["id"]
30
- next unless label
31
- next if field["purpose"] == NOTES_PURPOSE # skip notesPlain when fetching all
32
- env_data[label.to_s] = (field["value"] || "").to_s
30
+ # Only include actual fields from the item
31
+ next unless field.is_a?(Hash)
32
+
33
+ # Strip whitespace from label and treat empty strings as nil
34
+ label = (field["label"] || field["id"])&.strip
35
+ next if label.nil? || label.empty?
36
+
37
+ # Skip notesPlain when fetching all fields
38
+ next if field["purpose"] == NOTES_PURPOSE
39
+
40
+ # Get the value and filter out empty values
41
+ value = field["value"]
42
+ next if value.nil? || (value.is_a?(String) && value.strip.empty?)
43
+
44
+ env_data[label.to_s] = value.to_s
33
45
  end || {}
34
46
  end
35
47
 
@@ -1,4 +1,5 @@
1
1
  require "json"
2
+ require "open3"
2
3
 
3
4
  module Opdotenv
4
5
  class OpClient
@@ -71,11 +72,8 @@ module Opdotenv
71
72
 
72
73
  def capture(args)
73
74
  # Use exec-style array to prevent shell injection
74
- # IO.popen with array arguments avoids shell interpretation
75
- out = IO.popen(args, err: [:child, :out]) do |io|
76
- io.read
77
- end
78
- status = $CHILD_STATUS
75
+ # Open3.capture2e captures both stdout and stderr, and properly returns exit status
76
+ out, status = Open3.capture2e(*args)
79
77
 
80
78
  # For JSON output, try to parse even if exit code is non-zero
81
79
  # Some op commands may return non-zero but still output valid JSON
@@ -88,7 +86,13 @@ module Opdotenv
88
86
  end
89
87
  end
90
88
 
91
- raise OpError, out if status.nil? || !status.success?
89
+ unless status.success?
90
+ # Never leak command output in error messages for security
91
+ # Extract safe error information without exposing secrets
92
+ exit_code = status.exitstatus
93
+ command_name = args.first || "op"
94
+ raise OpError, "Command failed: #{command_name} (exit code: #{exit_code})"
95
+ end
92
96
  out
93
97
  end
94
98
  end
@@ -54,7 +54,9 @@ module Opdotenv
54
54
  )
55
55
  rescue => e
56
56
  # Only log errors, not warnings, to avoid noise in production
57
- Rails.logger&.error("Opdotenv: Failed to load #{parsed[:path]}: #{e.message}")
57
+ # Never log exception messages that might contain secrets from command output
58
+ # Use exception class name instead of message for security
59
+ Rails.logger&.error("Opdotenv: Failed to load #{parsed[:path]}: #{e.class.name}")
58
60
  end
59
61
  end
60
62
  end
@@ -1,3 +1,3 @@
1
1
  module Opdotenv
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.3"
3
3
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opdotenv
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
- - amkisko
7
+ - Andrei Makarov
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
@@ -35,42 +35,42 @@ dependencies:
35
35
  requirements:
36
36
  - - "~>"
37
37
  - !ruby/object:Gem::Version
38
- version: '13.0'
38
+ version: '13'
39
39
  type: :development
40
40
  prerelease: false
41
41
  version_requirements: !ruby/object:Gem::Requirement
42
42
  requirements:
43
43
  - - "~>"
44
44
  - !ruby/object:Gem::Version
45
- version: '13.0'
45
+ version: '13'
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: rspec
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - "~>"
51
51
  - !ruby/object:Gem::Version
52
- version: '3.12'
52
+ version: '3'
53
53
  type: :development
54
54
  prerelease: false
55
55
  version_requirements: !ruby/object:Gem::Requirement
56
56
  requirements:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
- version: '3.12'
59
+ version: '3'
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: simplecov
62
62
  requirement: !ruby/object:Gem::Requirement
63
63
  requirements:
64
64
  - - "~>"
65
65
  - !ruby/object:Gem::Version
66
- version: '0.21'
66
+ version: '0.22'
67
67
  type: :development
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '0.21'
73
+ version: '0.22'
74
74
  - !ruby/object:Gem::Dependency
75
75
  name: rspec_junit_formatter
76
76
  requirement: !ruby/object:Gem::Requirement
@@ -105,28 +105,42 @@ dependencies:
105
105
  requirements:
106
106
  - - "~>"
107
107
  - !ruby/object:Gem::Version
108
- version: '1.0'
108
+ version: '1'
109
109
  type: :development
110
110
  prerelease: false
111
111
  version_requirements: !ruby/object:Gem::Requirement
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '1.0'
115
+ version: '1'
116
+ - !ruby/object:Gem::Dependency
117
+ name: standard-performance
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '1'
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '1'
116
130
  - !ruby/object:Gem::Dependency
117
131
  name: appraisal
118
132
  requirement: !ruby/object:Gem::Requirement
119
133
  requirements:
120
134
  - - "~>"
121
135
  - !ruby/object:Gem::Version
122
- version: '2.4'
136
+ version: '2'
123
137
  type: :development
124
138
  prerelease: false
125
139
  version_requirements: !ruby/object:Gem::Requirement
126
140
  requirements:
127
141
  - - "~>"
128
142
  - !ruby/object:Gem::Version
129
- version: '2.4'
143
+ version: '2'
130
144
  - !ruby/object:Gem::Dependency
131
145
  name: webmock
132
146
  requirement: !ruby/object:Gem::Requirement
@@ -147,28 +161,28 @@ dependencies:
147
161
  requirements:
148
162
  - - "~>"
149
163
  - !ruby/object:Gem::Version
150
- version: '0.14'
164
+ version: '0.15'
151
165
  type: :development
152
166
  prerelease: false
153
167
  version_requirements: !ruby/object:Gem::Requirement
154
168
  requirements:
155
169
  - - "~>"
156
170
  - !ruby/object:Gem::Version
157
- version: '0.14'
171
+ version: '0.15'
158
172
  - !ruby/object:Gem::Dependency
159
173
  name: rbs
160
174
  requirement: !ruby/object:Gem::Requirement
161
175
  requirements:
162
176
  - - "~>"
163
177
  - !ruby/object:Gem::Version
164
- version: '3.0'
178
+ version: '3'
165
179
  type: :development
166
180
  prerelease: false
167
181
  version_requirements: !ruby/object:Gem::Requirement
168
182
  requirements:
169
183
  - - "~>"
170
184
  - !ruby/object:Gem::Version
171
- version: '3.0'
185
+ version: '3'
172
186
  - !ruby/object:Gem::Dependency
173
187
  name: anyway_config
174
188
  requirement: !ruby/object:Gem::Requirement
@@ -211,13 +225,13 @@ files:
211
225
  - lib/opdotenv/railtie.rb
212
226
  - lib/opdotenv/source_parser.rb
213
227
  - lib/opdotenv/version.rb
214
- homepage: https://github.com/amkisko/opdotenv
228
+ homepage: https://github.com/amkisko/opdotenv.rb
215
229
  licenses:
216
230
  - MIT
217
231
  metadata:
218
- source_code_uri: https://github.com/amkisko/opdotenv
219
- changelog_uri: https://github.com/amkisko/opdotenv/blob/main/CHANGELOG.md
220
- bug_tracker_uri: https://github.com/amkisko/opdotenv/issues
232
+ source_code_uri: https://github.com/amkisko/opdotenv.rb
233
+ changelog_uri: https://github.com/amkisko/opdotenv.rb/blob/main/CHANGELOG.md
234
+ bug_tracker_uri: https://github.com/amkisko/opdotenv.rb/issues
221
235
  rdoc_options: []
222
236
  require_paths:
223
237
  - lib