mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-23 03:27:43 +09:00
fix(firewall): a failed status probe no longer fabricates inactive
The §D matrix pinned this live: in a capability-restricted environment (unprivileged LXC — ufw exists, is on PATH, and fails on dropped CAP_NET_ADMIN) ufw status exits non-zero, and _check_ufw returned active=False with no error signal — "probe failed" indistinguishable from "firewall off", the same dishonesty class as plan 74's "not installed", one rung down the ladder. active/running are now tri-state: rc=0 parses a determined answer; non-zero with a dbus/not-running signature is a determined not-running (verified on Rocky 9: rc=36); anything else is None + error. Not-installed stays a determined False. any_active propagates the None, and the firewall tab renders an amber Status Unknown instead of collapsing it to Inactive.
This commit is contained in:
1 parent
c242d4cab5
commit
2f002c5963
3 files changed
+45
-14
No files matched your search
@@ -52,24 +52,38 @@ class FirewallService:
|
||||
|
||||
# Same separation as _check_ufw: a probe that fails must not be able to
|
||||
# unsay an `installed` that was already determined correctly.
|
||||
running = False
|
||||
#
|
||||
# running is tri-state. `firewall-cmd --state` answers rc=0 + "running"
|
||||
# when up; a non-zero rc with a dbus/not-running error means the daemon
|
||||
# is down — a *determined* not-running (verified on Rocky 9: rc=36,
|
||||
# DBUS_ERROR on stderr). Any other failure shape is "could not check":
|
||||
# None, never a fabricated inactive.
|
||||
running = None if installed else False
|
||||
error = None
|
||||
default_zone = None
|
||||
if installed:
|
||||
try:
|
||||
result = run_privileged(['firewall-cmd', '--state'])
|
||||
running = 'running' in (result.stdout or '').lower()
|
||||
|
||||
if result.returncode == 0:
|
||||
running = 'running' in (result.stdout or '').lower()
|
||||
else:
|
||||
evidence = ((result.stderr or '') + (result.stdout or '')).lower()
|
||||
if 'not running' in evidence or 'dbus' in evidence:
|
||||
running = False
|
||||
else:
|
||||
error = ((result.stderr or result.stdout or '')
|
||||
.strip()[:200] or 'firewall-cmd --state failed')
|
||||
if running:
|
||||
result = run_privileged(['firewall-cmd', '--get-default-zone'])
|
||||
default_zone = (result.stdout or '').strip()
|
||||
except Exception:
|
||||
running = False
|
||||
default_zone = None
|
||||
except Exception as e: # noqa: BLE001
|
||||
error = str(e)
|
||||
|
||||
return {
|
||||
'installed': installed,
|
||||
'running': running,
|
||||
'default_zone': default_zone
|
||||
'default_zone': default_zone,
|
||||
'error': error,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -89,17 +103,29 @@ class FirewallService:
|
||||
except Exception:
|
||||
installed = False
|
||||
|
||||
active = False
|
||||
# active is tri-state. `ufw status` answers rc=0 with "Status:
|
||||
# active|inactive" — both determined. A non-zero rc (e.g. an
|
||||
# unprivileged LXC, where ufw exists and is on PATH but fails on
|
||||
# dropped CAP_NET_ADMIN) or an exception is "could not check": None,
|
||||
# never a fabricated inactive — the shape plan 74 warned about,
|
||||
# verified live in the §D capability-restricted container.
|
||||
active = None if installed else False
|
||||
error = None
|
||||
if installed:
|
||||
try:
|
||||
result = run_privileged(['ufw', 'status'])
|
||||
active = 'Status: active' in (result.stdout or '')
|
||||
except Exception:
|
||||
active = False
|
||||
if result.returncode == 0:
|
||||
active = 'Status: active' in (result.stdout or '')
|
||||
else:
|
||||
error = ((result.stderr or result.stdout or '')
|
||||
.strip()[:200] or 'ufw status failed')
|
||||
except Exception as e: # noqa: BLE001
|
||||
error = str(e)
|
||||
|
||||
return {
|
||||
'installed': installed,
|
||||
'active': active
|
||||
'active': active,
|
||||
'error': error,
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@@ -420,11 +420,11 @@ const FirewallTab = () => {
|
||||
<>
|
||||
<div className="firewall-header">
|
||||
<div className="firewall-status-row">
|
||||
<div className={`status-indicator ${isActive ? 'active' : 'inactive'}`}>
|
||||
<div className={`status-indicator ${isActive == null ? 'unknown' : isActive ? 'active' : 'inactive'}`}>
|
||||
<span className="sec-shield">
|
||||
<Shield size={17} />
|
||||
</span>
|
||||
<span className="status-indicator__label">{isActive ? 'Firewall Active' : 'Firewall Inactive'}</span>
|
||||
<span className="status-indicator__label">{isActive == null ? 'Firewall Status Unknown' : isActive ? 'Firewall Active' : 'Firewall Inactive'}</span>
|
||||
<span className="firewall-type">{activeFirewall?.toUpperCase()}</span>
|
||||
</div>
|
||||
<div className="firewall-actions">
|
||||
|
||||
@@ -749,6 +749,11 @@
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
&.unknown .sec-shield {
|
||||
background: var(--amber-bg);
|
||||
color: var(--amber);
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: 13.5px;
|
||||
font-weight: $font-weight-semibold;
|
||||
|
||||
Reference in new issue
Block a user