-
v2.1.0 Stable
released this
2026-08-04 23:17:31 +00:00 | 0 commits to main since this releaseHighlights
- Remote shell jobs — administrators can queue arbitrary shell commands
(or one-click presets) against a kiosk from the admin UI; the device runs
them as root and reports back the exit code and output. Off by default,
per device. - Touchscreens now follow screen rotation — touch input is re-mapped
withxinput map-to-outputafter every rotation, at cold boot, and when
a USB touchscreen reconnects. - Agent startup crash fixed — the 2.0.0 agent could crash on launch
with"'http' is not a package"due to asys.pathshadowing bug. - Image fixes for real-world hardware — NTP time sync for devices with
dead RTC batteries, and AMD GPU firmware so rotation works on AMD APUs.
No breaking changes. 2.0.0 agents keep working against a 2.1.0 server —
they simply ignore the newjobsfield in check-in responses. Remote shell
jobs require a 2.1.0 agent and an explicit per-kiosk opt-in.Upgrading already-deployed kiosks: the agent package now depends on
xinputandx11-xserver-utils, soapt install --only-upgrade kioskos-agentpulls the touch-mapping tools onto devices imaged before they
were in the ISO. For the image-level fixes (time sync, AMD firmware) run the
one-shotscripts/hotfix-amd-firmware-timesync.sh
on each device — idempotent, and it reboots only when the GPU fix requires it.
Control (Django control server)
Remote shell jobs
- New
KioskJobmodel and full job lifecycle:pending → running → succeeded / failed / timed_out, pluscancelled(before delivery),
expired(not delivered within the 1-hour TTL — a device unplugged for a
fortnight must not come back and run last month's upgrade), andlost
(delivered but no result within timeout + grace, e.g. the command rebooted
the device). - Jobs are pulled, not pushed: the server holds them until the device's
next check-in, so the feature works for kiosks behind NAT on customer
networks. Delivery latency is bounded by the check-in interval. - Each job is handed out exactly once — rows are claimed with a
compare-and-swap onstatus, so two racing check-ins cannot both be told
to run the same command. Up to 5 jobs are delivered per check-in. - Named presets for routine fleet operations: update all packages,
upgrade the agent, restart the agent, reboot, report disk usage, tail the
agent journal.rebootandrestart_agentdetach and delay so the job
can report success before taking the agent down with it. - Off by default: a new per-kiosk
shell_enabledflag gates both
queueing and delivery. The agent runs jobs as root, so the capability is
granted deliberately per device, never fleet-wide. - Kiosk detail page grew a shell job panel: queue a preset or a custom
command, watch status, and read captured stdout/stderr; jobs not yet
delivered can be cancelled. - Expired/lost transitions are applied lazily on the check-in and job-list
paths — the deployment has no worker process, and check-in is the only
clock the server can rely on. - Every queue, delivery, and completion is recorded as a
KioskEvent
(newjobevent type), so the audit trail shows what ran where, who
asked for it, and how it ended. Thecreated_byadmin is kept even if
the account is later deleted. - Output is truncated server-side at 64 kB per stream (keeping the tail,
where failures explain themselves) as a backstop behind the agent's own
32 kB cap. - Test suite extended with full coverage of queueing, claiming, result
reporting, cancellation, expiry/lost reaping, and permission boundaries.
KioskOS Agent (
kioskos-agent2.1.0)Remote shell jobs
- New
agent/shell.pyjob runner: jobs execute on a dedicated worker
thread, one at a time — a ten-minute package upgrade must not freeze the
check-in loop, which is also the dead-browser watchdog; serial execution
keeps twoaptruns from fighting over the dpkg lock. - Commands run via
bash -cin their own process group (a timeout
SIGTERMs, then SIGKILLs the whole tree, not just the shell), with stdin
closed (anything that prompts fails fast instead of hanging) and a fixed
environment (DEBIAN_FRONTEND=noninteractive, sanePATH,
LC_ALL=C.UTF-8). - Captured output is capped at 32 kB per stream, keeping the tail.
- Results that cannot be posted (device offline) are held and retried
on later check-ins, bounded to the 50 most recent. - Device-side veto: a new
shell_enabledkey in
/etc/kioskos/config.json(defaulttrue) lets an operator mark a
device as never accepting remote commands regardless of what the control
server says; refused jobs report exit code 126 so the admin sees a reason
instead of a job that silently never finishes. - On shutdown the runner stops taking new jobs but lets a running job
finish — interrupting an upgrade mid-dpkgwould be worse than losing
the result. New test moduletests/test_shell.py.
Touchscreen rotation (2.0.1)
- Fixed touch input staying in the panel's native orientation after screen
rotation:set_orientation()now re-maps every calibratable touch device
onto the rotated output viaxinput map-to-output. Touch devices are
identified by the libinputCalibration Matrixproperty, so mice and
other relative pointers are never affected. - The agent package now depends on
xinputandx11-xserver-utils— the
toolsdisplay.pyactually shells out to — so upgrading the package
pulls them onto devices imaged before they were added to the ISO.
Startup crash & self-update fixes (2.0.2)
- Fixed an agent crash on startup (
No module named 'http.client'; 'http' is not a package): the service ran with
WorkingDirectory=/opt/kioskos/agent, andpython -mputs the working
directory first onsys.path, so the agent's ownhttp.pyshadowed the
stdlibhttppackage thatrequestsimports. The service now runs from
/opt/kioskosand setsPYTHONSAFEPATH=1so the working directory can
never leak ontosys.pathagain. - Self-update now refreshes all apt sources instead of only the kioskos
repo — dependencies introduced by a new agent version come from the
Debian repos, which ISO-imaged devices have no cached lists for — and
tolerates a skewed clock during the refresh (dead RTC batteries make apt
reject Release files as "not valid yet").
Multi-display & cold-boot touch mapping (2.0.3)
- Touch devices are no longer all mapped to the primary output: one display
gets every touch device (the common kiosk); equal counts of touch devices
and displays are paired deterministically (device IDs ascending, outputs
left-to-right); a count mismatch falls back to the primary output with a
warning. Mirrored layouts share one rectangle, so any pairing is correct
there. - Fixed touch mapping not applied on cold boot: the agent rotates the
screen as soon as the X socket exists — before Xorg has enumerated input
devices via udev — so there was nothing to map yet. A startup thread now
polls for touch devices and maps them as soon as they appear, and the
check-in loop re-applies mappings every cycle, so a USB touchscreen that
reconnects mid-session heals within one interval instead of staying on
the identity matrix.
KioskOS OS (image & build system)
systemd-timesyncdadded to the image and enabled at provision time:
kiosks often have dead RTC batteries, and a skewed clock breaks both apt
("Release file not valid yet") and TLS to the control server.firmware-amd-graphicsadded: without it theamdgpudriver cannot
load on AMD APUs, X falls back to the EFI framebuffer, and screen
rotation is unavailable.xinputadded for the agent's touch-input remapping.- New one-shot hotfix script
(kiosk/scripts/hotfix-amd-firmware-timesync.sh) brings already-deployed
devices in line with the image fixes above — idempotent, fleet-friendly
over SSH, and reboots only when the GPU fix requires it (--no-rebootto
suppress). - Calamares installer branding now reports the real product version
(2.1.0 — it had still claimed 1.0.0). ARCHITECTURE.mddocuments the full remote shell job design (lifecycle,
the two-switch permission model, endpoints, and device-side execution).
Protocol (agent ↔ server API
v1)New in check-in responses
jobs: an array of{id, command, timeout, preset}shell jobs
claimed by this check-in. Each job appears in exactly one response.
Absent/empty for kiosks withoutshell_enabled; older agents ignore it.
New endpoints
Endpoint Auth Purpose POST /api/v1/jobs/{id}/result/device token Device reports exit_code,stdout,stderr,duration_seconds,timed_out.POST /api/v1/kiosks/{uid}/jobs/admin session Queue a job ( commandorpreset, plus optionaltimeout,expires_in).GET /api/v1/kiosks/{uid}/jobs/admin session Job history for a device, filterable by status.GET /api/v1/jobs/{id}/admin session One job with its captured output. POST /api/v1/jobs/{id}/cancel/admin session Cancel an undelivered job ( 409once it has been handed out).GET /api/v1/job-presets/admin session Named commands offered by the UI. Security model
- The result endpoint is scoped to the reporting device — a kiosk can
only close out a job that was handed to it, so a leaked device token
cannot forge results for the rest of the fleet. - Queueing requires an admin session; a device token is refused, so a
compromised kiosk cannot queue work for itself. - Two switches, both required: the server-side per-kiosk
shell_enabled
flag (default off, checked at queue time and delivery time) and the
device-sideshell_enabledconfig key (default on, the operator's veto).
- Remote shell jobs — administrators can queue arbitrary shell commands
-
v2.0.0 Stable
released this
2026-07-26 03:28:30 +00:00 | 2 commits to main since this release⚠️ Breaking changes & upgrade notes
2.0.0 is a breaking release. Devices no longer self-register.
- An administrator now creates each kiosk in the control server and issues a
one-time enrollment code, which the device redeems for its auth token. - Agents older than 2.0.0 cannot enroll against a 2.0.0 server.
- Already-enrolled devices keep their tokens and keep checking in, but must
be re-imaged (or upgraded and re-enrolled) to obtain browser sessions
— kiosk pages now authenticate to terminal APIs through a device-session
cookie that only 2.0.0 agents can obtain. - The standalone
kioskos-browser.serviceunit is gone. Upgrading via
install.shdisables and removes the legacy unit, its generated
start-browser.shlauncher, andbrowser.env. The agent is now the only
browser launcher.
Upgrade path: deploy the 2.0.0 control server first (existing devices
continue to check in), then roll out 2.0.0 images/agents and enroll each
device with a fresh code.
Protocol (agent ↔ server API
v1)Breaking
POST /api/v1/register/now requiresenrollment_code. Anonymous
self-registration is removed; every other field in the request is
self-asserted, recorded for inventory only, and never trusted. Unknown,
expired, and redeemed codes all return the same403.
New endpoints
Endpoint Auth Purpose POST /api/v1/browser-grant/device token Mint a single-use URL (2-minute expiry) that sets an HttpOnlydevice-session cookie and redirects to the target page. Off-originnext=values are discarded.GET /api/v1/setup/status/·POST /api/v1/setup/public (one-shot) First-boot onboarding: report whether an admin exists / create the first admin. POST /api/v1/auth/login/·/logout/·GET /auth/me/session Admin UI session authentication. POST /api/v1/kiosks/{uid}/enrollment-code/admin session Issue a fresh one-time enrollment code. POST /api/v1/kiosks/{uid}/command/admin session Queue a one-shot reload_browser/restart_browsercommand.Response & field changes
- Registration, check-in, and config responses now carry
screen_orientation(normal/left/right/inverted—
values pass straight through toxrandr --rotate). - Check-in responses carry
command: the pending one-shot command,
delivered exactly once (the server clears the slot in the same request).
Empty string when none is queued. Delivery latency is bounded by
checkin_interval(default 60 s). config_updatedis derived from adminconfig_updateevents newer than
the device'slast_seen_at.
Security model
- Devices authenticate with
Authorization: Token <token>; the token is
minted only by redeeming an enrollment code and never enters the browser. - Admin endpoints use session auth with CSRF protection; registration,
login, and setup are rate-limited.
Control (Django control server)
New admin web UI
- Complete Angular + PrimeNG single-page admin interface replacing raw API
usage: login page, kiosk list with live online/offline/unenrolled status,
kiosk detail with a full configuration form, and an event history table. - Kiosk lifecycle from the UI: create (returns an enrollment code to hand to
the installer), edit, delete, re-issue enrollment codes, and queue
remote browser actions. - First-boot onboarding page: a fresh install walks the operator through
creating the initial admin account.
Enrollment & authentication
- One-time enrollment codes (
XXXX-XXXX-XXXX): human-typeable alphabet
that drops easily-misread characters (O/0, I/1, S/5, Z/2), 7-day expiry,
single-use, and unique per kiosk. Re-issuing a code never invalidates a
working device token, so it cannot knock a kiosk offline. - Registration rejects unknown, expired, and already-redeemed codes with an
identical response, so the endpoint cannot be used to probe which codes
exist. - First-boot setup endpoint (
/api/v1/setup/) is open only while no admin
exists, then permanently closed. - Session-based auth endpoints for the admin UI (
/auth/login/,
/auth/logout/,/auth/me/) with CSRF protection. - Rate limiting on registration, login, and setup endpoints.
Device management features
- Browser session grants: the server mints single-use, short-lived grant
URLs that give the kiosk browser anHttpOnlydevice-session cookie —
the device token itself never reaches the browser. - Screen orientation per kiosk (
normal,left,right,inverted),
editable in the admin UI and delivered to the device with every
registration and check-in response. - One-shot remote commands: admins can queue
reload_browseror
restart_browserfrom the kiosk detail page. The command is delivered on
the device's next check-in and cleared atomically, so it fires exactly
once; queueing a new command replaces a pending one. - Every admin config change and queued command is recorded as a kiosk event
and drives theconfig_updatedflag on the next check-in.
Operations
- Dockerfile and entrypoint reworked: migrations, static file collection,
and Gunicorn startup are handled on container boot. - Test suite expanded to 47 tests covering enrollment, check-in, commands,
orientation, onboarding, and admin auth.
KioskOS Agent (
kioskos-agent2.0.0)Enrollment & sessions
- Registration redeems the admin-issued enrollment code; the agent no longer
invents its own identity. Clear operator-facing errors distinguish a
missing code from a rejected one. - Registration is retried from the check-in loop rather than only at
startup, since it can now legitimately fail on a bad or expired code. - Before each browser launch the agent exchanges its token for a browser
grant URL, giving kiosk pages a device session without ever exposing
the token to Chromium. If the grant cannot be obtained the agent falls
back to the plain URL (a visible page beats a blank screen) and marks the
launch degraded.
Reliability (white-screen fixes)
- The agent waits for the X display before the first browser launch —
previously Chromium could start into a not-yet-existing display and die
with nothing to relaunch it. - A degraded launch is self-healing: on the first successful check-in
after launching without a session (network still coming up, grant
refused), the agent restarts the browser with a fresh grant instead of
waiting for a URL change. A degraded first launch also triggers an
immediate check-in rather than sleeping a full interval. - Dead-browser watchdog: every check-in cycle (even while offline) the
agent relaunches Chromium if its process has died — including browsers
that outlived an agent restart. - Stale Chromium
SingletonLockfiles are removed before launch and the
user-data directory ownership is corrected, eliminating silent
fails-to-display after crashes.
Display & kiosk behavior
- Screen orientation is applied with
xrandr— at boot before the
browser launches (so the fullscreen window sizes itself to the rotated
geometry) and at runtime on change, followed by a browser restart. The
setting persists locally and survives offline reboots. - Remote commands:
reload_browserperforms a SIGHUP page reload;
restart_browserkills and relaunches Chromium with a fresh session. - Chromium now launches with kiosk printing enabled and media-stream
permission prompts auto-accepted.
Setup wizard
- The wizard cannot complete without a saved configuration: cancelling
or failing any step returns to the previous menu or offers a restart, and
the.setup-completemarker is written only after the config is
confirmed and saved. DHCP and static-IP failures now offer
retry / go back / continue-anyway, matching the existing WiFi flow. - New
kioskos-setupcommand re-runs the TUI wizard from any console,
VT, or SSH session and restarts the agent on success; the wizard prints
that recovery hint on any abnormal exit.
Security
/etc/kioskos/config.jsonis written0600with atomic replace — since
2.0.0 it holds a real credential that gates terminal APIs.- Single browser launcher: the legacy
kioskos-browser.service+
start-browser.shpath is removed (it raced the agent, restarting old
browser instances the agent had just killed).
KioskOS OS (image & build system)
Installer & first boot
- The GRUB "Install KioskOS" entry no longer runs the TUI setup wizard
or the agent inside the live installer session — configuration made there
landed in the tmpfs overlay and never propagated into the installed
system, and a registration attempt would have burned the one-time
enrollment code. Setup now runs on the installed system's first boot. - USB config preload (
kioskos-preload): first boot searches a
KIOSKOS-CONFIG-labeled partition, removable media, and/bootfor a
pre-provisionedkioskos-config.json, validates it, applies the network
settings, and skips the wizard — enabling zero-touch mass deployment. - The setup service no longer marks setup complete on its own
(ExecStartPostremoved); completion is owned by the wizard itself.
Boot ordering & session
kioskos-agent.servicenow orders afternetwork-online.target
(withNetworkManager-wait-onlineenabled), so the browser is not
launched against a dead network.- Mouse cursor auto-hides after 10 seconds of inactivity
(unclutter-xfixes), in kiosk mode only — the installer session keeps a
normal cursor. - The dead XFCE autostart browser entry and
browser.envwere removed from
the overlay; the agent is the single browser launcher.
Build system
- GRUB packages switched to the
-binvariants (grub-pc-bin,
grub-efi-amd64-bin,grub-efi-arm64-bin) to avoid postinst conflicts
inside the chroot build, for both amd64 and aarch64. - Intel/AMD CPU microcode included on amd64 images.
- Added
x11-xserver-utils(providesxset/xrandr) and
unclutter-xfixesto the image package set. - The overlay-shipped
/etc/kioskos/config.jsonis locked to
root:root 0600in the image. - Documentation (
README,ARCHITECTURE.md) updated to match the real
boot flow and 2.0.0 security model.
- An administrator now creates each kiosk in the control server and issues a
-
v1.0.0 Stable
released this
2026-06-08 04:27:21 +00:00 | 16 commits to main since this release -
v0.1.0 Stable
released this
2026-05-23 04:10:33 +00:00 | 39 commits to main since this releaseProof of concept release.