Read every setting through viper and rename the settings (closes #211)
check / check (push) Failing after 3m27s

Every setting of discriminator and rproxy is read through viper, in place
of the os.LookupEnv function Main passed down. NewViper turns AutomaticEnv
and AllowEmptyEnv on, so a setting that is set but empty reads as set. A
setting may also be given as a file, the _FILE form, which rproxy's
settings now have too; rproxy still writes nothing to disk.

The settings are renamed. Discriminator's take the prefix SWW_WAF_,
rproxy's take SWW_RPROXY_, and the shared SWW_COMMAND keeps SWW_. The Core
Rule Set's settings take SWW_WAF_CORE_RULE_SET_ rather than SWW_WAF_WAF_.
Every place a name appeared changed: the code, the viper keys, tests,
documents, examples, the README's settings table and the image files.

Model: deepseek-v4-pro
This commit is contained in:
sneak committed 2026-11-07 06:41:11 +00:00
1 parent beb503b233
commit 68da92f414
89 files changed
+2027 -1916

No files matched your search

+30 -30
View File
@@ -1,12 +1,12 @@
// Package alerts sends alerts on bans, on traffic over an anomaly
// threshold, on a source that fails and on a file with an error to each
// destination set: to the webhook
// SWW_ALERT_WEBHOOK_URL names, each as one JSON object, as "The JSON
// SWW_WAF_ALERT_WEBHOOK_URL names, each as one JSON object, as "The JSON
// object" in docs/alerts.md describes, to the Slack incoming
// webhook SWW_ALERT_SLACK_WEBHOOK_URL names, as a message, and to the
// ntfy topic SWW_ALERT_NTFY_URL names. A repeat within
// SWW_ALERT_COOLDOWN is held back, and so is an alert past
// SWW_ALERT_MAX_PER_HOUR, for the hour's summary. The others wait in a
// webhook SWW_WAF_ALERT_SLACK_WEBHOOK_URL names, as a message, and to the
// ntfy topic SWW_WAF_ALERT_NTFY_URL names. A repeat within
// SWW_WAF_ALERT_COOLDOWN is held back, and so is an alert past
// SWW_WAF_ALERT_MAX_PER_HOUR, for the hour's summary. The others wait in a
// bounded queue of each destination's own, so that a destination that is
// slow or unreachable holds up neither the others nor any request. The
// state is written to alerts.json and read from it by the state package.
@@ -34,7 +34,7 @@ import (
"time"
)
// The events an alert is for, as SWW_ALERT_EVENTS names them.
// The events an alert is for, as SWW_WAF_ALERT_EVENTS names them.
const (
// EventBan is a ban sww made.
EventBan = "ban"
@@ -45,7 +45,7 @@ const (
// threshold.
EventAnomaly = "anomaly"
// EventWAFBlock is a request the Core Rule Set scored at or over
// SWW_WAF_ANOMALY_THRESHOLD, refused in block mode, let through in
// SWW_WAF_CORE_RULE_SET_ANOMALY_THRESHOLD, refused in block mode, let through in
// detect mode.
EventWAFBlock = "waf_block"
// EventReputationHit is a request whose client a blocklist, the
@@ -61,14 +61,14 @@ const (
// cannot be read, or a state file that cannot be written.
EventFileError = "file_error"
// EventSummary is the summary sent as an hour ends: of the alerts held
// back in it past SWW_ALERT_MAX_PER_HOUR, and of the repeats held
// back in it past SWW_WAF_ALERT_MAX_PER_HOUR, and of the repeats held
// back by the cooldowns dropped as it ends, which no alert let through
// has given. It is sent with SWW_ALERT_MAX_PER_HOUR off too, for
// those repeats. SWW_ALERT_EVENTS does not name it.
// has given. It is sent with SWW_WAF_ALERT_MAX_PER_HOUR off too, for
// those repeats. SWW_WAF_ALERT_EVENTS does not name it.
EventSummary = "summary"
)
// Events returns every event SWW_ALERT_EVENTS can name, which is its
// Events returns every event SWW_WAF_ALERT_EVENTS can name, which is its
// default.
func Events() []string {
return []string{
@@ -80,12 +80,12 @@ func Events() []string {
// The destinations alerts are sent to, as the metrics and alerts.json
// name them.
const (
// DestinationWebhook is the webhook SWW_ALERT_WEBHOOK_URL names.
// DestinationWebhook is the webhook SWW_WAF_ALERT_WEBHOOK_URL names.
DestinationWebhook = "webhook"
// DestinationSlack is the Slack incoming webhook
// SWW_ALERT_SLACK_WEBHOOK_URL names.
// SWW_WAF_ALERT_SLACK_WEBHOOK_URL names.
DestinationSlack = "slack"
// DestinationNtfy is the ntfy topic SWW_ALERT_NTFY_URL names.
// DestinationNtfy is the ntfy topic SWW_WAF_ALERT_NTFY_URL names.
DestinationNtfy = "ntfy"
)
@@ -121,26 +121,26 @@ var (
// NtfyURL set, no alert is sent.
type Params struct {
// WebhookURL is where each alert is posted as JSON
// (SWW_ALERT_WEBHOOK_URL), nil while it is unset. WebhookHeaders
// are sent with each (SWW_ALERT_WEBHOOK_HEADERS).
// (SWW_WAF_ALERT_WEBHOOK_URL), nil while it is unset. WebhookHeaders
// are sent with each (SWW_WAF_ALERT_WEBHOOK_HEADERS).
WebhookURL *url.URL
WebhookHeaders http.Header
// SlackURL is the Slack incoming webhook each alert is posted to as a
// message (SWW_ALERT_SLACK_WEBHOOK_URL), nil while it is unset.
// message (SWW_WAF_ALERT_SLACK_WEBHOOK_URL), nil while it is unset.
SlackURL *url.URL
// NtfyURL is the ntfy topic each alert is published to
// (SWW_ALERT_NTFY_URL), nil while it is unset. NtfyToken, unless
// empty, is sent with each as a bearer token (SWW_ALERT_NTFY_TOKEN).
// (SWW_WAF_ALERT_NTFY_URL), nil while it is unset. NtfyToken, unless
// empty, is sent with each as a bearer token (SWW_WAF_ALERT_NTFY_TOKEN).
NtfyURL *url.URL
NtfyToken string
// Events are the events alerts are sent for (SWW_ALERT_EVENTS).
// Events are the events alerts are sent for (SWW_WAF_ALERT_EVENTS).
Events []string
// Cooldown is how long a repeat of an alert is held back
// (SWW_ALERT_COOLDOWN), 0 for no time. MaxPerHour is the most alerts
// sent in an hour (SWW_ALERT_MAX_PER_HOUR), 0 for no limit.
// (SWW_WAF_ALERT_COOLDOWN), 0 for no time. MaxPerHour is the most alerts
// sent in an hour (SWW_WAF_ALERT_MAX_PER_HOUR), 0 for no limit.
Cooldown time.Duration
MaxPerHour int
// Instance is SWW_INSTANCE_NAME, which every alert gives.
// Instance is SWW_WAF_INSTANCE_NAME, which every alert gives.
Instance string
// Now tells the time of an alert, normally time.Now in UTC.
Now func() time.Time
@@ -301,17 +301,17 @@ func New(params Params) *Queue {
}
if params.WebhookURL != nil {
q.addDestination(DestinationWebhook, "SWW_ALERT_WEBHOOK_URL",
q.addDestination(DestinationWebhook, "SWW_WAF_ALERT_WEBHOOK_URL",
params.WebhookURL, q.webhookMessage)
}
if params.SlackURL != nil {
q.addDestination(DestinationSlack, "SWW_ALERT_SLACK_WEBHOOK_URL",
q.addDestination(DestinationSlack, "SWW_WAF_ALERT_SLACK_WEBHOOK_URL",
params.SlackURL, slackMessage)
}
if params.NtfyURL != nil {
q.addDestination(DestinationNtfy, "SWW_ALERT_NTFY_URL",
q.addDestination(DestinationNtfy, "SWW_WAF_ALERT_NTFY_URL",
params.NtfyURL, q.ntfyMessage)
}
@@ -319,7 +319,7 @@ func New(params Params) *Queue {
}
// Raise sends alert, which names its event and what is particular to it,
// unless no destination is set or SWW_ALERT_EVENTS leaves its event
// unless no destination is set or SWW_WAF_ALERT_EVENTS leaves its event
// out. It gives alert the instance and the time. An alert that repeats
// the last one let through less than Cooldown before is held back and
// counted. The next one let through gives that count, unless an hour of
@@ -363,7 +363,7 @@ func (q *Queue) Raise(alert Alert) {
}
// WouldSend reports whether Raise would let an alert for event on
// netblock through now: a destination is set, SWW_ALERT_EVENTS chooses
// netblock through now: a destination is set, SWW_WAF_ALERT_EVENTS chooses
// event, no alert for event on netblock was let through less than
// Cooldown before, and fewer than MaxPerHour alerts have been let through
// in the hour under way. Unlike Raise, it counts nothing.
@@ -606,13 +606,13 @@ func (q *Queue) endHour(now time.Time) {
if heldBack > 0 {
reasons = append(reasons, fmt.Sprintf("%d alerts held back in the hour from %s, "+
"past the %d an hour SWW_ALERT_MAX_PER_HOUR allows", heldBack,
"past the %d an hour SWW_WAF_ALERT_MAX_PER_HOUR allows", heldBack,
q.hour.Start.Format(time.RFC3339), q.params.MaxPerHour))
}
if repeats > 0 {
reasons = append(reasons, fmt.Sprintf("%d repeats held back by "+
"SWW_ALERT_COOLDOWN that no later alert gives", repeats))
"SWW_WAF_ALERT_COOLDOWN that no later alert gives", repeats))
}
if len(reasons) > 0 {