Commit fc119f5
Paul C
v22.7.0: Predictive Ops — unified Inbox, 9 analyzers, scanner convergence, Apps drawer
Major feature drop. New `src/predictive/` module (7600 lines, 157 tests)
gives WolfStack a single forward-looking ops pipeline that replaces the
duplicated threshold logic that lived in `alerting.rs`, `collect_issues`,
and `security.rs`.
Headline features
- 🔮 Predictive Inbox — new top-nav surface aggregating findings from
every reachable cluster peer. Snooze / dismiss / ack-as-intentional
per finding. First-appearance dispatch to existing Discord/Slack/
Telegram/email channels (once per finding, not on every refresh).
Cluster-aware filter + grouping; multi-cluster operators get a
per-cluster filter and grouped headers.
- ⊞ Apps & Tools drawer — top icon strip cut from 11 icons to 4
(Datacenter, Issues, Inbox, Apps). Everything else (App Store,
Global View, 3D Room, WolfFlow, WolfAgents, Cluster Browser,
Databases, Control Panel, plugins) lives in a slide-out panel
with icon + name + description per tile.
Analyzers shipped
- Host disk-fill (linear-fit ETA per mount, sparse df with kill-on-drop
timeout so a hung NFS can't stall the orchestrator)
- Docker + LXC container storage-fill (runtime-specific finding types
so acks scope precisely; container-ID rotation guard with FNV-1a
deterministic hash so a container restart doesn't fit a regression
through two different containers)
- Docker container restart-loop (delta on RestartCount, tier bumped
one when state == "restarting")
- Host thresholds — CPU / memory / disk-free / swap / load / failed-
systemd (replaces collect_issues + alerting::check_thresholds)
- Container memory pressure (replaces alerting::check_container_thresholds)
- Certificate expiry (Let's Encrypt + /etc/wolfstack/tls/, severity
by days remaining, already-expired = Critical)
- Backup freshness (per enabled schedule; missed-by-Nx interval tier)
- VM disk-fill (qcow2 sparse-vs-allocated)
- Security posture — first analyzer to consume the unified
NetworkReachability classifier; service_bound_publicly,
sshd_password_auth, sshd_root_login with severity matrix:
PublicInternet > LocalNetwork > OverlayOnly > LoopbackOnly
Scanner convergence
- alerting::check_thresholds and check_container_thresholds dispatch
retired in cached_status_bg (the old loop becomes a no-op short
circuit with a comment pointing at predictive::notify). The notify
channels themselves stay — predictive's first-appearance dispatch
fires them.
- security.rs posture scans (service-on-public, sshd config) are
now duplicated by security_posture.rs which uses the unified
reachability classifier; security.rs's active-attack scans
(brute-force, miners, /tmp binaries, suspicious outbound) stay
for now since they're event-detection at a different cadence.
Discipline guards (every analyzer)
- Snapshot-clone discipline in the orchestrator — read locks held
only long enough to clone, no analyzer holds a read lock during
computation
- Auto-resolve: covered-but-not-emitted scopes flip to
Approved/ConditionCleared so disk-freed-itself proposals don't
ghost in the inbox; data-source-down (empty covered) auto-resolves
nothing
- Per-tick concurrent sampling via tokio::join! with kill-on-drop
child-process timeouts
- Three independent suppression layers (ack store, current proposal
status, analyzer-internal thresholds) tested separately
Cluster aggregation
- GET /api/proposals/cluster fans out to peers via existing
build_node_urls + X-WolfStack-Secret, 30s in-memory cache
invalidated on every state-change endpoint
- Per-peer fetch failures surface as a yellow warning ("K of N
responded — Inbox may be incomplete") with cluster-grouped
unreachable list — never silent gaps
- Per-task (id, hostname, cluster) preserved through panic so
operator gets actionable peer attribution even on task panic
XSS hardening
- showToast() rebuilt to use replaceChildren + textContent for the
message; audit confirmed zero callers across app.js + wolfrouter.js
pass intentional HTML, so 1000+ call sites are now hardened with
no regression. A peer responding `{"error": "<script>..."}` can
no longer escape into the operator's DOM.
Tests: 157 unit tests across 17 predictive modules. Independent
code-reviewer agent passes on items 1-2 + reviewer-fix delta with
all BLOCKER/MAJOR findings addressed (DefaultHasher non-determinism,
panicked-task identity, three-read-locks-stall, stale pending
proposals, AckScope serde-tag clash).
Plan complete: every analyzer item from the original roadmap is
live. Future iterations cover AI-source proposals using the same
Inbox surface, OneClick remediation handlers (today's plans are
all Manual), and per-tenant RBAC.1 parent e00dfda commit fc119f5
23 files changed
Lines changed: 9065 additions & 57 deletions
File tree
- src
- api
- containers
- predictive
- web
- js
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2274 | 2274 | | |
2275 | 2275 | | |
2276 | 2276 | | |
| 2277 | + | |
| 2278 | + | |
| 2279 | + | |
| 2280 | + | |
| 2281 | + | |
| 2282 | + | |
2277 | 2283 | | |
2278 | 2284 | | |
2279 | 2285 | | |
| |||
2611 | 2617 | | |
2612 | 2618 | | |
2613 | 2619 | | |
| 2620 | + | |
2614 | 2621 | | |
2615 | 2622 | | |
2616 | 2623 | | |
| |||
2627 | 2634 | | |
2628 | 2635 | | |
2629 | 2636 | | |
| 2637 | + | |
| 2638 | + | |
| 2639 | + | |
| 2640 | + | |
| 2641 | + | |
2630 | 2642 | | |
2631 | 2643 | | |
2632 | 2644 | | |
| |||
2703 | 2715 | | |
2704 | 2716 | | |
2705 | 2717 | | |
| 2718 | + | |
| 2719 | + | |
| 2720 | + | |
2706 | 2721 | | |
2707 | 2722 | | |
2708 | 2723 | | |
| |||
3626 | 3641 | | |
3627 | 3642 | | |
3628 | 3643 | | |
| 3644 | + | |
3629 | 3645 | | |
3630 | 3646 | | |
3631 | 3647 | | |
| |||
3938 | 3954 | | |
3939 | 3955 | | |
3940 | 3956 | | |
| 3957 | + | |
3941 | 3958 | | |
3942 | 3959 | | |
3943 | 3960 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
31 | 32 | | |
32 | 33 | | |
33 | 34 | | |
| |||
387 | 388 | | |
388 | 389 | | |
389 | 390 | | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
390 | 407 | | |
| 408 | + | |
391 | 409 | | |
392 | | - | |
| 410 | + | |
393 | 411 | | |
394 | 412 | | |
395 | 413 | | |
| |||
413 | 431 | | |
414 | 432 | | |
415 | 433 | | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
416 | 439 | | |
417 | 440 | | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
418 | 457 | | |
419 | 458 | | |
420 | 459 | | |
| |||
1555 | 1594 | | |
1556 | 1595 | | |
1557 | 1596 | | |
1558 | | - | |
1559 | | - | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
| 1602 | + | |
| 1603 | + | |
| 1604 | + | |
| 1605 | + | |
| 1606 | + | |
| 1607 | + | |
| 1608 | + | |
| 1609 | + | |
| 1610 | + | |
| 1611 | + | |
| 1612 | + | |
| 1613 | + | |
| 1614 | + | |
| 1615 | + | |
| 1616 | + | |
| 1617 | + | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
1560 | 1623 | | |
1561 | 1624 | | |
1562 | 1625 | | |
| |||
1731 | 1794 | | |
1732 | 1795 | | |
1733 | 1796 | | |
1734 | | - | |
1735 | | - | |
| 1797 | + | |
| 1798 | + | |
| 1799 | + | |
| 1800 | + | |
| 1801 | + | |
| 1802 | + | |
| 1803 | + | |
| 1804 | + | |
| 1805 | + | |
| 1806 | + | |
| 1807 | + | |
| 1808 | + | |
| 1809 | + | |
| 1810 | + | |
| 1811 | + | |
| 1812 | + | |
1736 | 1813 | | |
1737 | 1814 | | |
1738 | 1815 | | |
| |||
0 commit comments