legion-settings 1.3.1 → 1.3.4

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: cb0e2c44578e9e5b6cbb495c5160e1a37c067ea5692979e50e89494d33da9888
4
- data.tar.gz: ebca4fdb1fb58e2fa315620209ccbe5f5302057a7dc0d4a256f9689ea8d5d8b0
3
+ metadata.gz: f66aca7decaa9e60f84abf3d4b2538f42a90978289916f535395991161bb8e24
4
+ data.tar.gz: 41c5f1bac7ec1e12d0034ad872816405588d880542efbe7c420ec958697f1991
5
5
  SHA512:
6
- metadata.gz: 738f2ced6bf58fcb2d9ad4fca307d63abea4241bd6c5e788ff3ee47346f8f1054fd1cceb94d86e2f393f7985a0a835076513b94de730a89e9e233d923d5c1775
7
- data.tar.gz: ac60c369c84bd0dcb53b84f5fcdf9440fcd25ea00d15bb32386b67a4b999ceead7dde040fa66de53c9e6b06a5e99628b674923d0503dcbbe945a5b30a7d88bb6
6
+ metadata.gz: 967b78c6ca4e9e2bee7a2ac1e53c6198a0b0606985e16fca8734c061be6b5b5b4f30e7ed882c387af00554f3323e9008269e036eaec09e9b7ee12d1e1c8ad349
7
+ data.tar.gz: 2451834575d97a57f1f11c41556f48cf581358624c793d8ac011158b174df2072988d1135af0b9fc3656d1fd608734ab155a2f5b7419d71f77a613e5d8677994
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Legion::Settings Changelog
2
2
 
3
+ ## [1.3.4] - 2026-03-18
4
+
5
+ ### Fixed
6
+ - Added `logger` gem to test dependencies for Ruby 4.0 compatibility
7
+
8
+ ## [1.3.3] - 2026-03-17
9
+
10
+ ### Fixed
11
+ - Config JSON parse error now includes the filename at ERROR level instead of burying it in DEBUG
12
+
13
+ ## [1.3.2] - 2026-03-17
14
+
15
+ ### Added
16
+ - `dig(*keys)` method on `Legion::Settings` and `Legion::Settings::Loader` for nested key access
17
+
3
18
  ## [1.3.1] - 2026-03-16
4
19
 
5
20
  ### Added
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
5
5
  gemspec
6
6
  group :test do
7
7
  gem 'legion-logging'
8
+ gem 'logger'
8
9
  gem 'rake'
9
10
  gem 'rspec'
10
11
  gem 'rspec_junit_formatter'
data/README.md CHANGED
@@ -36,12 +36,13 @@ Each Legion module registers its own defaults via `merge_settings` during startu
36
36
 
37
37
  ### Secret Resolution
38
38
 
39
- Settings values can reference external secret sources using URI syntax. Two schemes are supported:
39
+ Settings values can reference external secret sources using URI syntax. Three schemes are supported:
40
40
 
41
41
  | Scheme | Format | Resolution |
42
42
  |--------|--------|------------|
43
- | `vault://` | `vault://path/to/secret#key` | Reads from HashiCorp Vault via `Legion::Crypt` |
43
+ | `vault://` | `vault://path/to/secret#key` | Reads static KV secrets from HashiCorp Vault via `Legion::Crypt` |
44
44
  | `env://` | `env://ENV_VAR_NAME` | Reads from environment variable |
45
+ | `lease://` | `lease://name#key` | Reads from dynamic Vault leases via `Legion::Crypt::LeaseManager` |
45
46
 
46
47
  Array values act as fallback chains — the first non-nil result wins:
47
48
 
@@ -59,7 +60,7 @@ Call `Legion::Settings.resolve_secrets!` to resolve all URIs in-place. In the Le
59
60
 
60
61
  ```ruby
61
62
  Legion::Settings.resolve_secrets!
62
- # All vault:// and env:// references are now replaced with their resolved values
63
+ # All vault://, env://, and lease:// references are now replaced with their resolved values
63
64
  ```
64
65
 
65
66
  ### Schema Validation
