Skip to content

feat: expand energy gateway authorized-client support - #107

Merged
Bre77 merged 3 commits into
mainfrom
fm/tfa-authclient-impl
Aug 2, 2026
Merged

feat: expand energy gateway authorized-client support#107
Bre77 merged 3 commits into
mainfrom
fm/tfa-authclient-impl

Conversation

@Bre77

@Bre77 Bre77 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Intent

Implement the energy-gateway authorized-client findings from a live-verified aiopowerwall/Powerwall-3 test session (findings.md, relayed by the captain): (1) BREAKING rename of AuthorizedClientState - PENDING->PENDING_VERIFICATION, old PENDING_VERIFICATION(2)->PENDING_VERIFICATION_TIMEOUT (a terminal presence-proof-window-expired state, not in-progress), plus INVALID=0/REMOVED=4; (2) AuthorizedClientKeyType gains INVALID=0/ECC=2, drop the 'not published' caveat; (3) Tesla.ec_public_der_spki/_b64 helpers mirroring the existing rsa_public_der_pkcs1 pair, since ECC keys must be SPKI DER not a raw X9.62 point; (4) typed remove_authorized_client(public_key: bytes|str) on TeslemetryEnergySite (was an untyped params passthrough) and a new implementation on the base tesla EnergySite via the same _command('authorization', ...) route add_authorized_client uses - the base-class route is explicitly documented as inferred/unverified (only local v1r removal was hardware-verified) and does not assert on response fields since the response message is empty; (5) add_authorized_client docstring documents the ~9-minute presence-proof window, that PENDING_VERIFICATION_TIMEOUT is terminal, that re-registering the same key resets the window as the correct retry, the 59s physical-toggle observation, and no cloud auto-verify observed; (6) remove_authorized_client docstring documents the security asymmetry - removal needs no physical presence proof, so any paired key can revoke every other key including the owner's; (7) deliberately do NOT offer ECC as an RSA alternative in any TEDAPI-aimed keygen/pairing helper (ECC registers fine but cannot authenticate the LAN TEDapi v1r protocol - its SignatureData oneof has no ECDSA member) - Tesla.rsa_private_key's RSAPrivateKey assertion is kept as-is; (8) new AuthorizationRole and AuthorizedVerificationType enums for typing list_authorized_clients output. Scope is deliberately KISS: enum/docstring/method-signature changes plus two small helper properties, no new abstractions. Added tests pin the corrected enum values against the gateway's real numbers (so a regression to the old mislabelled names fails), the SPKI helper's output shape/length, and remove_authorized_client's bytes-to-base64/str-passthrough encoding on both the base and Teslemetry energy site classes. Updated tests/test_teslemetry_authorized_clients.py's existing assertions to the corrected enum names/values (this is the intentional breaking change, not a regression). Also added an AGENTS.md entry (CLAUDE.md is a symlink to it) summarizing this durable knowledge for future sessions. No CHANGELOG.md file exists in this repo - the project's release-notes convention is the PR/commit message plus the GitHub Release generated from the version-bump tag, not a tracked changelog file, so the breaking-rename callout belongs in the commit message and PR body rather than a new changelog file.

What Changed

  • Correct authorized-client state/key enums, including the breaking state rename, and add typed authorization roles and verification data while preserving unknown values.
  • Add ECC SPKI public-key helpers and authorized-client removal support for Fleet API and Teslemetry energy sites.
  • Document gateway pairing, verification timeout/retry behavior, ECC limitations, and the security implications of key removal; add focused coverage for enums, key encoding, parsing, and removal payloads.

Risk Assessment

✅ Low: The follow-up correctly adds typed roles and verification fields with per-value enum normalization, unknown-value preservation, absent-field handling, and focused coverage, resolving the prior intent-conformance issue without widening scope.

Testing

Inspected the authorized-client changes, ran both focused test modules successfully, and captured a concrete API/cryptographic transcript demonstrating corrected enum values, valid EC SPKI output, bytes-to-base64 Fleet removal, and string-passthrough Teslemetry removal; no working-tree artifacts or actionable failures remained.

