Stable releases of October 8, 2026¶
Everything that shipped on the stable channel on October 8, 2026 — v2.10.11 through v2.10.12, newest first. v2.10.12 is what you install; the versions below it are how you get there.
Stable v2.10.12¶
- fix(agent): make #846's slice tests run without root
- merge: the controller pushes each site's real slice limits from DB truth at startup, so one missed push no longer lasts forever
- merge: a provisioning placeholder no longer cements itself into the slice limits, neither in the cache nor in the unit
- merge: the admin delete buttons have a name, and the blocklist dialog stops answering in German regardless of the chosen language
- fix(agent): an unconfirmed slice call must not touch a unit that already exists (#846)
- fix(settings): add accessible names to remaining admin-only delete buttons
- fix(agent): don't let a provisioning placeholder cement itself into the slice-limits cache (#846)
- fix(packages): reconcile slice limits from DB truth at controller start
- merge: the customer dashboard stops pitching a bigger package over a single throttled window
- fix(dashboard): gate customer upsell tile on sustained throttle, not a single window
- merge: deleting a backup schedule keeps the key its repository needs, so the next schedule can still read the old snapshots
- merge: the icon-only delete and revoke buttons a customer sees have a name a screen reader can read
- merge: a malware hit from another tenant's tmp is no longer this site's finding, and a skipped file is no longer counted against a server-wide tally
- fix(malware): the coverage check derives its numbers from one webroot pass, not maldet's tmp-inclusive tally
- fix(malware): a scan attributes a finding to this site only when it is actually this site's
- merge: whether an invitation leaves the server is written down, not inherited from an upstream default
- fix(groupware): the appointment notification setting is written down instead of inherited from an upstream default
- merge: a malware scan that skips files says so, per reason, instead of claiming a clean pass
- fix(malware): the skip reason is three numbers the UI composes, not a German sentence from Go
- fix(malware): a scan that skips files reports it instead of claiming a clean pass
- merge: a single 700ms throttle tick no longer warns the customer or pitches a bigger package — only sustained throttling does
- merge: reporting a malware finding as a false positive no longer hides it from the operator, the score or a later payload at the same path
- fix(settings): add accessible names to icon-only revoke/delete buttons
- fix(malware): the message for a finding without a content checksum names the limit of its own advice
- fix(resources): decide CPU-throttle Now vs Sustained in one place, not per surface (#843)
- fix(backup): a repository key outlives the plan it belonged to, and an existing repository is never assumed to be ours
- fix(malware): a false alarm is reported with a reason and bound to the file content, not clicked away
Stable v2.10.11¶
- merge: deleting a site removes its per-user residue, including the waf exclusions a same-named successor would have inherited
- fix(delete): a removed site takes its tmp directory, its WAF exceptions and its PrestaShop includes with it
- fix(wordpress): a live check that cannot read the installation no longer wipes its cached version, title and URL
- merge: a failed backup is retried three times inside its period, and the advisor names a day without one
- feat(backup): a failed schedule run gets up to three attempts with a growing delay, and an exhausted period is visible without searching the history
- merge: the a11y gate scans the two toolkit detail pages, and a missing site url is a dash instead of a nameless link
- fix(a11y): the WordPress and Joomla detail pages no longer render a linkless when no site URL is known
- merge: the retention gate and the history share one predicate, and cascade deletes name what they take with them
- merge: a screenshot gets its own working dir on disk, and the agent clears what older versions left in tmpfs
- fix(screenshot): chromium captures get their own non-tmpfs profile directory, cleaned up after each run
- merge: clamav reloads its database without holding two engines, and a memory cap bounds what is left
- fix(malware): disable clamd's own double-engine reload, which was the real cause of the memory spike
- fix(backup): history rows of snapshots that still exist are not history, and a cascading delete names the schedules it destroys
- merge: the wordpress import wizard is translated in thirteen languages
- merge: the settings namespace is translated in thirteen languages
- fix(i18n): translate the WordPress import wizard across 13 languages
- merge: an import asks the agent whether a site exists instead of guessing from the error text
- fix(import): whether a website reached the server is asked of the server, not read out of the error text
- merge: reading a backup repository key needs the password again, and replacing it names the loss
- fix(i18n): translate the 11 single-word repairSystem labels the untranslated guardrail cannot see
- fix(import): a website the agent refused to create is named as such, with what to do about it
- fix(backup): reading or replacing a repository key asks for the password again and is logged
- fix(i18n): translate the remaining English copies in settings.json across 13 languages
- fix(release): a change to the a11y gate itself makes the gate run
- fix(malware): clamav-daemon gets a memory ceiling, so a signature reload kills only itself
- merge: the a11y gate keeps chromium's caches inside its own work dir and on disk, not in tmpfs
- fix(a11y-gate): scope Chromium's caches and browser profile into the run's own work dir, prefer a disk-backed tmp root
- merge: a space check on a tmpfs path is capped by what the machine really has free
- fix(backup): the room check on tmpfs is bounded by real free memory, not the tmpfs quota
- merge: the german restore report says wiederhergestellt throughout
- merge: the uptime mail names its time zone, and a dead rate-limit formatter is gone
- merge: the stall watchdog gives the upload tail its own budget, and the docs name what lftp and ssh already do
- docs: CLAUDE.md carries invariants and signposts, domain knowledge moves to docs/
- docs: drop the three hand-kept code inventories and the dead path that made reading them mandatory
- merge: a backup checks what the panel says must be in the snapshot and reports what is not
- fix(backup): a gap is read again over two minutes before it counts, so a deletion that takes a while no longer makes a healthy run incomplete
- feat(backup): the incomplete view words an expected item per kind in all 15 languages, and the note states when the check can raise a false alarm
- fix(backup): the expectation leaves out what the records place on another server and names a certificate by its lineage path
- feat(backup): a run reports what the panel expected in the snapshot and it lacks, and settles each gap against the records before it counts
- merge: a backup target on the customer's own host must carry its own credentials, and saving one without them is refused
- fix(backup): a schedule that points at its own host must carry its own credentials, saved or refused up front
- merge: an ftp backup no longer installs a package mid-run, and lftp's own timeouts are nailed down by a test
- fix(backup): a missing lftp stops an FTP operation with a message instead of being installed in the middle of it
- merge: a forged mail snapshot cannot set ownership, setuid or device files in a maildir
- Merge branch 'main' of https://git.netcell-it.de/projekte/netcell-webpanel
- merge: punctuation guardrail, typography, restore wording and the setup wizard in six languages
- fix(backup): a mail restore no longer trusts a forged snapshot's device nodes, setuid bits or escaping symlinks
- fix(i18n): the untranslated guardrail's baseline can only shrink — --update refuses to add, --accept-new with a reason is the one way in
- fix(i18n): the first-run setup wizard is translated in Spanish, French, Italian, Dutch, Polish and Turkish
- feat(i18n): a guardrail for English copies in the other languages — a ratchet with a baseline of 1361, new copies fail the release gate
- fix(i18n): the onboarding was an English copy in six languages — 24 of 45 texts, including 'Package created!' and 'Customer Created!', are translated in es, fr, it, nl, pl and tr
- merge: a forged certbot renewal conf can no longer carry root hooks into a restore
- fix(backup): the watchdog gives the upload tail its own budget and keeps the scan phase strict
- fix(backup): a restored renewal config can't smuggle a root hook past certbot's own timer
- fix(backup): normalize what a forged restore snapshot can set inside the customer's web root
- feat(i18n): fail the release on punctuation the language does not allow
- fix(i18n): French no-break spaces, Chinese and Japanese full-width signs in every file, not only the backup texts
- Merge remote-tracking branch 'origin/fix/ja-restore-term' into fix/typography-source
- fix(i18n): one dash in every language, French protected spaces and the Japanese colon in the whole backup file
- fix(i18n): French uses protected spaces before colon, semicolon and question mark in the backup texts, Chinese and Japanese use their own dash and colon
- fix(i18n): German says wiederhergestellt for restoring in the restore report as everywhere else
- fix(i18n): Japanese says 復元 for restoring a backup everywhere instead of mixing it with リストア
- refactor(acme): remove the rate-limit message formatter nothing calls
- fix(uptime): the outage mail names its time zone, taken from the same source as the schedules
- merge: schedule hours name the panel server's zone, and the retention text is one key per language
- merge: a restored customer config is checked by directive and path, not by bytes
- merge: the stall watchdog judges progress by restic's own counters
- fix(backup): a customer config restore refuses vhost and include files that leave the customer's area, naming file, line and directive
- fix(backup): the stall watchdog judges a run by restic's own progress counters instead of the bytes it moves
- fix(i18n): the retention of a schedule is one key with the number as a parameter in every language
- merge: the audit log names the acting person and reports schedule times in the schedule's zone
- merge: backup quick view, log ordering and pool rendering from the panel
- feat(audit): the log sorts on the server by the columns the endpoint allows, and the user column names a person, a system process or only an id
- fix(audit): the audit log names the acting person
- feat(backup): the count of older snapshots names its source and time, and deleting history entries says the backups stay
- fix(backup): a restore report counts databases, not problems, and a config-only restore no longer claims files and databases came back
- fix(backup): the quick view of the snapshots no longer reports zero legacy snapshots where the repository holds them, and says where its count comes from
- fix(logs): the audit log and the notification log list the newest entries first unless an order is asked for
- fix(prestashop): a direct link to one installation opens it instead of saying there are none
- fix(a11y): ten of seventeen settings sections had unnamed switches, inputs or a low-contrast tag, and the gate only ever scanned the default section
- fix(backup): after a config restore the customer's PHP pool is rendered from the panel instead of being read from the snapshot
- Merge: a full restore works again, and a stalled run that only prints status is stopped
- fix(backup): a full restore no longer mixes include and exclude patterns, which restic refuses
- fix(backup): a customer's mail and full restore carries the customer's own mail domains, so it no longer refuses every domain
- fix(a11y): the tab bar of the toolkit detail pages is a valid tablist, switches and the Joomla language select have names
- fix(backup): restic's own status heartbeat no longer counts as a sign of life, so a silent blackhole is ended
- feat(backup): a waiting or running backup can be canceled, status 'canceled' is neutral, the active-task card meets contrast
- feat(audit): changes to backup schedules, keys and snapshots are readable, credentials show only that they changed
- Merge: the rest of the backup audit — what a restore may write, what a dump may do, and what gets deleted
- feat(backup): a queued or running backup can be canceled, ends as canceled instead of failed, and is on record
- fix(backup): a restore is watched for stalls, waits for live locks and reads restic's summary
- fix(backup): destroying or shortening a backup is on record, and lowering the retention below what exists needs a confirmation
- fix(backup): an older panel's database restore is refused with the reason instead of leaving a database nobody can open
- fix(backup): a schedule's hour is read in the panel host's time zone instead of UTC
- fix(backup): database dumps carry routines and events, and PostgreSQL privileges granted to the customer's own roles come back
- fix(backup): a database dump is imported behind the client's sandbox, under an account that reaches one database, and with the owner decided by the panel
- fix(backup): a scope with nothing to back up ends quietly instead of as a failed run
- fix(backup): a schedule's retention counts only its own planned runs, back up now keeps a pool of its own, and older snapshots are listed instead of silently outliving the rule
- fix(backup): the platform's global sieve script is no longer part of a customer's snapshot
- fix(backup): a customer's restore writes only that customer's own files, and a restored config that fails its test is rolled back
- fix(backup): a run that left databases out is incomplete instead of success, and a restore no longer suppresses the day's planned backup
- feat(backup): a restore reports its outcome as stable codes the panel can translate
- feat(backup): a job also reports what the run backed up, next to the repository growth
- fix(backup): a blackholed target is cut off after a quiet window, CPU alone no longer counts as life
- docs: the target-change note records the decided path rule, the closed applyUpdate finding and the worker test gap
- fix(backup): a target change is judged on the resulting schedule and the operator's credentials go only to the operator's host; restore and browse inputs are checked where they are used
- docs: say what the a11y gate does not look at
- feat(backup): schedules name their time zone with a one-time notice, lowering the retention needs a typed confirmation, new restore codes
- fix(ui): a failed user list, cache status or app restart says so instead of looking empty or done
- fix(ui): a delete or mail-migration status poll that can no longer be answered ends with a sentence instead of running forever
- feat(backup): snapshots show their retention pool, older unassigned ones are listed apart with per-snapshot delete, job status 'nothing' is neutral
- feat(backup): config parts of a restore report are named and say they were rolled back
- feat(backup): an incomplete run sits between success and failure and names what is missing, prune_failed is no longer shown as pending
- fix(backup): reject a weak fallback repo key, mask the S3 access key, redact job errors for customers
- fix(backup): reject flag-shaped browse paths and bound full-restore to known backup directories
- feat(backup): a run shows what it backed up and what it added, a restore that stopped says which databases are back