fix(settings): a plugin's password is sealed at rest, and a blank box keeps it (#5671)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m13s
CI / unit (push) Successful in 1m27s
CI / publish (push) Successful in 1m2s

The UniFi password sat in plugin.unifi in plain text: SECRET_KEYS covers
whole settings, and a plugin's settings are one dict. Saving the plugin's
settings page also wiped it, since the password box is never filled back
in and its blank value was stored.

- A plugin field whose name holds password, secret or token is a
  credential (is_plugin_secret). set_setting seals it inside the dict,
  every read opens it, startup seals any plaintext left from before, and
  the undecryptable-secrets banner names it as plugin.<name>.<field>.
- The settings page uses the same test for its password boxes, and a blank
  box keeps the saved value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 07:06:31 -04:00
co-authored by Claude Opus 5.5
parent 002181253e
commit eea29123f9
6 changed files with 191 additions and 3 deletions
+3
View File
@@ -155,6 +155,9 @@ def create_app(
for _name in ("metric_label", "metric_about", "metric_unit", "metric_value", "source_label",
"cert_left", "field_label"):
app.jinja_env.globals[_name] = getattr(_fmt, _name)
# Which plugin settings fields are credentials (a password box, never echoed).
from .core.settings import is_plugin_secret as _is_plugin_secret
app.jinja_env.globals["is_plugin_secret"] = _is_plugin_secret
from .alerts.service import rule_condition as _rule_condition
app.jinja_env.globals["rule_condition"] = _rule_condition
from .models.monitors import MONITOR_TYPE_LABELS as _type_labels