diff --git a/README.md b/README.md index b4c1037..2f7abf5 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,6 @@ TTY detection, and security headers are always applied. | `BIND_ADDRESS` | IP address the HTTP listener binds. Loopback by default, so the cleartext listener is not published on every interface. The Docker image ships `0.0.0.0` instead. See [Bind address](#bind-address) | `127.0.0.1` (image: `0.0.0.0`) | | `DATA_DIR` | Directory for all SQLite databases | `/var/lib/webhooker` | | `DEBUG` | Enable debug logging | `false` | -| `MAINTENANCE_MODE` | Report `maintenanceMode: true` in the healthcheck JSON. It does not change how any request is served — no maintenance page exists | `false` | | `METRICS_USERNAME` | Basic auth username for `/metrics`. Must be set together with `METRICS_PASSWORD`; one without the other fails startup | `""` | | `METRICS_PASSWORD` | Basic auth password for `/metrics`. Must be set together with `METRICS_USERNAME`; one without the other fails startup | `""` | | `SENTRY_DSN` | Sentry error reporting DSN. Unset leaves error reporting off; a value the Sentry SDK cannot parse fails startup rather than serving with reporting silently off | `""` | @@ -515,8 +514,8 @@ no report is being sent — which is why it aborts rather than starting with reporting off. Leaving it unset is not a mistake and not affected: error reporting is simply off and startup is normal. -Boolean variables (`DEBUG`, `MAINTENANCE_MODE`) accept exactly the -spellings Go's `strconv.ParseBool` accepts — `1`, `t`, `T`, `TRUE`, +The boolean variable `DEBUG` accepts exactly the spellings Go's +`strconv.ParseBool` accepts — `1`, `t`, `T`, `TRUE`, `true`, `True`, `0`, `f`, `F`, `FALSE`, `false`, `False` — and nothing else. `yes`, `on`, and `off` are rejected rather than quietly treated as false. @@ -2775,7 +2774,7 @@ abuse limit later; they are tracked as future work. | Method | Path | Description | | ------ | --------------------------- | ----------- | | `GET` | `/` | Root redirect, 303 (authenticated → `/hooks`, unauthenticated → `/pages/login`) | -| `GET` | `/.well-known/healthcheck` | Health check (JSON: `status`, `now`, `uptimeSeconds`, `uptimeHuman`, `version`, `appname`, `maintenanceMode`) | +| `GET` | `/.well-known/healthcheck` | Health check (JSON: `status`, `now`, `uptimeSeconds`, `uptimeHuman`, `version`, `appname`) | | `GET`, `HEAD` | `/s/*` | Static file serving (embedded CSS, JS). `GET` and `HEAD` only — `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `TRACE` and `CONNECT` are answered `405 Method Not Allowed` with `Allow: GET, HEAD`. Any other method (such as `PROPFIND`) is refused by chi before it reaches this route, and gets `405` without an `Allow` header. Pinned by `TestStaticServesOnlyGetAndHead` | | `POST` | `/h/{uuid}` | Webhook receiver endpoint. `POST` only — every other method is answered `405 Method Not Allowed` with `Allow: POST`. Rate limited (see [Rate Limiting](#rate-limiting)) | diff --git a/internal/config/config.go b/internal/config/config.go index f1b74b8..386f17a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -149,7 +149,6 @@ type ConfigParams struct { type Config struct { DataDir string Debug bool - MaintenanceMode bool Environment string MetricsPassword string MetricsUsername string @@ -658,11 +657,6 @@ func loadFromEnv() (*Config, error) { return nil, err } - maintenanceMode, err := envBool("MAINTENANCE_MODE", false) - if err != nil { - return nil, err - } - retentionSweepInterval, err := envPositiveDuration( "RETENTION_SWEEP_INTERVAL", defaultRetentionSweepInterval, @@ -712,7 +706,6 @@ func loadFromEnv() (*Config, error) { return &Config{ DataDir: DataDir(), Debug: debug, - MaintenanceMode: maintenanceMode, Environment: environment, MetricsUsername: metricsUsername, MetricsPassword: metricsPassword, @@ -799,7 +792,6 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) { // host can reach the admin UI. "bindAddress", s.BindAddress, "debug", s.Debug, - "maintenanceMode", s.MaintenanceMode, "dataDir", s.DataDir, "retentionSweepInterval", s.RetentionSweepInterval.String(), // Logged because a perfectly valid non-positive value here diff --git a/internal/config/env_test.go b/internal/config/env_test.go index 29985c6..6978f0f 100644 --- a/internal/config/env_test.go +++ b/internal/config/env_test.go @@ -18,10 +18,9 @@ const testEnvKey = "WEBHOOKER_TEST_VALUE" // Real configuration variables exercised by the config.New tests. const ( - envKeyPort = "PORT" - envKeyDebug = "DEBUG" - envKeyMaintenanceMode = "MAINTENANCE_MODE" - envKeyBindAddress = "BIND_ADDRESS" + envKeyPort = "PORT" + envKeyDebug = "DEBUG" + envKeyBindAddress = "BIND_ADDRESS" ) // Sample BIND_ADDRESS values used by the tables below. @@ -604,12 +603,6 @@ func flagEnvValueCases() []badEnvValueCase { value: "ture", expectError: true, }, - { - name: "unparseable MAINTENANCE_MODE aborts startup", - key: envKeyMaintenanceMode, - value: "sometimes", - expectError: true, - }, } } @@ -656,8 +649,7 @@ func TestNewUsesDefaultsWhenUnset(t *testing.T) { t.Setenv("WEBHOOKER_ENVIRONMENT", "dev") for _, key := range []string{ - envKeyPort, envKeyDebug, envKeyMaintenanceMode, - envKeyBindAddress, envKeySentryDSN, + envKeyPort, envKeyDebug, envKeyBindAddress, envKeySentryDSN, } { require.NoError(t, os.Unsetenv(key)) } @@ -668,7 +660,6 @@ func TestNewUsesDefaultsWhenUnset(t *testing.T) { assert.Equal(t, 8080, cfg.Port) assert.False(t, cfg.Debug) - assert.False(t, cfg.MaintenanceMode) // Loopback, not the wildcard: the default must not publish the // cleartext admin UI and the unauthenticated receiver on every diff --git a/internal/handlers/settings.go b/internal/handlers/settings.go index 0ba9f78..a21f878 100644 --- a/internal/handlers/settings.go +++ b/internal/handlers/settings.go @@ -53,13 +53,6 @@ func settingRows(cfg *config.Config) []settingRow { }, {"DATA_DIR", "Directory for all SQLite databases", cfg.DataDir}, {"DEBUG", "Enable debug logging", strconv.FormatBool(cfg.Debug)}, - { - "MAINTENANCE_MODE", - "Report maintenanceMode: true in the healthcheck JSON. " + - "It does not change how any request is served — no " + - "maintenance page exists", - strconv.FormatBool(cfg.MaintenanceMode), - }, { "METRICS_USERNAME", "Basic auth username for /metrics. Must be set together " + diff --git a/internal/handlers/settings_test.go b/internal/handlers/settings_test.go index 1155bcf..f8b06a8 100644 --- a/internal/handlers/settings_test.go +++ b/internal/handlers/settings_test.go @@ -62,14 +62,12 @@ func settingsShown( func TestSettingsPageShowsLoadedConfiguration(t *testing.T) { t.Parallel() - // DEBUG and MAINTENANCE_MODE get opposite values, and each of - // METRICS_USERNAME, METRICS_PASSWORD and SENTRY_DSN is the only one - // of the three set in one of the content tests, so each row is - // checked against its own field. + // Each of METRICS_USERNAME, METRICS_PASSWORD and SENTRY_DSN is the + // only one of the three set in one of the content tests, so each + // row is checked against its own field. cfg := &config.Config{ DataDir: t.TempDir(), Debug: true, - MaintenanceMode: false, Environment: config.EnvironmentDev, MetricsUsername: "scraper", MetricsPassword: "", @@ -96,7 +94,6 @@ func TestSettingsPageShowsLoadedConfiguration(t *testing.T) { "BIND_ADDRESS": "192.0.2.10", "DATA_DIR": cfg.DataDir, "DEBUG": "true", - "MAINTENANCE_MODE": "false", "METRICS_USERNAME": "scraper", "METRICS_PASSWORD": "not set", "SENTRY_DSN": "not set", diff --git a/internal/healthcheck/healthcheck.go b/internal/healthcheck/healthcheck.go index 03c7281..cd3fcef 100644 --- a/internal/healthcheck/healthcheck.go +++ b/internal/healthcheck/healthcheck.go @@ -7,7 +7,6 @@ import ( "time" "go.uber.org/fx" - "sneak.berlin/go/webhooker/internal/config" "sneak.berlin/go/webhooker/internal/database" "sneak.berlin/go/webhooker/internal/globals" "sneak.berlin/go/webhooker/internal/logger" @@ -18,7 +17,6 @@ type HealthcheckParams struct { fx.In Globals *globals.Globals - Config *config.Config Logger *logger.Logger Database *database.Database } @@ -64,7 +62,6 @@ func (s *Healthcheck) Healthcheck() *Response { UptimeHuman: s.uptime().String(), Appname: s.params.Globals.Appname, Version: s.params.Globals.Version, - Maintenance: s.params.Config.MaintenanceMode, } return resp @@ -78,7 +75,6 @@ type Response struct { UptimeHuman string `json:"uptimeHuman"` Version string `json:"version"` Appname string `json:"appname"` - Maintenance bool `json:"maintenanceMode"` } func (s *Healthcheck) uptime() time.Duration { diff --git a/internal/server/server.go b/internal/server/server.go index 86dee1c..12521c1 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -159,12 +159,6 @@ func (s *Server) Run() { s.serve() } -// MaintenanceMode returns whether the server is in maintenance -// mode. -func (s *Server) MaintenanceMode() bool { - return s.params.Config.MaintenanceMode -} - // enableSentry initialises the Sentry SDK when error reporting is // configured, and reports the failure when it is configured and cannot // be initialised. A DSN that is not set is not a failure: reporting