Repository navigation
Conversation
…e paste in the E2E
# Conflicts: # Sources/App/Frontend/IncomingURLHandler.swift # Sources/App/Resources/en.lproj/Localizable.strings # Sources/App/Settings/Kiosk/KioskView.swift # Sources/Shared/Resources/Swiftgen/Strings.swift
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved entitlement mismatches, destructive URL handling, secret logging, and incomplete credential transfers block approval.
15 open issues
Preserve lowercase app-group identifier · New Lowercase app-group entitlement identifier · New Lowercase Catalyst extension app-group · New Match extension entitlement to lowercase app group · New Preserve lowercase Watch app-group name · New Lowercase complication app-group entitlement · New Validate migration before wiping local data · New Redact migration secrets from URL logs · New Propagate mTLS identity export failures · New Propagate keychain write errors · New Reject duplicate migration URL parameters · New Enforce timeout without awaiting blocked permission reads · New Gracefully decode unknown migration stores · New Persist handoff suspension across extension processes · New Anchor confirmation dialog to Transfer again button · New
What changed in this PR
Adds an encrypted, on-device setup transfer from the existing Home Assistant app to the Open Home Foundation app, while allowing both Apple accounts to build from the same codebase.
Changes:
- Adds transfer packaging, import, handoff persistence, onboarding screens, and mTLS identity export/import.
- Integrates migration announcements, permissions, and connection suspension into the app lifecycle.
- Makes identifiers, signing, Firebase configuration, and distribution account-specific.
- Adds localized transfer text, reusable UI components, and migration tests.
| File | Description |
|---|---|
Tests/Shared/DesignSystem/Gallery/FrontendComponentMapping.test.swift |
Classifies section pills as app-specific components. |
Tests/App/Onboarding/Migration/ClientIdentityExport.test.swift |
Tests mTLS identity export/import round trips. |
Tests/App/Onboarding/Migration/AppMigrationScreens.test.swift |
Adds migration-screen snapshot coverage. |
Tests/App/Onboarding/Migration/AppMigrationLinkTests.swift |
Tests migration links, encryption, and handoff persistence. |
Sources/WatchWidgets/WatchWidgetConstants.swift |
Removes the legacy bundle-identifier fallback. |
Sources/WatchApp/Info.plist |
Parameterizes display and companion identifiers. |
Sources/Shared/Notifications/LocalPush/LocalPushEvent.swift |
Uses the configured application identifier. |
Sources/Shared/Environment/CrashReporter.swift |
Reads the official bundle prefix from configuration. |
Sources/Shared/Environment/AppConstants.swift |
Resolves configured background-task identifiers. |
Sources/Shared/API/Webhook/Networking/WebhookManager.swift |
Adds webhook-request suspension guards. |
Sources/Shared/API/HAAPI.swift |
Adds connection-suspension checks. |
Sources/HANetworking/Sources/ClientIdentityExport.swift |
Defines transferable mTLS identity material. |
Sources/HANetworking/Sources/ClientCertificateManager+Export.swift |
Implements mTLS identity export and restoration. |
Sources/HANetworking/Sources/ClientCertificate.swift |
Exposes certificate-chain helpers within the module. |
Sources/HADesignSystem/Sources/Gallery/DesignSystemComponent.swift |
Registers section-pill gallery variants. |
Sources/HADesignSystem/Sources/Components/HASectionPill.swift |
Adds reusable capsule-shaped section headers. |
Sources/HADesignSystem/Sources/Components/HAAlertView.swift |
Updates alert alignment, spacing, and shape. |
Sources/HADesignSystem/Sources/Components/CardView.swift |
Supports configurable card corner radii. |
Sources/App/WhatsNew/WhatsNewCatalog.swift |
Suppresses release announcements during migration messaging. |
Sources/App/Utilities/RemindersSync/RemindersSyncBackgroundRefresher.swift |
Uses the configured background-task identifier. |
Sources/App/Settings/Settings/SettingsView.swift |
Adds access to migration from Settings. |
Sources/App/Settings/Settings/SettingsItem.swift |
Defines the migration settings entry. |
Sources/App/Settings/Settings/ServersListView.swift |
Adds an add-server accessibility identifier. |
Sources/App/Settings/Sensors/Permissions/SensorPermissionsViewModel.swift |
Reuses permission-to-Settings destination mapping. |
Sources/App/Settings/Sensors/Permissions/SensorPermission.swift |
Exposes permission-specific Settings destinations. |
Sources/App/Settings/Kiosk/ConditionalContainerView.swift |
Adds handoff-aware kiosk presentation logic. |
Sources/App/Resources/pt-BR.lproj/Localizable.strings |
Adds Brazilian Portuguese transfer text. |
Sources/App/Resources/Info.plist |
Registers migration schemes and account-specific metadata. |
Sources/App/Resources/es.lproj/Localizable.strings |
Adds Spanish transfer text. |
Sources/App/Resources/es-MX.lproj/Localizable.strings |
Adds Mexican Spanish transfer text. |
Sources/App/Resources/en.lproj/Localizable.strings |
Defines English transfer strings. |
Sources/App/Resources/en-GB.lproj/Localizable.strings |
Adds British English transfer text. |
Sources/App/Onboarding/Views/CheckmarkDrawOnView.swift |
Makes success illustrations configurable. |
Sources/App/Onboarding/Steps/Welcome/OnboardingWelcomeView.swift |
Offers transfer from the existing app. |
Sources/App/Onboarding/Steps/Permissions/OnboardingPermissionsNavigationView.swift |
Adapts success-screen layout. |
Sources/App/Onboarding/Migration/AppMigrationTransferredItem.swift |
Defines displayed transfer categories. |
Sources/App/Onboarding/Migration/AppMigrationSummary.swift |
Summarizes transferred servers and permissions. |
Sources/App/Onboarding/Migration/AppMigrationSuccessView.swift |
Animates the completion-screen transition. |
Sources/App/Onboarding/Migration/AppMigrationSessionStore.swift |
Persists pending and completed transfer sessions. |
Sources/App/Onboarding/Migration/AppMigrationSession.swift |
Generates session identifiers and encryption keys. |
Sources/App/Onboarding/Migration/AppMigrationRole.swift |
Determines app roles and peer addressing. |
Sources/App/Onboarding/Migration/AppMigrationProgressView.swift |
Displays staged transfer progress. |
Sources/App/Onboarding/Migration/AppMigrationProgressScript.swift |
Defines progress narration and timing. |
Sources/App/Onboarding/Migration/AppMigrationPermissionsViewModel.swift |
Tracks and requests destination-app permissions. |
Sources/App/Onboarding/Migration/AppMigrationPermissionsView.swift |
Presents permission reauthorization controls. |
Sources/App/Onboarding/Migration/AppMigrationPayload.swift |
Defines the serialized setup-transfer payload. |
Sources/App/Onboarding/Migration/AppMigrationPasteboard.swift |
Exchanges expiring, device-local encrypted payloads. |
Sources/App/Onboarding/Migration/AppMigrationOverviewView.swift |
Explains transfer contents and follow-up steps. |
Sources/App/Onboarding/Migration/AppMigrationNoServersView.swift |
Redirects unconfigured previous-app users to the new app. |
Sources/App/Onboarding/Migration/AppMigrationLink.swift |
Parses and generates migration URLs. |
Sources/App/Onboarding/Migration/AppMigrationKeychainStore.swift |
Maps transferable Keychain services. |
Sources/App/Onboarding/Migration/AppMigrationItemRow.swift |
Renders transfer inventory rows. |
Sources/App/Onboarding/Migration/AppMigrationIntroView.swift |
Introduces the setup-transfer flow. |
Sources/App/Onboarding/Migration/AppMigrationImportView.swift |
Displays import progress and failure states. |
Sources/App/Onboarding/Migration/AppMigrationImportState.swift |
Models import-screen phases. |
Sources/App/Onboarding/Migration/AppMigrationImporter.swift |
Restores transferred databases, settings, and credentials. |
Sources/App/Onboarding/Migration/AppMigrationHaptics.swift |
Centralizes transfer haptic feedback. |
Sources/App/Onboarding/Migration/AppMigrationHandoffStore.swift |
Persists the previous app’s handoff state. |
Sources/App/Onboarding/Migration/AppMigrationHandoffPhase.swift |
Models persistent handoff phases. |
Sources/App/Onboarding/Migration/AppMigrationGrantedPermissions.swift |
Collects existing device-permission grants. |
Sources/App/Onboarding/Migration/AppMigrationGetNewAppView.swift |
Guides installation before transfer. |
Sources/App/Onboarding/Migration/AppMigrationFollowUpItem.swift |
Defines post-transfer setup tasks. |
Sources/App/Onboarding/Migration/AppMigrationFlowView.swift |
Connects import, completion, and permission screens. |
Sources/App/Onboarding/Migration/AppMigrationExportView.swift |
Presents export and post-handoff actions. |
Sources/App/Onboarding/Migration/AppMigrationExportState.swift |
Models export-screen phases. |
Sources/App/Onboarding/Migration/AppMigrationExporter.swift |
Packages configuration and credentials for transfer. |
Sources/App/Onboarding/Migration/AppMigrationExportContainerView.swift |
Binds export presentation to coordinator state. |
Sources/App/Onboarding/Migration/AppMigrationError.swift |
Defines localized transfer failures. |
Sources/App/Onboarding/Migration/AppMigrationCrypto.swift |
Encrypts and authenticates payloads with AES-GCM. |
Sources/App/Onboarding/Migration/AppMigrationCompleteView.swift |
Presents completion, source erasure, and next steps. |
Sources/App/Onboarding/Migration/AppMigrationAnnouncementView.swift |
Announces the account transition and transfer entry point. |
Sources/App/Onboarding/Migration/AppMigrationAnnouncementItem.swift |
Models announcement details. |
Sources/App/Onboarding/Migration/AppMigrationAnnouncement.swift |
Controls announcement eligibility and store links. |
Sources/App/Onboarding/Container/OnboardingNavigationView.swift |
Adds migration routing and previous-app onboarding restrictions. |
Sources/App/Onboarding/API/OnboardingDestination.swift |
Adds the migration navigation destination. |
Sources/App/Notifications/NotificationManagerLocalPushInterfaceExtension.swift |
Excludes servers while connections are suspended. |
Sources/App/Frontend/WebView/HomeAssistantView/LaunchMessagesState.swift |
Queues the migration launch announcement. |
Sources/App/Frontend/WebView/HomeAssistantView/HomeAssistantView.swift |
Presents the migration announcement sheet. |
Sources/App/Frontend/IncomingURLHandler.swift |
Routes incoming migration links. |
Sources/App/Container/OnboardingStateObservable.swift |
Prioritizes the persisted handoff screen. |
Sources/App/Container/ContainerView.swift |
Hosts migration export content. |
Sources/App/BackgroundRefreshManager.swift |
Uses the configured refresh-task identifier. |
Sources/App/AppDelegate.swift |
Restores suspension state and adjusts push setup. |
Sources/App/Accessibility/AccessibilityIdentifier.swift |
Defines migration UI automation identifiers. |
HomeAssistant.xcodeproj/xcshareddata/xcschemes/Extensions-PushProvider.xcscheme |
Targets the OHF debug application. |
fastlane/lanes/testing.rb |
Selects account-specific symbol downloads. |
fastlane/lanes/setup.rb |
Initializes account-aware Fastlane settings. |
fastlane/lanes/provisioning.rb |
Uses account-specific provisioning directories. |
fastlane/lanes/local_distribution.rb |
Checks profiles in the selected account directory. |
fastlane/lanes/account.rb |
Resolves account settings from xcconfig files. |
fastlane/Fastfile |
Loads account-resolution helpers. |
fastlane/Deliverfile |
Removes the fixed application identifier. |
fastlane/Appfile |
Reads the selected application identifier. |
Configuration/Scripts/fix_xcode_12.5_target_platform_issues.sh |
Parameterizes generated helper bundle identifiers. |
Configuration/Scripts/copy_firebase_configuration.sh |
Copies account-specific Firebase configuration. |
Configuration/HomeAssistant.xcconfig |
Derives shared settings from the selected account. |
Configuration/HomeAssistant.release.xcconfig |
Selects account-specific release provisioning profiles. |
Configuration/HomeAssistant.debug.xcconfig |
Configures account-aware debug naming and signing. |
Configuration/Firebase/ohf/GoogleService-Info-Release.plist |
Adds OHF release Firebase configuration. |
Configuration/Firebase/ohf/GoogleService-Info-Debug.plist |
Adds OHF debug Firebase configuration. |
Configuration/Firebase/nabu-casa/GoogleService-Info-Release.plist |
Stores legacy release Firebase configuration by account. |
Configuration/Firebase/nabu-casa/GoogleService-Info-Debug.plist |
Stores legacy debug Firebase configuration by account. |
Configuration/Entitlements/WatchWidgets.entitlements |
Parameterizes Watch widget sharing entitlements. |
Configuration/Entitlements/WatchApp.entitlements |
Parameterizes Watch app sharing entitlements. |
Configuration/Entitlements/Extension-ios.entitlements |
Parameterizes iOS extension sharing entitlements. |
Configuration/Entitlements/Extension-catalyst.entitlements |
Parameterizes Catalyst extension sharing entitlements. |
Configuration/Entitlements/App-ios.entitlements |
Parameterizes iOS app sharing entitlements. |
Configuration/Entitlements/App-catalyst.entitlements |
Parameterizes Catalyst app sharing entitlements. |
Configuration/Accounts/ohf.xcconfig |
Defines OHF identity, capabilities, and signing settings. |
Configuration/Accounts/nabu-casa.xcconfig |
Defines legacy identity, capabilities, and signing settings. |
Configuration/Account.xcconfig |
Selects OHF as the default account. |
.gitignore |
Excludes local account overrides. |
.github/workflows/distribute.yml |
Selects distribution accounts and corresponding secrets. |
Review effort: Balanced
The app group entitlement is derived from an explicit lowercase base per account, since the Nabu Casa bundle identifier is mixed case. A transfer started by the existing app only wipes what the new app holds once the payload has been opened and matched to the session, migration links are parsed without trapping on repeated parameters, and their key and session values are redacted from URL logs. Keychain and identity restores fail the import instead of being logged away, an identity that cannot be exported fails the export, unknown keychain stores decode and are skipped, the permission snapshot really stops at its budget, and the hand-off phase in the app group suspends connections from every process of the app. Confirmations on the onboarding scaffold's secondary action are presented by that button. Translated strings are left to Lokalise.
|
Found 2 unused localization strings in the codebase. Click to see detailsTo remove them, run the |
…the how-it-works snapshot
There was a problem hiding this comment.
Test coverage of this pull request is below 90%
The unit tests run 51.63% of the lines this pull request
adds or changes (1015 of 1966 coverable lines).
The per-file breakdown, and the changed lines no test runs, are in the
job summary. Adding tests for those lines and pushing dismisses this
review automatically.
Lines that carry no executable code, and files the unit test targets do not
build, are not counted. If the new code genuinely cannot be unit tested, a
maintainer can dismiss this review.
The coordinator takes its dependencies (role, the other app, pacing, push registration) from an injectable struct, the views that watch it accept it as a parameter, and the role can be overridden by tests. The new tests drive both sides of the transfer against each other, including a restart and the erase round trip, plus the stores, the errors, the suspended-connection guards and the remaining screens.
…hand-off and the flow's success state
There was a problem hiding this comment.
Test coverage of this pull request is below 90%
The unit tests run 86.57% of the lines this pull request
adds or changes (1714 of 1980 coverable lines).
The per-file breakdown, and the changed lines no test runs, are in the
job summary. Adding tests for those lines and pushing dismisses this
review automatically.
Lines that carry no executable code, and files the unit test targets do not
build, are not counted. If the new code genuinely cannot be unit tested, a
maintainer can dismiss this review.
Patch coverage is now 90.95%, at or above the 90% threshold.
The announcement drops its "What this means" section and is titled "Home Assistant has moved". The welcome notice explains the new App Store listing, the overview's second list is "Set up again manually", the open check asks "Did the old app open?", and the erased screen's button reads "Open the new app".
Brings in the registration ownership from #6088. A transfer carries the existing app's registration records, which name that app's vendor identifier as their owner, so the Open Home Foundation app would treat every transferred server as a restored device's registration, hold back its reports and ask whether to replace the old device. After the import the coordinator now takes those registrations over, keeping the same mobile_app device; the reconnect stays with the push token adoption so the new token is what reaches Home Assistant. The E2E vendor override is left out of the transferred preferences, and the migration UI test's build file gets an ID of its own after colliding with E2EFlow.swift.
…ion E2E With location undecided and an HTTP-only server the app covers the frontend with its location decision, also on a relaunch after onboarding, so the sidebar underneath never opened. The driver now closes that cover first and reaches Settings the way E2EFlow does.



AI Policy
Select exactly one option that describes AI usage in this contribution:
Summary
The app moves to the Open Home Foundation Apple account under a new bundle identifier, so users end up with two apps side by side. This adds an in-app transfer between them: the existing app packages its servers, sign-ins, settings and mTLS identities into an encrypted payload, hands it over through the pasteboard and a custom URL scheme, and the new app imports it. The existing app then refuses to set up new servers, points at the new app, and can erase itself once the transfer is verified.
The Apple account is selected through configuration (
Configuration/Account.xcconfig) instead of a branch, so the same code builds either app.Screenshots
Snapshot references for every transfer screen, light and dark, are under
Tests/App/Onboarding/Migration/__Snapshots__/AppMigrationScreens.test/.Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#
Any other notes
Draft while the remaining pieces land:
Configuration/Accounts/ohf.xcconfig: push provider (app-push-provider, needed onio.home-assistant.appandio.home-assistant.app.PushProvider, blocks the TestFlight upload), Critical Alerts on the PushProvider App ID (it currently carries Critical Messaging), Thread network credentials, user-assigned device name. CarPlay is granted.Tests/UI/MigrationE2ETests.swift) run only locally with two installed builds and a reachable server; they are not wired into CI.homeassistant-ohf,homeassistant-nc) with Universal Links.RegistrationOwnershipafter the import.