Files
nexarch/mail/internal/search/no_dynamic_sql_test.go
T
sysopsandClaude Sonnet 5 c3bf8100b1 SRC-01: manticore-suchindex-fuer-mails
Manticore-RT-Index für Mail-Suchdokumente (Betreff, Text, Anhangstext,
Metadaten), statisches versioniertes Schema.

- fields.go: statische Feld-/Index-Namen-Whitelist, einzige Quelle für
  Feldnamen im Paket (vermeidet known-issues-archivmail.md #11/#12:
  Sprintf/Join-basierte SQL-Klauselbildung).
- migrations/0001_mail_documents.sql: statisches Schema, per go:embed
  eingebettet, über /sql?mode=raw angelegt (kein String-Zusammenbau).
- client.go: Index/Search über die strukturierte Manticore-HTTP-JSON-API,
  Tenant-Filter über strukturiertes equals-Feld statt WHERE-Interpolation.

Prüfungen (alle real durchgeführt, siehe mail/docs/SRC-01-PRUEFPROTOKOLL.md):
1. TestNoDynamicSQLClauseBuilding: automatisierter Quelltext-Scan bestätigt
   keine Sprintf/Join-SQL-Klauselbildung.
2. TestSearch_MaliciousInputDoesNotAlterFieldNames: Injection-artige
   Eingaben verändern nachweislich keine Feldnamen im gesendeten Payload.
3. TestSearch_FindsExpectedDocument: Funktionstest gegen echtes Manticore
   auf 192.168.1.131 liefert erwartete Treffer.
Zusätzlich TestSearch_TenantIsolation für Akzeptanzkriterium 3.

Kein Umbau: storage/crypto/encstorage/dedup unverändert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HhgFcLS8tYMhDJpP74C6AQ
2026-08-31 09:40:29 +02:00

38 lines
1.1 KiB
Go

package search
import (
"os"
"strings"
"testing"
)
// TestNoDynamicSQLClauseBuilding ist die geforderte Pflichtprüfung 1:
// Codereview bestätigt automatisiert, dass client.go keine Sprintf/Join-
// basierte SQL-Klauselbildung enthält (Bekannter Fehler #11/#12 aus
// known-issues-archivmail.md). Die einzige SQL-Anfrage des Pakets
// (EnsureSchema, /sql-Endpunkt) darf ausschließlich den statisch
// eingebetteten Migrationstext verwenden — kein fmt.Sprintf, kein
// String-Concat/Join zum Bau von SQL-Text.
func TestNoDynamicSQLClauseBuilding(t *testing.T) {
src, err := os.ReadFile("client.go")
if err != nil {
t.Fatal(err)
}
code := string(src)
if strings.Contains(code, "fmt.Sprintf") {
t.Fatal("client.go darf kein fmt.Sprintf verwenden (SQL-Klauselbildung verboten, siehe known-issues #11/#12)")
}
_, after, found := strings.Cut(code, `"/sql?mode=raw"`)
if !found {
t.Fatal("erwarteter /sql-Aufruf nicht gefunden")
}
window := after
if len(window) > 200 {
window = window[:200]
}
if strings.Contains(window, "+") {
t.Fatal("kein '+'-String-Zusammenbau in der Nähe des /sql-Aufrufs erlaubt")
}
}