mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-22 22:48:11 +02:00
Lot 17 : interrupteurs système tenus par la façade (LOKI_SYSTEM=rust)
La façade sert /api/internet (moteur web, serveur Crawl4AI et sa clé jamais rendue, joignabilité avec son cache de 30 s), /api/computer (interrupteur du navigateur, binaire trouvé, vision), /api/apikey (clé de complétion, repli sur config.env, adresse /v1 à coller dans un client tiers) et /api/network (écoute du moteur) quand LOKI_SYSTEM=rust (expérimental ; le Go reste le défaut). Restent au Go derrière son API interne (facade_system.go) : le cache de joignabilité de ses outils web (/internal/v1/web/reach/reset), le Chromium des outils browser_* (/internal/v1/cdp/shutdown) et le redémarrage qui applique une clé neuve quand la façade ne pilote pas le moteur (/internal/v1/service/action). Le relais du tunnel garde l'hôte et X-Forwarded-Proto du client. Correction en passant : maskAPIKey paniquait sur une clé d'un octet, et /api/apikey tombait à chaque lecture. Parité : parity_system_test.go tire du Go 61 appels de route avec la base et les sondes reçues par trois faux Crawl4AI après chacun, et huit dispositions du dossier de Playwright, rejoués par tests/system.rs ; ce qui reste au Go vérifié de bout en bout ; TestFacadeSysteme, TestFacadeRelaisGardeHote et TestMaskAPIKeyCourte côté Go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tcGfJWefW5kUGoC2wL8cv
This commit is contained in:
19 files changed
+3110
-3
No files matched your search
@@ -645,3 +645,116 @@ func TestFacadeMoteur(t *testing.T) {
|
||||
t.Fatalf("arrêt de la dictée : %d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
// Une clé de complétion d'un ou deux octets ne fait plus tomber /api/apikey.
|
||||
func TestMaskAPIKeyCourte(t *testing.T) {
|
||||
for k, want := range map[string]string{
|
||||
"": "",
|
||||
"k": "…",
|
||||
"ab": "…",
|
||||
"abc": "…bc",
|
||||
"abcdefghijklm": "…lm",
|
||||
"sk-loki-0123456789abcdef": "sk-loki-0…cdef",
|
||||
} {
|
||||
if got := maskAPIKey(k); got != want {
|
||||
t.Errorf("maskAPIKey(%q) = %q, attendu %q", k, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Les interrupteurs système (LOKI_SYSTEM=rust, lot 17) partent à la façade ;
|
||||
// l'API interne lui rend ce qui vit ici : cache de joignabilité des outils
|
||||
// web, navigateur piloté, redémarrage du moteur.
|
||||
func TestFacadeSysteme(t *testing.T) {
|
||||
testHome(t)
|
||||
t.Setenv("LOKI_CONTAINER", "1")
|
||||
f := demarrerFacade(t)
|
||||
t.Setenv(facadeChatEnv, "")
|
||||
local := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "go") }
|
||||
for p := range facadeSystemRoutes {
|
||||
w := httptest.NewRecorder()
|
||||
withFacadeChat(p, local)(w, httptest.NewRequest("GET", p, nil))
|
||||
if w.Body.String() != "go" {
|
||||
t.Fatalf("%s servi ailleurs sans LOKI_SYSTEM : %q", p, w.Body.String())
|
||||
}
|
||||
}
|
||||
t.Setenv(facadeSystemEnv, "rust")
|
||||
for p := range facadeSystemRoutes {
|
||||
w := httptest.NewRecorder()
|
||||
withFacadeChat(p, local)(w, httptest.NewRequest("POST", p, strings.NewReader("{}")))
|
||||
if w.Body.String() != f.reply {
|
||||
t.Fatalf("%s : réponse %q", p, w.Body.String())
|
||||
}
|
||||
}
|
||||
if n := len(f.recu()); n != len(facadeSystemRoutes) {
|
||||
t.Fatalf("reçu par la façade : %d appels", n)
|
||||
}
|
||||
|
||||
// Cache de joignabilité vidé.
|
||||
reachMu.Lock()
|
||||
reachURL = "http://ancien"
|
||||
reachMu.Unlock()
|
||||
w := httptest.NewRecorder()
|
||||
handleInternalReachReset(w, httptest.NewRequest("POST", "/internal/v1/web/reach/reset", nil))
|
||||
reachMu.Lock()
|
||||
vide := reachURL == ""
|
||||
reachMu.Unlock()
|
||||
if w.Code != 204 || !vide {
|
||||
t.Fatalf("reach/reset : %d, cache vidé : %v", w.Code, vide)
|
||||
}
|
||||
w = httptest.NewRecorder()
|
||||
handleInternalCDPShutdown(w, httptest.NewRequest("POST", "/internal/v1/cdp/shutdown", nil))
|
||||
if w.Code != 204 {
|
||||
t.Fatalf("cdp/shutdown : %d", w.Code)
|
||||
}
|
||||
|
||||
// Redémarrage : seulement si le moteur tourne quand if_active est posé.
|
||||
var actions []string
|
||||
old := internalServiceAction
|
||||
t.Cleanup(func() { internalServiceAction = old })
|
||||
internalServiceAction = func(a string) error {
|
||||
actions = append(actions, a)
|
||||
if a == "start" {
|
||||
return errTuneBusy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, c := range []struct {
|
||||
body, want string
|
||||
code int
|
||||
}{
|
||||
{`{"action":"restart","if_active":true}`, `{"error":"","ran":false}`, 200},
|
||||
{`{"action":"restart"}`, `{"error":"","ran":true}`, 200},
|
||||
{`{"action":"start"}`, `{"error":"` + errTuneBusy.Error() + `","ran":true}`, 200},
|
||||
{`{"action":"reload"}`, `{"error":"action inconnue : reload"}`, 400},
|
||||
{`{"action":`, `{"error":"unexpected EOF"}`, 400},
|
||||
} {
|
||||
w := httptest.NewRecorder()
|
||||
handleInternalServiceAction(w, httptest.NewRequest("POST", "/internal/v1/service/action", strings.NewReader(c.body)))
|
||||
if got := strings.TrimSpace(w.Body.String()); w.Code != c.code || got != c.want {
|
||||
t.Fatalf("%s : %d %s", c.body, w.Code, got)
|
||||
}
|
||||
}
|
||||
if strings.Join(actions, ",") != "restart,start" {
|
||||
t.Fatalf("actions : %v", actions)
|
||||
}
|
||||
}
|
||||
|
||||
// Le relais vers la façade garde l'hôte et le schéma du client : la clé de
|
||||
// complétion y calcule l'adresse à coller dans un client tiers.
|
||||
func TestFacadeRelaisGardeHote(t *testing.T) {
|
||||
var host, proto string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
host, proto = r.Host, r.Header.Get("X-Forwarded-Proto")
|
||||
}))
|
||||
defer srv.Close()
|
||||
t.Setenv(internalTokenEnv, jetonTest)
|
||||
t.Setenv(facadeAddrEnv, strings.TrimPrefix(srv.URL, "http://"))
|
||||
r := httptest.NewRequest("GET", "/api/apikey", nil)
|
||||
r.Host = "loki.exemple.fr"
|
||||
r.Header.Set("X-Forwarded-Proto", "https")
|
||||
facadeRelayAs(httptest.NewRecorder(), r, "")
|
||||
if host != "loki.exemple.fr" || proto != "https" {
|
||||
t.Fatalf("hôte %q, schéma %q", host, proto)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user