Add audit and reports page, and a change journal

ProxMenux modifies the host: it rewrites configuration files, installs packages, enables services. Until now nobody could say afterwards what had changed, and showing the script does not answer that question — a four-hundred-line function may alter two values, and the reader has no way to know which two. This adds the two halves of an answer.

The change journal records what ProxMenux does as it does it. Eleven bash primitives capture the previous state, apply the change and record it in the same step, writing to a spool that the Monitor reads back. One hundred and thirteen functions across twenty-five scripts are instrumented, covering post-install, shared storage, security tooling, container conversions, disk operations and the PVE 8 to 9 upgrade path. The page shows the difference — rotate 7 becoming rotate 14 — and never the script. Restore and backup scripts are deliberately left out: a restore puts the host back to a state some other script already recorded.

The Audit and reports page answers the other half: what state is this host in, regardless of who put it there. Forty-three checks across seven areas read the host and classify each result as critical, warning, observation, conformant, unverified or not applicable, with the evidence they read attached to each one. A declared policy lets the reader say what this particular host is expected to do — which guests must have a backup, which storages are essential — so the report judges the host against its own intent rather than a generic template. An inventory records the hardware, network and guest topology behind those readings, a comparison shows what moved between two runs, and six report profiles produce a printable document scoped to what the reader needs. Everything is available in the eight supported languages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
MacRimi
2026-09-08 21:06:04 +02:00
co-authored by Claude Opus 5
parent ae75508eff
commit da8a480eff
102 changed files with 24118 additions and 1403 deletions
+52 -11
View File
@@ -54,6 +54,10 @@ elif [[ -f "$LOCAL_SCRIPTS_DEFAULT/global/disk_ops_helpers.sh" ]]; then
source "$LOCAL_SCRIPTS_DEFAULT/global/disk_ops_helpers.sh"
fi
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
fi
load_language
initialize_cache
@@ -471,6 +475,8 @@ format_and_mount_disk() {
local disk="$1"
local mount_path="$2"
local filesystem="$3"
local FUNC_VERSION="1.0"
pmx_journal_context "format_and_mount_disk" "$FUNC_VERSION"
# Final confirmation before any destructive operation
local disk_size
@@ -480,6 +486,8 @@ format_and_mount_disk() {
14 80; then
return 1
fi
pmx_record_execution "format disk ${disk} as ${filesystem} for ${mount_path}" \
"wipe disk, create partition and format as ${filesystem}"
show_proxmenux_logo
if [[ "$MODE_PVESM" -eq 1 && "$MODE_FSTAB" -eq 1 ]]; then
msg_title "$(translate "Add Local Disk (Proxmox storage + host mount)")"
@@ -544,6 +552,8 @@ mount_disk_permanently() {
local partition="$1"
local mount_path="$2"
local filesystem="$3"
local FUNC_VERSION="1.0"
pmx_journal_context "mount_disk_permanently" "$FUNC_VERSION"
if [[ "$filesystem" == "zfs" ]]; then
if ! zpool list "$STORAGE_ID" >/dev/null 2>&1; then
@@ -562,6 +572,8 @@ mount_disk_permanently() {
msg_ok "$(translate "Mount point created")"
msg_info "$(translate "Mounting disk...")"
pmx_record_execution "mount ${partition} at ${mount_path}" \
"mount -t ${filesystem} ${partition} ${mount_path}"
if ! mount -t "$filesystem" "$partition" "$mount_path" 2>/dev/null; then
msg_error "$(translate "Failed to mount disk")"
return 1
@@ -574,13 +586,13 @@ mount_disk_permanently() {
if [[ -n "$disk_uuid" ]]; then
# Remove any existing fstab entry for this UUID or mount point
sed -i "\|UUID=$disk_uuid|d" /etc/fstab
sed -i "\|[[:space:]]${mount_path}[[:space:]]|d" /etc/fstab
echo "UUID=$disk_uuid $mount_path $filesystem defaults,nofail 0 2" >> /etc/fstab
pmx_edit_file /etc/fstab "\|UUID=$disk_uuid|d"
pmx_edit_file /etc/fstab "\|[[:space:]]${mount_path}[[:space:]]|d"
echo "UUID=$disk_uuid $mount_path $filesystem defaults,nofail 0 2" | pmx_append_file /etc/fstab
msg_ok "$(translate "Added to /etc/fstab using UUID")"
else
sed -i "\|[[:space:]]${mount_path}[[:space:]]|d" /etc/fstab
echo "$partition $mount_path $filesystem defaults,nofail 0 2" >> /etc/fstab
pmx_edit_file /etc/fstab "\|[[:space:]]${mount_path}[[:space:]]|d"
echo "$partition $mount_path $filesystem defaults,nofail 0 2" | pmx_append_file /etc/fstab
msg_ok "$(translate "Added to /etc/fstab using device path")"
fi
@@ -604,10 +616,14 @@ mount_disk_permanently() {
# but the change is harmless: existing owners keep their access.
_apply_lxc_bind_mount_perms() {
local mount_path="$1"
local FUNC_VERSION="1.0"
pmx_journal_context "_apply_lxc_bind_mount_perms" "$FUNC_VERSION"
[[ "${MODE_FSTAB:-0}" -eq 1 ]] || return 0
[[ -d "$mount_path" ]] || return 0
msg_info "$(translate "Applying host permissions for unprivileged LXC bind-mounts...")"
pmx_record_execution "apply LXC bind-mount permissions to ${mount_path}" \
"chmod o+rwx and setfacl on ${mount_path}"
chmod o+rwx "$mount_path" 2>/dev/null || true
if command -v setfacl >/dev/null 2>&1; then
setfacl -m o::rwx "$mount_path" 2>/dev/null || true
@@ -619,6 +635,8 @@ _apply_lxc_bind_mount_perms() {
mount_existing_disk() {
local disk="$1"
local mount_path="$2"
local FUNC_VERSION="1.0"
pmx_journal_context "mount_existing_disk" "$FUNC_VERSION"
local existing_fs
existing_fs=$(blkid -s TYPE -o value "$disk" 2>/dev/null || true)
@@ -635,6 +653,7 @@ mount_existing_disk() {
msg_ok "$(translate "Mount point created")"
msg_info "$(translate "Mounting existing") $existing_fs $(translate "filesystem...")"
pmx_record_execution "mount existing disk ${disk} at ${mount_path}" "mount ${disk} ${mount_path}"
if ! mount "$disk" "$mount_path" 2>/dev/null; then
msg_error "$(translate "Failed to mount disk")"
return 1
@@ -645,9 +664,9 @@ mount_existing_disk() {
local disk_uuid
disk_uuid=$(blkid -s UUID -o value "$disk" 2>/dev/null)
if [[ -n "$disk_uuid" ]]; then
sed -i "\|UUID=$disk_uuid|d" /etc/fstab
sed -i "\|[[:space:]]${mount_path}[[:space:]]|d" /etc/fstab
echo "UUID=$disk_uuid $mount_path $existing_fs defaults,nofail 0 2" >> /etc/fstab
pmx_edit_file /etc/fstab "\|UUID=$disk_uuid|d"
pmx_edit_file /etc/fstab "\|[[:space:]]${mount_path}[[:space:]]|d"
echo "UUID=$disk_uuid $mount_path $existing_fs defaults,nofail 0 2" | pmx_append_file /etc/fstab
msg_ok "$(translate "Added to /etc/fstab")"
fi
@@ -664,6 +683,8 @@ add_proxmox_dir_storage() {
local content="$3"
local storage_kind="dir"
local pool_name="$storage_id"
local FUNC_VERSION="1.0"
pmx_journal_context "add_proxmox_dir_storage" "$FUNC_VERSION"
if [[ "${FILESYSTEM:-}" == "zfs" ]]; then
storage_kind="zfspool"
@@ -681,6 +702,7 @@ add_proxmox_dir_storage() {
8 60; then
return 0
fi
pmx_record_execution "remove existing Proxmox storage ${storage_id}" "pvesm remove ${storage_id}"
pvesm remove "$storage_id" 2>/dev/null || true
fi
@@ -688,12 +710,16 @@ add_proxmox_dir_storage() {
local pvesm_output
local add_ok=false
if [[ "$storage_kind" == "zfspool" ]]; then
pmx_record_execution "add ZFS pool ${pool_name} as Proxmox storage ${storage_id}" \
"pvesm add zfspool ${storage_id} --pool ${pool_name} --content ${content}"
if pvesm_output=$(pvesm add zfspool "$storage_id" \
--pool "$pool_name" \
--content "$content" 2>&1); then
add_ok=true
fi
else
pmx_record_execution "add directory ${path} as Proxmox storage ${storage_id}" \
"pvesm add dir ${storage_id} --path ${path} --content ${content}"
if pvesm_output=$(pvesm add dir "$storage_id" \
--path "$path" \
--content "$content" 2>&1); then
@@ -742,6 +768,9 @@ add_proxmox_dir_storage() {
# ==========================================================
add_disk_to_proxmox() {
local FUNC_VERSION="1.0"
pmx_journal_context "add_disk_to_proxmox" "$FUNC_VERSION"
# Check required tools
for tool in parted mkfs.ext4 mkfs.xfs blkid lsblk sgdisk; do
if ! command -v "$tool" >/dev/null 2>&1; then
@@ -749,7 +778,7 @@ add_disk_to_proxmox() {
msg_title "$(translate "Add Local Disk as Proxmox Storage")"
msg_info "$(translate "Installing required tools...")"
apt-get update &>/dev/null
apt-get install -y parted e2fsprogs util-linux xfsprogs gdisk btrfs-progs &>/dev/null
pmx_install_pkg parted e2fsprogs util-linux xfsprogs gdisk btrfs-progs
stop_spinner
break
fi
@@ -990,6 +1019,8 @@ view_disk_storages() {
_remove_pvesm_storage() {
local storage_id="$1"
local FUNC_VERSION="1.0"
pmx_journal_context "_remove_pvesm_storage" "$FUNC_VERSION"
local path pool content stype
path=$(get_storage_config "$storage_id" | awk '$1 == "path" {print $2}')
pool=$(get_storage_config "$storage_id" | awk '$1 == "pool" {print $2}')
@@ -1017,6 +1048,7 @@ _remove_pvesm_storage() {
# Step 1: Remove from Proxmox
msg_info "$(translate "Removing storage from Proxmox...")"
pmx_record_execution "remove Proxmox storage ${storage_id}" "pvesm remove ${storage_id}"
if ! pvesm remove "$storage_id" 2>/dev/null; then
msg_error "$(translate "Failed to remove storage from Proxmox.")"
echo ""
@@ -1029,6 +1061,7 @@ _remove_pvesm_storage() {
# Step 2: Unmount if mounted (dir-backed storages only)
if [[ -n "$path" ]] && mountpoint -q "$path" 2>/dev/null; then
msg_info "$(translate "Unmounting disk...")"
pmx_record_execution "unmount disk from ${path}" "umount ${path}"
if umount "$path" 2>/dev/null; then
msg_ok "$(translate "Disk unmounted from") $path"
else
@@ -1045,7 +1078,9 @@ _remove_pvesm_storage() {
msg_info "$(translate "Removing from /etc/fstab...")"
local tmp
tmp=$(mktemp)
awk -v mp="$path" '$2 != mp' /etc/fstab > "$tmp" && mv "$tmp" /etc/fstab
if awk -v mp="$path" '$2 != mp' /etc/fstab > "$tmp"; then
pmx_write_file /etc/fstab < "$tmp" && rm -f "$tmp"
fi
systemctl daemon-reload 2>/dev/null || true
msg_ok "$(translate "Removed from /etc/fstab")"
fi
@@ -1053,6 +1088,7 @@ _remove_pvesm_storage() {
# Step 3b: Export ZFS pool if applicable
if [[ -n "$pool" ]] && zpool list "$pool" >/dev/null 2>&1; then
msg_info "$(translate "Exporting ZFS pool...") $pool"
pmx_record_execution "export ZFS pool ${pool}" "zpool export ${pool}"
if zpool export "$pool" 2>/dev/null; then
msg_ok "$(translate "ZFS pool exported:") $pool"
else
@@ -1069,6 +1105,7 @@ _remove_pvesm_storage() {
read -r
echo ""
msg_warn "$(translate "Rebooting the system...")"
pmx_record_execution "reboot host after removing storage ${storage_id}" "reboot"
reboot
else
echo ""
@@ -1082,6 +1119,8 @@ _remove_pvesm_storage() {
_remove_fstab_entry() {
local mount_point="$1"
local FUNC_VERSION="1.0"
pmx_journal_context "_remove_fstab_entry" "$FUNC_VERSION"
local fs fstype
while IFS= read -r line; do
@@ -1122,6 +1161,7 @@ _remove_fstab_entry() {
if $mounted; then
msg_info "$(translate "Unmounting") $mount_point..."
pmx_record_execution "unmount disk from ${mount_point}" "umount ${mount_point}"
if umount "$mount_point" 2>/dev/null; then
msg_ok "$(translate "Unmounted successfully")"
else
@@ -1133,7 +1173,8 @@ _remove_fstab_entry() {
local tmp
tmp=$(mktemp)
awk -v mp="$mount_point" '$2 != mp' /etc/fstab > "$tmp"
mv "$tmp" /etc/fstab
pmx_write_file /etc/fstab < "$tmp"
rm -f "$tmp"
systemctl daemon-reload 2>/dev/null || true
msg_ok "$(translate "Removed from /etc/fstab")"