mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 15:08:16 +02:00
Correctifs repris d'AJEAN : chiffrement, preset externe, heartbeat, commande du moteur
- Désactivation du chiffrement (amont cac0cda, 19918c6) : une valeur illisible ne bloque plus tout (quarantaine datée + copie du keyvault), et la reprise au démarrage déchiffre aussi les conversations au lieu de retirer la clé après les seules pages. Propre à Loki : les images de conversation (chatimg/) sont maintenant déchiffrées elles aussi — elles restaient chiffrées sans clé. Les .bak chiffrés devenus illisibles sont retirés. - Preset externe (amont #95) : `loki serve` sort sans erreur (plus de boucle systemd « MODEL non défini »), le pré-vol l'accepte, le superviseur du conteneur ne le prend plus pour un plantage. - Unité systemd du moteur : TimeoutStopSec=5 (bascule de preset bloquée 90 s en pleine génération). - Heartbeat SSE (amont #105) : plus d'écriture après le retour du handler. - Paramètres → Configuration : commande exacte du moteur copiable (clé API masquée, Strata compris) et nombre de couches du modèle à côté de NGL, lu dans l'en-tête GGUF (amont #108, #43) ; aussi dans l'éditeur de preset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4a9a5a1712
commit
127013b32b
16 files changed
+479
-34
No files matched your search
@@ -2,6 +2,7 @@ package loki
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -261,3 +262,84 @@ func TestChiffrementGardeLesPointeursLisibles(t *testing.T) {
|
||||
t.Fatalf("pointeur chiffré non réparé : %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
// Une seule valeur indéchiffrable bloquait toute la désactivation, et les images
|
||||
// de conversation (chatimg/) restaient chiffrées sans clé une fois le keyvault
|
||||
// retiré. Désormais : tout ce qui se lit est déchiffré, l'illisible part en
|
||||
// quarantaine, et la désactivation aboutit.
|
||||
func TestDisableMemEncryptionSurvitAuxValeursIllisibles(t *testing.T) {
|
||||
testHome(t)
|
||||
clearMemDEK()
|
||||
seedPages(t)
|
||||
if _, err := EnableMemEncryption("pass-de-test-1234"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img := []byte("\x89PNG octets d'image de test")
|
||||
ref, err := storeChatImage(img, "image/png")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
imgPath := filepath.Join(chatImgDir(), strings.TrimPrefix(ref, imgRefScheme))
|
||||
if raw, _ := os.ReadFile(imgPath); !looksEncrypted(raw) {
|
||||
t.Fatal("l'image devrait être chiffrée")
|
||||
}
|
||||
other := make([]byte, 32)
|
||||
other[0] = 7
|
||||
alien, err := encPage(other, []byte("conversation chiffrée avec une autre clé"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := putBytes(bkChat, "vieille", alien); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := DisableMemEncryption(); err != nil {
|
||||
t.Fatalf("la désactivation aurait dû aboutir : %v", err)
|
||||
}
|
||||
if memEncActive() {
|
||||
t.Fatal("le chiffrement devrait être désactivé")
|
||||
}
|
||||
if b, _ := os.ReadFile(imgPath); string(b) != string(img) {
|
||||
t.Fatalf("image pas déchiffrée : %q", b)
|
||||
}
|
||||
if v := getBytes(bkChat, "vieille"); len(v) != 0 {
|
||||
t.Fatal("la valeur illisible aurait dû quitter la base")
|
||||
}
|
||||
q, _ := filepath.Glob(filepath.Join(LokiHome(), "chiffre-illisible-*", "valeurs.json"))
|
||||
if len(q) != 1 {
|
||||
t.Fatalf("quarantaine attendue, trouvée : %v", q)
|
||||
}
|
||||
if qb, _ := os.ReadFile(q[0]); !strings.Contains(string(qb), "vieille") {
|
||||
t.Fatal("la quarantaine doit contenir la valeur illisible")
|
||||
}
|
||||
if baks, _ := filepath.Glob(filepath.Join(chatImgDir(), "*.bak")); len(baks) != 0 {
|
||||
t.Fatalf(".bak chiffrés restés derrière : %v", baks)
|
||||
}
|
||||
}
|
||||
|
||||
// Déchiffrement interrompu puis repris au démarrage : la reprise retirait la clé
|
||||
// après les seules pages, et les conversations restaient chiffrées pour toujours.
|
||||
func TestResumeInterruptedDecryptDechiffreLesConversations(t *testing.T) {
|
||||
testHome(t)
|
||||
clearMemDEK()
|
||||
seedPages(t)
|
||||
if _, err := EnableMemEncryption("pw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
enc, err := encodeMemContent([]byte(`{"titre":"conversation"}`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := putBytes(bkChat, "conv:x", enc); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := writeMigrationJournal("decrypt"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resumeMemMigration()
|
||||
if memEncActive() {
|
||||
t.Fatal("la reprise aurait dû terminer le déchiffrement")
|
||||
}
|
||||
if v := getBytes(bkChat, "conv:x"); string(v) != `{"titre":"conversation"}` {
|
||||
t.Fatalf("conversation restée chiffrée après la reprise : %q", v)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user