Skip to content

fix: register a verifiable discovery host, and match panelbench's TLS port (1.2.1) - #49

Merged
cayossarian merged 3 commits into
mainfrom
fix/discovery-host-and-tls-port-convention
Aug 29, 2026
Merged

fix: register a verifiable discovery host, and match panelbench's TLS port (1.2.1)#49
cayossarian merged 3 commits into
mainfrom
fix/discovery-host-and-tls-port-convention

Conversation

@cayossarian

@cayossarian cayossarian commented Aug 29, 2026

Copy link
Copy Markdown
Member

Follow-on to #48, which merged while these were being written. Ships as 1.2.1, not 1.2.0: that version is already installed from the #48 merge, so the add-on store would never offer these under it.

Both come from a repeat of the firmware-upgrade rehearsal on 1.2.0 / panelbench 2.5.1. The gateway fix from #48 worked and both emulators advertised the same address, but the swap still failed for two harness reasons.

Supervisor discovery registered a host the certificate does not name

register_panel registered the container hostname. Under host_network: true that is only a per-add-on alias for the host — it is absent from the leaf's SAN and it differs between the two emulators.

async_step_hassio rewrites an existing entry's host to whatever the add-on registers. That is deliberate and documented, and it is not guarded the way the integration's other discovery routes are, because an add-on legitimately reallocates its own ports and the guard would freeze an entry against its own add-on. The consequence is that whatever gets registered here had better be an address the certificate names.

It was not. An entry a user had configured by IP was silently moved to the hostname within a minute of creation, and the panelbench swap then failed hostname verification — the panel is meant to keep its identity across that swap, which is what the shared authority exists for.

The advertised address is what the leaf names and what stays constant across the swap, so it is what gets registered now. The container hostname stays as the fallback where no advertise address is configured, where it still beats refusing to register.

The TLS port disagreed with panelbench

The port was allocated from its own base of 8443; panelbench derives it as the HTTP port plus 1000. A real panel keeps 443 across a firmware upgrade, so two emulators standing in for the same panel either side of one have to agree on where it serves TLS — a panel whose TLS port moved across the swap is not a panel that was upgraded.

Now derived with the same https_port_for helper panelbench uses, so the two read alike and neither can drift without the other noticing. Deriving also removes the second pool: one allocation per panel, and releasing it releases the pair, so the two pools can no longer fall out of step. Pair-retry semantics are unchanged — either half may be the one in use, both move together, so the next allocation is a clean pair.

The offset is asserted in a test rather than left implicit in a constant, because it is a contract with another repository that would otherwise break silently.

This is user-visible for anyone who noted the port from 1.2.0: a panel on HTTP 8081 now serves TLS on 9081 rather than 8443. Nothing needs changing by hand, since the port is published in discovery, but the changelog calls it out for firewall rules written against the old number.

Changelog

1.2.0's entry is left describing only what it shipped. Its TLS port paragraph had been edited in place to describe the derived port, which 1.2.0 does not do — that release allocated from a separate base — so it has been restored; saying otherwise would misdescribe the build people are currently running.

Testing

489 passed, up from 486 on #48's head. The same three failures remain (test_graph_builder_topology ×2, test_main_logging) and are pre-existing on main, unrelated: the pin is ebus-sdk==0.23.1 while the vendored emitter targets the 0.1.x Device API.

Three new tests: the registered host is the advertised address; the hostname fallback still applies with no advertise address configured; and the offset matches panelbench's, pinned by value so a one-sided change fails here rather than in a rehearsal.

run-local.sh now prints the HTTPS port alongside the HTTP one, since it is derived rather than typed and adding a panel by hand needs it.

Follow-up, not in this PR

panelbench needs the same host change. supervisor_discovery.py:121 there still does host = _container_hostname(), so after the swap the entry is rewritten to panelbench's own hostname and hostname verification fails at the same point. Fixing the simulator half alone does not complete the rehearsal; both halves are needed. That repo is owned by another change in flight.

…ostname

The integration's Supervisor path rewrites an existing entry's host to whatever
the add-on registers, deliberately and without the guard its other discovery
routes apply — an add-on legitimately reallocates its own ports, so freezing the
entry against its own add-on would be worse. The consequence is that whatever is
registered here had better be an address the panel's certificate names.

The container hostname is not. Under `host_network: true` it is only a per-add-on
alias for the host, so it is absent from the leaf's SAN and differs between the
two emulators. An entry a user had configured by IP was silently moved to it
within a minute of creation, and the panelbench swap then failed hostname
verification — the panel is meant to keep its identity across that swap, which
is the whole point of the shared authority.

The advertised address is what the leaf names and what stays constant across the
swap, so it is what gets registered. The hostname remains the fallback for an
install that configures no advertise address, where it is still better than
refusing to register at all.

Note that panelbench needs the same change for the rehearsal to work end to end:
it still registers its container hostname, so the entry is rewritten again after
the swap.
The TLS port was allocated from its own base of 8443 while panelbench derives it
as the HTTP port plus 1000. A real panel keeps 443 across a firmware upgrade, so
two emulators that stand in for the same panel either side of one have to agree
on where it serves TLS — a panel whose TLS port moved across the swap is not a
panel that was upgraded.

Adopted panelbench's rule, down to the `https_port_for` helper, so the two read
the same and neither can drift without the other noticing. Deriving also removes
the second pool: there is one allocation per panel now, and releasing it releases
the pair, so the two pools can no longer fall out of step. Pair-retry semantics
are unchanged — either half may be the one in use, and both move together, so
the next allocation is a clean pair.

The offset is asserted in a test rather than left implicit in a constant, since
it is a contract with another repository and changing it on one side alone
breaks the rehearsal silently.
1.2.0 is already installed from the previous merge, so these two fixes cannot
ship under that version — the add-on store would never offer them.

The 1.2.0 entry is left describing only what it shipped. Its TLS port paragraph
had been edited in place to describe the derived port, which 1.2.0 does not do:
that release allocated from a separate base of 8443, and saying otherwise would
misdescribe the build people are running.
@cayossarian cayossarian changed the title fix: register a verifiable discovery host, and match panelbench's TLS port fix: register a verifiable discovery host, and match panelbench's TLS port (1.2.1) Aug 29, 2026
@cayossarian
cayossarian merged commit 2be4e40 into main Aug 29, 2026
2 checks passed
@cayossarian
cayossarian deleted the fix/discovery-host-and-tls-port-convention branch August 29, 2026 02:07
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.

1 participant