---
name: wg_peer_revoke
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func WGPeerRevoke(deviceID, operator, reason string, configPath, auditDBPath string) (WGPeerRevokeAudit, error)"
description: "Kill switch: revoca peer permanentemente. Anade a blacklist + audit log hash-chained inviolable (SHA256 chain). Para dispositivos perdidos/comprometidos."
tags: [wireguard, hub, revoke, kill-switch, audit, security]
uses_functions:
  - wg_peer_remove_go_infra
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: deviceID
    desc: "Identificador unico del dispositivo a revocar. Debe coincidir con '# DeviceID:<id>' en wg0.conf."
  - name: operator
    desc: "Nombre del operador que ejecuta la revocacion. Se guarda en audit log. No puede ser vacio."
  - name: reason
    desc: "Motivo de la revocacion (ej. 'dispositivo perdido', 'comprometido'). No puede ser vacio. No incluir PII."
  - name: configPath
    desc: "Ruta absoluta al wg0.conf del hub. El peer se elimina del config activo via syncconf."
  - name: auditDBPath
    desc: "Ruta al SQLite de audit. Se crea con schema si no existe. Contiene la cadena de hashes inviolable."
output: "WGPeerRevokeAudit con DeviceID, PublicKey, RevokedAt (unix), RevokedBy, Reason, PrevHash y ThisHash. ThisHash = SHA256(PrevHash|DeviceID|PublicKey|RevokedAt|Operator|Reason)."
tested: true
tests:
  - "audit DB contiene registro con this_hash != prev_hash"
  - "segunda revoke del mismo peer → error already revoked"
test_file_path: "functions/infra/wg_peer_revoke_test.go"
file_path: "functions/infra/wg_peer_revoke.go"
---

## Ejemplo

```go
audit, err := infra.WGPeerRevoke(
    "device-laptop-alice",
    "operator-bob",
    "dispositivo perdido en viaje",
    "/etc/wireguard/wg0.conf",
    "/var/lib/wg-hub/revoked.db",
)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("revoked: device=%s pubkey=%s hash=%s\n",
    audit.DeviceID, audit.PublicKey, audit.ThisHash)
```

## Cuando usarla

Cuando un dispositivo esta perdido, robado o comprometido y NO debe poder volver a conectarse nunca. Deja registro inmutable en audit DB con hash chain SHA256 y escribe la PublicKey en `/etc/wireguard/wg_revoked.list`. Para baja temporal (rotar claves, reconfigurar) usa `wg_peer_remove_go_infra`.

## Gotchas

- **Reason obligatorio**: reason vacio devuelve error antes de tocar nada.
- **Idempotencia**: revocar el mismo deviceID dos veces devuelve `already revoked`. La comprobacion es sobre la audit DB, no sobre el config.
- **Audit DB borrada**: si auditDBPath se borra, la chain se reinicia desde genesis (prev_hash vacio). El break de integridad es visible (primer registro sin prev_hash). El sistema lo acepta pero queda evidencia del gap.
- **Blacklist `/etc/wireguard/wg_revoked.list`**: requiere permisos de escritura en `/etc/wireguard/`. Si falla, el audit DB ya tiene el registro (no se revierte) pero la funcion devuelve error indicando el gap.
- **Reason no debe contener PII**: se guarda en texto plano en SQLite y en la blacklist. Usar referencias internas en vez de nombres reales.
- **syncconf**: hereda el requisito de privilegios de WGPeerRemove. Ver gotchas de `wg_peer_remove_go_infra`.
