Skip to content
Merged
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 2026.10.5.1 — 2026-10-05

- Support public HTTPS addresses beyond Nabu Casa: your own domain or reverse proxy, including nonstandard ports.
- Preserve independent OAuth permissions, exact Origin/resource/port binding and existing Nabu Casa grants.
- Reject ambiguous URLs, embedded control characters, credentials, invalid ports and browser IPv4 representations.
- Document valid TLS, proxy setup and the security assessment; update all five language guides.
- Update GitHub Actions checkout and Python setup to v7.

Configure an origin such as `https://ha.example.org:8125`; the MCP URL is that origin followed by `/api/grok_connector/mcp`. The public endpoint needs a valid TLS certificate and must be reachable by Grok. Changing the configured origin requires fresh pairing. An update using the same origin preserves configuration and OAuth grants. Custom proxy/Grok live acceptance remains deployment-specific.

## 2026.10.4.1 — 2026-10-04

First stable release, based on the accepted 0.1.0b7 implementation.
Expand Down
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Select any entity for reading. Expose commands as named action sequences using H

## Requirements and current status

- Home Assistant **2026.9.4 or newer**, HACS and enabled Nabu Casa remote access.
- Home Assistant **2026.9.4 or newer**, HACS and public HTTPS access to HA. Use Nabu Casa remote access or your own DNS hostname with a valid TLS certificate; a nonstandard HTTPS port is supported.
- A Grok client/account that offers custom remote MCP connectors with OAuth. Availability in Grok's Tesla interface is a separate client capability; this integration cannot enable it.
- The beta series passed automated checks, GitHub CI, live HACS installation, native HA configuration/action editing and OAuth/MCP acceptance over Nabu Casa. Grok web in Chrome successfully paired and read selected states; the user confirmed light-on and light-off commands after the b7 fix. The first stable release packages that implementation with the requested date-based version. The Tesla client and other device sequences need their own acceptance testing. See [validation evidence](docs/VALIDATION.md).

Expand All @@ -37,10 +37,10 @@ This is an independent integration, not the official Home Assistant MCP Server o
Install the published release through HACS:

1. In HACS, open **Custom repositories** and add `https://github.com/Jenik5/GrokConnectorForHomeAssistant` as an **Integration**.
2. Download **2026.10.4.1** or a later stable release. Stable releases do not require beta versions to be enabled in HACS.
2. Download **2026.10.5.1** or a later stable release. Stable releases do not require beta versions to be enabled in HACS.
3. Restart Home Assistant to load the newly installed Python integration.
4. Open **Settings → Devices & services → Add integration → Grok Connector**.
5. Enter your Nabu Casa remote-access HTTPS origin, for example `https://your-instance.ui.nabu.casa`, and choose the MCP language.
5. Enter your public HTTPS origin, for example `https://your-instance.ui.nabu.casa` or `https://ha.example.org:8125`, and choose the MCP language. Enter only the origin, without credentials, a path, query or fragment.
6. Select entities whose states Grok may read. Any entity domain is allowed; the list can be empty for an actions-only connector.
7. Open **Configure → Actions** to see configured commands. Each row shows its name and description, with edit and remove icons. Use **Add action** below the list to add a command; submit the list to save your changes. Successful options saves close the dialog automatically; validation problems remain visible.

Expand Down Expand Up @@ -108,6 +108,14 @@ The connector supports up to 64 reading entities and 64 named actions. Each sequ

A separate HA user or HA long-lived access token is not needed: this server issues its own restricted credentials. Keep the pairing code private. Creating a new code invalidates the previous unused code.

### Using your own public address

Version **2026.10.5.1** adds custom HTTPS origins beyond Nabu Casa; the older `2026.10.4.1` release remains Nabu Casa-only. The MCP URL is your configured origin followed by `/api/grok_connector/mcp`, for example `https://ha.example.org:8125/api/grok_connector/mcp`.

