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