Skip to content

Feat/battery threshold#7

Draft
damian-ds7 wants to merge 24 commits into
noctalia-dev:mainfrom
damian-ds7:feat/battery-threshold
Draft

Feat/battery threshold#7
damian-ds7 wants to merge 24 commits into
noctalia-dev:mainfrom
damian-ds7:feat/battery-threshold

Conversation

@damian-ds7

@damian-ds7 damian-ds7 commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Plugin

  • Id: damian-ds7/battery-threshold
  • New plugin
  • Update to an existing plugin (version bumped in plugin.toml)

What it does

Ports the battery threshold plugin from legacy-v4-plugins/battery-threshold.
It lets you set a battery charging threshold, and automatically reapplies it on system restart.

  • The setup_rules.sh script which runs on setup creates a user group called battery_ctl, adds user to it, and installs the custom udev rule.
  • The 99-battery-threshold.rules file configures the system to grant group-write access of the battery limit threshold file to that battery_ctl group.
  • On threshold change the value is saved to threshold.txt file so that it can be set automatically on system launch.

External dependencies

Uses polkit to make initial setup easier with an auth popup via pkexec, but it's not required and can be ran manually by user with sudo

Testing

Tested opening panel via ipc and bar widget, setting threshold via ipc and slider, threshold persistence after reboot

  • Tested on Niri
  • Tested on Hyprland
  • Tested on Sway
  • Tested on another compositor:
  • Noctalia version tested against: noctalia v5.0.0 (a34e23c)

Screenshots / Videos

image

Checklist

  • The directory name matches the part of id after the / in plugin.toml exactly.
  • It ships plugin.toml, README.md, thumbnail.webp, and translations/en.json.
  • version follows semver and is bumped in this PR; min_noctalia is the version I tested against.
  • I only added or edited translations/en.json (no machine-translated locales).
  • I did not edit catalog.toml; CI generates it.
  • This PR touches exactly one plugin directory.

Code review attestation

Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:

  • The code is readable and not obfuscated, minified, or generated.
  • It does not download and execute remote code.
  • Every network call, filesystem write, and spawned process is something the description above accounts for.
  • I have the right to publish this code under the license declared in plugin.toml.

Regarding translations, I didn't add anything new just restructured existing ones to work with new format

@spiros132 spiros132 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some feedback about the PR! :D

Comment thread battery-threshold/translations/en.json Outdated
Comment thread battery-threshold/widget.luau Outdated
Comment thread battery-threshold/widget.luau Outdated
Comment thread battery-threshold/widget.luau Outdated
Comment thread battery-threshold/service.luau
Comment thread battery-threshold/service.luau Outdated
Comment thread battery-threshold/service.luau Outdated
Comment thread battery-threshold/service.luau Outdated
Comment thread battery-threshold/plugin.toml Outdated
Comment thread battery-threshold/panel.luau Outdated
@damian-ds7
damian-ds7 force-pushed the feat/battery-threshold branch from 3e0bb43 to f61b992 Compare July 14, 2026 14:32
@damian-ds7

Copy link
Copy Markdown
Contributor Author

I had to add some machine translated bits for a few missing translations though, is that gonna be a problem? I can remove them if yes

@damian-ds7
damian-ds7 requested a review from spiros132 July 14, 2026 14:33
@ItsLemmy

ItsLemmy commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

It's Ok to use help of LLM for translations, but basically you should not submit translations for languages that you cannot fully understand and fix manually.

So only submit english + the languages you fully master that exist in noctalia core.

I'm adding this to the PR checklist for clarity.

Currently there is no Turkish translations available in v5, so the tr.json file should be removed.

Let us know for the other languages, thanks.

@damian-ds7

Copy link
Copy Markdown
Contributor Author

Cool, yeah I don't really understand those, I just copied translation files from the old plugin so I'm gonna remove them all later

@ItsLemmy
ItsLemmy marked this pull request as draft July 15, 2026 13:29
@damian-ds7
damian-ds7 force-pushed the feat/battery-threshold branch from cf534fa to 62bee30 Compare July 15, 2026 19:02
@damian-ds7
damian-ds7 marked this pull request as ready for review July 15, 2026 19:02
@ItsLemmy

Copy link
Copy Markdown
Contributor
  1. blocking - battery-threshold/service.luau:34

The configurable battery path is concatenated directly into runAsync. Noctalia executes string commands through /bin/sh -lc, so shell metacharacters in the configured directory can execute arbitrary commands as the Noctalia user. Paths containing spaces also break the writable check.

The setup command at battery-threshold/service.luau:138 has the same unquoted construction problem.

  1. blocking - battery-threshold/service.luau:141

The plugin elevates setup_rules.sh from the user-writable materialized plugin directory. The script then reads another user-writable file at battery-threshold/setup_rules.sh:16 and installs it into /etc/udev/rules.d at battery-threshold/setup_rules.sh:48.

Either file can be replaced while authentication is pending, allowing substituted root script or udev-rule content to be installed with elevated privileges. This creates a local privilege-escalation path.

  1. blocking - battery-threshold/plugin.toml:10

The manifest declares only polkit, but the plugin invokes test, pkexec, bash, readlink, getent, groupadd, usermod, cp, and udevadm. The udev rule also invokes chgrp and chmod.

Repository policy requires external commands to be listed in dependencies and documented. Missing tools can make the required setup fail without the catalog disclosing those requirements.

  1. non-blocking - battery-threshold/service.luau:59

threshold.txt is written using a relative path and the write result is ignored. It is then read at battery-threshold/service.luau:102.

Relative paths resolve inside the materialized plugin directory, which is not update-safe. A plugin update or failed write can silently lose the slider-selected threshold. Noctalia's pluginDataDir() should be used for persistent plugin data.

@ItsLemmy
ItsLemmy marked this pull request as draft July 15, 2026 23:58
@damian-ds7

Copy link
Copy Markdown
Contributor Author

Regarding this

The plugin elevates setup_rules.sh from the user-writable materialized plugin directory. The script then reads another user-writable file at battery-threshold/setup_rules.sh:16 and installs it into /etc/udev/rules.d at battery-threshold/setup_rules.sh:48.
Either file can be replaced while authentication is pending, allowing substituted root script or udev-rule content to be installed with elevated privileges. This creates a local privilege-escalation path.

Do you have a suggestion on what could be changed? I honestly can't think of any way to make it fully secure other than just ditching the interactive setup and letting user handle all of it. I could just add a note in the docs that threshold file has to be writable and let user set it up, while leaving the setup script in here as a convenient way of doing it.

If I did that I also don't have to list all the external tools used by the script right?

@ItsLemmy

Copy link
Copy Markdown
Contributor

You can keep the setup script. We already allow this pattern in the IdeaPad conservation-mode plugin, so removing interactive setup is not required.

Please make the script self-contained instead of loading and copying a second file from the plugin directory. Write the fixed udev rule directly from setup_rules.sh, safely quote the script path and username in service.luau, validate the target user, and preferably run it visibly through a terminal with sudo like the IdeaPad plugin.

Also be aware the plugin.toml has changed, min_noctalia is gone and you need plugin_api .
Probably best to run the python .github/workflows/validate-plugins.py to check yourself

The readme should follow the README_TEMPALTE.md as much as possible, and list all the external commands you use in there.

The thumbnail text is truncated "lifesp" you should regenerate with a shorter sentence.

@damian-ds7

Copy link
Copy Markdown
Contributor Author

Thanks for feedback, I'll get to it when I have some time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants