Commit Graph

59 Commits

Author SHA1 Message Date
940aa64fcf feat(haproxy,torrent): declarative per-vhost waf_bypass + durable torrent exposure (ref #917)
haproxyctl: honour an opt-in `waf_bypass = true` field per vhost so the
generator emits `use_backend <backend>` (nginx_vhosts) instead of forcing
mitmproxy_inspector under waf_enabled. Makes the WAF-bypass of media/large-
upload services (nc/photoprism/matrix/torrent) declarative, auditable and
regen-durable instead of fragile hand-edits of the generated haproxy.cfg.
Normal vhosts are unaffected (verified in isolation).

secubox-torrent postinst: register torrent.<host>.<suffix> in haproxy.toml
(backend=nginx_vhosts, waf_bypass=true, ssl=true) idempotently and run a
drift-guarded `haproxyctl generate` — which refuses safely on a board that
still has un-migrated hand-edit vhosts (live cfg untouched) and succeeds on a
fresh board. Torrent bypasses sbxwaf by design, so no sbxwaf route is needed.

CLAUDE.md: WAF-bypass section updated — default stays 'never bypass'; the ONLY
sanctioned exception is the declarative waf_bypass=true in haproxy.toml, never
a hand-edit of the generated cfg.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-28 19:38:59 +02:00
b6ab518e2a release: bump minor on the 87 modules converted to Wants=secubox-core (Phase 2)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:08:22 +02:00
2ec7cef1b2 feat(profiles): Phase 2 — Requires=secubox-core → Wants= on all units (remove hard cascade)
secubox-core.service is a Type=oneshot (mkdir+chown) that RemainAfterExit=yes. A hard
Requires= on ~108 units cascade-stops them all if core is restarted/fails (e.g. a
secubox-core package upgrade) — a thundering-herd outage. After= keeps the ordering;
Wants= keeps the soft dependency without the cascade. Prereq for mass native apply
(Phase 3). Scaffolds (new-module.sh/new-package.sh) updated so future units use Wants=.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:06:54 +02:00
238637e09a release(webui): bump 127 arch:all packages for hybrid-dark reskin bake-in 2026-07-10 09:07:42 +02:00
3197f866e4 feat(webui): fleet reskin — apply hybrid-dark cyan overlay to all 116 crt-light panels
Add /shared/hybrid-dark.css: a shared overlay that remaps the design tokens
(consumed by crt-light.css, sidebar-light.css and every module's inline styles)
to the cyan hybrid-dark palette from /certs/ + /wireguard/. body.hybrid-dark
(specificity 0,1,1) beats :root and inline :root, so one token remap flips the
whole tree — no per-panel rewrite. Each panel gains the overlay <link> + the
hybrid-dark body class (2-line additive swap; crt-light.css kept as base).
See .claude/WEBUI-PANEL-GUIDELINES.md.

Panels with fully bespoke styles (certs/wireguard/users/nac already hybrid;
~14 non-crt-light custom panels) are untouched.
2026-07-10 08:40:10 +02:00
CyberMind
82b0522c5b
Aggregator résilience: sweep async (243 handlers) + threadpool 80 (#738) (#739)
* perf(aggregator): async-sweep — 243 blocking route handlers async def→def (#738)

Mounted in the aggregator's single event loop, an 'async def' route handler
that runs blocking code (subprocess/journalctl/openssl/argon2) freezes the
WHOLE loop -> aggregator.sock Connection refused -> 502 board-wide.

Deterministic AST codemod (scripts/async-sweep.py) converts route handlers
that (a) are decorated with an HTTP verb, (b) contain a known blocking call,
(c) have NO await/async-with/async-for/yield, (d) are never used as a
coroutine elsewhere -> plain 'def'. Starlette then runs them in the AnyIO
threadpool, so the blocking call no longer stalls the gateway. await/stream/
websocket handlers are left untouched. Every file py_compile-checked.

243 handlers across 56 modules (system 17, qos 13, netdiag/hexo 12, hub 11...).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(aggregator): raise AnyIO threadpool to 80 tokens (#738)

The async-sweep moves ~243 blocking handlers to the threadpool. With ~110
modules in one process, the default 40-token pool can queue head-of-line under
concurrent blocking load. Raise to 80 on startup (best-effort, never breaks
boot).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(hub): double-buffer status cache + emojized health page (#738)

Navbar status (menu + health-batch) is now a strict double-buffer cache:
- request handlers NEVER compute on the request path — they return the current
  snapshot instantly (or a 'warming' placeholder), so the sidebar's polling can
  no longer serialize behind a ~3s systemctl walk and starve the loop;
- the background refresher is kicked from the request path (_ensure_bg) because
  mounted sub-apps receive neither startup nor @app.middleware events under the
  aggregator — the previous lazy-start middleware never fired there;
- snapshots are built complete then swapped atomically, so the dashboard never
  shows partial/bad counts.

Served by the dedicated secubox-hub process (:8001, isolated loop) the navbar
stays <50ms and holds 200 under 25+ concurrent polls where the aggregator-
mounted copy wedged (000). health.js: 🟢🟡🔴 emoji status indicators.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* style(hub): render health status emoji cleanly (neutralize .led dot) (#738)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* perf(sidebar): kill per-module health storm, use batch endpoint (#738)

The navbar refreshed LEDs by firing ONE /api/v1/<module>/health request per
module — ~119 requests every 30s, in batches of 8 — straight at the aggregator's
single shared event loop. Combined with the in-process module mount this is a
prime driver of the recurring board-wide 502 wedge (user-identified).

checkAllHealth + refreshStaleHealth now call /api/v1/hub/public/health-batch
ONCE (served by the dedicated, double-buffered hub process) and populate every
module's LED from that single response. 119 reqs/cycle -> 1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 08:06:15 +02:00
c01f10c474 docs(wiki): refonte 126 modules — snapshots WebUI déterministes + READMEs 4 langues (ref #742)
Capture des 126 dashboards authentifiés (JWT minté serveur, injection localStorage)
avec attente de COMPLÉTION d'affichage déterministe (sentinelles de chargement
purgées + réseau calmé, plafond --delay) au lieu d'un sleep fixe. 126/126 OK.

- capture-screenshots.py: _wait_content_ready déterministe, mode --token (bypass
  login), goto domcontentloaded (plus de stall networkidle sur dashboards live)
- generate-docs.py: 23 modules jusqu'ici non documentés ajoutés (descriptions
  réelles depuis debian/control, EN/FR/DE/ZH), licence MIT→LicenseRef-CMSD-1.0,
  images wiki en URL raw.githubusercontent absolue (relatif = 404 sur GitHub wiki)
- 126 snapshots + thumbnails régénérés
- 126 READMEs paquet succincts + pages wiki MODULES/CATEGORIES ×4 langues

Gap modules documentés vs découverts: 23 → 0.
2026-06-26 10:14:14 +02:00
6b7d7f8607 fix(#623): shared /run|/var/lib|/var/cache|/etc/secubox parents stay 1777/0755 in all postinsts
Systemic clobber: the scaffold boilerplate (install -d -m 750 /var/lib/secubox,
/run/secubox) put restrictive modes on SHARED parents in ~56 module postinsts,
reverting them to 0750 on every install/upgrade and breaking traversal for
non-secubox daemons (kbin/toolbox 500). Empirically confirmed install -d -m only
modes the final component, so /parent/leaf forms are harmless — only bare-parent
targets were rewritten. Multi-arg lines (incl. ones making /var/lib world-writable
1777) split per-parent: /run/secubox=1777 root:root, /var/lib|cache|etc=0755
secubox:secubox; module-private leaves keep 0750. Scaffold + PATTERNS.md fixed so
new packages don't reintroduce it.
2026-06-18 10:32:58 +02:00
41d78ef455 docs(haproxy): tidy 1.3.1 changelog (secubox-errors path, drift guard, traversal fix) 2026-06-17 08:47:11 +02:00
fbd474b2c3 fix(haproxy): postinst set shared /run|/var/lib/secubox to 0750, breaking traversal (kbin/toolbox 500) -> 0755 parents, 0750 leaves (ref #626) 2026-06-17 08:46:26 +02:00
c47e454532 fix(haproxy): ship error pages to /etc/haproxy/secubox-errors (avoid file conflict with haproxy pkg) (ref #626) 2026-06-17 08:44:06 +02:00
e12790efbd fix(haproxy): repair broken generate (set -e abort + dup backend) + drift guard (ref #626)
haproxyctl generate exited 1 producing no backends: set -e + && {} vhost-loop
chains aborted on the first non-SSL vhost, and a duplicate mitmproxy_inspector
(auto + user TOML) was fatal. Converted chains to if/then/fi, dedup user
backends. Added a drift guard: refuse to install a cfg with fewer vhosts/
backends than live, so a successful regen can't silently drop hand-maintained
vhosts (kbin/gitea/matrix/...) absent from haproxy.toml.
2026-06-17 08:36:27 +02:00
ce636273a6 feat(haproxy): smart self-healing error pages + wire errorfile in generator (closes #626)
502/503/504 poll the URL and auto-reload on backend recovery (live status +
manual retry); 400/403/408/500 branded static. haproxyctl now emits errorfile
directives (durable across regen) + retries/redispatch in defaults. Pages shipped
to /etc/haproxy/errors/.
2026-06-17 07:46:43 +02:00
24000d67ea fix(services): add RuntimeDirectoryPreserve=yes to 96 secubox-* units
Hub + portal stayed `inactive (dead)` on real-hardware boot. The
journal error was `Failed to set up mount namespacing: /run/systemd/
unit-root/run/secubox: No such file or directory` at the NAMESPACE
step. Root cause: 96 services declare `RuntimeDirectory=secubox`
without the matching `RuntimeDirectoryPreserve=yes`. When any of them
stops (including any of the LXC-backed services that fail their
health probe and Restart=on-failure for a few cycles), systemd
removes /run/secubox on the way out. The next service with the same
RuntimeDirectory= that tries to namespace its inputs hits the gap
and falls into 226/NAMESPACE failure — Restart hammers a few times,
then the unit goes failed-permanent.

Earlier fmrelay + sentinelle units got the fix individually
(v2.12.0/v2.12.3 era). Now applied to all 96 remaining units in a
single sweep via:

  sed -i '/^RuntimeDirectory=secubox/a RuntimeDirectoryPreserve=yes' "$f"

No version bumps in changelog — `dpkg -i --force-depends` in the
live-USB slipstream picks up the new .deb regardless of version
number.
2026-05-26 09:50:22 +02:00
CyberMind
feab3c8238
fix(secubox-haproxy): v1.3.0 — atomic cmd_generate + always-emit canonical backends + cfg.d extras (closes #286) (#316)
Recurring "broken-by-vhost-add" bug: every haproxyctl vhost add ran
cmd_generate which wiped operator-added backends (nginx_vhosts,
gitea_ssh, webui-lan, …) and emitted the wrong cert path.

cmd_generate now:
 - Writes to a tempfile, validates haproxy -c -f, then atomically
   installs via install(1). Live cfg is LEFT UNTOUCHED on failure.
 - DATA_PATH defaults to /data/haproxy (charter), /srv/haproxy
   fallback. HAPROXY_DATA_PATH env override.
 - Always emits mitmproxy_inspector + nginx_vhosts + webui_direct
   regardless of waf_enabled.
 - Reads /etc/haproxy/cfg.d/*.cfg as operator extras and appends them
   verbatim — webui-lan, gitea-ssh etc. survive regens.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-21 11:18:53 +02:00
CyberMind
5e93c73600
feat(navbar): consolidate to 6 charter categories + fix dropped menu entries (closes #306) (#307)
The hub's `_compute_menu_sync()` drops menu entries lacking an `id`
field. 6+ packages (lyrion, yacy, zigbee, rustdesk, grafana, authelia)
shipped a different schema (`title/url/section/module`) so they NEVER
appeared in the navbar. Plus the existing CATEGORY_META declared 12
sections (dashboard/security/network/system/core/users/services/
privacy/monitoring/publishing/apps/admin), not the 6 SecuBox charter
modules.

Changes:
* All 121 packages/secubox-*/menu.d/*.json normalised to the canonical
  schema (id, name, path, category, icon, order, description). Legacy
  schema aliases (title/url/module/section) preserved as fallbacks then
  dropped from the file.
* Each menu entry's category remapped to one of the 6 charter modules:
  AUTH (auth/users/identity/zkp/nac/openclaw),
  WALL (crowdsec/waf/mitmproxy/hardening/threat-* /cve-triage/...),
  BOOT (kernel-build/eye-remote/master-link/droplet/cloner/backup/...),
  MIND (ai-gateway/mcp-server/grafana/ndpid/netifyd/glances/...),
  ROOT (system/hub/portal/console/admin/vault/vm/rtty/...),
  MESH (wireguard/dns/tor/matrix/gitea/nextcloud/mail/lyrion/yacy/
        zigbee/dns-provider/rustdesk/... — all network + comms apps).
* secubox-hub v1.4.0 — CATEGORY_META rewritten with the 6 charter
  modules carrying their official color from DESIGN-CHARTER.md and
  the complementary-pair order. DEFAULT_MENU fallback remapped too.
* secubox-zigbee v2.5.3 — www/zigbee/index.html rewritten with the
  canonical SecuBox scaffold (body display:flex, sidebar 220px fixed,
  .main reserving 48px for the global-menu-bar). MESH palette.

Browser side: operators need to clear localStorage sbx_menu_cache (or
hard-refresh after the 1h TTL) to see the new sections after deploy.

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
2026-05-21 10:03:05 +02:00
8e8708f95d ci+packaging: unblock v2.9.0 release — 4 package fixes + partial-release resilience
Five package builds failed on v2.9.0 first attempt, and the release
pipeline cascaded to skip all downstream jobs (collect/publish/images/
live-usb/create-release) because GH Actions treats *any* matrix failure
as a global failure for `needs:` purposes. This commit fixes both
root causes:

Package fixes:
- secubox-eye-square: drop debian/compat (conflicted with control's
  `Build-Depends: debhelper-compat (= 13)`)
- secubox-defaults: same — drop debian/compat
- secubox-metoblizer: switch from legacy `Build-Depends: debhelper
  (>= 13)` (which then requires a debian/compat file) to the modern
  `Build-Depends: debhelper-compat (= 13)` virtual package
- secubox-haproxy: override dh_usrlocal — it can only rehome /usr/local
  directories (Policy 9.1.2), not the individual admin tools we
  deliberately drop there per issue #44

Pipeline resilience:
- build-packages.yml `collect` job: `if: always() && != cancelled` so we
  bundle whatever .deb files the matrix produced even when entries failed
- build-packages.yml `publish` job: predicate now reads collect's success
  rather than the matrix's overall conclusion
- release.yml `build-images`, `build-live-usb`, `publish`,
  `create-release`: all gain `if: always() && needs.build-packages.result
  != 'cancelled'` so a partial build matrix doesn't black-hole the
  release. `create-release` already gracefully skips its
  `if: needs.build-images.result == 'success'` download steps when
  images failed, so the partial release ships what's available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 10:14:50 +02:00
8152484c42 fix(secubox-render-nginx-webui): use nginx -t exit code (not grep)
Under set -euo pipefail, `if ! nginx -t 2>&1 | grep -q "syntax is ok"`
was flaky: when nginx -t emits dozens of warnings before the success
line, the grep pipeline doesn't see the match reliably. Replaced with
a direct exit-code check (nginx -t returns 0 on success even with
warnings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:14:13 +02:00
94c7351185 fix(secubox-haproxy): drop JWT from /webui/nginx-config (postinst-friendly)
The endpoint is called by the secubox-render-nginx-webui script via the
secubox-haproxy unix socket. The script has no JWT token at hand (it runs
from postinst triggers as root). Requiring JWT broke the trigger-driven
render flow.

Rationale for making the endpoint public:
- The content is fully derivable from /webui/admin-domain (already public).
- Unix-socket access is root-only at the filesystem level.
- The rendered vhost contains no secrets.

Test updated: test_nginx_config_requires_jwt → test_nginx_config_is_public.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:10:17 +02:00
CyberMind
122cd6cebc
WebUI Obfuscation - admin.HOSTNAME.secubox.in Only (#96)
* docs(spec+plan): WebUI obfuscation design and implementation plan (ref #44)

Spec: docs/superpowers/specs/2026-05-12-webui-obfuscation-design.md
Plan: docs/superpowers/plans/2026-05-12-webui-obfuscation.md

The design locks the SecuBox WebUI to admin.<HOSTNAME>.<DOMAIN_SUFFIX>
via strict-regex ACLs in HAProxy AND nginx, both driven by
/etc/default/secubox as the single source of truth. New package
secubox-defaults ships the env file; secubox-haproxy API exposes
/webui/admin-domain (info), /webui/nginx-config (JWT, rendered vhost),
/webui/refresh (JWT, cache invalidate). A safe renderer script writes
the nginx vhost atomically; haproxyctl + Python /generate both inject
the strict ACL at the top of http-in and https-in frontends.

Plan has 15 tasks with TDD steps, exact file paths, and complete code
in every step (no TBD/TODO). Acceptance criteria + integration test
script included.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(secubox-defaults): scaffold package skeleton (ref #44)

* feat(secubox-defaults): ship /etc/default/secubox env file (ref #44)

* feat(secubox-defaults): postinst autodetect + dpkg-trigger (ref #44)

* feat(secubox-haproxy): webui_identity helper + tests (ref #44)

Implement webui_identity module that parses /etc/default/secubox
and exposes canonical admin URL + regex pattern for HAProxy acl.

New module:
- api/webui_identity.py: Parses SECUBOX_HOSTNAME and SECUBOX_DOMAIN_SUFFIX
  with LRU cache and invalidation support.

Tests (TDD):
- tests/test_webui_identity.py: 5 test cases covering basic parsing,
  missing hostname validation, custom suffix handling, comment handling,
  and cache invalidation.
- tests/conftest.py: sys.path bootstrap for api/ imports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(webui_identity): catch OSError on defaults read + test (ref #44)

* feat(secubox-haproxy): GET /webui/admin-domain endpoint (ref #44)

* feat(secubox-haproxy): GET /webui/nginx-config rendered vhost (ref #44)

* feat(secubox-haproxy): POST /webui/refresh cache invalidation (ref #44)

* feat(secubox-haproxy): secubox-render-nginx-webui safe renderer (ref #44)

* feat(haproxyctl): inject strict-regex WebUI ACL at frontend top (ref #44)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(secubox-haproxy): /generate symmetry with strict WebUI ACL (ref #44)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(secubox-haproxy): dpkg-trigger refresh on secubox-defaults-changed (ref #44)

* build(secubox-haproxy): depend on secubox-defaults (ref #44)

* test(infra): integration test for WebUI obfuscation (ref #44)

* docs: HISTORY Session 159 — WebUI obfuscation (ref #44)

Records the complete WebUI obfuscation work: new secubox-defaults
package, three /webui/* endpoints, nginx renderer script, haproxyctl
+ Python generator symmetry, dpkg trigger plumbing, integration test.
Includes notes on the brainstorming → spec → plan → subagent-driven
execution flow and the 6 fix iterations caught by reviewers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: CyberMind-FR <gandalf@Gk2.net>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:07:11 +02:00
c911e8192f fix(haproxy): generator emits mitmproxy_inspector + safe regen wrapper
Triggered by cpf.gk2.secubox.in returning "Wrong Domain". Root cause: the
secubox-haproxy generators (both bash haproxyctl and Python FastAPI) emit
config rules that point to dead/wrong backends, leading to HTTPS-wide
metablog/streamlit outages when a regen runs.

Generator fixes:
- packages/secubox-haproxy/api/main.py: use_backend waf_inspector
  → use_backend mitmproxy_inspector (2 occurrences). waf_inspector
  pointed to 127.0.0.1:8890 which is not listening; mitmproxy_inspector
  is the actual healthy WAF backend at 10.100.0.60:8080.
- packages/secubox-haproxy/sbin/haproxyctl: default_backend fallback
  → default_backend mitmproxy_inspector (2 occurrences). The fallback
  backend deny_status 503's unknown hosts; switching to mitmproxy_inspector
  lets mitmproxy dispatch all hosts via its routes JSON (245 routes vs
  93 declared in haproxy.toml).

New safe regen wrapper:
- scripts/secubox-haproxy-regen-safe: snapshot → regen via haproxyctl →
  validate via haproxy -c -f → atomic swap → reload. On validation
  failure, current cfg is preserved and the broken candidate is saved
  for forensics. Prevents another silent breakage like Session 156.

Board-side state (not in repo): /etc/haproxy/haproxy.cfg patched in
place to mirror these fixes, secubox-haproxy.service stopped until
user confirms safe to re-enable. All 245 routes verified live (cpf,
arm, lldh, admin, pub, werdl, 3d, 42, zkp all HTTP 200 with correct
content).

See .claude/HISTORY.md Session 156 for full symptom chain and the
6-layer root cause analysis.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:52:44 +02:00
bd7dda0c6f feat(secubox): complete meta-script generator Tasks 14-17
Task 14: Arch Profiles
- Add profiles/arch/arm64.yaml and profiles/arch/amd64.yaml
- Add ResolveWithArch() to merger for base → arch → tier chain
- Add tests for arch profile resolution

Task 15: Package secubox.yaml for All Packages
- Add scripts/generate-secubox-yaml.py generator script
- Generate 131 debian/secubox.yaml files with:
  - Category detection (security, network, system, etc.)
  - Tier assignment (all, lite, standard, pro)
  - API socket and UI path detection

Task 16: APT Repository Setup
- Add apt/conf/ reprepro configuration (multi-arch arm64/amd64)
- Add apt/hooks/lintian-check pre-publish validation
- Add scripts/apt-publish.sh and scripts/apt-sync.sh
- Add apt/README.md documentation

Task 17: CI Integration
- Add .github/workflows/build-secubox-cli.yml
- Build for linux-amd64 and linux-arm64
- Version injection via ldflags
- GitHub releases on tag push

Code Quality Fixes (Tasks 10-13):
- Add atomic writes for OTA boot control files (0600 perms)
- Fix NVME device extraction (nvme0n1p2 → nvme0n1)
- Add scanner.Err() checks in hardware detection
- Fix URL injection validation in fetch command
- Add proper cleanup on checksum failures

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-11 05:32:29 +02:00
68e7763fc3 docs: Add Eye Remote Multigadget skill and wiki
- Add /multigadget skill covering autorun, storage, round UI, tooling
- Add Eye-Remote-Multigadget.md unified wiki hub
- Add Build-System.md to wiki with build documentation
- Add AI-BUILD-PROMPT.md for GPT/Gemini assistance
- Update sidebar and home page with new links
- Update WIP.md with #70 and #71 done

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-10 09:12:42 +02:00
e2989322f4 feat(api): Add /health endpoint to 53 modules
Auto-generated health check endpoints for sidebar status:
- Returns {status: "ok", module: "name"}
- Public endpoint (no auth required)
- Used by sidebar.js for LED status display

Added via scripts/add-health-endpoints.py

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-09 10:40:05 +02:00
067cb77cc5 feat(ui): Universal hybrid-skin theme with global status/menu bars
- Add hybrid-skin.css: Glass Morphism + Matrix Terminal universal theme
- Update sidebar.js v2.23.0:
  - Remove light/dark theme switching (single hybrid theme)
  - Add global status bar (bottom) with health metrics
  - Add global menu bar (top) replacing individual page headers
  - Load health data from /api/v1/hub/health endpoint
- Update sidebar.css: Transparent header/footer to fix white corners
- Update design-tokens.css: Add .hybrid-skin to dark theme selector
- Update index.html files: Apply hybrid-skin body class
- Add SOC dashboard (soc/index.html): Reference implementation
- Add Health Doctor Pattern documentation
- Update module APIs with /health endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-08 16:42:51 +02:00
271f4d4585 fix(crowdsec,waf): Fix dashboard API data and display
CrowdSec Dashboard:
- Update alerts router to use cscli instead of LAPI (bouncer key lacks alerts access)
- Fix alerts display to use source_ip and country fields
- Add loadMachines() function for machines count
- Update version display parsing

WAF Dashboard:
- Fix _get_bans() to flatten nested CrowdSec decision data
- Add country, ASN columns to bans table
- Update bans API to include metadata (country, asn, asn_org)

Config fixes on MOCHAbin (manual):
- Add lapi_key to /etc/secubox/secubox.conf
- Create empty /etc/crowdsec/online_api_credentials.yaml
- Add NoNewPrivileges=false drop-in for sudo access

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-06 12:12:25 +02:00
d234100568 fix(haproxy): Read config from [main] TOML section correctly
- Fix _cfg() and _compute_status_sync() to read from cfg["main"]
- TOML structure uses [main] section for waf_enabled, ports, etc.
- Fixes waf_enabled showing false when TOML has true

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-06 06:49:09 +02:00
5d9cbaac6c fix(haproxy): Load config directly from TOML, fix duplicate HTML IDs
- Add _get_haproxy_config() to load /etc/secubox/haproxy.toml directly
  using tomllib, bypassing broken secubox_core.config.get_config()
- Replace all get_config("haproxy") calls with _get_haproxy_config()
- Fix duplicate id="vhosts" in HTML (stat card vs tab content)
- Rename stat card IDs: vhosts -> vhosts-count, backends -> backends-count
- Update JavaScript loadStatus() to use correct element IDs

This fixes the dashboard showing 0 vhosts and empty VHOSTS tab.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-06 06:46:11 +02:00
2a1dde2698 fix(haproxy-ui): Add form CSS and remove unused function
- Added missing CSS for .form-group, .form-row, .form-check classes
- Removed unused toggleVhostWAF() function (WAF toggle now in edit modal)
- Proper styling for form elements with P31 Phosphor theme
2026-05-02 18:04:53 +02:00
acdb94b88d feat(haproxy-ui): Update Certificates table with CRUD buttons 2026-05-02 18:02:28 +02:00
db04ffb2f6 feat(haproxy-ui): Update Backends table with CRUD buttons 2026-05-02 18:01:43 +02:00
3df7247127 feat(haproxy-ui): Update VHosts table with CRUD buttons 2026-05-02 18:00:45 +02:00
4b2b2147e6 feat(haproxy-ui): Add Certificate CRUD functions 2026-05-02 17:59:51 +02:00
591d2892c8 feat(haproxy-ui): Add Server CRUD functions 2026-05-02 17:58:55 +02:00
d51e26eed3 feat(haproxy-ui): Add Backend CRUD functions 2026-05-02 17:57:48 +02:00
ebb1bb440e feat(haproxy-ui): Add VHost CRUD functions 2026-05-02 17:56:51 +02:00
251b292964 feat(haproxy-ui): Add validation and enhanced API functions 2026-05-02 17:55:43 +02:00
f0970d616c feat(haproxy-ui): Add modal and toast HTML containers with CSS and JS functions 2026-05-02 17:53:49 +02:00
7155083e63 perf(api): Add double-buffer pre-cache to CrowdSec, HAProxy, Users
Implement background refresh caching pattern for instant API responses:

CrowdSec (status.py):
- Add status, metrics, hub caches with 30s refresh
- Parallel computation using ThreadPoolExecutor
- File persistence for fast startup
- Before: 1800ms → After: 45ms (40x faster)

HAProxy (main.py):
- Add status cache with 30s refresh
- Integrate with existing health monitor
- Before: 353ms → After: 50ms (7x faster)

Users (main.py):
- Add status cache with 60s refresh
- Fallback to file-based user count
- Before: 1906ms → After: 37ms (51x faster)

All modules now respond in <50ms for status endpoints.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-30 14:27:15 +02:00
9f47e544a3 fix(haproxy): Create /etc/haproxy and remove RuntimeDirectory=haproxy
- postinst creates /etc/haproxy if haproxy package not installed
- Remove RuntimeDirectory=haproxy to avoid NAMESPACE errors
- Fixes systemd namespace setup failure when haproxy not present

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 09:05:39 +02:00
4321a7ce6f fix(haproxy): Prevent service restart loop
- Move directory creation from import-time to startup event
- Add try/except to handle permission errors gracefully
- Create haproxy data directories in postinst
- Increase RestartSec from 5s to 30s
- Add StartLimitBurst to prevent rapid restart spam

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-27 08:55:47 +02:00
3240e441c7 fix(ebin): EspressoBin eMMC boot fixes
- secubox-haproxy: Remove ReadWritePaths sandboxing causing NAMESPACE errors
- secubox-net-fallback: Skip lan* interfaces (DSA downstream ports)
- netplan: Add dummy0 with 10.55.255.1/24 to all board configs
- flash-emmc: Fix eMMC detection using boot0 partition
- flash-emmc.cmd: Support multiple image filenames

Fixes issues encountered when booting SecuBox from EspressoBin V7 eMMC.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-20 07:59:42 +02:00
cf7ea44c78 fix(kiosk): Skip X11 config on bare metal, disable service sandboxing
- X11 setup now exits early for bare metal (VM_TYPE=none) without
  creating config files - Intel/AMD/NVIDIA auto-detect perfectly
- Remove static fallback 10-modesetting.conf that caused conflicts
- Sanitize GPU_INFO in config comments to remove special chars
- Disable PrivateTmp and ProtectSystem for haproxy, metrics, threats
  services - causes Python symlink namespace errors on some kernels
- Add fix-namespace-errors.sh script for quick fixes on running systems

Fixes: X11 "no screens found" on Intel HD Graphics 630
Fixes: "Failed to set up mount namespacing" for Python services

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-15 09:52:20 +02:00
de77a1aa4e feat(build): Add modular build system and fix package dependencies
Build System:
- Add image/lib/common.sh with shared build functions
- Add profiles for vm-x64, x64-live, rpi400, espressobin-v7
- Add BUILD-SYSTEM.md documentation
- Add splash screens (boot.png, tui-splash.sh, kiosk-loading.sh)
- Add Plymouth theme for boot splash

Package Dependencies:
- Fix python3-uvicorn -> python3-uvicorn | python3-pip
- Fix python3-fastapi -> python3-fastapi | python3-pip
- Fix python3-httpx -> python3-httpx | python3-pip
- Allows packages to install when pip-provided deps are used

Documentation:
- Add Build-System.md wiki page
- Update _Sidebar.md with build system links
- Add VM-Testing.md improvements

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-10 17:31:24 +02:00
2d2870d8a9 fix(systemd): Add RuntimeDirectory for /run/secubox socket support
- Add RuntimeDirectory=secubox to all services using ProtectSystem
- Change ProtectSystem=strict to ProtectSystem=full for compatibility
- Add systemd overrides in build script for cached packages
- Create tmpfiles.d entry for /run/secubox

This fixes the namespace issue where services couldn't create sockets
in /run/secubox due to ProtectSystem=strict mount namespacing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-04-03 08:54:19 +02:00
659cbb9303 feat(api): Add repo scan-local and IoT Guard Cast debug module
secubox-repo:
- Add /scan-local endpoint to import local .deb packages
- Add /scan-local/preview for dry-run package discovery
- Fix success detection for repoctl ANSI output
- Fix _update_stats to use dict format for distributions
- Make summary endpoint handle both list and dict formats

secubox-iot-guard:
- Add Google Cast/Chromecast debug module
- Add /cast/devices endpoint to find Cast devices via ARP/mDNS
- Add /cast/diagnose/{ip} for full diagnostic (CrowdSec, Suricata, DNS, nftables)
- Add /cast/whitelist/{ip} to apply whitelist rules
- Add /cast/capture/{ip} for packet capture debugging
- Add /cast/config/nftables and /cast/config/unbound for config generation
- Support Google OUI detection and Cast domain whitelisting

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-28 05:57:38 +01:00
913f6c3bfb Fix body class and menu duplicates across all modules
- Changed body class from "crt-body crt-scanlines" to "crt-light" on all pages
- Fixed portal menu to point to /portal/ instead of /c3box/
- Removed c3box/portal duplicate in menu
- All pages now start with light theme, sidebar.js handles theme switching

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-26 07:11:59 +01:00
cbe7e4ac3a Add CRT light theme across all UI modules
- Create crt-light.css with lighter P31 phosphor colors
- Create sidebar-light.css matching light theme
- Update 49 HTML files to use light theme CSS
- Add apply-light-theme.py script for automated theme application

Theme changes:
- Background: #050803 (dark) -> #e8f5e9 (mint green)
- Cards: #080d05 -> #c8e6c9 (pale green)
- P31 peak: #33ff66 -> #00dd44 (darker for contrast)
- Font: JetBrains Mono / Courier Prime

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-25 08:55:45 +01:00
a4fa81d349 Add complete package READMEs and multilingual wiki documentation
- Generate README.md for all 45 secubox-* packages with screenshots
- Add multilingual wiki pages (EN, FR, DE, ZH) documenting 47 modules
- Add generate-docs.py tool for documentation generation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-24 15:31:34 +01:00
e3ef51ba8b Apply CRT P31 Phosphor theme to all 38 module UIs
Converted all SecuBox module frontends to CRT design system:
- P31 Phosphor color palette (green phosphor with amber accents)
- Bloom text-shadow effects on headers and active elements
- Monospace Courier Prime typography throughout
- Dark tube glass backgrounds (#050803, #080d05)
- CRT overlays (scanlines, vignette via body classes)

Updated components across all modules:
- Buttons: CRT border glow on hover
- Cards: Inset shadows, ghost borders
- Tables: Amber headers, green data rows
- Badges: Phosphor glow variants
- Modals: Dark backdrop, dim border
- Tabs: Uppercase with letter-spacing
- Forms: Dark inputs with focus glow

Each module now includes:
- crt-system.css (design tokens)
- crt-engine.js (typewriter, audio, toasts)
- Courier Prime font preconnect
- body.crt-body.crt-scanlines classes

Modules updated (38):
auth, backup, c3box, cdn, crowdsec, dns, dpi, droplet,
exposure, gitea, haproxy, hardening, hub, mail, mail-lxc,
mediaflow, metablogizer, mitmproxy, nac, netdata, netmodes,
nextcloud, portal, publish, qos, repo, streamforge, streamlit,
system, tor, traffic, users, vhost, waf, watchdog, webmail,
webmail-lxc, wireguard

Added: scripts/apply-crt-theme.py for future theme updates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-23 18:56:11 +01:00