Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent async_create_entry from reauth/reconfigure flows #127527

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions homeassistant/config_entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2709,6 +2709,20 @@ def async_create_entry( # type: ignore[override]
options: Mapping[str, Any] | None = None,
) -> ConfigFlowResult:
"""Finish config flow and create a config entry."""
if self.source in {SOURCE_REAUTH, SOURCE_RECONFIGURE}:
report_issue = async_suggest_report_issue(
self.hass, integration_domain=self.handler
)
_LOGGER.warning(
(
"Detected %s config flow creating a new entry, "
"when it is expected to update an existing entry and abort. "
"This will stop working in %s, please %s"
),
self.source,
"2025.11",
report_issue,
)
result = super().async_create_entry(
title=title,
data=data,
Expand Down
86 changes: 86 additions & 0 deletions tests/test_config_entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6671,3 +6671,89 @@ async def test_state_cache_is_cleared_on_entry_disable(hass: HomeAssistant) -> N
)
loaded = json_loads(json_dumps(entry.as_json_fragment))
assert loaded["disabled_by"] == "user"


@pytest.mark.parametrize(
("original_unique_id", "new_unique_id"),
[
("unique", "unique"),
("unique", "new"),
("unique", None),
(None, "unique"),
],
)
@pytest.mark.parametrize(
"source",
[config_entries.SOURCE_REAUTH, config_entries.SOURCE_RECONFIGURE],
)
async def test_create_entry_reauth_reconfigure(
hass: HomeAssistant,
source: str,
original_unique_id: str | None,
new_unique_id: str | None,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test to highlight unexpected behavior on create_entry."""
entry = MockConfigEntry(
title="From config flow",
domain="test",
entry_id="01J915Q6T9F6G5V0QJX6HBC94T",
data={"host": "any", "port": 123},
unique_id=original_unique_id,
)
entry.add_to_hass(hass)

mock_setup_entry = AsyncMock(return_value=True)

mock_integration(hass, MockModule("test", async_setup_entry=mock_setup_entry))
mock_platform(hass, "test.config_flow", None)

class TestFlow(config_entries.ConfigFlow):
VERSION = 1

async def async_step_user(self, user_input=None):
"""Test user step."""
return await self._async_step_confirm()

async def async_step_reauth(self, entry_data):
"""Test reauth step."""
return await self._async_step_confirm()

async def async_step_reconfigure(self, user_input=None):
"""Test reauth step."""
return await self._async_step_confirm()

async def _async_step_confirm(self):
"""Confirm input."""
await self.async_set_unique_id(new_unique_id)
return self.async_create_entry(
title="From config flow",
data={"token": "supersecret"},
)

assert len(hass.config_entries.async_entries("test")) == 1

with mock_config_flow("test", TestFlow):
if source == config_entries.SOURCE_REAUTH:
result = await entry.start_reauth_flow(hass)
elif source == config_entries.SOURCE_RECONFIGURE:
result = await entry.start_reconfigure_flow(hass)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.CREATE_ENTRY

entries = hass.config_entries.async_entries("test")
if original_unique_id is not None and original_unique_id == new_unique_id:
# Show that the previous entry got binned and recreated
assert len(entries) == 1
assert entries[0].entry_id != entry.entry_id
else:
# Show that a new entry got created
assert len(entries) == 2

assert (
f"Detected {source} config flow creating a new entry, when it is expected "
"to update an existing entry and abort. This will stop working in "
"2025.11, please create a bug report at https://github.com/home"
"-assistant/core/issues?q=is%3Aopen+is%3Aissue+"
"label%3A%22integration%3A+test%22"
) in caplog.text