Skip to content

Commit 55d8149

Browse files
authored
Split DevicesController: extract validate_config WS command (esphome#734)
1 parent 5c7451b commit 55d8149

3 files changed

Lines changed: 56 additions & 27 deletions

File tree

‎esphome_device_builder/controllers/devices/__init__.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
on-subscription mDNS A-record refresh loop.
4141
- ``state_callbacks`` — the six per-attribute mDNS callbacks
4242
(state / ip / version / mac / api_encryption / config_hash).
43+
- ``validate`` — ``devices/validate`` WS command body
44+
(``esphome config`` subprocess + ANSI-conceal-SGR redaction).
4345
- ``storage_regen`` — background ``--only-generate`` scheduler
4446
+ the disk-stamp guard that keeps it from looping on a
4547
broken YAML.

‎esphome_device_builder/controllers/devices/controller.py‎

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
reachability,
7272
state_callbacks,
7373
storage_regen,
74+
validate,
7475
)
7576
from ._yaml_search import (
7677
DEFAULT_CONTEXT_LINES,
@@ -80,7 +81,6 @@
8081
from ._yaml_search_cache import YamlSearchCache
8182
from .helpers import (
8283
_build_address_cache_args,
83-
_redact_concealed_secrets,
8484
_rewrite_required_yaml_leaf,
8585
_validate_archive_configuration,
8686
friendly_name_slugify,
@@ -1515,32 +1515,14 @@ async def validate_config(
15151515
message_id: str = "",
15161516
**kwargs: Any,
15171517
) -> None:
1518-
"""
1519-
Validate a device YAML config. Streams output per-connection.
1520-
1521-
``show_secrets`` passes ``--show-secrets`` to ``esphome config``
1522-
so resolved ``!secret`` values appear in the output instead of
1523-
the default ``<removed>`` redaction. Default is ``False`` —
1524-
secrets only appear when the user actively asks for them.
1525-
Mirrors the legacy dashboard's ``streamer_mode`` semantics
1526-
but as a per-call opt-in rather than a global setting, so one
1527-
user wanting to see secrets in a multi-user deployment doesn't
1528-
change the default for everyone else.
1529-
"""
1530-
config_path = str(self._db.settings.rel_path(configuration))
1531-
cmd = [*self._esphome_cmd, "--dashboard", "config", config_path]
1532-
line_transform: Callable[[str], str] | None = None
1533-
if show_secrets:
1534-
cmd.append("--show-secrets")
1535-
else:
1536-
# ``esphome config`` without ``--show-secrets`` doesn't
1537-
# redact — it wraps each ``password|key|psk|ssid`` value
1538-
# in the ANSI conceal SGR (8/28). Browsers don't honour
1539-
# that escape, so the resolved secret bytes were leaking
1540-
# plain into the validate dialog. Strip the wrapped runs
1541-
# before the line leaves the WS handler.
1542-
line_transform = _redact_concealed_secrets
1543-
await self._stream_subprocess(cmd, client, message_id, line_transform=line_transform)
1518+
"""Validate a device YAML config; streams output per-connection."""
1519+
await validate.validate_config(
1520+
self,
1521+
configuration=configuration,
1522+
show_secrets=show_secrets,
1523+
client=client,
1524+
message_id=message_id,
1525+
)
15441526

15451527
@api_command("devices/logs")
15461528
async def stream_logs(
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""``devices/validate`` WS command body."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING, Any
6+
7+
from .helpers import _redact_concealed_secrets
8+
9+
if TYPE_CHECKING:
10+
from collections.abc import Callable
11+
12+
from .controller import DevicesController
13+
14+
15+
async def validate_config(
16+
controller: DevicesController,
17+
*,
18+
configuration: str,
19+
show_secrets: bool,
20+
client: Any,
21+
message_id: str,
22+
) -> None:
23+
"""
24+
Validate a device YAML config; streams output per-connection.
25+
26+
``show_secrets`` passes ``--show-secrets`` to ``esphome
27+
config`` when True so resolved ``!secret`` values appear
28+
in the output; when False, ANSI-conceal-wrapped secret
29+
runs are stripped from each line before it leaves the
30+
WS handler.
31+
"""
32+
config_path = str(controller._db.settings.rel_path(configuration))
33+
cmd = [*controller._esphome_cmd, "--dashboard", "config", config_path]
34+
line_transform: Callable[[str], str] | None = None
35+
if show_secrets:
36+
cmd.append("--show-secrets")
37+
else:
38+
# ``esphome config`` without ``--show-secrets`` doesn't
39+
# redact; it wraps each ``password|key|psk|ssid`` value
40+
# in the ANSI conceal SGR (8/28). Browsers don't honour
41+
# the escape, so the resolved secret bytes were leaking
42+
# plain into the validate dialog. Strip the wrapped runs
43+
# before the line leaves the WS handler.
44+
line_transform = _redact_concealed_secrets
45+
await controller._stream_subprocess(cmd, client, message_id, line_transform=line_transform)

0 commit comments

Comments
 (0)