Use a hostname you control, publicly reachable by the Grok client, with a certificate valid for that hostname. HTTPS is required on the public connection; the backend may use HTTP behind a trusted TLS-terminating reverse proxy. Preserve the connector's MCP, OAuth and `/.well-known/` paths, request bodies, query strings, cookies, `Authorization`, `Origin` and `MCP-Session-Id` headers. An interactive proxy login in front of these endpoints is not supported by this integration. Configure HA's `use_x_forwarded_for` and narrowly scoped `trusted_proxies` only as required by [HA's reverse proxy documentation](https://www.home-assistant.io/integrations/http/#reverse-proxies).

The integration checks URL syntax, not DNS resolution, certificate validity or public reachability. IP literals, localhost/single-label names, credentials and paths are rejected. A terminal slash and explicit port 443 are normalized; other ports remain part of the OAuth issuer, resource and allowed Origin. Use trusted applications on the same hostname, since browser cookies are scoped to a hostname rather than a port. Changing the configured origin invalidates the resource binding of existing grants and requires new pairing. Existing Nabu Casa configurations retain the same canonical origin and credentials. See the [security assessment](docs/SECURITY-ASSESSMENT-2026-10-05.md).

Changing the reading list or any action, including its name/description or sequence, **revokes existing connector access**. Create a new pairing code and reconnect Grok. Changing only the language or an action icon preserves access. **Configure → Revoke Grok access** invalidates access/refresh tokens and pending authorization; approved OAuth client metadata remains available for reauthorization.

## Languages
Expand Down
2 changes: 1 addition & 1 deletion custom_components/grok_connector/const.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Independent paths and bounds of the community connector."""
DOMAIN = 'grok_connector'
VERSION = '2026.10.4.1'
VERSION = '2026.10.5.1'
MCP_PATH = '/api/grok_connector/mcp'
OAUTH_PATH = '/api/grok_connector/oauth'
RESOURCE_METADATA_PATH = '/.well-known/oauth-protected-resource' + MCP_PATH
Expand Down
2 changes: 1 addition & 1 deletion custom_components/grok_connector/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
"issue_tracker": "https://github.com/Jenik5/GrokConnectorForHomeAssistant/issues",
"requirements": [],
"single_config_entry": true,
"version": "2026.10.4.1"
"version": "2026.10.5.1"
}
28 changes: 23 additions & 5 deletions custom_components/grok_connector/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,31 @@ def digest(value):


def public_base(value):
"""Canonical HTTPS origin selected by the HA administrator, never a fetch target."""
# urlsplit silently strips some control characters. Reject them before parsing.
if (not isinstance(value, str) or len(value) > 2048
or any(ord(c) < 33 or ord(c) == 127 for c in value)
or "?" in value or "#" in value):
raise ValueError("An HTTPS origin with a DNS hostname is required")
parsed = urlsplit(value)
host = parsed.hostname or ""
last_label = host.rsplit(".", 1)[-1]
if (parsed.scheme != "https" or not parsed.hostname
or not re.fullmatch(r"[a-z0-9-]+\.ui\.nabu\.casa", parsed.hostname)
or parsed.port not in (None, 443) or parsed.username or parsed.password
or parsed.path not in ("", "/") or parsed.query or parsed.fragment):
raise ValueError("A Nabu Casa HTTPS origin is required")
return "https://" + parsed.hostname
or not re.fullmatch(r"[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+",
host)
or len(host) > 253
# Browsers interpret hosts ending in a number as IPv4, including hex/octal.
or re.fullmatch(r"[0-9]+|0x[0-9a-f]*", last_label)
or parsed.username is not None or parsed.password is not None
or parsed.netloc.endswith(":") or parsed.path not in ("", "/")):
raise ValueError("An HTTPS origin with a DNS hostname is required")
try:
port = parsed.port
except ValueError:
raise ValueError("Invalid port") from None
if port is not None and not 1 <= port <= 65535:
raise ValueError("Invalid port")
return "https://" + host + (f":{port}" if port not in (None, 443) else "")


def allowed_callback(value):
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Connect Grok",
"description": "Use the HTTPS address of Nabu Casa remote access. This connector has independent permissions and credentials.",
"description": "Use the public HTTPS address of your Home Assistant (Nabu Casa remote access or your own domain, optionally with a port). This connector has independent permissions and credentials.",
"data": {
"public_url": "Nabu Casa HTTPS address",
"public_url": "Public HTTPS address",
"language": "Language of MCP tools"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Enter only an HTTPS origin ending in .ui.nabu.casa, without a path or query.",
"invalid_url": "Enter only an HTTPS origin with a hostname and optional port, without credentials, a path, query or fragment.",
"invalid_selection": "Choose at most 64 entities.",
"invalid_action": "Enter a name, an optional description and a valid nonempty Home Assistant action sequence."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Enter only an HTTPS origin ending in .ui.nabu.casa, without a path or query.",
"invalid_url": "Enter only an HTTPS origin with a hostname and optional port, without credentials, a path, query or fragment.",
"invalid_selection": "Choose at most 64 entities.",
"invalid_action": "Enter a name, an optional description and a valid nonempty Home Assistant action sequence."
},
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/translations/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Připojit Groka",
"description": "Použijte HTTPS adresu vzdáleného přístupu Nabu Casa. Tento konektor má vlastní oprávnění a přihlašovací údaje.",
"description": "Použijte veřejnou HTTPS adresu svého Home Assistantu (vzdálený přístup Nabu Casa nebo vlastní doména, případně s portem). Tento konektor má vlastní oprávnění a přihlašovací údaje.",
"data": {
"public_url": "HTTPS adresa Nabu Casa",
"public_url": "Veřejná HTTPS adresa",
"language": "Jazyk nástrojů MCP"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Zadejte samotnou HTTPS adresu končící .ui.nabu.casa, bez cesty a parametrů.",
"invalid_url": "Zadejte samotnou HTTPS adresu s názvem hostitele a volitelným portem, bez přihlašovacích údajů, cesty, parametrů a fragmentu.",
"invalid_selection": "Vyberte nejvýše 64 entit.",
"invalid_action": "Zadejte název, volitelný popis a platnou neprázdnou sekvenci akcí Home Assistantu."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Zadejte samotnou HTTPS adresu končící .ui.nabu.casa, bez cesty a parametrů.",
"invalid_url": "Zadejte samotnou HTTPS adresu s názvem hostitele a volitelným portem, bez přihlašovacích údajů, cesty, parametrů a fragmentu.",
"invalid_selection": "Vyberte nejvýše 64 entit.",
"invalid_action": "Zadejte název, volitelný popis a platnou neprázdnou sekvenci akcí Home Assistantu."
},
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Grok verbinden",
"description": "Verwenden Sie die HTTPS-Adresse des Nabu-Casa-Fernzugriffs. Dieser Connector hat eigene Berechtigungen und Zugangsdaten.",
"description": "Verwenden Sie die öffentliche HTTPS-Adresse Ihres Home Assistant (Nabu-Casa-Fernzugriff oder eigene Domain, optional mit Port). Dieser Connector hat eigene Berechtigungen und Zugangsdaten.",
"data": {
"public_url": "HTTPS-Adresse von Nabu Casa",
"public_url": "Öffentliche HTTPS-Adresse",
"language": "Sprache der MCP-Werkzeuge"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Geben Sie nur eine HTTPS-Adresse mit der Endung .ui.nabu.casa ein, ohne Pfad oder Parameter.",
"invalid_url": "Geben Sie nur eine HTTPS-Adresse mit Hostname und optionalem Port ein, ohne Zugangsdaten, Pfad, Parameter oder Fragment.",
"invalid_selection": "Wählen Sie höchstens 64 Entitäten aus.",
"invalid_action": "Geben Sie einen Namen, eine optionale Beschreibung und eine gültige, nicht leere Home-Assistant-Aktionssequenz ein."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Geben Sie nur eine HTTPS-Adresse mit der Endung .ui.nabu.casa ein, ohne Pfad oder Parameter.",
"invalid_url": "Geben Sie nur eine HTTPS-Adresse mit Hostname und optionalem Port ein, ohne Zugangsdaten, Pfad, Parameter oder Fragment.",
"invalid_selection": "Wählen Sie höchstens 64 Entitäten aus.",
"invalid_action": "Geben Sie einen Namen, eine optionale Beschreibung und eine gültige, nicht leere Home-Assistant-Aktionssequenz ein."
},
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Connect Grok",
"description": "Use the HTTPS address of Nabu Casa remote access. This connector has independent permissions and credentials.",
"description": "Use the public HTTPS address of your Home Assistant (Nabu Casa remote access or your own domain, optionally with a port). This connector has independent permissions and credentials.",
"data": {
"public_url": "Nabu Casa HTTPS address",
"public_url": "Public HTTPS address",
"language": "Language of MCP tools"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Enter only an HTTPS origin ending in .ui.nabu.casa, without a path or query.",
"invalid_url": "Enter only an HTTPS origin with a hostname and optional port, without credentials, a path, query or fragment.",
"invalid_selection": "Choose at most 64 entities.",
"invalid_action": "Enter a name, an optional description and a valid nonempty Home Assistant action sequence."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Enter only an HTTPS origin ending in .ui.nabu.casa, without a path or query.",
"invalid_url": "Enter only an HTTPS origin with a hostname and optional port, without credentials, a path, query or fragment.",
"invalid_selection": "Choose at most 64 entities.",
"invalid_action": "Enter a name, an optional description and a valid nonempty Home Assistant action sequence."
},
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/translations/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Połącz Groka",
"description": "Użyj adresu HTTPS zdalnego dostępu Nabu Casa. Ten konektor ma własne uprawnienia i dane uwierzytelniające.",
"description": "Użyj publicznego adresu HTTPS swojego Home Assistanta (zdalny dostęp Nabu Casa lub własna domena, opcjonalnie z portem). Ten konektor ma własne uprawnienia i dane uwierzytelniające.",
"data": {
"public_url": "Adres HTTPS Nabu Casa",
"public_url": "Publiczny adres HTTPS",
"language": "Język narzędzi MCP"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Podaj wyłącznie adres HTTPS kończący się na .ui.nabu.casa, bez ścieżki i parametrów.",
"invalid_url": "Podaj wyłącznie adres HTTPS z nazwą hosta i opcjonalnym portem, bez danych logowania, ścieżki, parametrów i fragmentu.",
"invalid_selection": "Wybierz najwyżej 64 encje.",
"invalid_action": "Podaj nazwę, opcjonalny opis i prawidłową niepustą sekwencję akcji Home Assistant."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Podaj wyłącznie adres HTTPS kończący się na .ui.nabu.casa, bez ścieżki i parametrów.",
"invalid_url": "Podaj wyłącznie adres HTTPS z nazwą hosta i opcjonalnym portem, bez danych logowania, ścieżki, parametrów i fragmentu.",
"invalid_selection": "Wybierz najwyżej 64 encje.",
"invalid_action": "Podaj nazwę, opcjonalny opis i prawidłową niepustą sekwencję akcji Home Assistant."
},
Expand Down
8 changes: 4 additions & 4 deletions custom_components/grok_connector/translations/sk.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"step": {
"user": {
"title": "Pripojiť Groka",
"description": "Použite HTTPS adresu vzdialeného prístupu Nabu Casa. Tento konektor má vlastné oprávnenia a prihlasovacie údaje.",
"description": "Použite verejnú HTTPS adresu svojho Home Assistanta (vzdialený prístup Nabu Casa alebo vlastná doména, prípadne s portom). Tento konektor má vlastné oprávnenia a prihlasovacie údaje.",
"data": {
"public_url": "HTTPS adresa Nabu Casa",
"public_url": "Verejná HTTPS adresa",
"language": "Jazyk nástrojov MCP"
}
},
Expand All @@ -18,7 +18,7 @@
}
},
"error": {
"invalid_url": "Zadajte samotnú HTTPS adresu končiacu na .ui.nabu.casa, bez cesty a parametrov.",
"invalid_url": "Zadajte samotnú HTTPS adresu s názvom hostiteľa a voliteľným portom, bez prihlasovacích údajov, cesty, parametrov a fragmentu.",
"invalid_selection": "Vyberte najviac 64 entít.",
"invalid_action": "Zadajte názov, voliteľný popis a platnú neprázdnu sekvenciu akcií Home Assistantu."
},
Expand Down Expand Up @@ -66,7 +66,7 @@
}
},
"error": {
"invalid_url": "Zadajte samotnú HTTPS adresu končiacu na .ui.nabu.casa, bez cesty a parametrov.",
"invalid_url": "Zadajte samotnú HTTPS adresu s názvom hostiteľa a voliteľným portom, bez prihlasovacích údajov, cesty, parametrov a fragmentu.",
"invalid_selection": "Vyberte najviac 64 entít.",
"invalid_action": "Zadajte názov, voliteľný popis a platnú neprázdnu sekvenciu akcií Home Assistantu."
},
Expand Down
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The reading list is a data-disclosure boundary, not an action-target boundary. A

## OAuth boundary

`security.py` owns an independent authority; it never accepts or forwards HA credentials. Resource/issuer URLs are bound to the configured Nabu Casa HTTPS origin. Temporary registrations, authorization transactions and pairing secrets expire. Approved client metadata and hashed grants are stored with HA's supported Store API.
`security.py` owns an independent authority; it never accepts or forwards HA credentials. Resource/issuer URLs are bound to the administrator-configured public HTTPS origin, including any nonstandard port. Both Nabu Casa and custom DNS hostnames are accepted. URL syntax validation rejects ambiguous authorities and browser IPv4 representations; it performs no DNS lookup or outbound request. Public reachability and valid TLS are the operator's responsibility. Temporary registrations, authorization transactions and pairing secrets expire. Approved client metadata and hashed grants are stored with HA's supported Store API. See the [custom-origin security assessment](SECURITY-ASSESSMENT-2026-10-05.md).

The browser form uses per-transaction Secure/HttpOnly/SameSite=Lax cookies, same-origin referrer metadata, HTML escaping and script-free CSP. `form-action` includes only the verified registered callback origin because Chrome applies this policy to the OAuth redirect as well. Authorization POST rejects a missing or mismatching transaction cookie and a foreign Origin. The server permits native/server clients that omit Origin; possession of the cookie and the single-use pairing secret is still required.

Expand Down
Loading
Loading