Add /health endpoint for system capability reporting

Unauthenticated endpoint that reports what's installed, what's
missing, and what's degraded — without exposing secrets or key
material. Reports:

- Module status (stegasoo, verisoo) with versions
- Optional capabilities: DCT, audio, video stego, LMDB, imagehash,
  USB monitoring, GPIO — each with actionable install hints
- Key existence (identity, channel, trusted count, backup status)
- Fieldkit status (killswitch, deadman, chain enabled)
- System info (Python version, platform, available memory)

Overall status is "ok" when core modules + keys are present,
"degraded" otherwise. Memory reporting helps diagnose Argon2
OOM issues on constrained hardware (RPi).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-04-01 19:48:12 -04:00
parent 792254699c
commit 586aa50c95

View File

@@ -222,6 +222,154 @@ def create_app(config: SoosefConfig | None = None) -> Flask:
def index():
return render_template("index.html")
# ── Health check ─────────────────────────────────────────────
@app.route("/health")
def health():
"""System health and capability report.
Unauthenticated — returns what's installed, what's missing,
and what's degraded. No secrets or key material exposed.
"""
import platform
import sys
from flask import jsonify
from soosef.keystore.manager import KeystoreManager
ks = KeystoreManager()
# Core modules
modules = {}
for name, import_path in [
("stegasoo", "soosef.stegasoo"),
("verisoo", "soosef.verisoo"),
]:
try:
mod = __import__(import_path, fromlist=["__version__"])
modules[name] = {"status": "ok", "version": getattr(mod, "__version__", "unknown")}
except ImportError as e:
modules[name] = {"status": "missing", "error": str(e)}
# Optional capabilities
capabilities = {}
# DCT steganography
try:
from soosef.stegasoo import has_dct_support
capabilities["stego_dct"] = {
"status": "ok" if has_dct_support() else "unavailable",
"hint": None if has_dct_support() else "Install soosef[stego-dct] (scipy, jpeglib, reedsolo)",
}
except ImportError:
capabilities["stego_dct"] = {"status": "missing", "hint": "Install soosef[stego-dct]"}
# Audio steganography
try:
from soosef.stegasoo import HAS_AUDIO_SUPPORT
capabilities["stego_audio"] = {
"status": "ok" if HAS_AUDIO_SUPPORT else "unavailable",
"hint": None if HAS_AUDIO_SUPPORT else "Install soosef[stego-audio] (soundfile, numpy)",
}
except ImportError:
capabilities["stego_audio"] = {"status": "missing", "hint": "Install soosef[stego-audio]"}
# Video steganography
try:
from soosef.stegasoo.constants import VIDEO_ENABLED
capabilities["stego_video"] = {
"status": "ok" if VIDEO_ENABLED else "unavailable",
"hint": None if VIDEO_ENABLED else "Requires ffmpeg in PATH",
}
except (ImportError, AttributeError):
capabilities["stego_video"] = {"status": "missing", "hint": "Requires ffmpeg"}
# LMDB (verisoo storage)
try:
import lmdb # noqa: F401
capabilities["lmdb"] = {"status": "ok"}
except ImportError:
capabilities["lmdb"] = {"status": "missing", "hint": "Install soosef[attest]"}
# Perceptual hashing
try:
import imagehash # noqa: F401
capabilities["imagehash"] = {"status": "ok"}
except ImportError:
capabilities["imagehash"] = {"status": "missing", "hint": "Install soosef[attest]"}
# USB monitoring
try:
import pyudev # noqa: F401
capabilities["usb_monitor"] = {"status": "ok"}
except ImportError:
capabilities["usb_monitor"] = {"status": "unavailable", "hint": "Install soosef[fieldkit] (Linux only)"}
# GPIO (RPi killswitch)
try:
import gpiozero # noqa: F401
capabilities["gpio"] = {"status": "ok"}
except ImportError:
capabilities["gpio"] = {"status": "unavailable", "hint": "Install soosef[rpi] (Raspberry Pi only)"}
# Key status (existence only, no material)
keys = {
"identity": "ok" if ks.has_identity() else "missing",
"channel_key": "ok" if ks.has_channel_key() else "missing",
"trusted_keys": len(ks.get_trusted_keys()),
}
# Backup status
backup_info = ks.last_backup_info()
keys["last_backup"] = backup_info["timestamp"] if backup_info else "never"
keys["backup_overdue"] = ks.is_backup_overdue(config.backup_reminder_days)
# Fieldkit status
fieldkit = {
"killswitch_enabled": config.killswitch_enabled,
"deadman_enabled": config.deadman_enabled,
"chain_enabled": config.chain_enabled,
}
if config.deadman_enabled:
from soosef.fieldkit.deadman import DeadmanSwitch
dm = DeadmanSwitch()
dm_status = dm.status()
fieldkit["deadman_armed"] = dm_status["armed"]
fieldkit["deadman_overdue"] = dm_status.get("overdue", False)
# System info (no secrets)
system = {
"python": sys.version.split()[0],
"platform": platform.machine(),
"os": platform.system(),
}
# Memory (for Argon2 sizing awareness)
try:
import os as _os
mem_bytes = _os.sysconf("SC_PAGE_SIZE") * _os.sysconf("SC_PHYS_PAGES")
system["memory_mb"] = mem_bytes // (1024 * 1024)
except (ValueError, OSError):
pass
# Overall status
all_ok = (
all(m["status"] == "ok" for m in modules.values())
and keys["identity"] == "ok"
and keys["channel_key"] == "ok"
)
return jsonify({
"status": "ok" if all_ok else "degraded",
"version": __import__("soosef").__version__,
"modules": modules,
"capabilities": capabilities,
"keys": keys,
"fieldkit": fieldkit,
"system": system,
})
return app