Make nmon easier to install and run without editing YAML by hand: - Settings: point-and-click forms over config.yaml (GET/PUT /api/v1/settings/form); the YAML editor moves to /settings/yaml. - First install: with no sign-in configured nmon starts in install mode, serves only the setup wizard (sign-in, basics, devices, alerting) and closes it for good once sign-in is saved. A self-signed certificate is generated when no TLS source is given. poller.interval becomes a config setting. - Reverse proxies: opt-in --http-listen plain-HTTP listener beside HTTPS; sign-in stays required. - Webhooks: Generic, Teams Adaptive Card, Slack and Discord presets, template preview and test send. - Help: the operations, coverage and profile docs served at /help. - Polling: per-device "Poll now", a dry-run test poll returning an SNMP trace, and time-limited in-memory SNMP debug recording, in the UI and as `nmon device poll`. - Ansible: deploys into install mode when no sign-in is set, and no longer overwrites the config.yaml the wizard wrote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017TuKgyKve2XLFtrrXWMi2w
45 lines
1.4 KiB
Go
45 lines
1.4 KiB
Go
package auth_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/v10networks/nmon/internal/auth"
|
|
"github.com/v10networks/nmon/internal/clock"
|
|
"github.com/v10networks/nmon/internal/testutil"
|
|
)
|
|
|
|
func TestInstallModeServesOnlyAllowedRoutesAndPagesAsAdmin(t *testing.T) {
|
|
clk := clock.Real()
|
|
pol := auth.NewPolicy().Public("GET /healthz").AllowInstall("GET /api/v1/ok", "POST /api/v1/ok")
|
|
svc, err := auth.New(context.Background(), auth.Options{Store: testutil.OpenStore(t, clk), Policy: pol, Install: true})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var who string
|
|
h := svc.Middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if p, ok := auth.FromContext(r.Context()); ok {
|
|
who = p.Actor() + "/" + string(p.Role)
|
|
}
|
|
}))
|
|
for _, tc := range []struct {
|
|
method, path string
|
|
want int
|
|
}{
|
|
{"GET", "/api/v1/ok", 200}, {"POST", "/api/v1/ok", 200}, {"PUT", "/api/v1/ok", 503}, {"GET", "/api/v1/other", 503},
|
|
{"GET", "/metrics", 503}, {"GET", "/devices", 200}, {"GET", "/healthz", 200}, {"POST", "/devices", 503},
|
|
} {
|
|
rec := httptest.NewRecorder()
|
|
who = ""
|
|
h.ServeHTTP(rec, httptest.NewRequest(tc.method, tc.path, nil))
|
|
if rec.Code != tc.want {
|
|
t.Errorf("%s %s = %d, want %d", tc.method, tc.path, rec.Code, tc.want)
|
|
}
|
|
if tc.want == 200 && tc.path != "/healthz" && who != "setup/admin" {
|
|
t.Errorf("%s %s ran as %q, want setup/admin", tc.method, tc.path, who)
|
|
}
|
|
}
|
|
}
|