Commit Graph
100 Commits
Author SHA1 Message Date
MacRimi 9656b04a3e Merge branch 'main' of https://github.com/MacRimi/ProxMenux 2026-06-05 17:12:27 +02:00
MacRimi 3629fe8848 Add beta 1.2.2.1 2026-06-05 17:12:23 +02:00
MacRimi e855fca0b3 new beta 1.2.2.1 2026-06-03 18:04:58 +02:00
MacRimiandClaude Opus 4.7 371f61fa08 install_proxmenux: clear stale beta_version.txt on every stable install
A user who rode the beta channel and later switched back to stable
keeps a leftover beta_version.txt under /usr/local/share/proxmenux/.
The `menu` launcher's beta-mode update check (`check_updates_beta`)
short-circuits when that file isn't present, but it stays put across
stable installs and updates today, so the user keeps seeing the
"Beta update available" prompt on top of the legitimate stable one
even though they're no longer on the beta channel.

Drop the marker on every stable install/update, in both the update
path (around the `cp ./version.txt` near the scripts-tree wipe) and
the fresh-install path (the symmetric block lower in the file).
The comment about which files survive a scripts-tree wipe is
updated to no longer mention beta_version.txt, since that's exactly
what we're removing.

If the user re-opts into the beta program, install_proxmenux_beta
re-creates the file — this only clears stale state that the user no
longer has any way to update from anyway.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-03 16:34:20 +02:00
MacRimiandClaude Opus 4.7 ae91fc4cdd Revert v1.2.2.1 patch release — keep code fix, drop unnecessary bump
PR #223 shipped the install_proxmenux.sh unit-rewrite fix together
with a version bump to 1.2.2.1 and a matching CHANGELOG entry.
With both the fix (#223) and the menu self-heal (#224) already in
main the bump turns out to be unnecessary for recovery:

* Users on v1.2.1 stable updating now pull the corrected installer
  from main and arrive at v1.2.2 working.
* Users stuck on a broken v1.2.2 get repaired by
  `auto_repair_monitor_unit` on every menu launch.
* Users on a healthy v1.2.2 had nothing to fix.

Leaving 1.2.2.1 published would force a no-op update prompt across
every healthy v1.2.2 install. Revert version.txt to 1.2.2 and drop
the v1.2.2.1 CHANGELOG section (EN+ES) so the public release notes
stay clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:06:39 +02:00
MacRimiandClaude Opus 4.7 7cea5563a7 menu: self-heal broken monitor unit on launch (belt-and-suspenders for #222)
The installer fix in this PR rewrites the systemd unit on every
v1.2.2.x update, which catches every user once they accept the
update prompt. But the prompt in `menu` uses `--defaultno` so a
user who presses Enter by reflex stays on the broken state and
opens a fresh issue, which is the scenario unfolding in #222.

Add a tiny `auto_repair_monitor_unit` function that runs before
`check_updates` on every menu launch. It only touches anything when
the bug's exact fingerprint is present:

  1. /etc/systemd/system/proxmenux-monitor.service exists
  2. Its ExecStart points at /usr/local/share/proxmenux/ProxMenux-Monitor.AppImage
  3. The extracted AppRun is already on disk at /usr/local/share/proxmenux/monitor-app/AppRun

When all three are true the function rewrites the unit, reloads
systemd, restarts the service, and logs a single msg_ok line. For
healthy installs and for hosts that never had the Monitor at all,
it returns immediately without touching anything — safe to ship
unconditionally.

Verified on .55 by simulating the broken unit (ExecStart on the
bare AppImage → 203/EXEC + activating loop) and running the new
menu script: unit rewritten to AppRun, service active, single
"ProxMenux Monitor unit repaired and restarted" line printed.

CHANGELOG entries (EN+ES) updated to mention the auto-repair so
users on the broken state know the simpler recovery is now "just
run menu".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 20:44:12 +02:00
MacRimiandClaude Opus 4.7 17c5b89cc8 v1.2.2.1: rewrite monitor unit on every update to point at AppRun (#222)
The v1.2.2 install layout extracts the AppImage into
/usr/local/share/proxmenux/monitor-app/ and runs AppRun out of that
directory — but install_proxmenux_monitor's update branch only
called create_monitor_service on fresh installs, leaving the inherited
unit's `ExecStart=/usr/local/share/proxmenux/ProxMenux-Monitor.AppImage`
in place. That path used to be the FUSE-mounted AppImage entry point,
which v1.2.2 deliberately replaced to clear a Wazuh rule-521 false
positive on /tmp/.mount_*. On PVE 9.x / Debian 13 the bare AppImage
fails to exec straight away (status=203/EXEC) so the service entered
the activating loop reported in #222 and never came back up.

Always rewrite the unit before the post-update `systemctl start` —
idempotent for installs whose unit is already correct, recovering
for those whose isn't. The new helper
`_proxmenux_rewrite_monitor_unit_for_apprun` mirrors the unit body
the fresh-install path emits in `create_monitor_service`, with the
same template-from-repo / inline-fallback fork, so both paths
converge on the same content.

Reproduced and validated on PVE 9.x lab:

  before:
    Process: ExecStart=/usr/local/share/proxmenux/ProxMenux-Monitor.AppImage
             (code=exited, status=203/EXEC)
    Active: activating (auto-restart)

  after:
    ExecStart=/usr/local/share/proxmenux/monitor-app/AppRun
    Active: active (running)

Bumps version.txt to 1.2.2.1 so the existing menu update path picks
this up automatically. For users already stuck on a broken v1.2.2,
re-running the installer manually applies the same fix:
  bash -c "$(wget -qLO - https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh)"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 20:31:33 +02:00
MacRimiandClaude Opus 4.7 5e795a654d doc-navigation: skip sidebar anchor-only entries from Prev/Next walk
`#host` and `#lxc-net` are visual sidebar section headers for the
Storage Share Manager page — they group their submenu items in the
sidebar tree but point back at the parent Overview with an anchor,
so they aren't standalone docs the reader advances to. Including
them in the flat Previous/Next sequence produced two regressions:

* On `/docs/storage-share/#host` the Next button targeted `#host`
  again, so clicking it didn't move. The earlier hash-tracking fix
  intended to catch this, but a `useEffect` with an empty dep array
  only runs on mount — and Next.js Link navigations don't fire
  `hashchange` when the path changes too, so a cross-page navigation
  that lands on `#host` (sidebar click) rendered with hash="" and
  re-collapsed to the section header.
* On `/docs/storage-share/lxc-mount-points/` the Next button pointed
  at `#lxc-net` instead of advancing to `lxc-nfs-client`, since the
  section header sat between the two real pages in the flat list.

Filter out any sidebar entry whose href contains `#` at walk time so
the flat list only carries real pages. With them gone, an anchored
URL collapses to its parent Overview and Next walks straight into
the first subpage. The hash effect + state are no longer needed so
the component drops them, keeping only the pathname-based match.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 19:49:36 +02:00
MacRimi 43e9d5db67 Update share_menu.sh 2026-06-02 18:43:03 +02:00
MacRimiandClaude Opus 4.7 bcf13d71b2 share_menu: drop redundant Host-only sub-header
The HOST block already groups everything that runs on the host
side, so the secondary "Host-only resources" divider between item 4
and item 5 was visual noise — the user reading the menu sees two
HOST sub-titles back to back and has to wonder how items 1-4 differ
from item 5 in scope. They don't; items 1-4 register an external or
local resource as a Proxmox storage, item 5 creates a local shared
directory. Both are host-side actions.

While here, retitle item 5 from "Add Shared Directory on Host" to
"Create Shared Directory on Host" — items 1-4 add an existing
external/local resource, item 5 creates a new one.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:40:25 +02:00
MacRimiandClaude Opus 4.7 0ac84dc3e4 lxc-mount-manager: start stopped CT on request and verify writes
Two related improvements to the post-add verification step that the
user hit while testing the stopped-CT case.

A stopped container couldn't be probed at all — the previous patch
just told the user "mount will activate on next start" and left
them to discover any issues later (the typical issue being
permission denied on the host directory, since the dialog confirms
the bind-mount was added but never proves it works). Offer to start
the container right now so the user gets feedback in the same
session; if they decline, fall back to the informational line.

The post-restart / post-start probe used `test -d $ct_mount_point`
which only checks that the directory is visible inside the
container. That always succeeds whenever the bind-mount took
effect, even if the host directory permissions don't let the
unprivileged-LXC mapped uid write — exactly the case the user just
ran into with /mnt/disk-sda (700 → others gets r-x). Replace with a
touch+rm probe in a new `_lmm_verify_writable` helper used by both
branches so the user is told straight away when writes will fail
and, when they will, is given the exact `chmod o+rwx` / `setfacl`
command and a pointer to the host-perms prompt.

Verified on .55 / LXC 112 (unprivileged) against /mnt/disk-sda:
container stopped → start prompt → start → directory visible →
touch probe → success.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:36:17 +02:00
MacRimiandClaude Opus 4.7 a5fdf43b70 lxc-mount-manager: drop dangling spinner on stopped-CT message
The earlier fix to handle stopped containers in the add flow used
`msg_info` for the "Container is stopped — mount will activate
automatically on next start" line. `msg_info` is the spinner-start
half of the msg_info/msg_ok pair — it never gets closed here
because there's nothing to wait on, so the spinner glyph stays
visible (⠋) right before the "Press Enter to continue" prompt.

Switch to `msg_ok` so the line renders as a clean static success
mark, matching the visual style of the other terminal messages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:33:46 +02:00
MacRimi bbfe3adc54 Update disk_host.sh 2026-06-02 18:29:29 +02:00
MacRimiandClaude Opus 4.7 a921aac51e disk_host: open host mount path for unprivileged LXC bind-mounts
The fstab-only mount method explicitly says "for LXC bind-mounts" in
its dialog wording, but the mount point left behind by mkfs +
mkdir is owned root:root with mode 0755. An unprivileged LXC sees
the directory through its uid offset (root inside → host uid 100000)
which lands under the directory's "others" bits — so the container
can read but never write, and the user has to track down the
chmod / setfacl step manually.

lxc-mount-manager_minimal.sh already offers exactly this fix as
`lmm_offer_host_permissions` when the user adds the bind-mount
through that script, but the disk-side script never closed its half
of the loop. Add a small `_apply_lxc_bind_mount_perms` helper that
runs `chmod o+rwx` plus `setfacl o::rwx + default ACL` whenever
MODE_FSTAB=1, and call it from both `mount_disk_permanently`
(format path) and `mount_existing_disk` (use_existing path). Pure
pvesm-only mounts keep the original behaviour — chmod o+rwx on a
VM/backup storage isn't desirable.

Verified on .55 against the existing /mnt/disk-sda + LXC 112
(unprivileged): unprivileged container root could not write before
(Permission denied), writes succeed after the perms are applied and
land on the host as uid 100000 as expected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:21:27 +02:00
MacRimiandClaude Opus 4.7 15ed0f84e7 disk_host: surface fstab-only mounts in view, filter out network shares
Two related gaps in the disk-host script that surfaced while testing
the new dual-flow (pvesm / fstab-only / both) added earlier today.

view_disk_storages used to read only from `pvesm status`, so a disk
added via the new fstab-only path — exactly the case where the user
wants a local disk available for LXC bind-mounts without registering
it as a Proxmox storage — never showed up. Replicate the same fstab
scan remove_disk_storage already performs and list those mounts in a
second section underneath the pvesm ones. Empty state and wording
updated so the panel no longer claims "No local storage configured
in Proxmox" when fstab-only mounts are present.

Both view_disk_storages (new code) and remove_disk_storage (existing
fstab branch) were happily picking up `/mnt/Archivos` and any other
CIFS/NFS share mounted under /mnt. samba_host.sh and nfs_host.sh own
those — surfacing them in the local-disk menus would let a user
remove a network share from the wrong screen. Filter by fstype
(skip cifs/smbfs/nfs/nfs4/nfsv4/sshfs/fuse) and additionally require
that the resolved source be a real block device, which drops bind
mounts and anything else whose backing source isn't a disk.

Verified on .55 with the test disk-sda fstab-only mount alongside
the existing //192.168.0.15/Archivos CIFS mount: only disk-sda is
listed by the local-disk view/remove flows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:15:37 +02:00
MacRimiandClaude Opus 4.7 2a376d2c9b scripts/share: don't reboot a stopped CT, add fstab-only mode to disk_host
Two release-day fixes in the host-side share tooling, both reported
during testing of the v1.2.2 candidate.

lxc-mount-manager_minimal.sh
  After adding a mount point on a stopped LXC the script offered to
  `pct reboot $ct` unconditionally — which fails on a stopped CT
  because `pct reboot` only accepts running ones, so the user saw a
  bogus "Failed to restart" right after a successful mount. Gate the
  prompt on `pct status` and, when the CT is stopped, tell the user
  the mount will activate on next start instead of trying to reboot
  it. The matching restart prompt in the remove flow (around line
  540) was already doing the check correctly; this just brings the
  add flow in line.

disk_host.sh
  The script always registered the disk as a Proxmox storage via
  `pvesm add dir|zfspool`. nfs_host.sh and samba_host.sh already
  offered a dual-flow chooser ("Proxmox storage" / "host fstab only"
  / both) so a user could mount the share on the host for LXC
  bind-mounts without surfacing it as a Proxmox storage. Replicate
  that chooser for local disks:

  * new `select_mount_method` checklist with `pvesm` and `fstab`,
    inserted after filesystem selection. ZFS is forced into the
    pvesm path because a ZFS pool can't be expressed as an fstab
    mount.
  * `configure_disk_storage` skips the Content Types prompt when
    only fstab is selected and renames "Storage ID" → "Mount Name"
    in the same case so the wording matches what the user will
    actually see (or not see) in Proxmox.
  * `format_and_mount_disk` title and summary lines adapt to the
    chosen mode.
  * the trailing `add_proxmox_dir_storage` call in `add_local_disk_storage`
    runs only when `MODE_PVESM=1`; in fstab-only mode the final
    message points users at the LXC Mount Manager for bind-mounts.

  Verified end-to-end on a 32 GB USB disk against LXC 112
  (unprivileged) on .55: fstab-only path → bind-mount → root inside
  CT writes mapped to host uid 100000, regular user writes mapped to
  host uid 101000, both reads/writes successful from inside the
  container.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 18:03:00 +02:00
MacRimi f27b3d480a Update lxc-mount-manager_minimal.sh 2026-06-02 17:49:37 +02:00
MacRimiandClaude Opus 4.7 5a116e77b9 Discord channel: split oversized digests across embeds (#220)
A mass-backup webhook that exceeded ~2 KB used to be silently
truncated by `desc = message[:MAX_EMBED_DESC]` with MAX_EMBED_DESC
set to 2048 — half of Discord's real description limit and far
below what a multi-VM backup digest produces. The trailing jobs
just vanished from the channel.

Bring the channel up to Discord's actual webhook contract:

* description limit raised to the real 4096-char cap
* if the body still doesn't fit, split it on line boundaries into
  one embed per chunk so every backup entry is preserved
* keep title + fields on the first embed only; attach the footer
  and timestamp to the last embed so the rendered card has the
  normal head/tail framing even when split across many embeds
* enforce Discord's 6000-char-per-embed cap (title + description +
  every field name+value) — only kicks in when many large fields
  combine with a chunk already near the description ceiling
* batch up to 10 embeds per webhook POST (Discord's per-message
  limit) and POST additional messages sequentially with a 0.4 s
  gap so a >10-embed digest doesn't trip the 5/2 s webhook rate
  limit

Verified with synthetic mass-backup payloads:
* 14 KB / 200 jobs → 4 embeds, 1 POST
* 60 KB / 60 lines → 15 embeds, 2 POSTs (10 + 5)

New AppImage SHA-256:
  16ad59ea63a64e5be460cd73f87315e8b39b756bf1c61f3cb2019e9fa3e76361

Closes #220.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 17:30:59 +02:00
MacRimiandClaude Opus 4.7 17cae5d3a4 Refresh AppImage binary + sha256 after NVMe-obs-count fix
New build picks up the get_disks_observation_counts NVMe-rename fix.

SHA-256:
  3b44eb1172b4b1b7e6a36d1c9f1cd5a237ec04d52543bb791358525b0653a402

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:52:39 +02:00
MacRimiandClaude Opus 4.7 642bd8ecae health_persistence: stop leaking obs counts across NVMe device renames
`get_disks_observation_counts` maps each serial's count to that
serial's "most recent" device_name (so renames like ata8 -> sdh keep
the badge attached). When several physical disks have passed through
the same kernel name across reboots — common with NVMe, the kernel
probes in a different order depending on which slots are populated —
disk_registry keeps a row per (device_name, serial) seen and the
"most recent" device_name for a serial can now be in use by an
entirely different disk.

Concrete case from the wild: serial 211716800490 was nvme0n1 during
the previous boot and earned a real I/O observation. After removing
four of five NVMes, the surviving disk (serial 243332800236) booted
into nvme0n1. The badge layer mirrored 211716800490's count onto
nvme0n1 — which is now a different physical disk — and showed
"1 obs." on the wrong drive, while the modal (which scopes by the
current (device_name, serial) registry row) found nothing and
rendered an empty history.

Only mirror a serial's count onto its device_name when that
device_name is currently owned by the same serial, determined from
the freshest disk_registry row. The serial-keyed entry stays
unconditional so observations remain reachable when the disk is
re-plugged under another device name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:52:11 +02:00
MacRimiandClaude Opus 4.7 92385f44b0 Drop stale ProxMenux-1.2.0.AppImage binary
The v1.2.0 binary lingered in the repo after later releases. Remove
it so AppImage/ holds only the current shipping artefact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:22:13 +02:00
MacRimiandClaude Opus 4.7 4cd1cb4e39 Refresh AppImage binary + sha256 for v1.2.2
The tracked binary still pointed at the build made before the
last two fixes landed (resolution_reason persistence in
health_persistence and disk-temp breakdown alignment in
storage-overview). Re-build the AppImage so the GitHub-published
binary matches what is actually running on the deploy targets.

New SHA-256:
  d043e2f27f21315931ab53d87f02390b1a66b0c1730e8b7699aafb565809efbb

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:21:24 +02:00
MacRimiandClaude Opus 4.7 7a1fe0b0fc storage-overview: drive disk-temp breakdown from configurable thresholds
`getDiskHealthBreakdown` carried its own hardcoded ladder (HDD ≤45
normal, ≤55 warning) that was much stricter than the configurable
defaults consumed by `getTempColor` via `useDiskTempThresholds`
(HDD warn 60, hot 65). HDDs at 48 °C therefore rendered a green
"Healthy 48°C" badge on the card but were tallied as "warning" in
the top-of-page "X normal, Y warning, Z critical" summary, leaving
the user with the misleading "6 normal, 5 warning" line.

Use the same threshold map as the per-disk badge so the colour and
the count are always consistent, and so Settings → Health Monitor
Thresholds → Disk temperature actually applies to the breakdown.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:13:55 +02:00
MacRimiandClaude Opus 4.7 3c5beb0286 Persist resolution_reason on resolve_error so the audit log is useful
The UPDATE in `_resolve_error_impl` only touched `resolved_at` — the
`reason` argument every caller passes was silently dropped, and the
`resolution_reason` / `resolution_type` columns stayed NULL for every
auto-resolved error. The columns were added back in a previous sprint
for exactly this audit-log purpose, but the writer was never updated
to populate them.

Fix the SQL to write `resolution_reason = ?` and tag
`resolution_type = COALESCE(existing, 'auto')` so admin-cleared
errors (whose type is set elsewhere) keep their value while the
default auto path correctly labels itself.

Verified end-to-end on the lab host: re-injected the `disk_nvme2n1`
warning, waited one scan cycle, the row now reads
`resolution_type='auto'` and
`resolution_reason='Transient I/O cleared, SMART now reports healthy'`
— previously these columns stayed NULL even though the resolve_error
call passed a descriptive reason.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 23:02:52 +02:00
MacRimiandClaude Opus 4.7 9677c5cb19 Health Monitor: reconcile stale disk warnings across reboots
When a host gets transient I/O events on a disk while smartctl is
momentarily unavailable (the canonical case: late in a noisy
shutdown), the disk-scan code records a `disk_<name>` WARNING tagged
"SMART: unavailable" exactly once and trusts the next scan to clear
it. That trust is misplaced: the clear path only fires when the
device shows up in the current dmesg window with zero events. After
a reboot, dmesg is empty for that device — so the device never gets
iterated, resolve_error is never called, and the dashboard stays
orange for a disk whose SMART now reports PASSED.

Caught on a lab host where `disk_nvme2n1` had been stuck as WARNING
for hours after a reboot. SMART was 100% healthy at the moment of
inspection (Critical Warning 0x00, 0 media errors, 100% spare). The
error's first_seen and last_seen were identical and pre-dated the
current boot, confirming a one-shot record that nothing had cleared.

Fix: add a `_reconcile_stale_disk_warnings()` pass at the top of
`_check_disks_optimized()`. For every active `disk_*` error
(skipping `disk_fs_*`, which is already reconciled separately):

  - device gone from /dev/   → resolve "Device no longer present"
  - device present + SMART PASSED → resolve "Transient I/O cleared,
    SMART now reports healthy"
  - device present + SMART UNKNOWN/FAILED → leave active so the
    main loop can re-classify on the next dmesg window

Acknowledged errors are left alone so the user's explicit dismiss
intent isn't overridden.

Verified end-to-end: re-injected the original `disk_nvme2n1`
warning into the persistence DB on the lab host, waited one scan
cycle, error was resolved automatically with `resolved_at` set and
`resolution_reason = 'Transient I/O cleared, SMART now reports
healthy'`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 22:54:14 +02:00
MacRimiandClaude Opus 4.7 d25faedc2b Rebuild AppImage with actual Next.js 15.1.9 + always reconcile node_modules
The previous bump commit (2f24de25) shipped a binary that still carried
Next.js 15.1.6 in the bundled chunks even though AppImage/package.json
was at 15.1.9. Root cause: build_appimage.sh only ran `npm install`
when `node_modules` did not exist; on the .50 build host node_modules
had been cached since the 1.2.1 build cycle, so the bump was silently
ignored and the build re-used the stale tree.

Fix the script: always run `npm install --legacy-peer-deps` on every
build. npm reconciles against the lockfile in under a second when
everything is already in sync, so the change is free on a warm tree
and correct on a stale one.

Rebuild from a clean node_modules on .50, redeploy to all four hosts
(SHA 4602b8d4aa130c6f...), runtime grep confirms the bundle now
contains 15.1.9 with no traces of 15.1.6 left. Same architecture and
threat model as before — Flask serves the static export on :8008,
no Next.js runtime — but the version banner now matches the lockfile.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 22:37:44 +02:00
MacRimiandClaude Opus 4.7 2f24de2592 Bump Next.js to 15.1.9 + doc nav handles in-page anchors + help_info_menu
Three changes that fold into the v1.2.2 release PR:

1. AppImage: bump Next.js 15.1.6 -> 15.1.9 (CVE-2025-55182)
   GHSA-9qr9-h5gf-34mp / React2Shell is a pre-auth RCE in React Server
   Components when Server Functions deserialize attacker payloads. The
   ProxMenux Monitor ships Next.js in `output: "export"` mode behind
   Flask on :8008, so there is no runtime Next.js server and no
   "use server" directive in the source tree — the exploitable path is
   not reachable. Bumping to 15.1.9 anyway because OpenVAS and similar
   scanners flag the version string from the JS bundle regardless of
   architecture; raising the floor removes false-positive noise across
   every install. Reported by @rost43 in #219.

2. web/components/ui/doc-navigation.tsx: handle sidebar entries that
   point to in-page anchors. The Storage Share Manager sidebar has
   entries for `/docs/storage-share#host` and
   `/docs/storage-share#lxc-net` as section headers, but
   usePathname() does not include the hash so every visit collapsed
   to the parent page. As a result Next/Previous on /docs/storage-share
   stayed stuck at #host, and Next from .../lxc-mount-points/ pointed
   back at #host instead of #lxc-net. Read window.location.hash on
   mount (and on hashchange) and try the pathname+hash match before
   falling back to the pathname-only lookup. SSR hydrates with an
   empty hash and refreshes once mounted — brief render before
   hydration is the same as the previous behaviour, so no regression.

3. scripts/help_info_menu.sh: user-side improvement (mirrored from
   develop).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 22:31:12 +02:00
MacRimiandClaude Opus 4.7 3b2665c4ac Release date: shift CHANGELOG v1.2.2 from 2026-05-31 to 2026-06-02
The drafting date (today) was used as a placeholder. The actual
release date is Tuesday 2026-06-02, when PR #218 merges and the
update notifier picks up 1.2.2. Aligns the changelog header in both
EN and ES with the publication date users will see.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:15:36 +02:00
MacRimiandClaude Opus 4.7 e83950c0c2 Release 1.2.2 — version.txt bump + CHANGELOG (EN+ES) + contributors
Final ingredient of the v1.2.2 stable release: flip version.txt from
1.2.1 to 1.2.2 so the stable channel's update notifier picks it up
on every running install, ship the consolidated v1.2.2 entry on both
CHANGELOG.md (English) and lang/es/CHANGELOG.md (Spanish), and add
the GitHub link to Jonatan Castro on the contributors page.

CHANGELOG.md entry (and its ES mirror) consolidates the four v1.2.1.x
betas into a single stable note grouped by theme — Health Monitor
configurability, Apprise full feature parity, LXC update detection,
Coral TPU latest upstream drivers, performance optimizations (smartctl
scheduler, fail2ban cache, lxc-info /proc), HTTPS terminal handshake,
PVE 9.x kernel update detection, NVIDIA installer improvements, i18n
documentation site — plus an Acknowledgments section crediting
@jcastro (5 direct commits), @pespinel (1 commit) and @ghosthvj
(field reports that shaped the GPU + Coral work).

contributors/page.tsx: Contributor interface now carries an optional
`githubUrl`; when set, the displayed name is wrapped in an
ExternalLink to that URL (target=_blank). Jonatan Castro's entry gets
`githubUrl: https://github.com/jcastro` so users can reach his repos
from the testers grid.

After this PR merges:
- Users running `menu` will be offered the 1.2.2 upgrade
- proxmenux.com/en/changelog and /es/changelog ship the new entry
  (deploy.yml triggers because CHANGELOG.md, lang/** and web/** are
  all touched)
- Jonatan Castro's name on the contributors page becomes clickable

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 19:14:34 +02:00
MacRimiandClaude Opus 4.7 d022c4fe81 Fix typo: contributor is JF_Car (one r), not JF_Carr
Last commit renamed images/avatars/JF_Car.png to JF_Carr.png on the
assumption the file name was the typo. It wasn't — the user's name
is actually JF_Car. Rename the file back and update the display
name + avatar URL in the contributors page accordingly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 18:40:36 +02:00
MacRimiandClaude Opus 4.7 66262fddc8 Contributors: switch new 4 testers to custom avatars
Replace the temporary github.com/<handle>.png placeholders with the
project's standard raw.githubusercontent.com/.../images/avatars/<name>.png
pattern used by every other contributor on the page.

Added avatar files:
- images/avatars/heriberto.png
- images/avatars/JF_Carr.png   (renamed from JF_Car.png on disk so the
                                filename matches the display name)
- images/avatars/rafapuerta.png
- images/avatars/JcMinarro.png

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 18:39:18 +02:00
MacRimiandClaude Opus 4.7 fcc2c3d542 Add 4 testers to contributors page + refine deploy.yml triggers
Contributors page (app/[locale]/docs/about/contributors/page.tsx):
add heriberto, JF_Carr, rafapuerta and JcMinarro to the testers
grid. All with the "testing" role and GitHub's default avatar URL
(https://github.com/<handle>.png) so the entries work immediately
without requiring custom avatar files. Swap to a per-contributor
/images/avatars/<name>.png later if/when custom artwork is ready.

deploy.yml triggers: drop `guides/**` (the legacy /guides/[slug]/
page that read those markdown files was removed in PR #211 — the
folder no longer affects what the web renders) and `scripts/**`
(the bash scripts get rsynced into public/scripts/ during prebuild
but they are downloaded by users via install_proxmenux.sh, not
browsed via the doc site, so a stale copy is harmless). Add
`lang/**` so future translated CHANGELOG / docs (e.g. the Spanish
CHANGELOG just shipped in PR #217) auto-deploy.

Local build verified: 232 pages, 14450 indexed words, no errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 18:37:48 +02:00
MacRimiandClaude Opus 4.7 e07bba7dbd lang/es/CHANGELOG.md: ship the Spanish-translated changelog
The Next.js changelog page (app/[locale]/changelog/page.tsx) already
has the per-locale lookup logic — it reads lang/<locale>/CHANGELOG.md
first and falls back to the canonical English CHANGELOG.md at the
repo root if no localized copy exists. The Spanish file has lived in
develop for weeks (65 KB, 1065 lines, full translation including the
v1.2.1 SR-IOV / GPU passthrough hardening notes) but was never
committed to the repo, so the live site at proxmenux.com/es/changelog
fell back to English on every visit.

Add the file to the tree so the lookup finds it. No code change in
the page — the resolution logic in `resolveChangelogPath()` already
handles both branches and is unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 18:16:11 +02:00
MacRimiandClaude Opus 4.7 e9e10e4ffa Fix doc nav + sidebar active-page detection after trailingSlash:true
PR #212 added `trailingSlash: true` to next.config.mjs so GitHub Pages
would serve the locale roots correctly. That changed what usePathname()
returns at runtime — `/docs/.../page/` with a trailing slash — but
the sidebar config (sidebarItems in DocSidebar.tsx) still declares
hrefs without the trailing slash. Every equality check
`pathname === item.href` therefore returned false on every page, and
two things broke:

1. components/ui/doc-navigation.tsx — the Previous/Next bar at the
   bottom of every doc page. With `findIndex` returning -1,
   `prevPage` was null and `nextPage = allPages[0]` (Introduction).
   So every doc page showed "Next: Introduction" regardless of
   where the user was.

2. components/DocSidebar.tsx — four comparisons that drove (a) the
   highlighted active item in the sidebar, (b) the active-section
   auto-open when navigating directly to a nested page, (c) the
   leaf-item highlight when the item has no submenu. All silently
   broken on every page.

Fix: a `stripTrailingSlash` helper plus a derived `currentPath` that
is compared instead of the raw `pathname`. `collectHrefs(...)` results
are also normalized at the point of comparison so the
`.includes(currentPath)` checks behave correctly.

Verified locally with `npm run build` — 232 pages indexed, no errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 14:44:52 +02:00
MacRimi 11884799b7 Update install_proxmenux.sh 2026-05-31 14:31:42 +02:00
MacRimi b24daf41e2 Update install_proxmenux.sh 2026-05-31 14:27:33 +02:00
MacRimi 2d971d229c Update README.md 2026-05-31 14:11:14 +02:00
MacRimi 01579e99fb Update ProxMenux 1.2.2 2026-05-31 14:02:44 +02:00
MacRimiandClaude Opus 4.7 f4f9b37510 LICENSE: strip project header so GitHub's licensee detects GPL-3.0
The previous commit added a 5-line project header above the canonical
GPL-3.0 text:

  ProxMenux — An Interactive Menu and Web Dashboard for Proxmox VE
  Copyright (c) 2025 MacRimi

  This program is licensed under the GNU General Public License v3.0.
  The full text of the license follows.

That header (~270 bytes in a 35 KB file) pushed the file below the
Sørensen-Dice similarity threshold GitHub's licensee gem uses to
fingerprint licenses, so the repo kept showing "License not
identifiable by GitHub" (API: spdx_id = "NOASSERTION", key = "other")
even though the canonical text was right below.

Strip the header. LICENSE is now byte-exact to the FSF reference:
https://www.gnu.org/licenses/gpl-3.0.txt
(SHA256: 3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986)

The project copyright still lives where GPL-3.0 expects it — in each
source file's header (as enforced by CONTRIBUTING.md's "Script Header
Template" section). LICENSE is the legal reference document; the
per-file copyright notice is the project-specific declaration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 14:00:29 +02:00
MacRimiandClaude Opus 4.7 65a1220758 Hotfix: trailingSlash:true so GitHub Pages serves the locale roots
The previous deploy went live but every visitor hit a 404. Root cause:

GitHub Pages serves the URL `/foo/` by looking for `out/foo/index.html`.
Next.js's static export with the default `trailingSlash: false` instead
emits `out/foo.html`, which Pages only serves for `/foo` (no trailing
slash).

The i18n root redirect in app/page.tsx points users at
`/<defaultLocale>/` (with slash) because that is what next-intl's
`<Link>` components generate. So every visitor landed on
`https://proxmenux.com/en/` → Pages looked for `out/en/index.html`,
did not find it (the export had emitted `out/en.html`), and fell back
to `out/404.html`. Result: the site looked deployed but every page
was a Next.js 404 template.

Setting `trailingSlash: true` makes the export emit
`out/<route>/index.html` for every page — locale roots
(`out/en/index.html`, `out/es/index.html`), nested doc pages
(`out/en/docs/monitor/dashboard/settings/index.html`, etc.), changelog,
guides — so Pages serves them directly.

Local verification: 232 pages built, root redirect intact at
out/index.html, and every locale + doc + guide URL now resolves to
its own index.html.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 13:48:21 +02:00
MacRimiandClaude Opus 4.7 4f3750a8ab Fix CI: add pagefind to web devDeps + portable AppImage cache path
Two regressions surfaced after the 1.2.2 release merge to main, both
in workflows that auto-trigger on push to main:

* Deploy to GitHub Pages — build failed with `pagefind: not found`
  (exit 127) after Next.js prerendered all 241 routes. pagefind was
  not declared in web/package.json; the local build only worked
  because the project root had its own package.json with pagefind
  as a devDep (the one we just gitignored in the previous commit).
  Add `pagefind: ^1.5.2` to web/package.json devDependencies and
  regenerate web/package-lock.json so `npm ci` in CI puts the
  binary at web/node_modules/.bin/pagefind.

* Build ProxMenux Monitor AppImage — failed at the first step with
  `mkdir: cannot create directory '/var/cache/proxmenux-build':
  Permission denied`. The cache path was hardcoded to /var/cache/,
  which is writable when the script runs as root (the .50 host
  manual build) but not as the unprivileged GitHub Actions runner.
  Switch to `${XDG_CACHE_HOME:-$HOME/.cache}/proxmenux-build/` —
  works identically in both environments.

Verified locally: `cd web && npm ci && npm run build` produces 2804
files in out/, 231 pages indexed by pagefind, root redirect intact.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 13:34:30 +02:00
MacRimi 964f2083b6 Merge main into develop to resolve conflicts before 1.2.2 release PR
# Conflicts:
#	AppImage/ProxMenux-Monitor.AppImage.sha256
#	LICENSE
#	install_proxmenux_beta.sh
2026-05-31 13:24:58 +02:00
MacRimi 9e8434a16b Release 1.2.2 stable — consolidated v1.2.1.x cycle
Promote the v1.2.1.x beta cycle to stable: version markers bumped
from 1.2.1.4-beta to 1.2.2 across version.txt, AppImage/package.json,
flask_server.py (3 places) and the four UI labels in login,
proxmox-dashboard, storage-overview and release-notes-modal.

Replace AppImage/ProxMenux-1.2.1.4-beta.AppImage with
ProxMenux-1.2.2.AppImage and regenerate the .sha256 sidecar
(097e2344675d4b21f1dd18c531c956c299a6507fbc3d0c9695418063581ba2b0).
The new binary is verified on all 4 lab hosts (.50 / .55 / .89 /
1.10) — same sha, all services active, runtime version markers
report 1.2.2.

CHANGELOG["1.2.2"] in release-notes-modal.tsx consolidates every beta
in the 1.2.1.x line (12 added / 13 changed / 18 fixed), and
CURRENT_VERSION_FEATURES is rewritten with the four stable highlights:
Health Monitor Thresholds, granular dismiss control (per-event
duration + Active Suppressions panel), Apprise notification channel
parity, and LXC update detection.
2026-05-31 13:15:39 +02:00
MacRimi 3eebbfb9d7 Update LICENSE 2026-05-31 12:54:33 +02:00
MacRimi 5ca3463bf6 complete i18n migration to /[locale]/ with EN+ES content
Full rewrite of the docs site under app/[locale]/ with next-intl
in localePrefix:"always" mode. Every page now exists at both
/en/<path> and /es/<path>; the root / shows a meta-refresh + JS
redirect to /<defaultLocale>/ so GitHub Pages serves something
on the apex URL.

Highlights:
- 107 doc pages migrated to file-per-page JSON namespaces under
  messages/en/ and messages/es/. Spanish content is fully
  translated (no copy-of-English placeholders).
- New documentation for the Active Suppressions section in the
  Settings tab and the per-event Dismiss dropdown in the Health
  Monitor modal.
- New screenshots: dismiss-duration-dropdown.png and an updated
  health-suppression-settings.png.
- Pagefind integrated for client-side search; index is built on
  every CI deploy (not committed).
- RSS feeds: per-locale at /<locale>/rss.xml plus root /rss.xml
  for backward compat.
- Removed the dead app/[locale]/guides/[slug]/ route — every
  guide now has its own static page and no markdown source
  remains.
- Fixed orphan link /guides/nvidia -> /guides/nvidia-manual in
  docs/hardware/nvidia-host.
- Removed obsolete components (footer2, calendar, drawer).

Verified locally with `npm ci && npm run build`: 2804 files in
out/, 231 pages indexed by pagefind, root redirect intact, both
locale roots and the new Active Suppressions docs render OK.
2026-05-31 12:41:10 +02:00
MacRimiandClaude Opus 4.7 875910b4d7 Refresh README, add CONTRIBUTING guide, harden CI
- README: modernize visual layout (status badges row, tagline,
  Ko-fi shields badge, expanded Contributing section). Update
  web URLs to proxmenux.com/en for the new locale-prefixed site.
- CONTRIBUTING.md: add as the canonical contributor guide. Fix
  the workflow section to branch from develop (not main), add
  a dedicated "dialog vs whiptail" section, reorder so Script
  Header comes first.
- deploy.yml: switch npm install -> npm ci so the build uses
  the committed lockfile; fix cache-dependency-path to track
  web/package-lock.json (was package.json); add scripts/** to
  the path triggers so script edits redeploy the doc site.
- .gitignore: ignore the accidental root-level package.json /
  package-lock.json (pagefind is declared in web/package.json)
  and the regenerated build artifacts web/public/pagefind/ and
  web/public/scripts/.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 12:38:48 +02:00
MacRimi 853bcbde35 Fix AppRise 2026-05-31 11:03:04 +02:00
MacRimi 2442ca63be Update AppImage 1.2.1.4 2026-05-31 10:36:16 +02:00
MacRimi 91ded0125e Update AppImage 1.2.1.4 2026-05-30 22:14:51 +02:00
MacRimi 4bf49675d2 Update ProxMenux 1.2.1.4-beta 2026-05-30 21:54:32 +02:00
MacRimi d2ef8f0899 update add_gpu_vm.sh 2026-05-28 20:49:59 +02:00
MacRimi 17248eeedf Update cleanup_gpu_hookscripts.sh 2026-05-28 17:13:22 +02:00
MacRimi 9bce6b0a6b Cleanup NEED_HOOK_SYNC 2026-05-28 17:07:40 +02:00
MacRimi fe1297936f Update AppImage 1.2.1.3 2026-05-27 17:55:41 +02:00
MacRimi e22ff85dc8 Update install_coral_lxc.sh 2026-05-27 17:36:11 +02:00
MacRimi 3143fedb7a Updates scripts share 2026-05-26 17:21:24 +02:00
MacRimi 2dc3a2b93c Update scripts share 2026-05-26 12:41:50 +02:00
MacRimi a3aa5d9c1a Update flask_server.py 2026-05-25 18:01:24 +02:00
MacRimi b299227da2 Update AppImage 1.2.1.3 2026-05-24 17:52:04 +02:00
MacRimi 3286fc315c Update AppImage 1.2.1.3 2026-05-24 16:42:44 +02:00
MacRimi 105576cf17 Update AppImage 2026-05-24 11:37:20 +02:00
MacRimi 4b934db7db Update AppImage 1.2.1.3 2026-05-23 21:27:18 +02:00
MacRimi 9d2685d4a8 Update beta_version.txt 2026-05-22 18:48:30 +02:00
MacRimi 4507eacf1a Merge branch 'develop' of https://github.com/MacRimi/ProxMenux into develop 2026-05-22 18:47:46 +02:00
MacRimi f2a40b993a Update AppImage 1.2.1.3 2026-05-22 18:47:30 +02:00
MacRimi 840385272c Add ProxMenux beta 1.2.1.3 2026-05-22 18:24:03 +02:00
MacRimi 95d0667077 Update AppImage 1.2.1.2 2026-05-21 22:25:29 +02:00
MacRimi 56fac4c34b Update AppImage 1.2.1.2 2026-05-21 22:00:35 +02:00
MacRimi 2d523b030f Update AppImage 1.2.1.2 2026-05-21 21:41:27 +02:00
MacRimi f5b7a0a74b Update AppImage 1.2.1.2 2026-05-21 21:17:59 +02:00
MacRimi 3e9dd599a6 Update AppImage 1..2.1.2 2026-05-21 19:31:47 +02:00
MacRimi 0651f57e86 Update customizable_post_install.sh 2026-05-21 18:43:27 +02:00
MacRimi 7eccc3119b Update customizable_post_install.sh 2026-05-21 18:21:25 +02:00
MacRimi 9545587b67 Update AppImage 1.2.1.2 2026-05-21 17:24:09 +02:00
MacRimi ef22c88861 Update AppImage 1.2.1.2 2026-05-21 17:18:23 +02:00
MacRimi 3723888b0c Update Install 2026-05-20 20:46:58 +02:00
MacRimi bb982629b5 Update roadmap 2026-05-20 20:19:39 +02:00
MacRimi 48300d7f01 Update roadmap 2026-05-20 20:12:18 +02:00
MacRimi 2ae838b4a4 Add Roadmap 2026-05-20 20:05:55 +02:00
MacRimi ceb563cd60 Add ProxMenux Phases 2026-05-20 19:50:17 +02:00
MacRimi 298cd2c6d4 Update Beta 1.2.1.2 2026-05-20 19:47:42 +02:00
MacRimi 4112323961 Update AppImage 2026-05-20 18:14:32 +02:00
MacRimi 1087a87ea2 Update samba_lxc_server.sh 2026-05-20 16:32:03 +02:00
MacRimiandClaude Opus 4.7 73389d842a Reset auth_fail cooldowns on NotificationManager.start()
Pedro Rico, 19/05: after reinstalling the Monitor from GitHub a real
SSH/web login failure went unnotified. Root cause was the auth_fail
cooldown surviving across the service restart — install_proxmenux_beta
extracts the new AppImage but leaves the notification_last_sent SQLite
table intact (desirable: we don't want to lose legitimate cooldowns
on every update). On startup `_load_cooldowns_from_db()` then loaded
the stale auth_fail row from the previous run into the in-memory
cache, and `_passes_cooldown` blocked the new event.

This extends the existing reset-on-start mechanism (already in place
for update_summary, proxmenux_update, post_install_update, …) to also
clear auth_fail rows. A security-relevant event shouldn't be silenced
because the same source IP happened to fail to log in yesterday.

- Rename `_UPDATE_EVENT_TYPES_RESET_ON_START` → `_EVENT_TYPES_RESET_ON_START`
  (the list no longer covers only update-status reports).
- Rename `_reset_update_cooldowns_on_start()` → `_reset_cooldowns_on_start()`
  for the same reason.
- Add `'auth_fail'` to the curated list.

High-frequency sources (log_critical_*, disk SMART errors, …) are
deliberately NOT on this list — they keep their 24h cooldown across
restarts to prevent inbox floods if the user toggles the service.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:18:49 +02:00
MacRimiandClaude Opus 4.7 4e26c5942f Reset update-type cooldowns on NotificationManager.start()
When the user reinstalls or restarts the Monitor (deploy of a new
beta AppImage), they expect to see a fresh "what's available now"
summary in Telegram/Gotify/etc. instead of silence — even if the
24h anti-spam cooldown for `update_summary` etc. hasn't expired yet.

Without this, the operator had to wait up to 24h after every
deploy before the next `update_summary`, `proxmenux_update`,
`post_install_update`, `pve_update`, `update_available`,
`nvidia_driver_update_available` or `secure_gateway_update_available`
notification fired. The 24h cooldown is the right default for steady
state (don't pester the user every poll cycle with the same "177
packages pending" reminder), but a service restart is an explicit
signal that the user wants a fresh status report.

- New _UPDATE_EVENT_TYPES_RESET_ON_START tuple lists the event types
  to clear (everything in the "*_update*" + "update_*" family).
- New _reset_update_cooldowns_on_start() runs at start() right after
  the running flag flips, before watchers/dispatcher come up.
- Patterns match both fingerprint shapes:
    "<host>:<entity>:<event_type>:"               trailing-colon form
    "<host>:<entity>:<event_type>"                no-suffix form (managed installs)
- In-memory `_cooldowns` cache is also pruned so the live dispatcher
  picks up the reset immediately, without waiting for the next
  `_load_cooldowns_from_db()` cycle.

Non-update cooldowns (auth_fail, log_critical_*, disk errors, …) are
preserved so a restart doesn't unleash a backlog of stale alerts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 01:03:44 +02:00
MacRimiandClaude Opus 4.7 06e6ae417e Fix notification dispatch: NameError in _dispatch_to_channels (Quiet Hours)
`_dispatch_to_channels` does NOT receive the NotificationEvent object —
only the rendered primitives (title, body, severity, event_type, …).
The Quiet Hours + Daily Digest merge introduced two references to
`event.severity` / `event` inside this function, which raised
`NameError: name 'event' is not defined` for every event passing
through dispatch.

The dispatch loop swallows the exception with a broad `except`, so the
visible symptom was "the Test button works but no real event ever
arrives" — both for community beta users (multiple reports on
Telegram, 9-18 May) and verified live on a test host (id 905 in
notification_history confirms the pipeline post-fix).

- _dispatch_to_channels: read `severity` / `event_type` directly
  instead of `event.severity` / `event.event_type`.
- _should_buffer_for_digest: take (ch_name, severity, event_type)
  primitives instead of a NotificationEvent.
- _buffer_digest_event: same — take (ch_name, event_type,
  event_group, severity, title, body).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:23:29 +02:00
MacRimiandClaude Opus 4.7 6eb1312c61 1.2.1.1-beta: notification + LXC + post-install fixes
- flask_notification_routes: PVE webhook X-Webhook-Secret written in
  standard base64 so PVE can decode it (GH #198)
- notification_channels: Gmail SMTP App Password handling — normalize
  tls_mode (None/empty → starttls), reject creds without host (false-
  positive sendmail delivery), surface "AUTH not advertised" hint
- notification_events: is_vzdump_active_on_host() reads /var/log/pve/
  tasks/active directly so backup_start fallback and vm_shutdown
  suppression survive a Monitor restart mid-backup
- notification_templates: extract --storage flag from vzdump log →
  "PBS-Cloud: vm/104/…" instead of generic "PBS:" prefix when multiple
  PBS endpoints exist
- health_monitor: pve_storage_capacity + zfs_pool_capacity respect
  per-item dismiss (don't keep category WARNING/CRITICAL after user
  dismisses); updates_check cache invalidated when /var/log/apt/
  history.log mtime advances
- lxc_mount_points: PVE volume size from subvol quota (df via
  /proc/<host_pid>/root/<target> + lxc.conf size=NNNG fallback);
  host_source_state detects "host detached" zombie binds; per-mount
  subprocess work parallelised via ThreadPoolExecutor so a CT with
  many bind mounts doesn't trip the Caddy 3s reverse-proxy timeout
- virtual-machines: "host detached" badge on bind mounts whose host
  source path disappeared
- auto/customizable_post_install: log2ram FUNC_VERSION 1.1 → 1.2; new
  log2ram-check.sh vacuums journal + truncates non-rotating logs
  (pveproxy/access.log, pveam.log) instead of only calling
  `log2ram write` (which leaves the tmpfs full); auto flow gains the
  missing SystemMaxUse in /etc/systemd/journald.conf

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 00:06:49 +02:00
MacRimi 81844fa456 Update AppImage 2026-05-18 18:09:15 +02:00
MacRimi 4bedeb9fcd Update appimage 2026-05-18 17:47:25 +02:00
MacRimi ab5c7093eb Update AppImage 2026-05-10 05:19:36 +02:00
MacRimi b4e8c5101a Update AppImage 2026-05-10 05:11:51 +02:00
MacRimi 911886b90c Update AppImage 2026-05-10 05:00:00 +02:00
MacRimi c14b72456f Update AppImage 2026-05-10 04:46:33 +02:00
MacRimi 6d7e06a0d2 Update AppImage 2026-05-09 23:37:46 +02:00
MacRimi 0288c14a29 Update AppImage 2026-05-09 23:22:45 +02:00
MacRimi 748334eed6 Update beta_version.txt 2026-05-09 19:10:56 +02:00
MacRimi 07301ea599 Update beta_version.txt 2026-05-09 19:10:05 +02:00
MacRimi 2f919de9e3 update beta ProxMenux 1.2.1.1-beta 2026-05-09 18:59:59 +02:00
MacRimi 5ed1fc44fd Update 1.2.1.1-beta 2026-05-09 18:31:47 +02:00
MacRimi da2e89bc94 Create CHANGELOG.md 2026-04-21 21:22:34 +02:00