p2.6: warn when permit_restricted has no key

CheckMappings now logs WARN for each permit_restricted name missing
from keys.toml, so a missing straylight-gs key is visible at start
and on reload instead of passing silently.
This commit is contained in:
2026-09-23 12:19:10 -07:00
parent d7873403ff
commit f748e695b1
3 changed files with 33 additions and 3 deletions
+3 -2
View File
@@ -110,8 +110,9 @@ under size cap; corrupt DB → warn and bypass.
A fleet caller remapped to it is still refused (tested). **P2.6 reverse:** a A fleet caller remapped to it is still refused (tested). **P2.6 reverse:** a
`permit_restricted` caller whose mapped workspace is not `guardian-star` is `permit_restricted` caller whose mapped workspace is not `guardian-star` is
refused (ERROR log, no Honcho request, never fall back to `hermes-fleet`). refused (ERROR log, no Honcho request, never fall back to `hermes-fleet`).
Checked at Search, at serve start, and on keys reload. Workspace is never taken Checked at Search, at serve start, and on keys reload. A `permit_restricted`
from the request. name with no key at all logs WARN (missing key does not pass silently).
Workspace is never taken from the request.
- Query: the question if given, else title + top 3 headings. - Query: the question if given, else title + top 3 headings.
- Return trimmed items: `{peer, content (≤300 chars), created_at, session}`; label clearly - Return trimmed items: `{peer, content (≤300 chars), created_at, session}`; label clearly
as prior fleet knowledge, not page content. as prior fleet knowledge, not page content.
+11 -1
View File
@@ -193,16 +193,26 @@ type CallerWS struct {
Name, Workspace string Name, Workspace string
} }
// CheckMappings logs ERROR for every permitted caller whose workspace is not Restricted. // CheckMappings logs ERROR for every permitted caller whose workspace is not
// Restricted, and WARN for every permit_restricted name with no key at all.
func (c *Client) CheckMappings(callers []CallerWS) { func (c *Client) CheckMappings(callers []CallerWS) {
if c == nil { if c == nil {
return return
} }
have := make(map[string]struct{}, len(callers))
for _, a := range callers { for _, a := range callers {
have[a.Name] = struct{}{}
if permitted(a.Name, c.Permit) && !restricted(a.Workspace) { if permitted(a.Name, c.Permit) && !restricted(a.Workspace) {
if c.Log != nil { if c.Log != nil {
c.Log.Error("restricted caller mapped off guardian-star", "caller", a.Name, "workspace", a.Workspace) c.Log.Error("restricted caller mapped off guardian-star", "caller", a.Name, "workspace", a.Workspace)
} }
} }
} }
for _, name := range c.Permit {
if _, ok := have[name]; !ok {
if c.Log != nil {
c.Log.Warn("permit_restricted caller has no key", "caller", name)
}
}
}
} }
+19
View File
@@ -1,11 +1,14 @@
package fleetctx package fleetctx
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"io" "io"
"log/slog"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"testing" "testing"
@@ -184,3 +187,19 @@ func TestConcurrentSearch(t *testing.T) {
t.Fatalf("calls %d", c.Calls.Load()) t.Fatalf("calls %d", c.Calls.Load())
} }
} }
func TestCheckMappingsWarnsMissingKey(t *testing.T) {
var buf bytes.Buffer
log := slog.New(slog.NewTextHandler(&buf, nil))
c := &Client{Permit: []string{"straylight-gs"}, Log: log}
c.CheckMappings(nil)
got := buf.String()
if !strings.Contains(got, "permit_restricted caller has no key") || !strings.Contains(got, "straylight-gs") {
t.Fatalf("missing warn: %s", got)
}
buf.Reset()
c.CheckMappings([]CallerWS{{Name: "straylight-gs", Workspace: "guardian-star"}})
if strings.Contains(buf.String(), "no key") || strings.Contains(buf.String(), "mapped off") {
t.Fatalf("mapped ok still logged: %s", buf.String())
}
}