diff --git a/AppImage/components/audit-changes.tsx b/AppImage/components/audit-changes.tsx index 2debc95d..ee1964ff 100644 --- a/AppImage/components/audit-changes.tsx +++ b/AppImage/components/audit-changes.tsx @@ -136,7 +136,7 @@ const POST_INSTALL_SOURCES = new Set(["auto", "customizable"]) // A few sources deserve a friendly name instead of a raw script identifier; // everything else shows the script it came from. -const FRIENDLY_SOURCE = new Set(["install_proxmenux"]) +const FRIENDLY_SOURCE = new Set(["install_proxmenux", "monitor"]) // Which of the three sections a change belongs to: installations are their // own block, post-install optimizations another, general scripts the rest. diff --git a/AppImage/messages/de/common.json b/AppImage/messages/de/common.json index a10e90d9..26df5fdc 100644 --- a/AppImage/messages/de/common.json +++ b/AppImage/messages/de/common.json @@ -5933,7 +5933,8 @@ "installs": "Installierte Pakete und Werkzeuge" }, "scriptLabel": { - "install_proxmenux": "ProxMenux-Installer" + "install_proxmenux": "ProxMenux-Installer", + "monitor": "ProxMenux-Monitor" } }, "comparison": { diff --git a/AppImage/messages/en/common.json b/AppImage/messages/en/common.json index 9b77ca41..b687d528 100644 --- a/AppImage/messages/en/common.json +++ b/AppImage/messages/en/common.json @@ -5999,7 +5999,8 @@ "installs": "Installed packages and utilities" }, "scriptLabel": { - "install_proxmenux": "ProxMenux installer" + "install_proxmenux": "ProxMenux installer", + "monitor": "ProxMenux Monitor" } }, "comparison": { diff --git a/AppImage/messages/es/common.json b/AppImage/messages/es/common.json index 87fd6745..709a5eb0 100644 --- a/AppImage/messages/es/common.json +++ b/AppImage/messages/es/common.json @@ -5933,7 +5933,8 @@ "installs": "Paquetes y utilidades instalados" }, "scriptLabel": { - "install_proxmenux": "Instalador de ProxMenux" + "install_proxmenux": "Instalador de ProxMenux", + "monitor": "Monitor de ProxMenux" } }, "comparison": { diff --git a/AppImage/messages/fr/common.json b/AppImage/messages/fr/common.json index d59342d0..5cc86ab5 100644 --- a/AppImage/messages/fr/common.json +++ b/AppImage/messages/fr/common.json @@ -5933,7 +5933,8 @@ "installs": "Paquets et utilitaires installés" }, "scriptLabel": { - "install_proxmenux": "Programme d'installation de ProxMenux" + "install_proxmenux": "Programme d'installation de ProxMenux", + "monitor": "Moniteur ProxMenux" } }, "comparison": { diff --git a/AppImage/messages/it/common.json b/AppImage/messages/it/common.json index 6e2fb22d..04c8e013 100644 --- a/AppImage/messages/it/common.json +++ b/AppImage/messages/it/common.json @@ -5933,7 +5933,8 @@ "installs": "Pacchetti e utilità installati" }, "scriptLabel": { - "install_proxmenux": "Installer di ProxMenux" + "install_proxmenux": "Installer di ProxMenux", + "monitor": "Monitor di ProxMenux" } }, "comparison": { diff --git a/AppImage/messages/pt/common.json b/AppImage/messages/pt/common.json index 3d27baa0..f191d588 100644 --- a/AppImage/messages/pt/common.json +++ b/AppImage/messages/pt/common.json @@ -5933,7 +5933,8 @@ "installs": "Pacotes e utilitários instalados" }, "scriptLabel": { - "install_proxmenux": "Instalador do ProxMenux" + "install_proxmenux": "Instalador do ProxMenux", + "monitor": "Monitor do ProxMenux" } }, "comparison": { diff --git a/AppImage/messages/sk/common.json b/AppImage/messages/sk/common.json index 8ea8883e..2503abed 100644 --- a/AppImage/messages/sk/common.json +++ b/AppImage/messages/sk/common.json @@ -5999,7 +5999,8 @@ "installs": "Nainštalované balíky a nástroje" }, "scriptLabel": { - "install_proxmenux": "Inštalátor ProxMenux" + "install_proxmenux": "Inštalátor ProxMenux", + "monitor": "ProxMenux Monitor" } }, "comparison": { diff --git a/AppImage/messages/sv/common.json b/AppImage/messages/sv/common.json index 5724e69b..e1b11c9d 100644 --- a/AppImage/messages/sv/common.json +++ b/AppImage/messages/sv/common.json @@ -5934,7 +5934,8 @@ "installs": "Installerade paket och verktyg" }, "scriptLabel": { - "install_proxmenux": "ProxMenux-installerare" + "install_proxmenux": "ProxMenux-installerare", + "monitor": "ProxMenux-övervakning" } }, "comparison": { diff --git a/AppImage/scripts/changes_journal.py b/AppImage/scripts/changes_journal.py index ffaaffa1..3003f83e 100644 --- a/AppImage/scripts/changes_journal.py +++ b/AppImage/scripts/changes_journal.py @@ -148,6 +148,43 @@ def read_object(digest: str) -> Optional[str]: return None +def record_install(packages: str, source: str = "monitor", + function: str = "monitor") -> bool: + """Record a package the Monitor installed on the host, so it appears in the + installed-packages section like anything the scripts install. The Monitor + is Python and cannot use the bash primitives, so it drops a spool entry in + the same shape they write; ingest() picks it up and dedupes it by package. + """ + packages = (packages or "").strip() + if not packages: + return False + entry = { + "recorded_at": int(time.time()), + "class": CLASS_INSTALLATION, + "operation": "install_package", + "source": source, + "function": function, + "function_version": "1.0", + "target": packages, + "installed": packages, + "before": "", + "after": "", + "capture": "created", + "revert": "purge", + "exactness": "none", + "result": "ok", + } + try: + SPOOL.mkdir(parents=True, exist_ok=True) + path = SPOOL / f"{entry['recorded_at']}-{os.getpid()}-{os.urandom(4).hex()}.json" + tmp = path.with_suffix(".json.tmp") + tmp.write_text(json.dumps(entry), encoding="utf-8") + os.replace(tmp, path) + return True + except OSError: + return False + + def ingest(limit: int = 5000) -> int: """Move what the scripts wrote into the table. diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py index 82b6d055..9316341e 100644 --- a/AppImage/scripts/flask_server.py +++ b/AppImage/scripts/flask_server.py @@ -10268,6 +10268,17 @@ def _ensure_smart_tools(install_if_missing=False): except Exception as e: install_errors.append(f"nvme-cli: {str(e)}") + # A package installed on the host belongs in the change journal, whoever + # installed it — here the Monitor rather than a script. + _just = [pkg for pkg, ok in (('smartmontools', installed.get('smartctl')), + ('nvme-cli', installed.get('nvme'))) if ok] + if _just: + try: + import changes_journal + changes_journal.record_install(' '.join(_just), 'monitor', 'install_smart_tools') + except Exception: + pass + return { 'smartctl': has_smartctl, 'nvme': has_nvme, @@ -11594,6 +11605,14 @@ def api_smart_tools_install(): if not success: all_success = False + _ok = [pkg for pkg, r in results.items() if r.get('success')] + if _ok: + try: + import changes_journal + changes_journal.record_install(' '.join(_ok), 'monitor', 'install_smart_tools') + except Exception: + pass + tools = _ensure_smart_tools() return jsonify({