Repository navigation
fix(config): refuse to start without a valid API_KEY #100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| package config | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "log" | ||
| "os" | ||
| "regexp" | ||
|
|
@@ -68,9 +70,20 @@ func Load() (*Config, error) { | |
| cfg.LogBufferSize = 1 | ||
| } | ||
|
|
||
| cfg.ApiKey, err = GetEnvAsUUID("API_KEY") | ||
| if err != nil { | ||
| log.Printf("[Error] Failed to load API Key, error: %v", err) | ||
| // The API key is the node's only authentication. A missing, malformed or all-zero key | ||
| // would leave the node accepting the all-zero UUID, so Load reports it as an error | ||
| // (main exits). cfg is still returned complete for NewTestConfig, which sets its own key. | ||
| var apiKeyErr error | ||
| if GetEnv("API_KEY", "") == "" { | ||
| apiKeyErr = errors.New("API_KEY is not set") | ||
| } else { | ||
| cfg.ApiKey, apiKeyErr = GetEnvAsUUID("API_KEY") | ||
| } | ||
| if apiKeyErr == nil && cfg.ApiKey == uuid.Nil { | ||
| apiKeyErr = errors.New("must not be the all-zero UUID") | ||
| } | ||
| if apiKeyErr != nil { | ||
| apiKeyErr = fmt.Errorf("invalid API_KEY: %w", apiKeyErr) | ||
|
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win Do not forward key bytes in validation errors. If a 45-character Based on learnings, errors for credential-bearing environment variables should name the variable rather than reveal its value. 🤖 Prompt for AI AgentsSource: Learnings |
||
| } | ||
|
|
||
| nodeHostStr := GetEnv("NODE_HOST", "0.0.0.0") | ||
|
|
@@ -84,7 +97,7 @@ func Load() (*Config, error) { | |
| cfg.NodeHost = "127.0.0.1" | ||
| } | ||
|
|
||
| return cfg, nil | ||
| return cfg, apiKeyErr | ||
| } | ||
|
|
||
| // NewTestConfig creates a config for testing | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| package config | ||
|
|
||
| import ( | ||
| "os" | ||
| "strings" | ||
| "testing" | ||
| ) | ||
|
|
||
| // unsetEnv removes name for the duration of the test (t.Setenv can only set, not unset). | ||
| func unsetEnv(t *testing.T, name string) { | ||
| t.Helper() | ||
| t.Setenv(name, "") // registers the restore of the original value | ||
| if err := os.Unsetenv(name); err != nil { | ||
| t.Fatalf("unset %s: %v", name, err) | ||
| } | ||
| } | ||
|
|
||
| func TestLoadRejectsMissingAPIKey(t *testing.T) { | ||
| unsetEnv(t, "API_KEY") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Isolate the missing-key test from If a developer has a 🤖 Prompt for AI Agents |
||
|
|
||
| cfg, err := Load() | ||
| if err == nil || !strings.Contains(err.Error(), "API_KEY is not set") { | ||
| t.Fatalf("expected a not-set error, got %v", err) | ||
| } | ||
| if cfg == nil { | ||
| t.Fatal("Load must still return the config (NewTestConfig relies on it)") | ||
| } | ||
| } | ||
|
|
||
| func TestLoadRejectsInvalidAPIKey(t *testing.T) { | ||
| cases := map[string]string{ | ||
| "empty": "", | ||
| "not a uuid": "not-a-uuid", | ||
| "all zero": "00000000-0000-0000-0000-000000000000", | ||
| } | ||
| for name, value := range cases { | ||
| t.Run(name, func(t *testing.T) { | ||
| t.Setenv("API_KEY", value) | ||
|
|
||
| cfg, err := Load() | ||
| if err == nil { | ||
| t.Fatalf("expected Load to fail for API_KEY=%q", value) | ||
| } | ||
| if cfg == nil { | ||
| t.Fatal("Load must still return the config (NewTestConfig relies on it)") | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestLoadAcceptsValidAPIKey(t *testing.T) { | ||
| const key = "3fa85f64-5717-4562-b3fc-2c963f66afa6" | ||
| t.Setenv("API_KEY", key) | ||
|
|
||
| cfg, err := Load() | ||
| if err != nil { | ||
| t.Fatalf("Load failed: %v", err) | ||
| } | ||
| if cfg.ApiKey.String() != key { | ||
| t.Fatalf("expected ApiKey %s, got %s", key, cfg.ApiKey) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Reject malformed UUID wrappers.
If
API_KEYisx3fa85f64-5717-4562-b3fc-2c963f66afa6y,uuid.Parseignores the outer characters andLoadaccepts the key. This conflicts with the requirement to reject malformed keys. Validate the input format before parsing it;uuid.Validatechecks the wrapper. (github.com)🤖 Prompt for AI Agents