Commit Graph
2813 Commits
Author SHA1 Message Date
dependabot[bot] 93f6926c89 Bump the actions group with 9 updates
Bumps the actions group with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `7` |
| [actions/setup-python](https://github.com/actions/setup-python) | `5` | `7` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4` | `7` |
| [actions/setup-node](https://github.com/actions/setup-node) | `4` | `7` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `4` | `8` |
| [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3` | `4` |
| [docker/build-push-action](https://github.com/docker/build-push-action) | `5` | `7` |
| [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) | `3` | `4` |
| [docker/login-action](https://github.com/docker/login-action) | `3` | `4` |


Updates `actions/checkout` from 4 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v7)

Updates `actions/setup-python` from 5 to 7
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5...v7)

Updates `actions/upload-artifact` from 4 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

Updates `actions/setup-node` from 4 to 7
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v7)

Updates `actions/download-artifact` from 4 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

Updates `docker/setup-buildx-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

Updates `docker/build-push-action` from 5 to 7
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v7)

Updates `docker/setup-qemu-action` from 3 to 4
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/v3...v4)

Updates `docker/login-action` from 3 to 4
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/setup-qemu-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-10-11 19:50:13 +00:00
github-actions[bot] 72bd369bfe chore: bump version to 1.11.20 [skip ci] 2026-10-11 04:59:48 +00:00
Juan Denis b86c03dc6b Don't 500 on uptime stop when its data dir is unwritable
Stop now persists the tracking flag, and the save created the data
directory unguarded. Where that fails (an unprivileged host or CI
runner) the save is now logged and reported false, as its docstring
already promised, instead of raising.
v1.11.19-dev.b86c03d
2026-10-11 00:52:44 -04:00
Juan Denis 498901e70e Keep the panel booting when uptime can't resume
Resuming uptime tracking at boot read the history through a helper
that first created /var/lib/serverkit. The image runs unprivileged, so
that makedirs raised and the app never started. Reading now creates
nothing, and a failed resume is logged instead of aborting boot.
2026-10-11 00:50:14 -04:00
Juan Denis 6cfebf8a54 Let the load-average test run where os lacks it
Windows has no os.getloadavg, so patching it raised before the test
could run; create=True supplies the attribute.
2026-10-10 23:44:20 -04:00
Juan Denis 3e63a7f4b7 Use the platform's EAI_NONAME in the DNS test
The test raised errno -2, Linux's value, so on Windows (11001) the
check read it as a resolver failure and the test failed.
2026-10-10 23:44:00 -04:00
Juan Denis e49c627640 Let memoized file rows skip unrelated re-renders
FileRow and FileCard were wrapped in memo, but every handler passed to
them was re-created on each render, so a keystroke or a selection
re-rendered every row of a large directory. useStableHandler gives the
rows fixed handler identities that still run the latest code.
2026-10-10 22:38:21 -04:00
Juan Denis 540b86c445 Give each schedule picker its own field ids
The picker hardcoded ids like sp-hour, so two on one page (one per
schedule card) produced duplicate ids and every label pointed at the
first picker's field.
2026-10-10 22:35:53 -04:00
Juan Denis 73a93a7b36 Let labels name the resource and server pickers
The pickers dropped an id, so the five labels above them named
nothing. They now put it on the trigger button; clicking the label
opens the picker. Ratchet 46 -> 41.
2026-10-10 22:35:28 -04:00
Juan Denis f033edb70d Use the shared uptime formatter on monitor pages
Monitors and MonitorDetail each carried a copy of formatUptimePercent.
2026-10-10 22:28:16 -04:00
Juan Denis c7a50510c7 Format build and backup durations through intl
Three hand-rolled copies printed untranslated "3m 0s" and never
reached hours ("75m 0s"). They now use the intl formatter ("1h 15m",
in the panel language), keeping each caller's placeholder. The cron
and deploy-console formats with tenths of a second stay as they are.
2026-10-10 22:27:17 -04:00
Juan Denis a636f2cdb1 Ratchet unassociated form labels at 46
The rest head a group of options, sit over read-only text, or label a
picker that does not forward an id yet. A new label must name its
field.
2026-10-10 22:25:44 -04:00
Juan Denis 0adb6bf752 Tie form labels to their fields
156 labels named no field: no htmlFor and no control inside, so
clicking one did not focus the input and screen readers announced the
input without a name. Each now points at its field through a useId()
id. The change is additive only (ids and htmlFor), checked by comparing
tokens with the previous version.
2026-10-10 22:25:37 -04:00
Juan Denis f3145289c8 Time out version and status probes after 60s
--version, which, postconf, pip list/freeze and mailq had opted out of
the run_checked default with timeout=None, so a wedged binary held a
request thread forever. Installs, migrations, dumps and restores keep
no timeout.
2026-10-10 22:22:40 -04:00
Juan Denis 6400b76a7d Drop imports that shadowed module-level names
Function-local re-imports of User, WorkspaceService and secrets, and a
local list named secrets, hid the module names they duplicated.
2026-10-10 22:20:03 -04:00
Juan Denis adb9ae8fbb Open clickable rows and cards from the keyboard
A row with onRowClick could only be opened with a mouse or the j/k
cursor: it took no Tab focus and ignored Enter. Clickable rows in the
tables, the grid and the card view are now focusable and open on Enter
or Space, with a focus ring. Keys on a button inside the row still
reach the button, and the cursor listener skips a key a row handled.
2026-10-10 22:17:18 -04:00
Juan Denis 291b5df844 Document every panel environment variable
About 30 of the ~70 variables the backend reads were documented
nowhere: the encryption-key file, extension signing keys, the pip
opt-in, the setup-code pin. docs/ENVIRONMENT.md lists them all with
defaults, and a guard fails when the backend reads one it doesn't list.
2026-10-10 22:13:09 -04:00
Juan Denis f840744341 Drop an unused install-dir constant
disk_reclaim_service read SERVERKIT_DIR, which app/paths.py treats as
the /var/serverkit data root, and never used the value.
2026-10-10 22:10:27 -04:00
Juan Denis dc81185b7d Lower the JWT-only ceiling to 598
Two JWT-only routes were removed with the dead /system endpoints.
2026-10-10 22:05:38 -04:00
Juan Denis ca4bdb2236 Drop a needless exhaustive-deps disable
load is a useCallback with no deps, so listing it is exact.
2026-10-10 22:01:34 -04:00
Juan Denis 95a9e227fc Fix row deletes that read state from first render
The vault secret and variable-group columns were memoized without the
state their delete handlers read. Deleting a secret then refreshed a
null vault and reported failure; deleting a group variable sent group
null; deleting a group after a workspace switch reloaded the old
workspace's groups.
2026-10-10 22:01:16 -04:00
Juan Denis 89eb7fb2e3 Keep a server name typed during the pair lookup
The lookup's answer checked the name as it was when the code was
typed, so a name entered while it was in flight was overwritten with
the agent's hostname.
2026-10-10 22:01:08 -04:00
Juan Denis ada4d49ea4 Reload the file listing when the source changes
The listing effect watched only the path. Switching to a remote agent
that advertises no allowed paths keeps the path, so the panel host's
files stayed on screen under the agent's header, and edits went to
the agent against the wrong host's entries.
2026-10-10 22:01:06 -04:00
Juan Denis 05e651be9d Fail CI on undefined names in the backend
A name used before it exists only fails when that line runs, so a
rarely-taken branch ships broken. Two routes 500'd on every call and
Stop crashed on compose-slot apps, both found by pyflakes in seconds.
The check now runs in the ratchet job and in preflight.
2026-10-10 21:56:37 -04:00
Juan Denis bee7a4a1aa Fix stopping an app that deploys on compose slots
A function-local import of SlotDeployService further down
stop_application made the name local to the whole function, so the
compose-slot branch raised UnboundLocalError before reaching it: Stop
on such an app always failed. The module already imports the class.
2026-10-10 21:55:33 -04:00
Juan Denis 9d750a4f6f Remove the /system process and service routes
Both used psutil without importing it, so every call has been a 500
since they were written. Nothing calls them: the process list and
service status come from /processes and /processes/services.
2026-10-10 21:51:15 -04:00
Juan Denis 99a19c2fb7 Read 40 more route bodies through json_object()
The first pass left routes that hand the body straight to a service
(create_zone(data), MonitorService.create(data), ...). Those services
read it as a dict, so a body of null, [] or a bare string still
crashed them into a 500. Agent long-poll, external webhook receivers
and the routes that already type-check their body are left alone.
2026-10-10 21:48:18 -04:00
Juan Denis f00a60ac31 Pin the current release in install examples
The copy-paste examples pinned v1.7.0, a release with a known advisory.
2026-10-10 21:35:14 -04:00
Juan Denis 4011389942 Stop dev setup scripts installing gevent
The panel runs a plain threaded gunicorn worker and gunicorn is already
in requirements.txt; the extra gevent and gevent-websocket installs were
left over from the old worker class.
2026-10-10 21:35:14 -04:00
Juan Denis 61994b248e Trim history from the deploy preflight docstring 2026-10-10 21:34:02 -04:00
Juan Denis 95e2e6e6da Move extension zip fetching into plugin_fetch
GitHub release resolution and the SSRF-guarded download (redirect
re-validation, byte caps, token scoping) were 250 lines of
plugin_service unrelated to installing. plugin_service re-exports the
names its own code calls, so existing monkeypatches on it still land;
tests that exercised the fetch internals directly now target
plugin_fetch.
2026-10-10 21:32:19 -04:00
Juan Denis 3451d5ba2c Split TemplateService into mixin modules
template_service.py held port allocation, magic-variable resolution and
the template catalog alongside install/update in one 2,800-line class.
Those three groups move verbatim into TemplatePortsMixin,
TemplateMagicMixin and TemplateCatalogMixin, each in its own module;
TemplateService inherits them, so its surface (106 attributes, same
classmethod/staticmethod kinds) and every caller are unchanged. Tests
that patched module globals now patch the module the code lives in.
2026-10-10 21:10:14 -04:00
Juan Denis b35f6df97a Validate the journal priority parameter
The value went straight to a privileged journalctl -p. As its own argv
element it could not inject options, but anything other than levels
0-7 now gets a 400 instead of a journalctl error.
2026-10-10 20:54:45 -04:00
Juan Denis ec8cd9462e Bound Docker metadata reads with a timeout
ps, inspect, info, version, tag and the network/volume inspects ran
with timeout=None, so a wedged dockerd held every request thread that
asked, forever; the panel runs a single worker process. They now give
up after 30s, and the Containers page reports Docker unreachable.
Pull, build, logs and compose stay unbounded on purpose.
2026-10-10 20:54:12 -04:00
Juan Denis 55d8fb1e44 Read route bodies through json_object()
328 more routes used a JSON body as a dict straight from
request.get_json(), so a body of null, [] or a bare string crashed them
into a 500. Bare reads become json_object(); the
'get_json(silent=True) or {}' reads of action routes become
json_object(optional=True), which still treats a missing body as {}.
Routes that take arrays or pass the body through untouched are left
alone. The full backend suite shows no new failures.

Also carries three files' bare section citations (apps, backups,
notifications) and the extended citation guard, which needed them.
2026-10-10 20:53:43 -04:00
Juan Denis c07eb056ad Regenerate the migration inventory
The File Manager dialog extraction removed one raw API call, one toast
extraction and two hand-rolled form groups.
2026-10-10 20:53:33 -04:00
Juan Denis c98952b907 Load two stylesheets nothing imported; lint for orphans
The Coexistence page and the extension crash card were written with
their own stylesheets, but neither file was ever imported, so both have
always rendered without their layout. A new lint step,
check-orphan-files, fails on any src file nothing imports (SCSS
included) unless it is kept with a reason; it is what found these two.
2026-10-10 20:40:35 -04:00
Juan Denis 48aed13d65 Delete four more frontend files nothing imports
An app-detail SettingsTab and its shared helper left behind when the
page merged into service detail, a re-export shim nobody imports, and
an unused utility; with their 13 strings in every locale.
2026-10-10 20:38:41 -04:00
Juan Denis e0e1d271a4 Delete the dead query-runner stylesheet
420 lines styled a query runner component removed long ago. One of its
unscoped rules, .sidebar-section, was still sizing the File Manager
rail by accident; that rule moves into the File Manager stylesheet so
the compiled CSS for it is unchanged (compared before and after).
2026-10-10 20:36:51 -04:00
Juan Denis c7ea877d88 Send the journal priority filter to the API
Picking a priority in the Terminal's journal view highlighted the level
but never sent it, so the list was unfiltered. The API already filtered
on ?priority=; the client now passes it, with the fresh value rather
than the previous render's.
2026-10-10 20:33:12 -04:00
Juan Denis 84ac8684e3 Guard the remaining Docker tabs against stale loads
Volumes, Networks and Compose had the same two bugs fixed earlier in
Containers and Images: a late answer from the previously selected
server replaced the current list, and a failed load showed an empty
list (or the old one) instead of the error.
2026-10-10 20:31:25 -04:00
Juan Denis a7413e34fa Move File Manager dialogs into components
Four inline dialogs kept their open flags, targets and input values as
ten separate useState calls on the page. One dialog state now says which
is open, and NamePromptModal / PermissionsModal own their inputs; the
browser test drives all three flows and passes on the old code too.
The create-file dialog had no way to open it and is removed with its
strings.
2026-10-10 20:28:55 -04:00
Juan Denis ddaeb549ad Remove bare plan-section citations
Comments cited plan sections as "(§G3)" or "(§8 unification)", which
point into the same git-ignored plans the plan-number citations did.
References next to a real document (docs/REDESIGN_MAP.md §3) stay. Code
and runtime strings are unchanged (AST and token comparison).
2026-10-10 20:25:49 -04:00
Juan Denis e94537d0a4 Cut docstrings that narrate refactor history
The worst cases the audit named: docstrings and header comments that
told how three old copies drifted, or quoted subprocess counts that
were stale the day they were written, instead of stating the contract.
Each now says what the function does and keeps one line of why. Also
drops the always-zero n_cloud counter that existed only to keep a boot
log line's or-chain intact.
2026-10-10 20:21:00 -04:00
Juan Denis 78201eeefc Format dates and numbers in the panel's language
107 direct toLocaleString/DateString/TimeString calls followed the
browser's locale (or a hard-coded en-US/en-GB) instead of the language
the panel is set to, and built a formatter per call. They now go
through utils/intl (formatDate/Time/DateTime/Number), keeping each
site's components via parts. A missing date now renders the fallback
dash instead of "Invalid Date". Ratchet ceiling 115 -> 4.
2026-10-10 20:19:32 -04:00
Juan Denis 07b992704d Use the persistent-state hook in Terminal and Databases
Terminal's six log preferences and the Databases sidebar repeated the
same lazy localStorage read plus mirroring effect the File Manager
just dropped.
2026-10-10 18:53:51 -04:00
Juan Denis dac348596a Persist File Manager prefs through one hook
Six view preferences each had a lazy localStorage read plus a copied
mirroring effect. usePersistentState does both and tolerates storage
that throws, so the page no longer crashes on it; the panel as a whole
still needs storage for its auth tokens.
2026-10-10 18:53:01 -04:00
Juan Denis 166e9acabf Split servers.py into area modules
The 3,000-line file mixed core server routes with Docker, agent
install/update/fleet and remote host operations. Those sections move
verbatim into servers_docker, servers_agents and servers_remote on the
same blueprint; the registered route map (127 rules, methods and
endpoint names) is identical before and after.

The controller-boundary scan only treated files that create a
Blueprint as controllers, so an area module would have escaped it; it
now also counts files that register routes.
2026-10-10 18:49:59 -04:00
Juan Denis bf5405df9e Move the health check's database probe into a service
The previous commit ran SELECT 1 directly in the route, a new
persistence crossing in the API layer that the controller-boundary
ratchet rejects.
2026-10-10 18:48:53 -04:00
Juan Denis 7476e216b8 Add Dependabot updates targeting dev
There was no Dependabot config, and its default PRs to main fail the
promotion gate. Weekly grouped minor/patch updates for backend and
frontend, monthly for GitHub Actions, all against dev.
2026-10-10 18:35:00 -04:00