p2.6: partition dcache by caller class; pin restricted workspace
Digest, chunk-embed, and question-embed keys include fleet|restricted so a fleet caller cannot observe a restricted cache hit. Digest.Run takes the class from permit_restricted. A permit_restricted caller whose keys.toml workspace is not guardian-star is refused at Search (no Honcho request) and flagged at serve start and keys reload. docs: P3 restricted callers search like the fleet; cache/logs isolate.
This commit is contained in:
@@ -76,11 +76,20 @@ func allowed(ws string, allow []string) bool {
|
||||
}
|
||||
|
||||
// Search returns prior knowledge for workspace. Failure → (nil, warning). Never
|
||||
// an error that fails the fetch. Restricted workspace requires caller ∈ Permit.
|
||||
// an error that fails the fetch.
|
||||
// Restricted workspace requires caller ∈ Permit. A permitted caller whose mapped
|
||||
// workspace is not Restricted is refused and never queried (no fallback).
|
||||
func (c *Client) Search(ctx context.Context, workspace, caller, query string) (items []Item, warn string) {
|
||||
if c == nil || query == "" {
|
||||
return nil, ""
|
||||
}
|
||||
if permitted(caller, c.Permit) && !restricted(workspace) {
|
||||
if c.Log != nil {
|
||||
c.Log.Error("restricted caller mapped off guardian-star", "caller", caller, "workspace", workspace)
|
||||
}
|
||||
c.Failures.Add(1)
|
||||
return nil, "context refused: workspace"
|
||||
}
|
||||
if restricted(workspace) && !permitted(caller, c.Permit) {
|
||||
if c.Log != nil {
|
||||
c.Log.Warn("context refused", "workspace", workspace, "caller", caller)
|
||||
@@ -178,3 +187,22 @@ func Query(question, title string, headings []string) string {
|
||||
}
|
||||
|
||||
func (c *Client) String() string { return fmt.Sprintf("fleetctx base=%s", c.Base) }
|
||||
|
||||
// CallerWS is a keys.toml name+workspace pair for startup/reload checks.
|
||||
type CallerWS struct {
|
||||
Name, Workspace string
|
||||
}
|
||||
|
||||
// CheckMappings logs ERROR for every permitted caller whose workspace is not Restricted.
|
||||
func (c *Client) CheckMappings(callers []CallerWS) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
for _, a := range callers {
|
||||
if permitted(a.Name, c.Permit) && !restricted(a.Workspace) {
|
||||
if c.Log != nil {
|
||||
c.Log.Error("restricted caller mapped off guardian-star", "caller", a.Name, "workspace", a.Workspace)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -30,6 +31,29 @@ func TestRestrictedRefusedWhenFleetCallerRemapped(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRestrictedCallerMappedToFleetMakesNoRequest(t *testing.T) {
|
||||
var hits atomic.Int32
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
hits.Add(1)
|
||||
w.WriteHeader(200)
|
||||
_, _ = w.Write([]byte("[]"))
|
||||
}))
|
||||
defer ts.Close()
|
||||
c := &Client{
|
||||
Base: ts.URL,
|
||||
Allow: []string{"guardian-star", "hermes-fleet"},
|
||||
Permit: []string{"straylight-gs"},
|
||||
HTTP: ts.Client(),
|
||||
}
|
||||
items, warn := c.Search(context.Background(), "hermes-fleet", "straylight-gs", "secret query")
|
||||
if hits.Load() != 0 {
|
||||
t.Fatalf("honcho hits %d", hits.Load())
|
||||
}
|
||||
if len(items) != 0 || warn == "" {
|
||||
t.Fatalf("items %v warn %q", items, warn)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRestrictedAllowedForPermittedCaller(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/v3/workspaces/guardian-star/search" {
|
||||
|
||||
Reference in New Issue
Block a user