Files
fn_registry/functions/infra/wg_peer_revoke_test.go
egutierrez 621e8895c9 feat(infra): auto-commit con 86 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:38:15 +02:00

105 lines
3.1 KiB
Go

package infra
import (
"database/sql"
"os"
"path/filepath"
"testing"
_ "github.com/mattn/go-sqlite3"
)
const wgRevokeTestConfig = `[Interface]
Address = 10.0.0.1/24
PrivateKey = SERVERKEY==
# DeviceID:device-revoke-001
[Peer]
PublicKey = PUBKEYREVOKE001==
AllowedIPs = 10.0.0.10/32
# DeviceID:device-revoke-002
[Peer]
PublicKey = PUBKEYREVOKE002==
AllowedIPs = 10.0.0.11/32
`
func TestWGPeerRevoke(t *testing.T) {
origSyncConf := wgSyncConfFn
wgSyncConfFn = func(iface, configPath string) error { return nil }
defer func() { wgSyncConfFn = origSyncConf }()
origBlacklist := wgAppendBlacklistFn
wgAppendBlacklistFn = func(line string) error { return nil }
defer func() { wgAppendBlacklistFn = origBlacklist }()
t.Run("audit DB contiene registro con this_hash != prev_hash", func(t *testing.T) {
dir := t.TempDir()
configPath := filepath.Join(dir, "wg0.conf")
auditDBPath := filepath.Join(dir, "revoked.db")
if err := os.WriteFile(configPath, []byte(wgRevokeTestConfig), 0600); err != nil {
t.Fatalf("write config: %v", err)
}
audit, err := WGPeerRevoke("device-revoke-001", "operator-alice", "dispositivo perdido", configPath, auditDBPath)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if audit.ThisHash == "" {
t.Error("this_hash is empty")
}
// En el primer registro prev_hash es vacio — this_hash debe diferir siempre.
if audit.ThisHash == audit.PrevHash {
t.Errorf("this_hash == prev_hash (%q), expected different values", audit.ThisHash)
}
if audit.PublicKey != "PUBKEYREVOKE001==" {
t.Errorf("public_key=%q, want PUBKEYREVOKE001==", audit.PublicKey)
}
// Verificar en la BD directamente.
db, err := sql.Open("sqlite3", auditDBPath)
if err != nil {
t.Fatalf("open audit db: %v", err)
}
defer db.Close()
var storedHash, storedPubKey string
if err := db.QueryRow("SELECT this_hash, public_key FROM revoked_peers WHERE device_id = ?",
"device-revoke-001").Scan(&storedHash, &storedPubKey); err != nil {
t.Fatalf("query audit record: %v", err)
}
if storedHash != audit.ThisHash {
t.Errorf("stored hash=%q, want %q", storedHash, audit.ThisHash)
}
if storedPubKey != "PUBKEYREVOKE001==" {
t.Errorf("stored public_key=%q, want PUBKEYREVOKE001==", storedPubKey)
}
})
t.Run("segunda revoke del mismo peer → error already revoked", func(t *testing.T) {
dir := t.TempDir()
configPath := filepath.Join(dir, "wg0.conf")
auditDBPath := filepath.Join(dir, "revoked.db")
if err := os.WriteFile(configPath, []byte(wgRevokeTestConfig), 0600); err != nil {
t.Fatalf("write config: %v", err)
}
// Primera revocacion.
if _, err := WGPeerRevoke("device-revoke-002", "operator-bob", "comprometido", configPath, auditDBPath); err != nil {
t.Fatalf("first revoke unexpected error: %v", err)
}
// Segunda revocacion del mismo deviceID → debe fallar por audit DB, no por config.
_, err := WGPeerRevoke("device-revoke-002", "operator-bob", "segundo intento", configPath, auditDBPath)
if err == nil {
t.Fatal("expected error on second revoke, got nil")
}
if !contains(err.Error(), "already revoked") {
t.Errorf("expected 'already revoked' error, got: %v", err)
}
})
}