mirror of
https://github.com/tiennm99/keepalive.git
synced 2026-10-11 03:13:31 +00:00
fix: close remaining secret leaks, timeout gaps and config blind spots
- Generated service names come only from a URL host, a key=value DSN's host=, or a MySQL tcp() address, so a password in a key=value DSN can no longer end up in the name printed on every log line. - connect_timeout is added only to postgres:// and postgresql:// URLs (parsed, so it never lands after a fragment) or as a key=value token, never glued onto a key=value value containing "://". - Driver parse errors that quote password fragments (mongo escape errors, lib/pq's missing "=" error) are replaced with generic hints. - MongoDB keeps its client only after a successful connect, so a failed connect is not disconnected twice. - Couchbase gets ready_timeout plus 1 minute to connect, so raising ready_timeout takes effect. - Shutdown waits at most 7 seconds, inside Docker's 10-second grace period. - Each adapter declares its config keys; unknown keys anywhere in the file, including under config, log a warning without blocking start.
This commit is contained in:
1 parent
e646af19b8
commit
47afb85093
14 files changed
+302
-45
No files matched your search
@@ -6,7 +6,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"maps"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -58,22 +60,48 @@ func loadConfigFile(path string) ([]serviceConfig, error) {
|
||||
if err := yaml.Unmarshal(data, &raw); err != nil {
|
||||
return nil, fmt.Errorf("parse config: %w", err)
|
||||
}
|
||||
if err := checkUnknownFields(data); err != nil {
|
||||
log.Printf("warning: %s: %v; unknown keys are ignored", path, err)
|
||||
for _, warning := range schemaWarnings(data, raw) {
|
||||
log.Printf("warning: %s: %s; ignoring it", path, warning)
|
||||
}
|
||||
return normalizeConfig(raw)
|
||||
}
|
||||
|
||||
// checkUnknownFields reports keys that appConfig does not define, such as a
|
||||
// misspelled interval. Keys under a service's config map are not checked.
|
||||
func checkUnknownFields(data []byte) error {
|
||||
// schemaWarnings lists every key the config schema does not define: keys
|
||||
// appConfig and serviceFileConfig lack (such as a misspelled interval), and
|
||||
// keys under a service's config map that its adapter does not read (such as
|
||||
// a misspelled namespace). Unknown keys are ignored, not fatal.
|
||||
func schemaWarnings(data []byte, raw appConfig) []string {
|
||||
var warnings []string
|
||||
|
||||
decoder := yaml.NewDecoder(bytes.NewReader(data))
|
||||
decoder.KnownFields(true)
|
||||
var raw appConfig
|
||||
if err := decoder.Decode(&raw); err != nil && !errors.Is(err, io.EOF) {
|
||||
return err
|
||||
var strict appConfig
|
||||
if err := decoder.Decode(&strict); err != nil && !errors.Is(err, io.EOF) {
|
||||
var typeErr *yaml.TypeError
|
||||
if errors.As(err, &typeErr) {
|
||||
warnings = append(warnings, typeErr.Errors...)
|
||||
} else {
|
||||
warnings = append(warnings, err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
for i, service := range raw.Services {
|
||||
adapterType := strings.TrimSpace(service.Adapter)
|
||||
known, ok := adapter.ConfigKeys[adapterType]
|
||||
if !ok {
|
||||
// normalizeConfig rejects the unknown adapter itself.
|
||||
continue
|
||||
}
|
||||
for _, key := range slices.Sorted(maps.Keys(service.Config)) {
|
||||
if key == "counter_key" || slices.Contains(known, key) {
|
||||
// normalizeConfig rejects config.counter_key with its own error.
|
||||
continue
|
||||
}
|
||||
warnings = append(warnings, fmt.Sprintf("services[%d].config: unknown key %q for adapter %s (known: %s)",
|
||||
i, key, adapterType, strings.Join(known, ", ")))
|
||||
}
|
||||
}
|
||||
return warnings
|
||||
}
|
||||
|
||||
func defaultConfigFile() (string, error) {
|
||||
|
||||
Reference in new issue
Block a user