feat(config): add environment variable validation#76
Conversation
📝 WalkthroughWalkthroughA new Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: Mahsum Aktas <mahsum@mahsumaktas.com>
04d6713 to
f8948e5
Compare
|
Hi @mahsumaktas , This issue was already assigned to @Sachindu-Nethmin before you added the PR. Only this one time I will be reviewing and merging this if there are no issues. But after this do not work on issues that are already assigned to others. It is best if you
Thanks. |
Kavirubc
left a comment
There was a problem hiding this comment.
Clean implementation of startup validation. Calling Validate() after applyDefaults() in all three load paths is the right order — defaults only touch thresholds and providers, never API keys or URLs, so no risk of false positives.
Exporting Validate() is a nice touch too, keeps it usable independently if needed down the line.
Two minor nits, neither blocking:
- Currently fail-fast (reports only the first missing field). If onboarding friction becomes an issue, collecting all errors in a single pass would be a small improvement.
- Any test outside the
configpackage that callsLoad()with a partial config will now fail at validation, which is correct behavior but worth keeping in mind as the test suite grows.
Build green, all load paths covered, tests solid. Approving.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
internal/core/config/config_test.go (1)
160-256: Well-structured table-driven tests — consider adding a whitespace-only value case.All 5 required fields and the partial-config scenario are covered.
Validate()explicitly callsstrings.TrimSpace, but no test case exercises a field value that is non-empty yet all-whitespace (e.g.,URL: " "). Adding one case would confirm thatstrings.TrimSpacebehavior is intentional and tested.♻️ Proposed additional test case
{ name: "partial config", cfg: Config{ Qdrant: QdrantConfig{ URL: "https://example.qdrant.io:6334", }, }, wantErr: "config validation failed: qdrant.api_key is empty (check QDRANT_API_KEY environment variable)", }, + { + name: "whitespace-only qdrant url", + cfg: func() Config { + cfg := baseConfig + cfg.Qdrant.URL = " " + return cfg + }(), + wantErr: "config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)", + },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/core/config/config_test.go` around lines 160 - 256, Add a whitespace-only value test to TestConfigValidate to exercise strings.TrimSpace behavior: create a new test case in the tests slice that copies baseConfig, sets a field to a whitespace-only string (e.g., cfg.Qdrant.URL = " " or cfg.Embedding.APIKey = " "), call cfg.Validate() and assert it returns the same error string as the empty-value case (e.g., "config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)"); this verifies Validate() treats all-whitespace as empty.internal/core/config/config.go (1)
190-215: Consider collecting all validation errors before returning.The current fail-fast approach (returning on the first empty field) requires a fix-and-restart cycle for each missing field. When multiple required fields are absent on a first deployment, users face sequential error discovery. Aggregating all failures into a single error would improve the startup experience.
♻️ Proposed refactor to collect all missing fields
func (c *Config) Validate() error { requiredFields := []struct { name string envVar string value string }{ {name: "qdrant.url", envVar: "QDRANT_URL", value: c.Qdrant.URL}, {name: "qdrant.api_key", envVar: "QDRANT_API_KEY", value: c.Qdrant.APIKey}, {name: "qdrant.collection", envVar: "QDRANT_COLLECTION", value: c.Qdrant.Collection}, {name: "embedding.api_key", envVar: "EMBEDDING_API_KEY", value: c.Embedding.APIKey}, {name: "llm.api_key", envVar: "LLM_API_KEY", value: c.LLM.APIKey}, } + var missing []string for _, field := range requiredFields { if strings.TrimSpace(field.value) == "" { - return fmt.Errorf( - "config validation failed: %s is empty (check %s environment variable)", - field.name, - field.envVar, - ) + missing = append(missing, fmt.Sprintf("%s (check %s environment variable)", field.name, field.envVar)) } } + if len(missing) > 0 { + return fmt.Errorf("config validation failed: missing required fields: %s", strings.Join(missing, "; ")) + } + return nil }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@internal/core/config/config.go` around lines 190 - 215, Change Config.Validate to collect all missing required fields instead of returning on the first error: iterate the requiredFields slice (the local variable in Validate that contains entries like {name: "qdrant.url", envVar: "QDRANT_URL", value: c.Qdrant.URL}), append a descriptive message for each empty value (use strings.TrimSpace(field.value) == "") to a list, and after the loop return a single aggregated error that joins all messages (or nil if none). Keep the same message format per field ("<name> is empty (check <envVar> environment variable)") and ensure the function still returns nil when there are no missing fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@internal/core/config/config_test.go`:
- Around line 160-256: Add a whitespace-only value test to TestConfigValidate to
exercise strings.TrimSpace behavior: create a new test case in the tests slice
that copies baseConfig, sets a field to a whitespace-only string (e.g.,
cfg.Qdrant.URL = " " or cfg.Embedding.APIKey = " "), call cfg.Validate() and
assert it returns the same error string as the empty-value case (e.g., "config
validation failed: qdrant.url is empty (check QDRANT_URL environment
variable)"); this verifies Validate() treats all-whitespace as empty.
In `@internal/core/config/config.go`:
- Around line 190-215: Change Config.Validate to collect all missing required
fields instead of returning on the first error: iterate the requiredFields slice
(the local variable in Validate that contains entries like {name: "qdrant.url",
envVar: "QDRANT_URL", value: c.Qdrant.URL}), append a descriptive message for
each empty value (use strings.TrimSpace(field.value) == "") to a list, and after
the loop return a single aggregated error that joins all messages (or nil if
none). Keep the same message format per field ("<name> is empty (check <envVar>
environment variable)") and ensure the function still returns nil when there are
no missing fields.
🧪 E2E Test✅ Bot responded: yes Test repo → gh-simili-bot/simili-e2e-22170026950 Auto-generated by E2E pipeline |
…ligh#76) Signed-off-by: Mahsum Aktas <mahsum@mahsumaktas.com> Co-authored-by: Kaviru Hapuarachchi <41495525+Kavirubc@users.noreply.github.com> Signed-off-by: Sachindu-Nethmin <sachindunethminweerasinghe@gmail.com>
Summary
Adds startup validation for required config fields so users get clear, actionable error messages instead of cryptic provider failures when environment variables are missing.
Closes #52
Changes
internal/core/config/config.goValidate() errormethod that checks 5 required fields:qdrant.url,qdrant.api_key,qdrant.collection,embedding.api_key,llm.api_key"config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)"Load(),LoadWithInheritance()(both no-extends and merged paths)Before / After
Before (missing
QDRANT_URL):After:
Tests
TestConfigValidate— 7 cases: all-valid, each missing field, partial configTestLoadValidatesExpandedEnvironmentVariables— end-to-end with real YAML +t.SetenvTestLoadWithInheritanceValidatesMergedConfig— validates merged parent+child configgo test ./internal/core/config✅Summary by CodeRabbit
Bug Fixes
Tests