@@ -0,0 +1,56 @@
1
+ # Design: Include Filename in JSON Parse Error Messages
2
+
3
+ ## Problem
4
+
5
+ When a user edits a config file and introduces a JSON syntax error, the settings loader logs:
6
+
7
+ ```
8
+ ERROR config file must be valid json
9
+ ```
10
+
11
+ The filename is only logged at DEBUG level on the next line:
12
+
13
+ ```ruby
14
+ Legion::Logging.error('config file must be valid json')
15
+ Legion::Logging.debug("file:#{file}, error: #{e}")
16
+ ```
17
+
18
+ This makes it nearly impossible for users to identify which file is broken, especially when multiple config files exist in `~/.legionio/settings/`. The settings loader silently skips the broken file, and downstream code fails with confusing errors (e.g., RubyLLM complaining about missing API keys because `llm.json` wasn't loaded).
19
+
20
+ ## Proposed Solution
21
+
22
+ Change `load_file` in `loader.rb` to include the filename and parse error in the ERROR message:
23
+
24
+ ```ruby
25
+ rescue Legion::JSON::ParseError => e
26
+ Legion::Logging.error("config file must be valid json: #{file}")
27
+ Legion::Logging.error(" parse error: #{e.message}")
28
+ end
29
+ ```
30
+
31
+ This is a one-line change (plus one added line) in `loader.rb:140-142`.
32
+
33
+ ### Before
34
+
35
+ ```
36
+ [2026-03-17 18:27:27 -0500] ERROR config file must be valid json
37
+ ```
38
+
39
+ ### After
40
+
41
+ ```
42
+ [2026-03-17 18:27:27 -0500] ERROR config file must be valid json: /Users/matt/.legionio/settings/llm.json
43
+ [2026-03-17 18:27:27 -0500] ERROR parse error: unexpected token at '{ "llm": { ... '
44
+ ```
45
+
46
+ ## Alternatives Considered
47
+
48
+ 1. **Raise instead of logging** — rejected; the current behavior of skipping broken files and continuing is correct for resilience. But the user needs to know what happened.
49
+ 2. **Add a `config validate` pre-check** — already exists (`legion config validate`), but users won't run it proactively. The error message at load time is the first line of defense.
50
+ 3. **Return the broken files in `loaded_files`** — would require API changes for minimal benefit.
51
+
52
+ ## Constraints
53
+
54
+ - Do not change the error-handling behavior (continue loading other files)
55
+ - Do not change method signatures
56
+ - The debug line can be removed since the info is now in the error message
@@ -0,0 +1,34 @@
1
+ # Implementation: Include Filename in JSON Parse Error Messages
2
+
3
+ ## Phase 1: Update Error Logging
4
+
5
+ ### Files to Modify
6
+
7
+ - `lib/legion/settings/loader.rb` — lines 140-142
8
+
9
+ ### Changes
10
+
11
+ Replace:
12
+
13
+ ```ruby
14
+ rescue Legion::JSON::ParseError => e
15
+ Legion::Logging.error('config file must be valid json')
16
+ Legion::Logging.debug("file:#{file}, error: #{e}")
17
+ ```
18
+
19
+ With:
20
+
21
+ ```ruby
22
+ rescue Legion::JSON::ParseError => e
23
+ Legion::Logging.error("config file must be valid json: #{file}")
24
+ Legion::Logging.error(" parse error: #{e.message}")
25
+ ```
26
+
27
+ ### Spec Coverage
28
+
29
+ - Add spec in `spec/legion/loader_spec.rb` that writes invalid JSON to a temp file, calls `load_file`, and asserts the error was logged with the filename
30
+
31
+ ### Version Bump
32
+
33
+ - Bump patch version in `lib/legion/settings/version.rb`
34
+ - Update CHANGELOG.md
@@ -38,7 +38,25 @@ module Legion
38
38
  vault: { connected: false }
39
39
  },
40
40
  cache: { enabled: true, connected: false, driver: 'dalli' },
41
- extensions: {},
41
+ extensions: {
42
+ core: %w[
43
+ lex-node lex-tasker lex-scheduler lex-health lex-ping
44
+ lex-telemetry lex-metering lex-log lex-audit
45
+ lex-conditioner lex-transformer lex-exec lex-lex lex-codegen
46
+ ],
47
+ ai: %w[lex-claude lex-openai lex-gemini],
48
+ gaia: %w[lex-tick lex-mesh lex-apollo lex-cortex],
49
+ categories: {
50
+ core: { type: :list, tier: 1 },
51
+ ai: { type: :list, tier: 2 },
52
+ gaia: { type: :list, tier: 3 },
53
+ agentic: { type: :prefix, tier: 4 }
54
+ },
55
+ blocked: [],
56
+ reserved_prefixes: %w[core ai agentic gaia],
57
+ reserved_words: %w[transport cache crypt data settings json logging llm rbac legion],
58
+ agentic: { allowed: nil, blocked: [] }
59
+ },
42
60
  reload: false,
43
61
  reloading: false,
44
62
  auto_install_missing_lex: true,
@@ -69,6 +87,10 @@ module Legion
69
87
  to_hash[key]
70
88
  end
71
89
 
90
+ def dig(*keys)
91
+ to_hash.dig(*keys)
92
+ end
93
+
72
94
  def []=(key, value)
73
95
  @settings[key] = value
74
96
  @indifferent_access = false
@@ -116,8 +138,8 @@ module Legion
116
138
  # @indifferent_access = false
117
139
  @loaded_files << file
118
140
  rescue Legion::JSON::ParseError => e
119
- Legion::Logging.error('config file must be valid json')
120
- Legion::Logging.debug("file:#{file}, error: #{e}")
141
+ Legion::Logging.error("config file must be valid json: #{file}")
142
+ Legion::Logging.error(" parse error: #{e.message}")
121
143
  end
122
144
  else
123
145
  Legion::Logging.warn("Config file does not exist or is not readable file:#{file}")
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module Settings
5
- VERSION = '1.3.1'
5
+ VERSION = '1.3.4'
6
6
  end
7
7
  end
@@ -37,6 +37,13 @@ module Legion
37
37
  nil
38
38
  end
39
39
 
40
+ def dig(*keys)
41
+ @loader = load if @loader.nil?
42
+ @loader.dig(*keys)
43
+ rescue NoMethodError, TypeError
44
+ nil
45
+ end
46
+
40
47
  def set_prop(key, value)
41
48
  @loader = load if @loader.nil?
42
49
  @loader[key] = value
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legion-settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -42,6 +42,8 @@ files:
42
42
  - Gemfile
43
43
  - LICENSE
44
44
  - README.md
45
+ - docs/plans/2026-03-17-config-error-filename-design.md
46
+ - docs/plans/2026-03-17-config-error-filename-implementation.md
45
47
  - legion-settings.gemspec
46
48
  - lib/legion/settings.rb
47
49
  - lib/legion/settings/loader.rb