From fd47aa99b6e23bc2ede5d9a700cd13688b961723 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Wed, 1 Jul 2026 08:37:43 +0200 Subject: [PATCH] =?UTF-8?q?fix(annuaire):=20threatmesh-bridge=20reads=20cs?= =?UTF-8?q?cli=20itself=20(heredoc/stdin=20clash)=20=E2=80=94=200.3.2=20(r?= =?UTF-8?q?ef=20#768)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/secubox-annuaire/debian/changelog | 2 +- .../sbin/sbx-threatmesh-bridge | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/packages/secubox-annuaire/debian/changelog b/packages/secubox-annuaire/debian/changelog index 475cdf13..807216eb 100644 --- a/packages/secubox-annuaire/debian/changelog +++ b/packages/secubox-annuaire/debian/changelog @@ -1,4 +1,4 @@ -secubox-annuaire (0.3.1-1~bookworm1) bookworm; urgency=medium +secubox-annuaire (0.3.2-1~bookworm1) bookworm; urgency=medium * feat(#768): threatmesh WAF hook — crowdsec -> mesh bridge. /usr/sbin/sbx-threatmesh-bridge reads local `cscli decisions list` and diff --git a/packages/secubox-annuaire/sbin/sbx-threatmesh-bridge b/packages/secubox-annuaire/sbin/sbx-threatmesh-bridge index 9556e11a..cb624738 100755 --- a/packages/secubox-annuaire/sbin/sbx-threatmesh-bridge +++ b/packages/secubox-annuaire/sbin/sbx-threatmesh-bridge @@ -2,16 +2,14 @@ # SPDX-License-Identifier: LicenseRef-CMSD-1.0 # SecuBox-Deb :: sbx-threatmesh-bridge (#768) # Federate this node's LOCAL crowdsec ban decisions into the gondwana threatmesh -# so every peer enforces them too. Reads `cscli decisions list`, publishes each -# NEW ban via `annuairectl ban` (TTL = the crowdsec duration, so it auto-expires -# in the mesh in step). Idempotent via a small state file; safe no-op without -# crowdsec or annuairectl. This is the WAF -> mesh hook: detect once, block fleet. +# so every peer enforces them too. Publishes each NEW ban via `annuairectl ban` +# (TTL = the crowdsec duration; reason = the scenario), idempotent via a state +# file. Safe no-op without crowdsec/annuairectl. WAF hook: detect once, block fleet. set -euo pipefail command -v cscli >/dev/null 2>&1 || exit 0 command -v annuairectl >/dev/null 2>&1 || exit 0 -STATE=/var/lib/secubox/annuaire/threatmesh-bridge.json -cscli decisions list -o json 2>/dev/null | python3 - "$STATE" <<'PY' +python3 - /var/lib/secubox/annuaire/threatmesh-bridge.json <<'PY' import json, os, re, subprocess, sys, time state_path = sys.argv[1] try: @@ -26,8 +24,10 @@ def dur_to_s(d): return sum(int(n) * mult[u] for n, u in re.findall(r"(\d+)([hms])", d or "")) or 3600 try: - data = json.load(sys.stdin) or [] -except Exception: + out = subprocess.check_output(["cscli", "decisions", "list", "-o", "json"], timeout=15) + data = json.loads(out or b"[]") or [] +except Exception as e: + print("threatmesh-bridge: cscli read failed:", e) sys.exit(0) published = 0 @@ -39,12 +39,11 @@ for alert in data: if not ip or ip in state: continue ttl = dur_to_s(dec.get("duration")) - reason = "crowdsec:" + (dec.get("scenario") or "").split("/")[-1] + reason = ("crowdsec:" + (dec.get("scenario") or "").split("/")[-1])[:64] r = subprocess.run(["annuairectl", "ban", ip, "--ttl", str(ttl), - "--reason", reason[:64], "--severity", "high"], - capture_output=True) + "--reason", reason, "--severity", "high"], capture_output=True) if r.returncode == 0: - state[ip] = now + ttl * 0.9 # refresh a little before expiry + state[ip] = now + ttl * 0.9 published += 1 os.makedirs(os.path.dirname(state_path), exist_ok=True)