From d7f42e368e04b8ed3cf58c40de2edffc00d08343 Mon Sep 17 00:00:00 2001 From: teknium1 <127238744+teknium1@users.noreply.github.com> Date: Mon, 8 Jun 2026 12:03:48 -0700 Subject: [PATCH] =?UTF-8?q?feat(photon):=20full=20channel=20parity=20?= =?UTF-8?q?=E2=80=94=20gateway=20setup,=20pairing,=20PII=20redaction,=20do?= =?UTF-8?q?c=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings Photon in line with how every other Hermes gateway channel behaves, instead of being a one-off with its own surfaces. - gateway setup: register a `setup_fn` so Photon appears in `hermes gateway setup` (the unified wizard) and runs the same device-login + project + user + sidecar flow as `hermes photon setup`. Adds `cli.gateway_setup()` as the zero-arg entry point. - PII redaction: flip `pii_safe` False -> True. The comment already said iMessage E.164 numbers should be redacted; the value contradicted it. Now matches BlueBubbles (the other iMessage channel) which is in _PII_SAFE_PLATFORMS β€” phone numbers are stripped before reaching the LLM. - Pairing/authz: already worked via the registry's allowed_users_env / allow_all_env generic path in authz_mixin; documented it. The adapter forwards unauthorized DMs to the gateway (no intake gating), so the pairing handshake fires and `hermes pairing approve photon ` works. - Docs: fixed the `hermes photon status` output block to match the real labels (project key / webhook key, not project secret / webhook secret), added the missing PHOTON_API_HOST / PHOTON_DASHBOARD_HOST / PHOTON_HOME_CHANNEL_NAME env vars, and added gateway-setup + authorize-users sections mirroring the other channel docs. Validation: 26/26 photon tests, 6504/6504 gateway+plugins tests, registry E2E confirms setup_fn dispatch + pii_safe + authz envs all wired. --- plugins/platforms/photon/adapter.py | 14 ++++-- plugins/platforms/photon/cli.py | 25 +++++++++++ website/docs/user-guide/messaging/photon.md | 49 +++++++++++++++++++-- 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/plugins/platforms/photon/adapter.py b/plugins/platforms/photon/adapter.py index 0747ab7db3e..30448da3a03 100644 --- a/plugins/platforms/photon/adapter.py +++ b/plugins/platforms/photon/adapter.py @@ -696,6 +696,10 @@ async def _standalone_send( def register(ctx) -> None: """Called by the Hermes plugin loader at startup.""" + # Local import to avoid argparse work at module load; reused for both the + # gateway-setup hook and the `hermes photon` CLI command below. + from . import cli as _cli + ctx.register_platform( name="photon", label="Photon iMessage", @@ -709,6 +713,9 @@ def register(ctx) -> None: "Spectrum project, links your phone number, installs the " "spectrum-ts sidecar)." ), + # Surfaces Photon in `hermes gateway setup` alongside every other + # channel β€” same unified onboarding wizard, no Photon-only detour. + setup_fn=_cli.gateway_setup, env_enablement_fn=_env_enablement, cron_deliver_env_var="PHOTON_HOME_CHANNEL", standalone_sender_fn=_standalone_send, @@ -717,8 +724,9 @@ def register(ctx) -> None: max_message_length=_MAX_MESSAGE_LENGTH, emoji="πŸ“±", # iMessage carries E.164 phone numbers β€” treat session descriptions - # as PII-sensitive so they get redacted in logs. - pii_safe=False, + # as PII-sensitive so they get redacted before reaching the LLM + # (matches the BlueBubbles iMessage channel in _PII_SAFE_PLATFORMS). + pii_safe=True, allow_update_command=True, platform_hint=( "You are communicating via Photon Spectrum (iMessage). " @@ -730,8 +738,6 @@ def register(ctx) -> None: ) # Register CLI subcommands β€” `hermes photon ...` - from . import cli as _cli # local import to avoid argparse at module load - ctx.register_cli_command( name="photon", help="Set up and manage the Photon iMessage integration", diff --git a/plugins/platforms/photon/cli.py b/plugins/platforms/photon/cli.py index 1316ace252b..615ed9db14a 100644 --- a/plugins/platforms/photon/cli.py +++ b/plugins/platforms/photon/cli.py @@ -300,6 +300,31 @@ def _cmd_webhook(args: argparse.Namespace) -> int: return 2 +# --------------------------------------------------------------------------- +# Gateway-setup entry point +# +# `hermes gateway setup` discovers platforms via the registry and calls each +# entry's zero-arg ``setup_fn``. Photon registers this function so it appears +# in the unified setup wizard alongside every other channel β€” same onboarding +# surface, no Photon-specific detour. It runs the identical device-login + +# project + user + sidecar flow as ``hermes photon setup`` with interactive +# defaults (phone is prompted when stdin is a TTY). + +def gateway_setup() -> None: + """Run Photon first-time setup from the `hermes gateway setup` wizard.""" + args = argparse.Namespace( + photon_command="setup", + project_name=None, + phone=None, + first_name=None, + last_name=None, + email=None, + no_browser=False, + skip_sidecar_install=False, + ) + _cmd_setup(args) + + # --------------------------------------------------------------------------- # Small interactive helpers diff --git a/website/docs/user-guide/messaging/photon.md b/website/docs/user-guide/messaging/photon.md index feb373618b4..41f4b54aa76 100644 --- a/website/docs/user-guide/messaging/photon.md +++ b/website/docs/user-guide/messaging/photon.md @@ -45,12 +45,20 @@ endpoint we'll retire the sidecar in a follow-up release. ## First-time setup +Either run the unified gateway wizard and pick **Photon iMessage**: + +```bash +hermes gateway setup +``` + +…or run the Photon setup directly (the wizard calls the same flow): + ```bash # Device-code login + project + user + sidecar deps, all in one hermes photon setup --phone +15551234567 ``` -The wizard: +The setup: 1. Opens `https://app.photon.codes/` for device approval 2. Creates a Spectrum-enabled project under your account @@ -62,6 +70,36 @@ Credentials are stored in `~/.hermes/auth.json` under `credential_pool.photon` (bearer token) and `credential_pool.photon_project` (project id + secret). +## Authorizing users + +Photon uses the same authorization model as every other Hermes +channel. Choose one approach: + +**DM pairing (default).** When an unknown number messages your Photon +line, Hermes replies with a pairing code. Approve it with: + +```bash +hermes pairing approve photon +``` + +Use `hermes pairing list` to see pending codes and approved users. + +**Pre-authorize specific numbers** (in `~/.hermes/.env`): + +```bash +PHOTON_ALLOWED_USERS=+15551234567,+15559876543 +``` + +**Open access** (dev only, in `~/.hermes/.env`): + +```bash +PHOTON_ALLOW_ALL_USERS=true +``` + +When `PHOTON_ALLOWED_USERS` is set, unknown senders are silently +ignored rather than offered a pairing code (the allowlist signals you +deliberately restricted access). + ## Registering the webhook Photon needs a public URL it can POST to. Expose your local listener @@ -109,17 +147,17 @@ Photon iMessage status ────────────────────── device token : βœ“ stored project id : 3c90c3cc-0d44-4b50-... - project secret : βœ“ stored + project key : βœ“ stored + webhook key : βœ“ set node binary : /usr/bin/node sidecar deps : βœ“ installed - webhook secret : βœ“ set ``` Common issues: - **`sidecar deps : βœ— run hermes photon install-sidecar`** β€” Node is installed but `spectrum-ts` isn't. Run the suggested command. -- **`webhook secret : ⚠ unset β€” verification disabled`** β€” the +- **`webhook key : ⚠ unset β€” verification disabled`** β€” the plugin will accept ANY POST to the webhook URL, which is unsafe. Re-run `hermes photon webhook register` and store the secret. - **`PHOTON_WEBHOOK_PORT` already in use** β€” set a different port via @@ -160,8 +198,11 @@ hermes photon webhook delete # remove one | `PHOTON_SIDECAR_AUTOSTART`| `true` | Whether the adapter spawns the sidecar | | `PHOTON_NODE_BIN` | `which node` | Override the Node binary path | | `PHOTON_HOME_CHANNEL` | (unset) | Default space ID for cron / notifications | +| `PHOTON_HOME_CHANNEL_NAME`| (unset) | Human label for the home channel | | `PHOTON_ALLOWED_USERS` | (unset) | Comma-separated E.164 allowlist | | `PHOTON_ALLOW_ALL_USERS` | `false` | Dev only β€” accept any sender | +| `PHOTON_API_HOST` | `spectrum.photon.codes` | Override the Spectrum management API host | +| `PHOTON_DASHBOARD_HOST` | `app.photon.codes` | Override the dashboard / device-login host | [photon]: https://photon.codes/ [app]: https://app.photon.codes/