Repository navigation
What's Changed
thin-edge.io 2.1.0 focuses on the day-to-day work of operating a fleet: controlling the services on a device from the cloud, running shell commands without extra plugins, registering devices in a single step, and managing Hardware Security Modules (HSM) directly with the tedge CLI. It also makes connection errors easier to diagnose and adds new packaging and container options, including OpenWrt (ipk) packages and ready-to-use tedge-p11-server container images.
There are no breaking changes in this release, so upgrading from 2.0.x is a drop-in replacement.
All notable changes are documented in this file.
✨ Highlights
Service commands: start, stop, and restart services from Cumulocity - #4308, #4338, #4366, #4371
Until now, restarting a misbehaving service on a remote device meant opening a remote shell or deploying a custom operation. With 2.1.0, a Cumulocity operator can open Services > service name > Commands in the Device Management application and start, stop, restart, or run any custom action that the service supports. The result is reported back as a regular operation, so every action is visible in the device's operation history.
A service tells thin-edge.io which actions it supports by publishing a single retained message. The actions then appear in Cumulocity automatically:
tedge mqtt pub --retain 'te/device/main/service/nodered/cmd/control' '{"actions":["restart","pause"]}'The actions run through the new tedge service command, which you can also use locally on the device:
tedge service restart noderedBy default, tedge service uses the init system configured in system.toml (for example systemd or OpenRC). For anything else, such as containers or applications with their own lifecycle, you can write a small service plugin and use a custom service type, so that custom actions like pause or reload-config are just as easy to add.
To support this, workflows can now handle several operations from a single definition and can run individual scripts through sudo using sudo = true, which keeps custom workflows short and avoids broad sudoers rules.
See the docs for more details:
- Service commands from Cumulocity
- Service control MQTT API
- tedge service CLI and the Service Plugin API
- Workflow features: one workflow for several operations and running a script with elevated privileges
Cumulocity Shell (Command) operation supported out of the box - #4323
The Cumulocity Shell tab now works on every thin-edge.io device without installing anything extra. Enter a command such as uptime or df -h, and the combined output is reported back as the operation result.
This replaces the community tedge-command-plugin with a native implementation that has several improvements:
- No extra dependencies:
jqand other tools are no longer needed, and the output is always correctly escaped - Safe on constrained devices: the output size is capped (
shell.max_output_size) and long-running commands are stopped after a timeout (shell.timeout, 10 minutes by default), so a command liketail -fcan no longer block the operation queue - Restart safe: a command that restarts the
tedge-agentor the device is never run a second time when the agent comes back up - Better failure reasons: a failed command reports its last line of output as the reason, not only the exit code
The feature is enabled by default. It can be turned off with tedge config set agent.enable.shell_execute false, or only the Cumulocity mapping can be disabled with tedge config set c8y.enable.shell_execute false. If you have the community package installed, the deb and rpm packages replace it automatically; see the migration notes in the docs.
The underlying shell_execute command is cloud agnostic, so it can also be triggered locally over MQTT.
Check out the Execute Shell Command documentation for the configuration options and security considerations.
Register a device with a single command and a clickable URL - #4296
Registering a device with the Cumulocity Certificate Authority is now quicker and more secure. tedge cert download c8y generates a random one-time password and prints a registration URL with the device ID and password already filled in:
$ sudo tedge cert download c8y --device-id "my-device-01"
Register the device on example.cumulocity.com:
device id: my-device-01
one-time password: CTodKOt02iaKIp6s9gTkECS5rkq0vnxv
Open the following URL to register the device:
https://example.cumulocity.com/apps/devicemanagement/index.html#/deviceregistration?externalId=my-device-01&one-time-password=CTodKOt02iaKIp6s9gTkECS5rkq0vnxv
Waiting for the device to be registered ...Open the link in a browser and complete the form. The command keeps polling in the background and stores the device certificate as soon as the registration is complete, so there is nothing to copy between the device and the browser.
You can still provide your own password with --one-time-password, or enter it without echoing it to the terminal using the new --prompt flag. Use --no-registration-url if the command output is logged.
See Registering a device from the device for the full walkthrough.
Manage your HSM with tedge hsm - #4287, #4311, #4239, #4330
Storing the device's private key in a Hardware Security Module (HSM), such as a TPM 2.0, is the most effective way to protect a device's identity. In previous releases, setting up the token still required vendor tools such as p11tool or pkcs11-tool. With 2.1.0, the full lifecycle of a PKCS #11 token is covered by tedge hsm:
| Command | What it does |
|---|---|
tedge hsm init |
Initialize a token. It selects the slot automatically, can be run again safely, and prints the token URI for use in scripts |
tedge hsm list-tokens |
List all available tokens with their PKCS #11 URIs (no PIN required) |
tedge hsm list-keys |
List the keys stored on a token |
tedge hsm create-key |
Create a key. It now reuses an existing key with the same label, so provisioning scripts can be run again safely (use --force-new to always create a new key) |
tedge hsm change-pin |
Change the user PIN, or reset it with the SO PIN, and keep device.cryptoki.pin in sync automatically |
tedge hsm delete-key |
Delete a key. It refuses to delete a key that is still configured unless --force is used |
When an HSM is configured, tedge cert download c8y also creates the private key automatically if the token doesn't have one yet. Combined with the registration URL above, a fresh device with a single HSM can be provisioned with one command:
tedge cert download c8y --device-id "$DEVICE_ID"See the HSM documentation for more details.
Faster web UIs over Cumulocity Remote Access - #4363
The c8y-remote-access-plugin can now multiplex many TCP connections over a single remote access session (using yamux). Previously, a web browser loading a page through Remote Access opened a new session, and a new operation, for each connection, with each one taking up to a second to set up. With multiplexing, every request reuses the same session, which makes web applications served from the device much more responsive and reduces the load on the Cumulocity Remote Access service.
The feature is negotiated automatically and is fully backward compatible: existing SSH, VNC, and PASSTHROUGH connections work as before, and clients without multiplexing support fall back to one session per connection. Client support, for example in the Cumulocity cloud HTTP proxy and go-c8y-cli, is being added separately.
See the Remote Access documentation for more details on using Remote Access with thin-edge.io.
Read the thin-edge.io configuration without file access - #4241
Applications running in a separate container, or as a user without access to /etc/tedge, often need to know basic settings such as the device ID or the cloud URL. The tedge-agent and the mappers now publish the settings that are safe to share as a retained JSON message on their config topic:
$ tedge mqtt sub 'te/device/main/service/tedge-mapper-c8y/config'
[te/device/main/service/tedge-mapper-c8y/config] {"url":"example.cumulocity.com","device.id":"my-device-01","auth_method":"certificate", ...}The same values are also available from the tedge-agent HTTP API. Secrets, such as private keys, PINs, and credential file paths, are never published. See the MQTT API and the REST API docs for more details.
🚀 Features
- flows: builtin group measurements flow transformer - #4201
- monitoring: improved placeholder replacement in system.toml - #4203
- packaging: add single-process supervisor run mode - #4207
- troubleshooting: rotate operation logs - #4205
- troubleshooting: include mosquitto.db in diagnostic collection - #4215
- bridge: Respect
max_payload_sizein tedge-mqtt-bridge - #4217 - bridge: Only publish messages from the bridge after all subscriptions have been acknowledged - #4213
- troubleshooting: Live log-level reloading for single process supervisor - #4212
- containers|hsm: build tedge-p11-server container images - #4239
- runtime: Use supervisor when running tedge-agent/tedge-mapper - #4244
- containers: update helm chart to use tedge run all - #4248
- cloud: use exponential backoff on cloud connection attempts - #4277
- packaging: support building opkg (ipk) packages - #4273
- c8y: retry on 404 errors when looking up the Cumulocity external identity - #4276
- connectivity: Set
User-Agentheader for HTTP operations - #4260 - cli: improve mqtt client auth errors by showing source settings - #4295
- hsm: HSM token setup and management commands under
tedge hsm- #4287 - workflows: config_snapshot workflow with get and upload steps - #4292
- c8y: Cumulocity CA registration URL with auto generated one-time password - #4296
- configuration: expose tedge configs to external clients - #4241
- cli: explain TLS failures that are Cumulocity's to fix - #4282
- hsm: hsm init Raspberry PI 4/5 OTP crypto module - #4311
- troubleshooting: used fixed width padding when logging the timestamp to improve log line readability - #4313
- feat: publish the sbom with every official release - #4321
- feat: tedge service CLI - #4308
- hsm: make the PKCS#11 C_FindObjects batch size configurable - #4330
- cli:
tedge connectchange error format and show unpaired key diagnostic - #4325 - troubleshooting: support the Cumulocity Command (shell) operation by default - #4323
- troubleshooting: multiplex connections over a single remote access session - #4363
- monitoring: maps service commands from Cumulocity - #4366
- workflows: define one workflow for several operations, and ship one for the service actions - #4371
- workflows: run a workflow script through sudo with sudo = true - #4381
- c8y: route URLs of all tenant domain names through the local proxy - #4393
🐛 Bug Fixes
- cli: tedge init ensures all configured paths exist - #4196
- software: remove apt plugin reliance on apt markers which are language specific - #4220
- plugins: avoid reading external log plugin's stdout to memory - #4222
- configuration: stop duplicate downloads and executing messages for config_update - #4231
- configuration: avoid reading external plugin stdout to memory - #4234
- hsm: extend cloud bridge connection timeout for slow HSM/TPM signing - #4263
- installation: Only assign tedge user to the tedge group if the group exists - #4269
- hsm: check if systemctl exists before trying to use it - #4270
- troubleshooting: ` in workflow log file names for FAT32 compatibility - #4275
- hsm: reclaim stale socket file on tedge-p11-server startup - #4264
- hsm: treat empty tedge-p11-server env vars as unset - #4278
- bridge: Retry subscriptions if unacked and don't block the bridge forever if never acked - #4261
- troubleshooting: update log types on config updates - #4259
- flows: keep valid messages when a bad one shares a replayed batch - #4280
- connectivity: Retry on a more precise set of HTTP status codes - #4283
- cli: avoid two double quotes around mqtt topic when displayed in error messages - #4294
- cli: add --connection-timeout to tedge mqtt pub/sub - #4291
- workflows: hanging workflow awaiting a sub-operation resumed on agent restart - #3847
- containers: skip publishing linux/arm/v6 tedge-p11-server container images - #4298
- c8y: change retry behaviour for statuses c8y http - #4293
- hsm: don't log in to tokens that don't require a login - #4301
- c8y: announce c8y supported operations only after the built-in bridge is up - #4286
- mqtt: mqtt.external listener cert auth - #4315
- bridge: Don't check mosquitto bridge config if using built-in bridge - #4310
- c8y: trim SmartREST operation results on a character boundary - #4324
- bridge: recover from unacknowledged messages instead of stalling - #4334
- mqtt: don't recreate tedge-mosquitto.conf when mqtt.bind.enabled is false - #4337
- workflows: kill the processes started by a script when its timeout expires - #4335
- hsm: configure tedge-p11-server to use tpmrm by default for tpm2 hsm - #4345
- security: bump cryptoki to 0.12.1 to address RUSTSEC-2026-0286 - #4346
- hsm: reload the PKCS#11 module when it fails with a fatal error - #4353
- c8y: don't erroneously log when converter receives smartrest operation notifications - #4343
- troubleshooting: disable Nagle's algorithm on the websocket connection - #4362
- troubleshooting: flush websocket after forwarding socket data - #4360
- security: resolve RUSTSEC-2026-0338 to 0342, update quinn-proto - #4370
- fix: resolve RUSTSEC-2026-0346 to 0349, update rustls - #4372
- c8y: avoid 502 when Cumulocity closes a reused connection - #4373
- mqtt: fix connection leak after several QoS 0 publishes - #4377
- security: update rustls-webpki to 0.103.16 - #4385
- fix(deps): bump rpassword to 7.5 - #4392
- c8y|flows: persist alarm journal from built-in alarms flow - #4384
- workflows: run interrupted software list requests again on restart - #4388
- cloud: let explicit device.id override certificate CN in user-defined mappers - #4398
- c8y: move a rejected operation of a child device or a service to FAILED - #4401
- cloud: provide ${mapper.*} flow params for built-in mappers without mapper.toml - #4402
- software: avoid duplicate software_list requests - #4361
📓 Documentation
- developer-exp: instructions for coding agents - #3946
- docs: fix broken formatting in hsm-support.md - #4206
- hsm: Add tedge-p11-server compatibility section - #4232
- c8y: Add missing c8y supported operations - #4284
- docs: finish cut-off Supported Operations sentence - #4314
- docs: add product security section for vulnerability reporting - #4320
⛵ Refactor
- cloud: don't set TEDGE_CLOUD_PROFILE in tedge-mapper - #4211
- refactor(rust2024): fix rust-2024-incompatible-pat lints - #4227
- refactor: Remove use of
logdependency from all crates excepttedge-agent- #4250 - c8y: Remove custom 404 retry for
c8y_http_proxy- #4300
🔎 Testing
- testing: fix flaky symlink flow-reload test - #4221
- software|testing: Make
Tests.Cumulocity.Software Management.Softwaresuite faster - #4237 - test(upload): make retry status tests independent of timing - #4390
- test(tedge_api): use SIGKILL so the signal test does not dump core - #4403
📋 Miscellaneous Tasks
- build(deps): bump tar from 0.4.45 to 0.4.46 - #4197
- build(deps): bump codecov/codecov-action from 6 to 7 - #4208
- chore: add review skill - #4204
- deps: resolve RUSTSEC-2026-0185, update
quinn- #4225 - build(deps): bump actions/checkout from 6 to 7 - #4223
- deps: resolve RUSTSEC-2026-0190, update anyhow - #4236
- build(deps): bump actions/setup-node from 6 to 7 - #4252
- build(deps): bump actions/setup-go from 6 to 7 - #4257
- build(deps): bump actions/setup-python from 6 to 7 - #4262
- chore: bump MSRV to 1.92 - #4271
- security: update time crate to 0.3.55 - #4357
🔎 CI/CD
Full Changelog: https://github.com/thin-edge/thin-edge.io/compare/2.0.1..2.1.0