mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 17:37:13 +00:00
|
Some checks are pending
License Headers / check (push) Waiting to run
* docs(device-guardian): Project A consolidation design — merge 5 device modules into nac (ref #817) * docs(device-guardian): Project A implementation plan — 9 tasks (ref #817) * feat(nac): SQLite device store + idempotent legacy migration (ref #817) Add packages/secubox-nac/api/store.py — pure-stdlib sqlite3 module with canon_mac(), DeviceStore (WAL, best-value upsert, list/get/count, history), and migrate_legacy() for idempotent, per-source best-effort import of mac-guard/device-intel/iot-guard legacy shapes. Reserved Project-B columns (plane/provenance/geo_cc/geo_asn) created but unused. Task 1 of the Device Guardian consolidation plan (docs/superpowers/plans/ 2026-07-05-device-guardian-consolidation.md). * fix(nac): store — preserve first_seen, skip corrupt legacy sources, no stray db, SPDX (ref #817) * feat(nac): unified dnsmasq+ISC+ARP discovery merge (ref #817) * fix(nac): discovery — latest ISC lease wins the IP on renewal (ref #817) The merge loop only updated ip/source on a strict rank increase (incoming_rank > existing_rank), so equal-rank sightings for the same MAC never touched ip/source. Since dnsmasq -> isc -> arp is processed in non-increasing rank order, multiple ISC dhcpd.leases blocks for one MAC (a fresh block per renewal) are equal-rank ties, and the first (oldest) block's ip was frozen instead of the latest one winning, as the original secubox-device-intel._get_dhcp_leases did. Change the condition to incoming_rank >= existing_rank so the latest same-or-higher-rank sighting updates source, and overwrites ip when the incoming ip is non-empty. Hostname rule and the lower-rank branch are unchanged, so a later ARP sighting still cannot clobber a higher-rank ip/hostname/source. Add test_isc_latest_lease_wins: two ISC lease blocks for one MAC with ip/hostname renewal, asserting the latest block wins. Confirmed this test fails against the pre-fix >-only logic. * feat(nac): absorbed enrichers — OUI vendor + device-type/risk + OpenWrt fingerprint (ref #817) * fix(nac): enrich — is_router strictly vendor-based; cover classify/oui edge cases (ref #817) * feat(nac): background collector + double-cache; handlers def, no inline scan (ref #817) Task 4 of the Device Guardian consolidation: a Collector background loop now owns all discover -> enrich -> upsert work (replacing _monitor_clients), publishing an in-memory snapshot(). The status, clients, and client/{mac} handlers become plain def reading the SQLite store / collector cache instead of calling _discover_clients() inline on every request -- the #808 aggregator SPOF. * fix(nac): finish #808 — def-convert alerts/list_quarantine/summary; first_seen + recent_events (ref #817) alerts/list_quarantine were still `async def` calling blocking _discover_clients() inline on the shared aggregator loop; summary awaited alerts on top of that (double loop-block). Converted all three to plain `def` reading the SQLite store/collector snapshot instead, completing the #808 SPOF fix started for status/clients/client. Also: collector.cycle_once() now stamps first_seen on newly discovered devices (store.upsert keeps the earliest via COALESCE), and get_client's recent_events merges the SQLite device_history (client_joined) with the JSON event log so a device's join event shows up again. * feat(nac): allow/deny actions + def-convert action handlers (finish #808) (ref #817) Task 5: fold mac-guard's allow/deny into nac's zones/nft. New POST /allow/{mac} and /deny/{mac} set allow_state in the SQLite store and mirror it into nft's existing inet secubox_nac blocked/lan_allowed sets via _nft_add_element/_nft_delete_element (mac-guard's separate inet secubox_mac_guard table stays retired; its element migration is Task 9). Carried from Task 4 review: zones, add_to_zone, remove_from_zone, approve_client, ban_client, update_client, quarantine_client and unquarantine were still async def wrapping blocking subprocess/nft calls on the shared aggregator loop (#808). Converted to plain def so FastAPI threadpools them off the loop; add_to_zone/ban_client's webhook notify now fires via a new _fire_webhook_sync helper (asyncio.run_coroutine_threadsafe against the loop captured at startup) since a plain def can no longer await _notify_webhooks directly. Tests: tests/test_actions.py mocks nft via monkeypatched _nft_add_element/_nft_delete_element/_nft_list_set (+ subprocess.run, since ban_client/unban_client build raw nft argv) into an in-memory set-membership dict; covers deny/allow/allow-then-deny, zones, add_to_zone+approve_client, and ban_client+unban_client. * feat(nac): absorbed endpoints — vendors/scan/probe/mdns/groups/export (ref #817) * fix(nac): /scan enriches + validates subnet; /probe IP + CSV injection guards (ref #817) * feat(nac): retire mac-guard/device-intel/iot-guard via 308 redirects; auth-gate network-anomaly (ref #817) secubox-mac-guard, secubox-device-intel and secubox-iot-guard are superseded by secubox-nac's consolidated Device Guardian. Their api/main.py are reduced to thin shims: every route 308-redirects to its secubox-nac equivalent (/devices->/clients, /device/{mac}-> /client/{mac}, /whitelist|/allow->/allow, /blacklist|/deny->/deny, /scan, /vendors, /groups, /export/* pass through unchanged, and a catch-all forwards anything else), with an X-SecuBox-Deprecated header. /health stays a plain 200 so liveness probes never 308-loop. Package removal is a separate, gated follow-up. secubox-network-anomaly stays (separate traffic-anomaly engine) but its /status endpoint was unauthenticated while every sibling route already required a JWT; it now matches. * feat(nac): webui — vendor/type/risk columns, groups view, export; drop retired webuis (ref #817) - clients.js: render enriched /clients fields — oui_vendor, device_type, risk_level (color-coded badge)/risk_score, and OpenWrt/SecuBox/Router fingerprint badges. All values are attacker-influenceable (DHCP hostname/vendor) and are rendered exclusively via E()/textContent, never innerHTML. Null/missing device_type/vendor/risk render as "unknown"/"—", never "null". Adds an Export CSV button (direct link to GET /export/csv — auth via the existing SSO session cookie, same as every other same-origin nav link in this app; no new auth scheme). - groups.js (new): list/create/delete device groups and assign a device to a group, hitting GET/POST/DELETE /groups* — mirrors zones.js's structure and auth (sbxFetch). - nav.js: register the new "Groupes" tab alongside Zones. - Remove packages/secubox-{mac-guard,device-intel,iot-guard}/www — their functionality is now consolidated into nac; secubox-network-anomaly/www is untouched (stays standalone per plan). Note for Task 9: device-intel/iot-guard's debian/rules unconditionally `cp -r www/<name>/.` — now broken since www/ is gone; mac-guard's rule is already guarded (`[ -d www ] && ... || true`). Needs a debian/rules fix when Task 9 retires/redirects these packages. * chore(nac): packaging — ieee-data dep, nft migration, retirement redirects, changelog 3.0.0; fix retired debian/rules www (ref #817) * fix(nac): whole-branch — lazy init for in-aggregator mount, collector off-loop, sqlite lock, batched zone lookup, sentinel-preserve (ref #817) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(nac): risk_score split — known router low, unknown router high (rogue-AP signal) (ref #817) Split the router risk axis out of the generic device-type/open-ports scoring: a router/gateway already known (allow-listed or already in the store) is trusted infrastructure -> low risk; a newly-seen/unknown router is a rogue-AP signal -> high risk, regardless of open ports. Removes the old flat -10 "trusted router" discount. Non-router devices keep the existing scoring unchanged. risk_score() gains an is_known=False parameter (backward compatible). collector.cycle_once() and main.scan() now compute is_known from the prior store row (existing row or allow_state == "allow") before upserting, reusing the row they already fetch for is_new/enrichment. * feat(nac): mesh-sync (p2p peers as devices) + fingerprinted-router classification for rogue-AP risk (ref #817) Part A: absorb iot-guard's missed "mesh-sync" capability. GET /mesh/peers and POST /mesh/sync now live in nac, reading live P2P peers over /run/secubox/p2p.sock (HTTP-over-UDS GET /peers, fail-safe -> [] on any error/timeout/absent socket) and upserting one sb:-prefixed synthetic device per peer (iot-guard's exact md5-hash MAC scheme), device_type "mesh_node", source "mesh". iot-guard's retired redirect-shim catch-all already forwards /mesh/* here, so no shim change needed. Part B: classify_device_type's "router" keyword list is much narrower than ROUTER_VENDORS (misses tp-link/asus/linksys/d-link/gl.inet/xiaomi/ huawei), so a router-vendor MAC with a generic hostname fingerprinted is_router=True still classified as device_type="unknown" and skipped risk scoring entirely (the omit-unknown guard) -- the known-router-vs- rogue-AP HIGH signal never fired for the most common vendor case. Both enrichment call sites (Collector.cycle_once and /scan) now reclassify device_type="unknown"+is_router to "router" before scoring. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(nac): postinst ensures secubox_nac table + zone sets (incl lxc_zone) Nothing shipped created nac's inet secubox_nac table or its zone sets — they were assumed to pre-exist (they don't: the live board had no such table), so operator 'move to zone' failed for every zone and the mac-guard element migration silently no-op'd. postinst now creates the table + all ZONES sets (lan_allowed, lxc_zone, iot_zone, guest_zone, quarantine_zone) + blocked, idempotently and best-effort, before the migration. Makes operator moves to the LXC Containers zone work on a fresh install. nft commands validated on gk2 (create/idempotent re-add/add-element/list), no live drift left. Co-Authored-By: Gerald KERMA <devel@cybermind.fr> --------- Co-authored-by: CyberMind-FR <gandalf@Gk2.net> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| 2026-04-21-eye-remote-v2-implementation.md | ||
| 2026-04-23-eye-remote-bootstrap.md | ||
| 2026-04-24-eye-remote-touchscreen-controller.md | ||
| 2026-04-26-eye-remote-swiss-army.md | ||
| 2026-05-02-haproxy-webui-crud.md | ||
| 2026-05-03-mitmproxy-waf-migration.md | ||
| 2026-05-05-openwrt-to-debian-migration.md | ||
| 2026-05-10-meta-script-generator.md | ||
| 2026-05-11-secubox-apt-clone.md | ||
| 2026-05-12-apt-public-repo-staging.md | ||
| 2026-05-12-gitea-repair.md | ||
| 2026-05-12-license-headers.md | ||
| 2026-05-12-metablog-gitea-ingest.md | ||
| 2026-05-12-metablog-site-schema.md | ||
| 2026-05-12-metablog-version-dashboard.md | ||
| 2026-05-12-multi-agent-worktree-workflow.md | ||
| 2026-05-12-opad-doctrine-documents.md | ||
| 2026-05-12-ssl-health-banner.md | ||
| 2026-05-12-streamlit-gitea-version-pinning.md | ||
| 2026-05-12-visitor-origin-feed.md | ||
| 2026-05-12-webui-obfuscation.md | ||
| 2026-05-13-eye-square-phase1-common-extraction.md | ||
| 2026-05-13-eye-square-phase2-variant-build.md | ||
| 2026-05-13-eye-square-phase3-python-kiosk.md | ||
| 2026-05-13-metablog-deploy-webhook.md | ||
| 2026-05-13-secubox-users-auth.md | ||
| 2026-05-14-converged-dashboard.md | ||
| 2026-05-15-mail-phase1-lxc-consolidation.md | ||
| 2026-05-15-mail-phase2-rspamd.md | ||
| 2026-05-16-cookie-audit-pipeline.md | ||
| 2026-05-16-eye-remote-multi-gadget-dhcp.md | ||
| 2026-05-18-dropletctl.md | ||
| 2026-05-20-grafana-yacy-rustdesk-lxc-modules.md | ||
| 2026-05-22-sentinelle-gsm-v0.3-observation-pipeline.md | ||
| 2026-05-22-sentinelle-gsm-v0.3.1-l3-scoring-baseline.md | ||
| 2026-05-22-sentinelle-gsm-webui-local-alerts.md | ||
| 2026-05-22-streamlit-idle-timeout.md | ||
| 2026-05-26-build-scripts-refactor.md | ||
| 2026-05-26-secubox-modules-consolidation.md | ||
| 2026-05-27-secubox-consolidation-audit.md | ||
| 2026-06-17-anti-track-v2-core.md | ||
| 2026-06-17-anti-track-v2-plan2a-learning.md | ||
| 2026-06-17-anti-track-v2-plan2b-dns.md | ||
| 2026-06-17-anti-track-v2-plan2b-ip-drop.md | ||
| 2026-06-17-anti-track-v2-plan2c-bypass-seed.md | ||
| 2026-06-17-anti-track-v2-plan2d-social-top5.md | ||
| 2026-06-17-banner-stream-inject-csp-r3-fix.md | ||
| 2026-06-17-social-ip-literal-fix.md | ||
| 2026-06-17-toolbox-clients-reset-all-and-emojis.md | ||
| 2026-06-18-ad-intelligence.md | ||
| 2026-06-18-hub-dashboard-latency.md | ||
| 2026-06-18-mitm-engine-migration.md | ||
| 2026-06-18-toolbox-selective-sni-splice.md | ||
| 2026-06-26-cookies-crosssite-trackers.md | ||
| 2026-06-26-waf-go-sbxwaf.md | ||
| 2026-06-27-ads-aggregate-mitm-stats.md | ||
| 2026-06-27-nft-based-network-stats.md | ||
| 2026-06-27-sw-neuter-targeted-autolearn.md | ||
| 2026-06-27-sw-revalidation-nudge.md | ||
| 2026-06-29-gondwana-phase1-mesh-substrate.md | ||
| 2026-06-30-annuaire-service-offers-subscriptions.md | ||
| 2026-06-30-gondwana-p2p-clone-distribute-emancipate.md | ||
| 2026-06-30-p2p-annuaire-service-registry.md | ||
| 2026-07-01-macro-subsystem-tor-exit.md | ||
| 2026-07-02-p2p-dht-federation-masterlink.md | ||
| 2026-07-03-rapport-kbin-media-types.md | ||
| 2026-07-03-secubox-proxypac.md | ||
| 2026-07-04-media-buffer-phase1.md | ||
| 2026-07-04-media-buffer-phase2-hls.md | ||
| 2026-07-04-mesh-federate-exclusion-lists.md | ||
| 2026-07-04-pdf-character-sheet.md | ||
| 2026-07-04-peertube-webui-admin-ops.md | ||
| 2026-07-04-vhost-exposure-switch.md | ||
| 2026-07-05-device-guardian-consolidation.md | ||
| 2026-07-06-frigate-foundation.md | ||
| 2026-07-06-sbxmitm-sentinel.md | ||
| 2026-07-06-sentinel-activation-toolbox-surfaces.md | ||
| 2026-07-07-sentinel-c2-autolearn.md | ||
| 2026-07-08-nextcloud-dashboard-real-manageable.md | ||
| 2026-07-09-openclaw-lxc-scanner.md | ||
| 2026-07-09-tor-enhancement-phase1.md | ||
| 2026-07-11-metablogizer-publisher-wizard.md | ||
| 2026-07-12-metalogue-osint-lxc.md | ||