feat(infra): auto-commit con 86 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user