asherah 0.9.0-aarch64-linux → 0.10.0-aarch64-linux
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 +4 -4
- data/README.md +336 -56
- data/lib/asherah/config.rb +64 -74
- data/lib/asherah/error.rb +11 -25
- data/lib/asherah/hooks.rb +239 -0
- data/lib/asherah/native/{libasherah-arm64.so → libasherah_ffi.so} +0 -0
- data/lib/asherah/native.rb +146 -0
- data/lib/asherah/session.rb +176 -0
- data/lib/asherah/session_factory.rb +35 -0
- data/lib/asherah/version.rb +1 -1
- data/lib/asherah.rb +286 -100
- metadata +43 -39
- data/.env.secrets.example +0 -9
- data/.rspec +0 -3
- data/.rubocop.yml +0 -112
- data/.ruby-version +0 -1
- data/CHANGELOG.md +0 -131
- data/CODE_OF_CONDUCT.md +0 -77
- data/CONTRIBUTING.md +0 -118
- data/Gemfile +0 -14
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -29
- data/SECURITY.md +0 -19
- data/asherah.gemspec +0 -39
- data/ext/asherah/checksums.yml +0 -5
- data/ext/asherah/extconf.rb +0 -7
- data/ext/asherah/native_file.rb +0 -64
data/lib/asherah.rb
CHANGED
|
@@ -1,135 +1,321 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require 'asherah/config'
|
|
5
|
-
require 'asherah/error'
|
|
6
|
-
require 'cobhan'
|
|
3
|
+
require "json"
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
require_relative "asherah/version"
|
|
6
|
+
require_relative "asherah/error"
|
|
7
|
+
require_relative "asherah/config"
|
|
8
|
+
require_relative "asherah/native"
|
|
9
|
+
require_relative "asherah/session_factory"
|
|
10
|
+
require_relative "asherah/session"
|
|
11
|
+
require_relative "asherah/hooks"
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[:SetEnv, [:pointer], :int32],
|
|
15
|
-
[:SetupJson, [:pointer], :int32],
|
|
16
|
-
[:EncryptToJson, [:pointer, :pointer, :pointer], :int32],
|
|
17
|
-
[:DecryptFromJson, [:pointer, :pointer, :pointer], :int32],
|
|
18
|
-
[:Shutdown, [], :void]
|
|
19
|
-
].freeze)
|
|
13
|
+
module Asherah
|
|
14
|
+
DEFAULT_SESSION_CACHE_MAX_SIZE = 1000
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
@mutex = Mutex.new
|
|
17
|
+
@factory = nil
|
|
18
|
+
# @sessions is an LRU cache. Ruby Hash preserves insertion order, so we
|
|
19
|
+
# implement LRU by delete-and-reinsert on hit (moves the entry to the
|
|
20
|
+
# end), and `shift` on overflow (removes the oldest, i.e. least-recently
|
|
21
|
+
# used). Bounded by @session_cache_max_size, which honors the
|
|
22
|
+
# SessionCacheMaxSize config field — same default (1000) as the Rust
|
|
23
|
+
# core and the other bindings.
|
|
24
|
+
@sessions = {}
|
|
25
|
+
@initialized = false
|
|
26
|
+
@session_cache_enabled = true
|
|
27
|
+
@session_cache_max_size = DEFAULT_SESSION_CACHE_MAX_SIZE
|
|
28
|
+
@verbose = false
|
|
24
29
|
|
|
25
30
|
class << self
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# References:
|
|
29
|
-
# https://github.com/golang/go/wiki/cgo#environmental-variables
|
|
30
|
-
# https://github.com/golang/go/issues/44108
|
|
31
|
+
# Configure Asherah using a block with snake_case accessors.
|
|
32
|
+
# Compatible with the canonical godaddy/asherah-ruby gem API.
|
|
31
33
|
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
# Asherah.configure do |config|
|
|
35
|
+
# config.service_name = "MyService"
|
|
36
|
+
# config.product_id = "MyProduct"
|
|
37
|
+
# config.kms = "static"
|
|
38
|
+
# config.metastore = "memory"
|
|
39
|
+
# end
|
|
40
|
+
def configure
|
|
41
|
+
@mutex.synchronize do
|
|
42
|
+
raise Error::AlreadyInitialized if @initialized
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
config = Config.new
|
|
45
|
+
yield config
|
|
46
|
+
config.validate!
|
|
47
|
+
|
|
48
|
+
json = config.to_json
|
|
49
|
+
pointer = Native.asherah_factory_new_with_config(json)
|
|
50
|
+
@factory = SessionFactory.new(pointer)
|
|
51
|
+
@sessions = {}
|
|
52
|
+
@initialized = true
|
|
53
|
+
@session_cache_enabled = config.enable_session_caching != false
|
|
54
|
+
@session_cache_max_size = positive_int(config.session_cache_max_size) || DEFAULT_SESSION_CACHE_MAX_SIZE
|
|
55
|
+
@verbose = config.verbose == true
|
|
56
|
+
end
|
|
42
57
|
end
|
|
43
58
|
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
raise Asherah::Error::AlreadyInitialized if @initialized
|
|
59
|
+
# Initialize Asherah with a PascalCase config hash.
|
|
60
|
+
# Also accepts snake_case string/symbol keys (auto-normalized).
|
|
61
|
+
def setup(config)
|
|
62
|
+
normalized = normalize_config(config)
|
|
63
|
+
json = JSON.generate(normalized)
|
|
50
64
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
config.validate!
|
|
54
|
-
@intermediated_key_overhead_bytesize = config.product_id.bytesize + config.service_name.bytesize
|
|
65
|
+
pointer = Native.asherah_factory_new_with_config(json)
|
|
66
|
+
factory = SessionFactory.new(pointer)
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
@mutex.synchronize do
|
|
69
|
+
raise Error::AlreadyInitialized if @initialized
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
@factory = factory
|
|
72
|
+
@sessions = {}
|
|
73
|
+
@initialized = true
|
|
74
|
+
@session_cache_enabled = truthy(normalized["EnableSessionCaching"], default: true)
|
|
75
|
+
@session_cache_max_size = positive_int(normalized["SessionCacheMaxSize"]) || DEFAULT_SESSION_CACHE_MAX_SIZE
|
|
76
|
+
@verbose = truthy(normalized["Verbose"], default: false)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
nil
|
|
80
|
+
rescue StandardError
|
|
81
|
+
factory&.close if defined?(factory) && factory
|
|
82
|
+
raise
|
|
63
83
|
end
|
|
64
84
|
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
# Run setup in a background Thread. Yields the result to +block+ on
|
|
86
|
+
# success. Exceptions raised by setup propagate via the Thread's
|
|
87
|
+
# joined error — the previous implementation called the block with
|
|
88
|
+
# the result on success but silently dropped the Thread's error
|
|
89
|
+
# state on failure, leaving callers unable to distinguish completion
|
|
90
|
+
# from an unsetup factory. The Thread aborts on exception
|
|
91
|
+
# (`Thread.report_on_exception = true`), so a stack trace lands on
|
|
92
|
+
# stderr; callers that need programmatic access should
|
|
93
|
+
# `thread.join` to re-raise. T-finding "setup_async/shutdown_async/
|
|
94
|
+
# encrypt_async/decrypt_async swallow Thread exceptions" in
|
|
95
|
+
# `docs/review-2026-05-05-findings.md`.
|
|
96
|
+
def setup_async(config, &block)
|
|
97
|
+
Thread.new do
|
|
98
|
+
Thread.current.report_on_exception = true
|
|
99
|
+
result = setup(config)
|
|
100
|
+
block&.call(result)
|
|
101
|
+
result
|
|
102
|
+
end
|
|
103
|
+
end
|
|
82
104
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
105
|
+
def shutdown
|
|
106
|
+
factory = nil
|
|
107
|
+
sessions = nil
|
|
108
|
+
@mutex.synchronize do
|
|
109
|
+
raise Error::NotInitialized unless @initialized
|
|
87
110
|
|
|
88
|
-
|
|
89
|
-
|
|
111
|
+
factory = @factory
|
|
112
|
+
sessions = @sessions.values
|
|
113
|
+
@factory = nil
|
|
114
|
+
@sessions = {}
|
|
115
|
+
@initialized = false
|
|
116
|
+
end
|
|
90
117
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
118
|
+
Array(sessions).each do |session|
|
|
119
|
+
begin
|
|
120
|
+
session.close unless session.closed?
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
warn "asherah: error closing session during shutdown: #{e.message}"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
factory&.close unless factory&.closed?
|
|
126
|
+
nil
|
|
94
127
|
end
|
|
95
128
|
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
129
|
+
# Run shutdown in a background Thread; see `setup_async` for the
|
|
130
|
+
# exception-propagation contract.
|
|
131
|
+
def shutdown_async(&block)
|
|
132
|
+
Thread.new do
|
|
133
|
+
Thread.current.report_on_exception = true
|
|
134
|
+
result = shutdown
|
|
135
|
+
block&.call(result)
|
|
136
|
+
result
|
|
137
|
+
end
|
|
138
|
+
end
|
|
103
139
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
140
|
+
def get_setup_status
|
|
141
|
+
@mutex.synchronize { @initialized }
|
|
142
|
+
end
|
|
107
143
|
|
|
108
|
-
|
|
109
|
-
|
|
144
|
+
def setenv(env = {})
|
|
145
|
+
data = case env
|
|
146
|
+
when String
|
|
147
|
+
JSON.parse(env)
|
|
148
|
+
else
|
|
149
|
+
env
|
|
150
|
+
end
|
|
151
|
+
unless data.respond_to?(:each_pair)
|
|
152
|
+
raise ArgumentError, "environment payload must be a Hash or JSON object"
|
|
153
|
+
end
|
|
154
|
+
data.each_pair do |k, v|
|
|
155
|
+
if v.nil?
|
|
156
|
+
ENV.delete(String(k))
|
|
157
|
+
else
|
|
158
|
+
ENV[String(k)] = v.to_s
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
nil
|
|
162
|
+
end
|
|
163
|
+
alias_method :set_env, :setenv
|
|
110
164
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
165
|
+
def encrypt(partition_id, payload)
|
|
166
|
+
raise ArgumentError, "payload cannot be nil" if payload.nil?
|
|
167
|
+
session = resolve_session(partition_id)
|
|
168
|
+
session.encrypt_bytes(payload)
|
|
114
169
|
end
|
|
115
170
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
171
|
+
def encrypt_string(partition_id, text)
|
|
172
|
+
raise ArgumentError, "text cannot be nil" if text.nil?
|
|
173
|
+
encrypt(partition_id, text)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def decrypt(partition_id, data_row_record)
|
|
177
|
+
raise ArgumentError, "data_row_record cannot be nil" if data_row_record.nil?
|
|
178
|
+
session = resolve_session(partition_id)
|
|
179
|
+
session.decrypt_bytes(data_row_record).force_encoding(Encoding::UTF_8)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def decrypt_string(partition_id, data_row_record)
|
|
183
|
+
raise ArgumentError, "data_row_record cannot be nil" if data_row_record.nil?
|
|
184
|
+
decrypt(partition_id, data_row_record).force_encoding(Encoding::UTF_8)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Run encrypt in a background Thread; see `setup_async` for the
|
|
188
|
+
# exception-propagation contract.
|
|
189
|
+
def encrypt_async(partition_id, payload, &block)
|
|
190
|
+
Thread.new do
|
|
191
|
+
Thread.current.report_on_exception = true
|
|
192
|
+
result = encrypt(partition_id, payload)
|
|
193
|
+
block&.call(result)
|
|
194
|
+
result
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Run decrypt in a background Thread; see `setup_async` for the
|
|
199
|
+
# exception-propagation contract.
|
|
200
|
+
def decrypt_async(partition_id, data_row_record, &block)
|
|
201
|
+
Thread.new do
|
|
202
|
+
Thread.current.report_on_exception = true
|
|
203
|
+
result = decrypt(partition_id, data_row_record)
|
|
204
|
+
block&.call(result)
|
|
205
|
+
result
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Install a log hook. Yields a +Hash+ +{level:, target:, message:}+ for
|
|
210
|
+
# every log record emitted by the underlying Rust crates. The block may
|
|
211
|
+
# fire from any thread; implementations must be thread-safe and
|
|
212
|
+
# non-blocking. Pass +nil+ to clear (equivalent to {clear_log_hook}).
|
|
213
|
+
#
|
|
214
|
+
# Replaces any previously installed log hook. Exceptions raised from the
|
|
215
|
+
# callback are caught and silently swallowed.
|
|
216
|
+
def set_log_hook(callback = nil, &block)
|
|
217
|
+
Hooks.set_log_hook(callback, &block)
|
|
218
|
+
end
|
|
119
219
|
|
|
120
|
-
|
|
121
|
-
|
|
220
|
+
# Remove the active log hook, if any. Idempotent.
|
|
221
|
+
def clear_log_hook
|
|
222
|
+
Hooks.clear_log_hook
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Install a metrics hook. Yields a +Hash+ +{type:, duration_ns:, name:}+
|
|
226
|
+
# for every metrics event. Timing events ({:encrypt, :decrypt, :store,
|
|
227
|
+
# :load}) carry a positive +duration_ns+ and a +nil+ +name+; cache events
|
|
228
|
+
# ({:cache_hit, :cache_miss, :cache_stale}) carry +duration_ns+ == 0 and
|
|
229
|
+
# the cache identifier in +name+.
|
|
230
|
+
#
|
|
231
|
+
# Installing a hook implicitly enables the global metrics gate; clearing
|
|
232
|
+
# it disables the gate. Replaces any previously installed metrics hook.
|
|
233
|
+
# Pass +nil+ to clear (equivalent to {clear_metrics_hook}).
|
|
234
|
+
def set_metrics_hook(callback = nil, &block)
|
|
235
|
+
Hooks.set_metrics_hook(callback, &block)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Remove the active metrics hook and disable metrics. Idempotent.
|
|
239
|
+
def clear_metrics_hook
|
|
240
|
+
Hooks.clear_metrics_hook
|
|
122
241
|
end
|
|
123
242
|
|
|
124
243
|
private
|
|
125
244
|
|
|
126
|
-
|
|
127
|
-
|
|
245
|
+
REQUIRED_KEYS = %w[ServiceName ProductID Metastore].freeze
|
|
246
|
+
|
|
247
|
+
def normalize_config(config)
|
|
248
|
+
unless config.respond_to?(:each_pair)
|
|
249
|
+
raise ArgumentError, "config must be a Hash-like object"
|
|
250
|
+
end
|
|
251
|
+
normalized = {}
|
|
252
|
+
config.each_pair do |key, value|
|
|
253
|
+
normalized[String(key)] = value
|
|
254
|
+
end
|
|
255
|
+
REQUIRED_KEYS.each do |key|
|
|
256
|
+
raise ArgumentError, "#{key} is required" if normalized[key].nil? || normalized[key].to_s.strip.empty?
|
|
257
|
+
end
|
|
258
|
+
normalized
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def truthy(value, default: false)
|
|
262
|
+
return default if value.nil?
|
|
263
|
+
|
|
264
|
+
case value
|
|
265
|
+
when true, "1", "true", "TRUE", "yes", "on" then true
|
|
266
|
+
when false, "0", "false", "FALSE", "no", "off" then false
|
|
267
|
+
else
|
|
268
|
+
default
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def resolve_session(partition_id)
|
|
273
|
+
raise ArgumentError, "partition_id cannot be empty" if String(partition_id).empty?
|
|
274
|
+
|
|
275
|
+
evicted = nil
|
|
276
|
+
session = @mutex.synchronize do
|
|
277
|
+
raise Error::NotInitialized unless @initialized
|
|
278
|
+
|
|
279
|
+
unless @session_cache_enabled
|
|
280
|
+
break @factory.get_session(partition_id)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# LRU: on hit, delete + reinsert to move the entry to the
|
|
284
|
+
# most-recently-used end of the Hash (Ruby Hash is insertion-
|
|
285
|
+
# ordered). On miss + overflow, `shift` removes the oldest entry,
|
|
286
|
+
# which is the least-recently-used.
|
|
287
|
+
if (existing = @sessions.delete(partition_id))
|
|
288
|
+
@sessions[partition_id] = existing
|
|
289
|
+
break existing
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
fresh = @factory.get_session(partition_id)
|
|
293
|
+
@sessions[partition_id] = fresh
|
|
294
|
+
if @sessions.size > @session_cache_max_size
|
|
295
|
+
_, evicted = @sessions.shift
|
|
296
|
+
end
|
|
297
|
+
fresh
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Close evicted session outside the lock — close hits the FFI and
|
|
301
|
+
# we don't want to serialize all encrypts behind one eviction.
|
|
302
|
+
if evicted
|
|
303
|
+
begin
|
|
304
|
+
evicted.close unless evicted.closed?
|
|
305
|
+
rescue StandardError => e
|
|
306
|
+
warn "asherah: error closing evicted session: #{e.message}"
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
session
|
|
311
|
+
end
|
|
128
312
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
313
|
+
def positive_int(value)
|
|
314
|
+
return nil if value.nil?
|
|
315
|
+
n = Integer(value)
|
|
316
|
+
n.positive? ? n : nil
|
|
317
|
+
rescue ArgumentError, TypeError
|
|
318
|
+
nil
|
|
133
319
|
end
|
|
134
320
|
end
|
|
135
321
|
end
|
metadata
CHANGED
|
@@ -1,68 +1,72 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: asherah
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
|
-
-
|
|
7
|
+
- Jay Gowdy
|
|
8
|
+
- Bo Thompson
|
|
9
|
+
- Michael Micco
|
|
10
|
+
- Dalibor Nasevic
|
|
8
11
|
autorequire:
|
|
9
|
-
bindir:
|
|
12
|
+
bindir: bin
|
|
10
13
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
14
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
15
|
dependencies:
|
|
13
16
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
17
|
+
name: ffi
|
|
15
18
|
requirement: !ruby/object:Gem::Requirement
|
|
16
19
|
requirements:
|
|
17
20
|
- - "~>"
|
|
18
21
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
22
|
+
version: '1.15'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
27
|
- - "~>"
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
29
|
+
version: '1.15'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: logger
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
requirements:
|
|
34
|
+
- - "~>"
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: '1.6'
|
|
37
|
+
type: :runtime
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - "~>"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '1.6'
|
|
44
|
+
description: Asherah application-layer encryption for Ruby with automatic key rotation,
|
|
45
|
+
powered by the native Rust implementation.
|
|
46
|
+
email: oss@godaddy.com
|
|
33
47
|
executables: []
|
|
34
|
-
extensions:
|
|
35
|
-
- ext/asherah/extconf.rb
|
|
48
|
+
extensions: []
|
|
36
49
|
extra_rdoc_files: []
|
|
37
50
|
files:
|
|
38
|
-
- ".env.secrets.example"
|
|
39
|
-
- ".rspec"
|
|
40
|
-
- ".rubocop.yml"
|
|
41
|
-
- ".ruby-version"
|
|
42
|
-
- CHANGELOG.md
|
|
43
|
-
- CODE_OF_CONDUCT.md
|
|
44
|
-
- CONTRIBUTING.md
|
|
45
|
-
- Gemfile
|
|
46
|
-
- LICENSE.txt
|
|
47
51
|
- README.md
|
|
48
|
-
- Rakefile
|
|
49
|
-
- SECURITY.md
|
|
50
|
-
- asherah.gemspec
|
|
51
|
-
- ext/asherah/checksums.yml
|
|
52
|
-
- ext/asherah/extconf.rb
|
|
53
|
-
- ext/asherah/native_file.rb
|
|
54
52
|
- lib/asherah.rb
|
|
55
53
|
- lib/asherah/config.rb
|
|
56
54
|
- lib/asherah/error.rb
|
|
57
|
-
- lib/asherah/
|
|
55
|
+
- lib/asherah/hooks.rb
|
|
56
|
+
- lib/asherah/native.rb
|
|
57
|
+
- lib/asherah/native/libasherah_ffi.so
|
|
58
|
+
- lib/asherah/session.rb
|
|
59
|
+
- lib/asherah/session_factory.rb
|
|
58
60
|
- lib/asherah/version.rb
|
|
59
|
-
homepage: https://github.com/godaddy/asherah-
|
|
61
|
+
homepage: https://github.com/godaddy/asherah-ffi
|
|
60
62
|
licenses:
|
|
61
|
-
-
|
|
63
|
+
- Apache-2.0
|
|
62
64
|
metadata:
|
|
63
|
-
homepage_uri: https://github.com/godaddy/asherah-
|
|
64
|
-
source_code_uri: https://github.com/godaddy/asherah-
|
|
65
|
-
|
|
65
|
+
homepage_uri: https://github.com/godaddy/asherah-ffi
|
|
66
|
+
source_code_uri: https://github.com/godaddy/asherah-ffi
|
|
67
|
+
github_repo: https://github.com/godaddy/asherah-ffi
|
|
68
|
+
changelog_uri: https://github.com/godaddy/asherah-ffi/releases
|
|
69
|
+
bug_tracker_uri: https://github.com/godaddy/asherah-ffi/issues
|
|
66
70
|
rubygems_mfa_required: 'true'
|
|
67
71
|
post_install_message:
|
|
68
72
|
rdoc_options: []
|
|
@@ -72,15 +76,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
72
76
|
requirements:
|
|
73
77
|
- - ">="
|
|
74
78
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
79
|
+
version: '3.0'
|
|
76
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
81
|
requirements:
|
|
78
82
|
- - ">="
|
|
79
83
|
- !ruby/object:Gem::Version
|
|
80
84
|
version: '0'
|
|
81
85
|
requirements: []
|
|
82
|
-
rubygems_version: 3.
|
|
86
|
+
rubygems_version: 3.5.22
|
|
83
87
|
signing_key:
|
|
84
88
|
specification_version: 4
|
|
85
|
-
summary:
|
|
89
|
+
summary: Asherah application-layer encryption for Ruby with automatic key rotation.
|
|
86
90
|
test_files: []
|
data/.env.secrets.example
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# Example secrets file for KMS integration tests
|
|
2
|
-
# Copy this file to .env.secrets and fill in actual values
|
|
3
|
-
#
|
|
4
|
-
# IMPORTANT: Never commit .env.secrets to version control
|
|
5
|
-
# The .env.secrets file is already in .gitignore
|
|
6
|
-
|
|
7
|
-
# AWS KMS Key ARN for integration tests (optional)
|
|
8
|
-
# Only needed if running spec/kms_spec.rb
|
|
9
|
-
# KMS_KEY_ARN=arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
AllCops:
|
|
2
|
-
TargetRubyVersion: 2.7
|
|
3
|
-
NewCops: enable
|
|
4
|
-
SuggestExtensions: false
|
|
5
|
-
Exclude:
|
|
6
|
-
- 'vendor/**/*' # Github Actions
|
|
7
|
-
- 'tmp/**/*'
|
|
8
|
-
|
|
9
|
-
Layout/LineLength:
|
|
10
|
-
Max: 120
|
|
11
|
-
|
|
12
|
-
# Metrics cops with reasonable limits
|
|
13
|
-
Metrics/BlockLength:
|
|
14
|
-
Max: 25
|
|
15
|
-
Exclude:
|
|
16
|
-
- 'spec/**/*'
|
|
17
|
-
- '*.gemspec'
|
|
18
|
-
- 'Rakefile'
|
|
19
|
-
|
|
20
|
-
Metrics/MethodLength:
|
|
21
|
-
Max: 15
|
|
22
|
-
Exclude:
|
|
23
|
-
- 'spec/**/*'
|
|
24
|
-
- 'tasks/**/*'
|
|
25
|
-
|
|
26
|
-
Metrics/AbcSize:
|
|
27
|
-
Max: 20
|
|
28
|
-
Exclude:
|
|
29
|
-
- 'spec/**/*'
|
|
30
|
-
- 'tasks/**/*'
|
|
31
|
-
|
|
32
|
-
Metrics/CyclomaticComplexity:
|
|
33
|
-
Max: 10
|
|
34
|
-
Exclude:
|
|
35
|
-
- 'spec/**/*'
|
|
36
|
-
|
|
37
|
-
Metrics/PerceivedComplexity:
|
|
38
|
-
Max: 10
|
|
39
|
-
Exclude:
|
|
40
|
-
- 'spec/**/*'
|
|
41
|
-
|
|
42
|
-
Metrics/ClassLength:
|
|
43
|
-
Max: 150
|
|
44
|
-
Exclude:
|
|
45
|
-
- 'spec/**/*'
|
|
46
|
-
|
|
47
|
-
Metrics/ModuleLength:
|
|
48
|
-
Max: 150
|
|
49
|
-
Exclude:
|
|
50
|
-
- 'spec/**/*'
|
|
51
|
-
|
|
52
|
-
# Style cops that were disabled but should be enabled
|
|
53
|
-
Style/WordArray:
|
|
54
|
-
MinSize: 3
|
|
55
|
-
EnforcedStyle: brackets
|
|
56
|
-
|
|
57
|
-
Style/SymbolArray:
|
|
58
|
-
MinSize: 3
|
|
59
|
-
EnforcedStyle: brackets
|
|
60
|
-
|
|
61
|
-
Style/MultilineBlockChain:
|
|
62
|
-
Enabled: true
|
|
63
|
-
Exclude:
|
|
64
|
-
- 'spec/**/*'
|
|
65
|
-
|
|
66
|
-
Style/BlockDelimiters:
|
|
67
|
-
EnforcedStyle: semantic
|
|
68
|
-
FunctionalMethods:
|
|
69
|
-
- let
|
|
70
|
-
- let!
|
|
71
|
-
- subject
|
|
72
|
-
- before
|
|
73
|
-
- after
|
|
74
|
-
Exclude:
|
|
75
|
-
- 'asherah.gemspec'
|
|
76
|
-
- 'ext/asherah/native_file.rb'
|
|
77
|
-
|
|
78
|
-
Style/GuardClause:
|
|
79
|
-
MinBodyLength: 3
|
|
80
|
-
Exclude:
|
|
81
|
-
- 'ext/asherah/native_file.rb'
|
|
82
|
-
|
|
83
|
-
# Naming cop adjustment
|
|
84
|
-
Naming/AccessorMethodName:
|
|
85
|
-
Exclude:
|
|
86
|
-
- 'lib/asherah.rb' # set_env is intentionally named
|
|
87
|
-
|
|
88
|
-
# Documentation cops
|
|
89
|
-
Style/Documentation:
|
|
90
|
-
Enabled: true
|
|
91
|
-
Exclude:
|
|
92
|
-
- 'spec/**/*'
|
|
93
|
-
- 'features/**/*'
|
|
94
|
-
|
|
95
|
-
Style/DocumentationMethod:
|
|
96
|
-
Enabled: false # YARD comments are optional
|
|
97
|
-
|
|
98
|
-
Style/EmptyClassDefinition:
|
|
99
|
-
Enabled: false
|
|
100
|
-
|
|
101
|
-
# Additional cops for code quality
|
|
102
|
-
Lint/UnusedMethodArgument:
|
|
103
|
-
Enabled: true
|
|
104
|
-
|
|
105
|
-
Lint/UnusedBlockArgument:
|
|
106
|
-
Enabled: true
|
|
107
|
-
|
|
108
|
-
Security/Eval:
|
|
109
|
-
Enabled: true
|
|
110
|
-
|
|
111
|
-
Security/JSONLoad:
|
|
112
|
-
Enabled: true
|
data/.ruby-version
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.2.2
|