feat(photon): full channel parity — gateway setup, pairing, PII redaction, doc fixes

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 <CODE>` 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.
This commit is contained in:
teknium1 2026-06-08 12:03:48 -07:00 committed by Teknium
parent 630318e958
commit d7f42e368e
3 changed files with 80 additions and 8 deletions

View file

@ -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",

View file

@ -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

View file

@ -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 <CODE>
```
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 <webhook-id> # 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/