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:
@@ -18,7 +18,18 @@ import (
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
const PromptVersion = "2"
|
||||
const (
|
||||
PromptVersion = "2"
|
||||
ClassFleet = "fleet"
|
||||
ClassRestricted = "restricted"
|
||||
)
|
||||
|
||||
func CallerClass(restricted bool) string {
|
||||
if restricted {
|
||||
return ClassRestricted
|
||||
}
|
||||
return ClassFleet
|
||||
}
|
||||
|
||||
type DB struct {
|
||||
sql *sql.DB
|
||||
@@ -83,18 +94,27 @@ func NormalizeQuestion(q string) string {
|
||||
return strings.ToLower(strings.Join(strings.Fields(q), " "))
|
||||
}
|
||||
|
||||
func DigestKey(contentHash, question, model, promptVer string) string {
|
||||
sum := sha256.Sum256([]byte(contentHash + "\x00" + NormalizeQuestion(question) + "\x00" + model + "\x00" + promptVer))
|
||||
func DigestKey(contentHash, question, model, promptVer, callerClass string) string {
|
||||
if callerClass == "" {
|
||||
callerClass = ClassFleet
|
||||
}
|
||||
sum := sha256.Sum256([]byte(contentHash + "\x00" + NormalizeQuestion(question) + "\x00" + model + "\x00" + promptVer + "\x00" + callerClass))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func EmbedKey(contentHash string, chunkIndex int, embedModel string) string {
|
||||
sum := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%d\x00%s", contentHash, chunkIndex, embedModel)))
|
||||
func EmbedKey(contentHash string, chunkIndex int, embedModel, callerClass string) string {
|
||||
if callerClass == "" {
|
||||
callerClass = ClassFleet
|
||||
}
|
||||
sum := sha256.Sum256([]byte(fmt.Sprintf("%s\x00%d\x00%s\x00%s", contentHash, chunkIndex, embedModel, callerClass)))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func QuestionEmbedKey(question, embedModel string) string {
|
||||
sum := sha256.Sum256([]byte("q\x00" + NormalizeQuestion(question) + "\x00" + embedModel))
|
||||
func QuestionEmbedKey(question, embedModel, callerClass string) string {
|
||||
if callerClass == "" {
|
||||
callerClass = ClassFleet
|
||||
}
|
||||
sum := sha256.Sum256([]byte("q\x00" + NormalizeQuestion(question) + "\x00" + embedModel + "\x00" + callerClass))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ func TestHitMissAndNormalise(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer d.Close()
|
||||
k1 := DigestKey("abc", "What Share?", "m", PromptVersion)
|
||||
k2 := DigestKey("abc", "what share?", "m", PromptVersion)
|
||||
k1 := DigestKey("abc", "What Share?", "m", PromptVersion, ClassFleet)
|
||||
k2 := DigestKey("abc", "what share?", "m", PromptVersion, ClassFleet)
|
||||
if k1 != k2 {
|
||||
t.Fatal("normalise")
|
||||
}
|
||||
@@ -25,15 +25,41 @@ func TestHitMissAndNormalise(t *testing.T) {
|
||||
if !ok || h.Text != "forty two" {
|
||||
t.Fatalf("%v %v", ok, h)
|
||||
}
|
||||
k3 := DigestKey("abd", "what share?", "m", PromptVersion)
|
||||
k3 := DigestKey("abd", "what share?", "m", PromptVersion, ClassFleet)
|
||||
if _, ok := d.GetDigest(k3); ok {
|
||||
t.Fatal("changed content must miss")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCallerClassPartitions(t *testing.T) {
|
||||
d, err := Open(filepath.Join(t.TempDir(), "c.db"), 1<<20, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer d.Close()
|
||||
fleet := DigestKey("h", "q", "m", PromptVersion, ClassFleet)
|
||||
restr := DigestKey("h", "q", "m", PromptVersion, ClassRestricted)
|
||||
if fleet == restr {
|
||||
t.Fatal("classes must not share a key")
|
||||
}
|
||||
d.PutDigest(restr, "secret", 1)
|
||||
if _, ok := d.GetDigest(fleet); ok {
|
||||
t.Fatal("fleet must not hit restricted digest")
|
||||
}
|
||||
if h, ok := d.GetDigest(restr); !ok || h.Text != "secret" {
|
||||
t.Fatalf("restricted hit %v %+v", ok, h)
|
||||
}
|
||||
if EmbedKey("h", 0, "e", ClassFleet) == EmbedKey("h", 0, "e", ClassRestricted) {
|
||||
t.Fatal("embed class")
|
||||
}
|
||||
if QuestionEmbedKey("q", "e", ClassFleet) == QuestionEmbedKey("q", "e", ClassRestricted) {
|
||||
t.Fatal("question embed class")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPromptVersionInvalidates(t *testing.T) {
|
||||
k1 := DigestKey("h", "q", "m", "1")
|
||||
k2 := DigestKey("h", "q", "m", "2")
|
||||
k1 := DigestKey("h", "q", "m", "1", ClassFleet)
|
||||
k2 := DigestKey("h", "q", "m", "2", ClassFleet)
|
||||
if k1 == k2 {
|
||||
t.Fatal("version")
|
||||
}
|
||||
@@ -59,7 +85,7 @@ func TestEvictUnderCap(t *testing.T) {
|
||||
}
|
||||
defer d.Close()
|
||||
for i := 0; i < 20; i++ {
|
||||
d.PutDigest(DigestKey("h", string(rune('a'+i)), "m", "1"), "xxxxxxxxxxxxxxxxxxxx", 1)
|
||||
d.PutDigest(DigestKey("h", string(rune('a'+i)), "m", "1", ClassFleet), "xxxxxxxxxxxxxxxxxxxx", 1)
|
||||
}
|
||||
if d.Size() > 400 {
|
||||
t.Fatalf("size %d", d.Size())
|
||||
|
||||
Reference in New Issue
Block a user