Add 80% limit warning, stop repeat notifications, fix review findings
Notifications: - Warn once when a counter reaches warn_percent of its limit, through separate warn_*_url endpoints. - Write ntf/ markers so a lost Redis reply cannot re-send a breach. - Retry only when the request never left or the web app answered 429/5xx. Fixes: - Retry transactions Redis rejected; treat pool timeouts as definite. - Install the signal handler before startup work. - Stop logging the login suffix; redact notify URL credentials. - Reject corrupt or empty CDBs, truncated hash tables included. - Require a Sentinel password, refuse example placeholders, and default admin_addr to localhost. - Normalise /counters domains, count on the arrival day, log rejections, hide internals in errors and exit 1 on a failed drain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c43ff17627
commit
54f9626121
+14
-2
@@ -78,7 +78,12 @@ func run(args []string, stdout, stderr io.Writer, getenv func(string) string, no
|
||||
}
|
||||
q.Set("address", addr)
|
||||
} else {
|
||||
q.Set("domain", strings.ToLower(strings.TrimSpace(*domain)))
|
||||
dom, err := api.NormalizeDomain(*domain)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "invalid domain %q: %v\n", *domain, err)
|
||||
return 1
|
||||
}
|
||||
q.Set("domain", dom)
|
||||
}
|
||||
if *dateFlag != "" {
|
||||
day, err := api.ParseDate(*dateFlag, now())
|
||||
@@ -87,7 +92,8 @@ func run(args []string, stdout, stderr io.Writer, getenv func(string) string, no
|
||||
return 1
|
||||
}
|
||||
q.Set("date", day)
|
||||
if t, _ := time.Parse("2006-01-02", day); now().UTC().Sub(t) > 31*24*time.Hour {
|
||||
today, _ := api.ParseDate("", now())
|
||||
if d, t := mustDay(today), mustDay(day); d.Sub(t) > 31*24*time.Hour {
|
||||
fmt.Fprintf(stderr, "warning: %s is more than 31 days ago; counter keys expire after 31 days and will read as 0\n", day)
|
||||
}
|
||||
}
|
||||
@@ -154,6 +160,12 @@ func run(args []string, stdout, stderr io.Writer, getenv func(string) string, no
|
||||
return 0
|
||||
}
|
||||
|
||||
// mustDay parses a date api.ParseDate already validated.
|
||||
func mustDay(s string) time.Time {
|
||||
t, _ := time.Parse("2006-01-02", s)
|
||||
return t
|
||||
}
|
||||
|
||||
// flows picks the table columns: --in or --out alone restrict the table to
|
||||
// that flow; neither or both show both flows.
|
||||
func flows(in, out bool) (showIn, showOut bool) {
|
||||
|
||||
@@ -57,6 +57,8 @@ func (f *fakeAPI) last() *http.Request {
|
||||
return f.requests[len(f.requests)-1]
|
||||
}
|
||||
|
||||
func (f *fakeAPI) rawQuery() string { return f.last().URL.RawQuery }
|
||||
|
||||
func writeConfig(t *testing.T, body string) string {
|
||||
t.Helper()
|
||||
p := filepath.Join(t.TempDir(), "config.toml")
|
||||
@@ -333,3 +335,36 @@ func TestRun_Version(t *testing.T) {
|
||||
t.Errorf("exit %d output %q", code, out)
|
||||
}
|
||||
}
|
||||
|
||||
// Keys live 31 days from their last increment, so a date exactly 31 days back
|
||||
// can still hold data.
|
||||
func TestDateWarning_Boundary(t *testing.T) {
|
||||
f := &fakeAPI{body: sampleResponse()}
|
||||
s := httptest.NewServer(f)
|
||||
defer s.Close()
|
||||
cfg := writeConfig(t, "auth_token = \"t\"\n")
|
||||
exact := now.UTC().AddDate(0, 0, -31).Format("2006-01-02")
|
||||
if _, _, errOut := runCLI(t, noEnv, "--config", cfg, "--url", s.URL, "--address", "me@example.com", "--date", exact); strings.Contains(errOut, "will read as 0") {
|
||||
t.Errorf("31 days back must not warn: %q", errOut)
|
||||
}
|
||||
older := now.UTC().AddDate(0, 0, -32).Format("2006-01-02")
|
||||
if _, _, errOut := runCLI(t, noEnv, "--config", cfg, "--url", s.URL, "--address", "me@example.com", "--date", older); !strings.Contains(errOut, "will read as 0") {
|
||||
t.Errorf("32 days back must warn: %q", errOut)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomainFlag_Normalised(t *testing.T) {
|
||||
f := &fakeAPI{body: sampleResponse()}
|
||||
s := httptest.NewServer(f)
|
||||
defer s.Close()
|
||||
cfg := writeConfig(t, "auth_token = \"t\"\n")
|
||||
if code, _, errOut := runCLI(t, noEnv, "--config", cfg, "--url", s.URL, "--domain", "Bücher.de"); code != 0 {
|
||||
t.Fatalf("exit %d: %s", code, errOut)
|
||||
}
|
||||
if !strings.Contains(f.rawQuery(), "domain=xn--bcher-kva.de") {
|
||||
t.Errorf("query = %q", f.rawQuery())
|
||||
}
|
||||
if code, _, _ := runCLI(t, noEnv, "--config", cfg, "--url", s.URL, "--domain", "a..b"); code == 0 {
|
||||
t.Error("an invalid domain must exit non-zero")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user