sync: scission owner/template + brain-template-export + BRAIN_MODE guard + /visualize scope filter + port orphelins fix
This commit is contained in:
105
scripts/brain-pair.sh
Executable file
105
scripts/brain-pair.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# brain-pair.sh — Pairing multi-machine type Bluetooth (ADR-041)
|
||||
#
|
||||
# Usage :
|
||||
# brain-pair.sh start → génère code, écoute sur le LAN
|
||||
# brain-pair.sh join <code> → scan LAN, envoie code, reçoit config
|
||||
# brain-pair.sh list → machines pairées (peers dans brain-compose.local.yml)
|
||||
# brain-pair.sh revoke <machine> → supprime une machine
|
||||
#
|
||||
# Sécurité : code 6 chiffres valide 60s, LAN only, MYSECRETS jamais échangé
|
||||
# Tier free : python3 stdlib uniquement
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BRAIN_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
CMD="${1:-help}"
|
||||
shift || true
|
||||
|
||||
case "$CMD" in
|
||||
start)
|
||||
python3 "$BRAIN_ROOT/scripts/brain-pair-server.py" "$BRAIN_ROOT"
|
||||
;;
|
||||
join)
|
||||
CODE="${1:-}"
|
||||
if [[ -z "$CODE" ]]; then
|
||||
echo "❌ Usage: brain-pair.sh join <code>"
|
||||
exit 1
|
||||
fi
|
||||
python3 "$BRAIN_ROOT/scripts/brain-pair-client.py" "$BRAIN_ROOT" "$CODE"
|
||||
;;
|
||||
list)
|
||||
python3 -c "
|
||||
import yaml, sys
|
||||
compose_path = '$BRAIN_ROOT/brain-compose.local.yml'
|
||||
try:
|
||||
with open(compose_path) as f:
|
||||
c = yaml.safe_load(f)
|
||||
peers = c.get('peers', {})
|
||||
machine = c.get('machine', 'unknown')
|
||||
print(f'Machine locale : {machine}')
|
||||
print(f'Peers configurés : {len(peers)}\n')
|
||||
for name, info in peers.items():
|
||||
status = '✅ active' if info.get('active') else '⬜ inactive'
|
||||
url = info.get('url', '—')
|
||||
print(f' {name} — {url} — {status}')
|
||||
if not peers:
|
||||
print(' (aucun peer)')
|
||||
except FileNotFoundError:
|
||||
print('❌ brain-compose.local.yml absent')
|
||||
"
|
||||
;;
|
||||
revoke)
|
||||
MACHINE="${1:-}"
|
||||
if [[ -z "$MACHINE" ]]; then
|
||||
echo "❌ Usage: brain-pair.sh revoke <machine>"
|
||||
exit 1
|
||||
fi
|
||||
python3 - "$BRAIN_ROOT" "$MACHINE" <<'PYEOF'
|
||||
import yaml, sys, os, subprocess
|
||||
|
||||
brain_root = sys.argv[1]
|
||||
machine = sys.argv[2]
|
||||
compose_path = os.path.join(brain_root, "brain-compose.local.yml")
|
||||
|
||||
with open(compose_path) as f:
|
||||
compose = yaml.safe_load(f)
|
||||
|
||||
peers = compose.get("peers", {})
|
||||
if machine not in peers:
|
||||
print(f"⚠️ Peer '{machine}' non trouvé")
|
||||
sys.exit(1)
|
||||
|
||||
peer_url = peers[machine].get("url", "")
|
||||
host = peer_url.replace("http://", "").replace("https://", "").split(":")[0]
|
||||
|
||||
# Retirer du compose
|
||||
del peers[machine]
|
||||
compose["peers"] = peers
|
||||
with open(compose_path, "w") as f:
|
||||
yaml.dump(compose, f, default_flow_style=False, allow_unicode=True)
|
||||
|
||||
# Retirer de authorized_keys (lignes contenant le nom de machine)
|
||||
ak_path = os.path.expanduser("~/.ssh/authorized_keys")
|
||||
if os.path.exists(ak_path):
|
||||
with open(ak_path) as f:
|
||||
lines = f.readlines()
|
||||
filtered = [l for l in lines if machine not in l]
|
||||
if len(filtered) < len(lines):
|
||||
with open(ak_path, "w") as f:
|
||||
f.writelines(filtered)
|
||||
print(f"✅ Clé SSH de {machine} retirée de authorized_keys")
|
||||
|
||||
print(f"✅ Peer '{machine}' révoqué de brain-compose.local.yml")
|
||||
PYEOF
|
||||
;;
|
||||
help|*)
|
||||
echo "brain-pair.sh — Pairing multi-machine (ADR-041)"
|
||||
echo ""
|
||||
echo "Usage :"
|
||||
echo " start → génère code 6 chiffres, écoute sur le LAN (60s)"
|
||||
echo " join <code> → scan LAN, envoie code, reçoit config"
|
||||
echo " list → machines pairées"
|
||||
echo " revoke <machine> → supprime un peer"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user