Evidence: Authorized-client API behavior demonstration
{
  "corrected_states": {
    "INVALID": 0,
    "PENDING_VERIFICATION": 1,
    "PENDING_VERIFICATION_TIMEOUT": 2,
    "VERIFIED": 3,
    "REMOVED": 4
  },
  "ecc_spki": {
    "der_length": 91,
    "der_prefix_hex": "30593013",
    "base64_round_trip": true
  },
  "fleet_remove_payload": {
    "authorization": {
      "remove_authorized_client_request": {
        "public_key": "cmF3LWRlci1ieXRlcw=="
      }
    }
  },
  "teslemetry_remove": {
    "method": "POST",
    "path": "api/1/energy_sites/12345/command/remove_authorized_client",
    "json": {
      "public_key": "already-base64=="
    }
  }
}

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • 🚨 tesla_fleet_api/teslemetry/energysite.py:73 - Required intent says the new AuthorizationRole and AuthorizedVerificationType enums are “for typing list_authorized_clients output,” but AuthorizedClient still explicitly models only public_key and state; captured roles and verification values remain accessible only through untyped raw. Please either add typed roles and verification fields (including enum normalization that preserves unknown values) or confirm that merely defining otherwise-unused enums satisfies the intended output typing.

🔧 Fix: Type authorized-client roles and verification
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Inspected the target diff against base commit 95daa121816c1b70937da94b8b250a6dbb80dd2a.
  • uv run pytest -q tests/test_energysite_authorized_clients.py tests/test_teslemetry_authorized_clients.py
  • Ran an end-to-end mocked API demonstration that generated a P-256 SPKI key, verified its 91-byte DER/base64 representation, and captured Fleet and Teslemetry removal request payloads.
  • git status --short confirmed testing created no working-tree changes.
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

firstmate crewmate added 3 commits August 2, 2026 17:31
…support

Live-verified against a real Powerwall 3: AuthorizedClientState was
mislabelled (a terminal timeout state was named as in-progress, which
hangs a poll-while-not-VERIFIED pairing flow forever). Corrects the
enum and adds the missing INVALID/REMOVED members.

BREAKING: AuthorizedClientState.PENDING -> PENDING_VERIFICATION, and
the old PENDING_VERIFICATION (value 2) -> PENDING_VERIFICATION_TIMEOUT
(a terminal failure, not in-progress).

Also:
- AuthorizedClientKeyType gains INVALID/ECC (both live-verified to
  register and list back correctly); drop the "not published" caveat.
- Tesla.ec_public_der_spki/_b64 mirror the RSA public-key helpers -
  ECC keys must be SPKI DER, not a raw point, or the gateway rejects
  them with an asn1 structure error.
- EnergySite.remove_authorized_client added to the base Fleet-API
  class (previously cloud-missing); TeslemetryEnergySite's variant is
  now typed to match add_authorized_client's encoding behavior.
- New AuthorizationRole/AuthorizedVerificationType enums for typing
  list_authorized_clients output.
- Docstrings document the ~9-minute presence-proof window, the
  removal security asymmetry (no presence proof required), and that
  ECC keys cannot authenticate the LAN TEDapi v1r protocol.
@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Aug 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6ec883ba5a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +196 to +200
return await self._command(
"authorization",
"remove_authorized_client_request",
{"public_key": public_key_b64},
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept empty successful removal responses

When the gateway returns an empty body—the new method contract explicitly allows this for some firmware—this call still passes through TeslaFleetApi._request, which rejects non-JSON responses at tesla/fleet.py:208-210 and attempts JSON decoding otherwise. A successful removal with a 204 or empty response will therefore raise ResponseError instead of returning success; normalize an empty successful response to {} before completing this command.

AGENTS.md reference: AGENTS.md:L151-L151

Useful? React with 👍 / 👎.

@Bre77
Bre77 merged commit 0cf9962 into main Aug 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fm Opened by a Firstmate crewmate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant