feat: add new Prometheus metrics and bearer token auth for /metrics

Add 6 new Prometheus metrics for richer observability:
- auth_attempts_by_country_total (counter by country)
- commands_executed_total (counter by shell via OnCommand callback)
- human_score (histogram of final detection scores)
- storage_login_attempts_total, storage_unique_ips, storage_sessions_total
  (gauges via custom collector querying GetDashboardStats on each scrape)

Add optional bearer token authentication for the /metrics endpoint via
web.metrics_token config option. Uses crypto/subtle.ConstantTimeCompare.
Empty token (default) means no auth for backwards compatibility.

Also adds "cisco" to pre-initialized session/command metric labels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 15:54:29 +01:00
parent 9aecc7ce02
commit df860b3061
16 changed files with 301 additions and 23 deletions

View File

@@ -75,6 +75,9 @@ func (a *AdventureShell) Handle(ctx context.Context, sess *shell.SessionContext,
return fmt.Errorf("append session log: %w", err)
}
}
if sess.OnCommand != nil {
sess.OnCommand("adventure")
}
if result.exit {
return nil

View File

@@ -345,6 +345,9 @@ func logAction(sess *shell.SessionContext, input, output string) tea.Cmd {
defer cancel()
_ = sess.Store.AppendSessionLog(ctx, sess.SessionID, input, output)
}
if sess.OnCommand != nil {
sess.OnCommand("banking")
}
return nil
}
}

View File

@@ -86,6 +86,9 @@ func (b *BashShell) Handle(ctx context.Context, sess *shell.SessionContext, rw i
return fmt.Errorf("append session log: %w", err)
}
}
if sess.OnCommand != nil {
sess.OnCommand("bash")
}
if result.exit {
return nil

View File

@@ -74,6 +74,9 @@ func (c *CiscoShell) Handle(ctx context.Context, sess *shell.SessionContext, rw
return fmt.Errorf("append session log: %w", err)
}
}
if sess.OnCommand != nil {
sess.OnCommand("cisco")
}
continue
}
@@ -92,6 +95,9 @@ func (c *CiscoShell) Handle(ctx context.Context, sess *shell.SessionContext, rw
return fmt.Errorf("append session log: %w", err)
}
}
if sess.OnCommand != nil {
sess.OnCommand("cisco")
}
if result.exit {
return nil

View File

@@ -69,6 +69,9 @@ func (f *FridgeShell) Handle(ctx context.Context, sess *shell.SessionContext, rw
return fmt.Errorf("append session log: %w", err)
}
}
if sess.OnCommand != nil {
sess.OnCommand("fridge")
}
if result.exit {
return nil

View File

@@ -24,6 +24,7 @@ type SessionContext struct {
Store storage.Store
ShellConfig map[string]any
CommonConfig ShellCommonConfig
OnCommand func(shell string) // called when a command is executed; may be nil
}
// ShellCommonConfig holds settings shared across all shell types.