kreds 1.1.0 → 1.1.2
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/CHANGELOG.md +9 -0
- data/README.md +106 -60
- data/kreds.gemspec +3 -2
- data/lib/kreds/fetch.rb +22 -45
- data/lib/kreds/inputs.rb +28 -0
- data/lib/kreds/version.rb +1 -1
- data/lib/kreds.rb +2 -1
- metadata +20 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 256854440242a87fc2debc95c8c7cda4c2c8fb836946179eccba3d8946863b25
|
4
|
+
data.tar.gz: 05c8465b2e8ab5a16f8b94cef84b85b074d5153bd60a143bd20719b0645b48e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea580b8a4dca8c842c7e6f9c84a678cac94b3136b084dc1c91cb8c44b73d69077532441138c4a9c8bd91f84aec8c80bbb5919a27313cc18cb20d6d2df838bc6d
|
7
|
+
data.tar.gz: a36ab8f0fe482843697cc96e28c903f08a61e35d0554bf56e696a06b4116af25ab8bb546fc546d2fa781bc37d1b137501f122224059dba298269d2128cd3bfac
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## v1.1.2
|
2
|
+
|
3
|
+
- Added input validation using `dry-types` for user-facing API
|
4
|
+
- Internal code optimizations
|
5
|
+
|
6
|
+
## v1.1.1
|
7
|
+
|
8
|
+
- Updated gemspec metadata to include the correct homepage URL
|
9
|
+
|
1
10
|
## v1.1.0
|
2
11
|
|
3
12
|
- Added block support for fallback behavior in all fetching methods
|
data/README.md
CHANGED
@@ -1,27 +1,56 @@
|
|
1
|
-
# Kreds
|
1
|
+
# Kreds: Streamlined Rails Credentials Access
|
2
2
|
|
3
3
|
[](http://badge.fury.io/rb/kreds)
|
4
|
-
[](https://github.com/brownboxdev/kreds/actions/workflows/ci.yml)
|
5
5
|
|
6
|
-
Kreds is a simpler, shorter, and safer way to access Rails credentials, with a few
|
6
|
+
Kreds is a simpler, shorter, and safer way to access Rails credentials, with a few extra features built in. Rails credentials are a convenient way to store secrets, but retrieving them could be more intuitive — that's where Kreds comes in.
|
7
7
|
|
8
|
-
|
8
|
+
**Key Features:**
|
9
|
+
|
10
|
+
- Simplified credential access with clear error messages
|
11
|
+
- Environment variable fallback support
|
12
|
+
- Environment-scoped credentials access (production, staging, development)
|
13
|
+
- Automatic blank value detection and prevention
|
14
|
+
|
15
|
+
**Before and After:**
|
9
16
|
|
10
17
|
```ruby
|
18
|
+
# Instead of this (long, silent failures if value is missing):
|
11
19
|
Rails.application.credentials[:recaptcha][:site_key]
|
12
|
-
|
20
|
+
# => nil
|
13
21
|
|
14
|
-
|
22
|
+
# Or this (long, unclear errors):
|
23
|
+
Rails.application.credentials[:captcha][:site_key]
|
24
|
+
# => undefined method `[]' for nil:NilClass (NoMethodError)
|
15
25
|
|
16
|
-
|
26
|
+
# Or even this (longer, still unclear errors):
|
27
|
+
Rails.application.credentials.fetch(:recaptcha).fetch(:key)
|
28
|
+
# => key not found: :key (KeyError)
|
29
|
+
|
30
|
+
# You can write this (shorter, human-readable errors):
|
17
31
|
Kreds.fetch!(:recaptcha, :site_key)
|
32
|
+
# => Blank value in credentials: [:recaptcha][:site_key] (Kreds::BlankCredentialsError)
|
33
|
+
Kreds.fetch!(:captcha, :site_key)
|
34
|
+
# => Credentials key not found: [:captcha] (Kreds::UnknownCredentialsError)
|
18
35
|
```
|
19
36
|
|
20
|
-
|
37
|
+
## Table of Contents
|
38
|
+
|
39
|
+
**Gem Usage:**
|
40
|
+
- [Installation](#installation)
|
41
|
+
- [Credential Fetching](#credential-fetching)
|
42
|
+
- [Environment-Scoped Credentials](#environment-scoped-credentials)
|
43
|
+
- [Environment Variables](#environment-variables)
|
44
|
+
- [Debug and Inspection](#debug-and-inspection)
|
45
|
+
|
46
|
+
**Community Resources:**
|
47
|
+
- [Contributing](#contributing)
|
48
|
+
- [License](#license)
|
49
|
+
- [Code of Conduct](#code-of-conduct)
|
21
50
|
|
22
51
|
## Installation
|
23
52
|
|
24
|
-
Add
|
53
|
+
Add Kreds to your Gemfile:
|
25
54
|
|
26
55
|
```ruby
|
27
56
|
gem "kreds"
|
@@ -29,103 +58,120 @@ gem "kreds"
|
|
29
58
|
|
30
59
|
And then execute:
|
31
60
|
|
32
|
-
```
|
61
|
+
```bash
|
33
62
|
bundle install
|
34
63
|
```
|
35
64
|
|
36
|
-
##
|
65
|
+
## Credential Fetching
|
37
66
|
|
38
|
-
|
67
|
+
**`Kreds.fetch!(*keys, var: nil, &block)`**
|
39
68
|
|
40
|
-
|
41
|
-
Kreds.fetch!(:aws, :s3, :credentials, :access_key_id)
|
42
|
-
```
|
69
|
+
Fetches credentials from the Rails credentials store.
|
43
70
|
|
44
|
-
|
71
|
+
**Parameters:**
|
72
|
+
- `*keys` - Variable number of symbols representing the key path
|
73
|
+
- `var` - Optional environment variable name as fallback
|
74
|
+
- `&block` - Optional block to execute if fetch fails
|
45
75
|
|
46
|
-
|
76
|
+
**Returns:** The credential value
|
47
77
|
|
48
|
-
|
78
|
+
**Raises:**
|
79
|
+
- `Kreds::UnknownCredentialsError` - if the key path doesn't exist
|
80
|
+
- `Kreds::BlankCredentialsError` - if the value exists but is blank
|
49
81
|
|
50
|
-
|
82
|
+
```ruby
|
83
|
+
# Basic usage
|
84
|
+
Kreds.fetch!(:aws, :s3, :credentials, :access_key_id)
|
51
85
|
|
52
|
-
|
86
|
+
# With environment variable fallback
|
87
|
+
Kreds.fetch!(:aws, :access_key_id, var: "AWS_ACCESS_KEY_ID")
|
53
88
|
|
54
|
-
|
55
|
-
Kreds.fetch!(:
|
89
|
+
# With block
|
90
|
+
Kreds.fetch!(:api_key) do
|
91
|
+
raise MyCustomError, "API key not configured"
|
92
|
+
end
|
56
93
|
```
|
57
94
|
|
58
|
-
|
95
|
+
## Environment-Scoped Credentials
|
59
96
|
|
60
|
-
|
97
|
+
**`Kreds.env_fetch!(*keys, var: nil, &block)`**
|
61
98
|
|
62
|
-
|
99
|
+
Fetches credentials scoped by the current Rails environment (e.g., `:production`, `:staging`, `:development`).
|
63
100
|
|
64
|
-
|
101
|
+
**Parameters:** Same as `fetch!`
|
65
102
|
|
66
|
-
|
67
|
-
Kreds.var!("AWS_ACCESS_KEY_ID")
|
68
|
-
```
|
69
|
-
|
70
|
-
This raises `Kreds::UnknownEnvironmentVariableError` if the variable is missing, and `Kreds::BlankEnvironmentVariableError` if it is present but the value is blank.
|
103
|
+
**Returns:** The credential value from `Rails.application.credentials[Rails.env]` followed by the provided key path
|
71
104
|
|
72
|
-
|
73
|
-
|
74
|
-
If your credentials are scoped by Rails environment (e.g., `:production`, `:staging`, `:development`), you can fetch keys under the current environment using:
|
105
|
+
**Raises:** Same exceptions as `fetch!`
|
75
106
|
|
76
107
|
```ruby
|
108
|
+
# Looks in credentials[:production][:recaptcha][:site_key] in production
|
77
109
|
Kreds.env_fetch!(:recaptcha, :site_key)
|
78
110
|
```
|
79
111
|
|
80
|
-
|
112
|
+
## Environment Variables
|
81
113
|
|
82
|
-
|
114
|
+
**`Kreds.var!(name, &block)`**
|
83
115
|
|
84
|
-
|
85
|
-
|
86
|
-
|
116
|
+
Fetches a value directly from environment variables.
|
117
|
+
|
118
|
+
**Parameters:**
|
119
|
+
- `name` - Environment variable name
|
120
|
+
- `&block` - Optional block to execute if variable is missing/blank
|
87
121
|
|
88
|
-
|
122
|
+
**Returns:** The environment variable value
|
89
123
|
|
90
|
-
|
124
|
+
**Raises:**
|
125
|
+
- `Kreds::UnknownEnvironmentVariableError` - if the variable doesn't exist
|
126
|
+
- `Kreds::BlankEnvironmentVariableError` - if the variable exists but is blank
|
91
127
|
|
92
128
|
```ruby
|
93
|
-
|
94
|
-
|
95
|
-
end
|
129
|
+
# Direct environment variable access
|
130
|
+
Kreds.var!("AWS_ACCESS_KEY_ID")
|
96
131
|
|
132
|
+
# With block
|
97
133
|
Kreds.var!("THREADS") { 1 }
|
98
134
|
```
|
99
135
|
|
100
|
-
|
136
|
+
## Debug and Inspection
|
101
137
|
|
102
|
-
|
138
|
+
**`Kreds.show`**
|
139
|
+
|
140
|
+
Useful for debugging and exploring available credentials in the Rails console.
|
141
|
+
|
142
|
+
**Returns:** Hash containing all credentials
|
103
143
|
|
104
144
|
```ruby
|
105
145
|
Kreds.show
|
146
|
+
# => { aws: { access_key_id: "...", secret_access_key: "..." }, ... }
|
106
147
|
```
|
107
148
|
|
108
|
-
|
109
|
-
|
110
|
-
## Problems?
|
111
|
-
|
112
|
-
Facing a problem or want to suggest an enhancement?
|
113
|
-
|
114
|
-
- **Open a Discussion**: If you have a question, experience difficulties using the gem, or have a suggestion for improvements, feel free to use the Discussions section.
|
149
|
+
## Contributing
|
115
150
|
|
116
|
-
|
151
|
+
### Getting Help
|
152
|
+
Have a question or need assistance? Open a discussion in our [discussions section](https://github.com/brownboxdev/kreds/discussions) for:
|
153
|
+
- Usage questions
|
154
|
+
- Implementation guidance
|
155
|
+
- Feature suggestions
|
117
156
|
|
118
|
-
|
119
|
-
|
157
|
+
### Reporting Issues
|
158
|
+
Found a bug? Please [create an issue](https://github.com/brownboxdev/kreds/issues) with:
|
159
|
+
- A clear description of the problem
|
160
|
+
- Steps to reproduce the issue
|
161
|
+
- Your environment details (Rails version, Ruby version, etc.)
|
120
162
|
|
121
|
-
|
163
|
+
### Contributing Code
|
164
|
+
Ready to contribute? You can:
|
165
|
+
- Fix bugs by submitting pull requests
|
166
|
+
- Improve documentation
|
167
|
+
- Add new features (please discuss first in our [discussions section](https://github.com/brownboxdev/kreds/discussions))
|
122
168
|
|
123
|
-
Before
|
169
|
+
Before contributing, please read the [contributing guidelines](https://github.com/brownboxdev/kreds/blob/master/CONTRIBUTING.md)
|
124
170
|
|
125
171
|
## License
|
126
172
|
|
127
|
-
The gem is available as open source under the terms of the [MIT License](https://github.com/
|
173
|
+
The gem is available as open source under the terms of the [MIT License](https://github.com/brownboxdev/kreds/blob/master/LICENSE.txt).
|
128
174
|
|
129
175
|
## Code of Conduct
|
130
176
|
|
131
|
-
Everyone interacting in the Kreds project is expected to follow the [code of conduct](https://github.com/
|
177
|
+
Everyone interacting in the Kreds project is expected to follow the [code of conduct](https://github.com/brownboxdev/kreds/blob/master/CODE_OF_CONDUCT.md).
|
data/kreds.gemspec
CHANGED
@@ -4,10 +4,10 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = "kreds"
|
5
5
|
spec.version = Kreds::VERSION
|
6
6
|
spec.authors = ["enjaku4"]
|
7
|
-
spec.homepage = "https://github.com/
|
7
|
+
spec.homepage = "https://github.com/brownboxdev/kreds"
|
8
8
|
spec.metadata["homepage_uri"] = spec.homepage
|
9
9
|
spec.metadata["source_code_uri"] = spec.homepage
|
10
|
-
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/
|
10
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
|
11
11
|
spec.metadata["rubygems_mfa_required"] = "true"
|
12
12
|
spec.summary = "The missing shorthand for Rails credentials"
|
13
13
|
spec.license = "MIT"
|
@@ -19,5 +19,6 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
+
spec.add_dependency "dry-types", "~> 1.8"
|
22
23
|
spec.add_dependency "rails", ">= 7.1", "< 8.1"
|
23
24
|
end
|
data/lib/kreds/fetch.rb
CHANGED
@@ -1,82 +1,59 @@
|
|
1
1
|
module Kreds
|
2
2
|
module Fetch
|
3
3
|
def fetch!(*keys, var: nil, &)
|
4
|
-
|
5
|
-
validate_var!(var)
|
4
|
+
symbolized_keys = Kreds::Inputs.process(keys, as: :symbol_array)
|
6
5
|
|
7
6
|
path = []
|
8
7
|
|
9
|
-
|
8
|
+
symbolized_keys.reduce(Kreds.show) do |hash, key|
|
10
9
|
path << key
|
11
|
-
fetch_key(hash, key, path,
|
10
|
+
fetch_key(hash, key, path, symbolized_keys)
|
12
11
|
end
|
13
12
|
rescue Kreds::BlankCredentialsError, Kreds::UnknownCredentialsError => e
|
14
|
-
fallback_to_var(e, var, &)
|
13
|
+
fallback_to_var(e, Kreds::Inputs.process(var, as: :string, optional: true), &)
|
15
14
|
end
|
16
15
|
|
17
16
|
def env_fetch!(*keys, var: nil, &)
|
18
|
-
fetch!(Rails.env, *keys, var
|
17
|
+
fetch!(Rails.env, *keys, var:, &)
|
19
18
|
end
|
20
19
|
|
21
20
|
def var!(var, &)
|
22
|
-
|
21
|
+
value = ENV.fetch(Kreds::Inputs.process(var, as: :string))
|
23
22
|
|
24
|
-
|
23
|
+
return raise_or_yield(Kreds::BlankEnvironmentVariableError.new("Blank value in environment variable: #{var.inspect}"), &) if value.blank?
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
raise_or_yield(
|
25
|
+
value
|
26
|
+
rescue KeyError
|
27
|
+
raise_or_yield(Kreds::UnknownEnvironmentVariableError.new("Environment variable not found: #{var.inspect}"), &)
|
29
28
|
end
|
30
29
|
|
31
30
|
private
|
32
31
|
|
33
|
-
def validate_keys!(keys)
|
34
|
-
raise Kreds::InvalidArgumentError, "No keys provided" if keys.empty?
|
35
|
-
|
36
|
-
return if keys.all? { _1.is_a?(Symbol) || _1.is_a?(String) }
|
37
|
-
|
38
|
-
raise Kreds::InvalidArgumentError, "Credentials Key must be a Symbol or a String"
|
39
|
-
end
|
40
|
-
|
41
|
-
def validate_var!(var)
|
42
|
-
raise Kreds::InvalidArgumentError, "Environment variable must be a String" if var.present? && !var.is_a?(String)
|
43
|
-
end
|
44
|
-
|
45
32
|
def fetch_key(hash, key, path, keys)
|
46
|
-
value = hash.fetch(key
|
33
|
+
value = hash.fetch(key)
|
47
34
|
|
48
|
-
raise Kreds::BlankCredentialsError, "Blank value in credentials:
|
49
|
-
raise Kreds::UnknownCredentialsError, "Credentials key not found:
|
35
|
+
raise Kreds::BlankCredentialsError, "Blank value in credentials: #{path_to_s(path)}" if value.blank?
|
36
|
+
raise Kreds::UnknownCredentialsError, "Credentials key not found: #{path_to_s(path)}[:#{keys[path.size]}]" unless value.is_a?(Hash) || keys == path
|
50
37
|
|
51
38
|
value
|
52
39
|
rescue KeyError
|
53
|
-
raise Kreds::UnknownCredentialsError, "Credentials key not found:
|
40
|
+
raise Kreds::UnknownCredentialsError, "Credentials key not found: #{path_to_s(path)}"
|
54
41
|
end
|
55
42
|
|
56
43
|
def fallback_to_var(error, var, &)
|
57
|
-
if var.
|
58
|
-
result, success = check_var(var)
|
59
|
-
|
60
|
-
return result if success
|
44
|
+
return raise_or_yield(error, &) if var.blank?
|
61
45
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
raise_or_yield(error, &)
|
66
|
-
end
|
67
|
-
|
68
|
-
def check_var(var)
|
69
|
-
value = ENV.fetch(var)
|
70
|
-
|
71
|
-
return [Kreds::BlankEnvironmentVariableError.new("Blank value in environment variable: #{var.inspect}"), false] if value.blank?
|
72
|
-
|
73
|
-
[value, true]
|
74
|
-
rescue KeyError
|
75
|
-
[Kreds::UnknownEnvironmentVariableError.new("Environment variable not found: #{var.inspect}"), false]
|
46
|
+
var!(var, &)
|
47
|
+
rescue Kreds::BlankEnvironmentVariableError, Kreds::UnknownEnvironmentVariableError => e
|
48
|
+
raise_or_yield(Kreds::Error.new("#{error.message}, #{e.message}"), &)
|
76
49
|
end
|
77
50
|
|
78
51
|
def raise_or_yield(error, &)
|
79
52
|
block_given? ? yield : raise(error)
|
80
53
|
end
|
54
|
+
|
55
|
+
def path_to_s(path)
|
56
|
+
"[:#{path.join("][:")}]"
|
57
|
+
end
|
81
58
|
end
|
82
59
|
end
|
data/lib/kreds/inputs.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "dry-types"
|
2
|
+
|
3
|
+
module Kreds
|
4
|
+
module Inputs
|
5
|
+
extend self
|
6
|
+
|
7
|
+
include Dry.Types()
|
8
|
+
|
9
|
+
TYPES = {
|
10
|
+
symbol_array: -> { self::Array.of(self::Coercible::Symbol).constrained(min_size: 1) },
|
11
|
+
string: -> { self::Strict::String },
|
12
|
+
boolean: -> { self::Strict::Bool }
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def process(value, as:, optional: false)
|
16
|
+
checker = type_for(as)
|
17
|
+
checker = checker.optional if optional
|
18
|
+
|
19
|
+
checker[value]
|
20
|
+
rescue Dry::Types::CoercionError => e
|
21
|
+
raise Kreds::InvalidArgumentError, e
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def type_for(name) = Kreds::Inputs::TYPES.fetch(name).call
|
27
|
+
end
|
28
|
+
end
|
data/lib/kreds/version.rb
CHANGED
data/lib/kreds.rb
CHANGED
@@ -2,6 +2,7 @@ require_relative "kreds/version"
|
|
2
2
|
|
3
3
|
require "rails"
|
4
4
|
|
5
|
+
require_relative "kreds/inputs"
|
5
6
|
require_relative "kreds/fetch"
|
6
7
|
require_relative "kreds/show"
|
7
8
|
|
@@ -13,6 +14,6 @@ module Kreds
|
|
13
14
|
class UnknownCredentialsError < Error; end
|
14
15
|
class UnknownEnvironmentVariableError < Error; end
|
15
16
|
|
16
|
-
extend ::Kreds::Fetch
|
17
17
|
extend ::Kreds::Show
|
18
|
+
extend ::Kreds::Fetch
|
18
19
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kreds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- enjaku4
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
9
9
|
cert_chain: []
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: dry-types
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.8'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.8'
|
12
26
|
- !ruby/object:Gem::Dependency
|
13
27
|
name: rails
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,15 +53,16 @@ files:
|
|
39
53
|
- kreds.gemspec
|
40
54
|
- lib/kreds.rb
|
41
55
|
- lib/kreds/fetch.rb
|
56
|
+
- lib/kreds/inputs.rb
|
42
57
|
- lib/kreds/show.rb
|
43
58
|
- lib/kreds/version.rb
|
44
|
-
homepage: https://github.com/
|
59
|
+
homepage: https://github.com/brownboxdev/kreds
|
45
60
|
licenses:
|
46
61
|
- MIT
|
47
62
|
metadata:
|
48
|
-
homepage_uri: https://github.com/
|
49
|
-
source_code_uri: https://github.com/
|
50
|
-
changelog_uri: https://github.com/
|
63
|
+
homepage_uri: https://github.com/brownboxdev/kreds
|
64
|
+
source_code_uri: https://github.com/brownboxdev/kreds
|
65
|
+
changelog_uri: https://github.com/brownboxdev/kreds/blob/master/CHANGELOG.md
|
51
66
|
rubygems_mfa_required: 'true'
|
52
67
|
rdoc_options: []
|
53
68
|
require_paths:
|