Commit Graph

2876 Commits

Author SHA1 Message Date
02c79eb706 feat(profiles): lifecycle + wake_class manifest policy (ref #896)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 11:46:39 +02:00
afc549ba14 docs(profiles): implementation plan — scale-to-zero public services (12 tasks, ref #896)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 11:43:27 +02:00
a2998c1a23 docs(profiles): spec — scale-to-zero for public services (sleep/wake + lifecycle policy)
Design brainstormed 2026-07-20: sleep=STOP(free RAM)+splash-on-wake; per-module
lifecycle (always-on|eager|on-demand|manual) + wake_class; secubox-waker
activator (nginx->waker->wakectl+splash+lock); secubox-sleeper hybrid idle
(front last-request+conns + optional module /idle hint); reuses the 0.7.0
observed-state actuator. Single spec covering wake-on-access + auto-sleep.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 11:43:27 +02:00
b5503a12d6 fix(profiles): standalone rollback clears the active pointer (state no longer matches a named profile) (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 11:06:24 +02:00
3edc32cd4b test(profiles): cover /apply active-unlink on rollback with no prior active (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 09:23:17 +02:00
ec4acb8e99 docs(profiles): changelog 0.7.0 + README actuation note (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 09:15:27 +02:00
e805387f28 fix(profiles): /apply reverts active pointer when the ctl rolls back (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:59:21 +02:00
813e543aa8 fix(profiles): rollback_to matches apply_plan's 300s derived-timeout cap (ref #893)
rollback_to's own default wait_timeout=30.0 re-capped the standalone/panel
rollback path (cli.py's rollback --yes calls rollback_to without passing
wait_timeout), defeating the derived-timeout wiring on that path. Also adds
an integration test that only passes because the derived timeout (105s)
exceeds a flat 30s, using apply_plan's injected clock/sleep — the previous
happy-path test converged on the first probe and would have passed even
without the wiring.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:53:59 +02:00
8407a322f3 fix(profiles): apply waits the per-module derived timeout, observed-state arbiter (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:46:09 +02:00
ff1c51222e fix(profiles): non-blocking systemctl + best-effort lxc, state-arbitrated (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:39:30 +02:00
3b00e53a4b fix(profiles): wait_state observes container state for LXC modules (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:31:47 +02:00
c7ec47ab0e fix(profiles): derive wait_state timeout per-module from systemd (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:26:54 +02:00
c8e23843ed fix(profiles): _run distinguishes TimeoutExpired from could-not-run (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 08:18:03 +02:00
649a544669 docs(profiles): implementation plan — actuation robustness, 7 tasks (ref #893)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 03:59:49 +02:00
be901fa7b3 docs(profiles): spec — actuation robustness, observed-state arbiter (ref #893)
The lite mass-apply test spuriously aborted because the actuator judged a
STOP/START by the command return code, not the observed state (metrics'
90s TimeoutStopSec > _run's 15s timeout -> rc=None -> spurious rollback).

Design: non-blocking commands + wait_state as sole arbiter (LXC via
lxc-info as root), wait_timeout derived per-module from systemd, _run
distinguishes TimeoutExpired from OSError, /apply reverts active on
rolled_back.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-20 03:47:58 +02:00
ffff1b70f5 fix(profiles): a condition-gated START is not an apply failure (no spurious rollback)
Some checks failed
License Headers / check (push) Has been cancelled
A unit whose systemd start-condition fails (e.g. hexo) can never go active, so
enable --now succeeds but wait_state timed out → apply of any profile listing such
a module rolled back. condition_failed() detects ConditionResult=no and _do_change/
_rollback treat that START as reached (the module is deliberately off here). Found
applying the full profile from the panel.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 10:49:46 +02:00
e2819f3d31 docs: webui→ctl — system-driving ops from a ProtectSystem=strict service need systemd-run (not plain sudo)
A sudo child inherits the service's read-only mount namespace (EROFS); systemd-run
runs the ctl in PID 1's context, outside the sandbox. Found in secubox-profiles 0.6.1.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 10:30:10 +02:00
b756c35eb0 fix(profiles): run apply/rollback via systemd-run (escape ProtectSystem=strict sandbox)
The panel's sudo child inherited the service's read-only mount namespace →
EROFS writing the 4R snapshot (and it couldn't drive systemd/LXC). Wrap the CLI in
systemd-run --wait --pipe so it runs in PID 1's context, outside the sandbox. Sudoers
grants updated to the systemd-run-wrapped exact commands. Found on the first real
panel apply.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 10:26:40 +02:00
CyberMind
9ed71c890b
Merge pull request #892 from CyberMind-FR/feat/profiles-apply-webui-ctl
feat(profiles): API/panel apply+rollback via webui→ctl (0.6.0)
2026-07-19 10:16:08 +02:00
76e3f81e83 fix(profiles): surface the apply/rollback report even on rolled_back (rc=2) + single-worker lock note
Final-review finding 1: _run_ctl_json parsed the --json report only after mapping
rc!=0 to 500, so a rolled_back apply showed a raw truncated string instead of the
report banner. Now parse first: a valid {status,...} report returns 200 and the panel
classifies applied-vs-failed. rc=3 (protected refusal, no report) still 409.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 10:14:46 +02:00
c27d6a6b03 fix(profiles): apply actuates the REQUESTED profile under a lock (TOCTOU) + panel preview isolation + honest toast
Task-4 review: /apply now takes {profile}, rewrites active + actuates under a shared
async lock (with /active + /rollback) so a concurrent tab can't make it apply the wrong
profile. Panel POSTs the previewed profile, previews into its own #basculeDiffList (poll
can't clobber it) + re-fetches the plan before confirm, and uses errorToast on any
non-success report. 157 tests.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 10:08:35 +02:00
58e30f5883 feat(profiles): panel Bascule — select/preview/apply/rollback (webui→ctl)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:56:00 +02:00
aa37a434e6 feat(profiles): NNP=false + scoped sudoers so the panel can sudo→profilectl
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:49:06 +02:00
723acccdc4 feat(profiles): API active/apply/rollback — delegate to root profilectl via sudo
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:32:56 +02:00
3beb36f281 feat(profiles): --json output for apply/rollback (panel consumes it)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:27:30 +02:00
26e3d9ab7f docs(plan): profiles API/panel apply+rollback (webui→ctl) — 4 tasks
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:25:56 +02:00
95eaf2e4a5 docs(profiles): spec — API/panel apply+rollback via webui→ctl (NNP=false + sudoers)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:24:13 +02:00
CyberMind
a8a3124387
Merge pull request #889 from CyberMind-FR/feat/profiles-phase2-core-wants
Some checks are pending
License Headers / check (push) Waiting to run
feat(profiles): Phase 2 — Requires=secubox-core → Wants= on all units (0.x minor)
2026-07-19 09:10:51 +02:00
968c3325b9 docs: Phase 2 (Wants=secubox-core) — WIP + HISTORY + module guideline rationale
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 09:10:08 +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
CyberMind
0c95b976e9
Merge pull request #887 from CyberMind-FR/fix/profiles-lxc-autostart-config
fix(profiles): LXC autostart via config-file edit (found in lyrion validation, 0.4.1)
2026-07-19 08:53:25 +02:00
2df40a6a38 fix(profiles): set lxc.start.auto by editing the container config (not lxc-update-config)
Found in the lyrion board validation: lxc-update-config -n -x is not a key-set tool
(rc=1). Edit <lxcpath>/<name>/config atomically (lxcpath via lxc-config lxc.lxcpath,
/data/lxc on gk2). Set autostart=0 before lxc-stop to beat the watchdog revive race.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 08:51:28 +02:00
CyberMind
6f912628e2
Merge pull request #886 from CyberMind-FR/feat/profiles-apply-phase3a
feat(profiles): Phase 3a apply actuator — root-only, validated on lyrion (0.4.0)
2026-07-19 08:44:41 +02:00
c839cc537d fix(profiles): apply/rollback restore real portal route + no raw traceback on corrupt JSON
Finding 1: load_routes() only returns a set of domain names (for
portal_routed), so _cmd_apply/_cmd_rollback were feeding {} into
apply_plan/rollback_to's routes=, meaning snapshot.capture always
recorded route: None for portal modules and rollback could never
restore a stopped module's WAF route. Added observe.load_route_values()
(dict domain -> [host, port]) and wired the CLI to pass it instead.

Finding 2: json.JSONDecodeError is a ValueError, not caught by
apply_plan's/_rollback_applied's except (ActuationError, OSError)
tuples nor by cli.main()'s handlers — a corrupt routes/snapshot file
escaped as a raw traceback. Added ValueError to both tuples in
api/apply.py and a rc-2 handler in cli.main().

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 08:41:41 +02:00
1f6caf3070 fix(profiles): map apply.ApplyError to rc 3 (no raw traceback on the board)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 08:32:04 +02:00
c9690a521a feat(profiles): secubox-profilectl apply/rollback (root-only, dry-run default) — 0.4.0
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 08:27:59 +02:00
c91afbd41d fix(profiles): rollback never stops protected modules, honors wait_state
_rollback_applied reversed changes from the pre-apply snapshot without
re-checking m.protected, so a protected module started successfully by
the plan could be STOPped if a later module then failed — the exact
lockout the forward-plan guard exists to prevent. Skip (audit
skipped-protected) any reverse STOP against a protected module instead.

Also stop discarding wait_state's return value in the same function:
a rollback step that timed out was unconditionally recorded as
"rollback" and counted in rolled_back, falsely claiming recovery.
Now audits rollback-timeout and excludes it from rolled_back.

Added tests for both fixes plus a missing rollback_to() coverage test.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:51:42 +02:00
c5e1657396 feat(profiles): apply orchestration — sequential, protected-guard, rollback-on-failure
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:43:24 +02:00
f01ed0bf6b chore(profiles): drop dead stat import in snapshot.py
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:40:07 +02:00
82ef43d3a0 fix(profiles): decouple LXC/host-unit toggle in actuate (ref Task 2 integration bug)
The LXC actuator only toggled the container, but is_on() reflects the host
systemd unit; STOP left the unit enabled+active for a dead container so
wait_state never converged and the orchestrator would roll back spuriously.
LXC START/STOP now also enable/disable the module's host units, container
first on START, host API first on STOP.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:37:34 +02:00
cc556d3461 feat(profiles): 4R snapshot (with portal route value) + append-only audit
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:33:34 +02:00
1bd5d7293d feat(profiles): actuators (systemd/lxc/portal) + state-wait
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:27:43 +02:00
201f879159 docs(plan): profiles Phase 3a apply actuator — 4 tasks TDD
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:24:36 +02:00
48649fa413 docs(profiles): spec Phase 3a — apply actuator (validated on lyrion)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:16:17 +02:00
CyberMind
753524c38a
Merge pull request #884 from CyberMind-FR/fix/cve-triage-panel-apply-sudo
Some checks are pending
License Headers / check (push) Waiting to run
fix(cve-triage): WAF panel delegates to root secubox-cvectl + webui→ctl guideline (1.1.2)
2026-07-19 07:14:23 +02:00
30931bc534 docs: guideline — webui delegates privileged ops to a confined, audited ctl
The webui/API runs unprivileged (secubox); operations touching root-owned config
or driving systemd/LXC/apps MUST delegate to the root helper secubox-<module>ctl
via scoped exact-command sudoers (shipped by the package), which acts as root and
audits each change. Documented in MODULE-COMPLIANCE (authoritative), MODULE-GUIDELINES
§7 (CTL), WEBUI-PANEL-GUIDELINES, and wiki/Architecture. Ref: secubox-cvectl fix.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 07:01:14 +02:00
213ff21c0d fix(cve-triage): panel delegates WAF generate to root secubox-cvectl via sudo
Aggregator-served panel (User=secubox) cannot read/write 0750 root:root
/etc/secubox/waf. Both routes now shell out to the root CLI (--json preview,
--apply --json write) via scoped exact-command sudoers grants. Adds CLI --json.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 06:54:33 +02:00
CyberMind
3b7645a58f
Merge pull request #882 from CyberMind-FR/feat/sbxwaf-static-detect
Some checks are pending
License Headers / check (push) Waiting to run
feat(sbxwaf): fingerprint scanners on static-asset paths (0.1.37)
2026-07-19 05:57:34 +02:00
90210e7c0c feat(sbxwaf): run detect/escalate on static-asset paths (0.1.37)
Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-19 05:49:41 +02:00