Skip to content

fix(gateway): restore mattermost/whatsapp/dingtalk/wecom interactive setup - #103

Closed
dizhaky wants to merge 2 commits into
mainfrom
claude/upbeat-pike-c717ff
Closed

fix(gateway): restore mattermost/whatsapp/dingtalk/wecom interactive setup#103
dizhaky wants to merge 2 commits into
mainfrom
claude/upbeat-pike-c717ff

Conversation

@dizhaky

@dizhaky dizhaky commented Jul 18, 2026

Copy link
Copy Markdown
Owner

The plugin-migration refactor (e39b468) removed these from the bespoke
setup dispatch claiming plugins/platforms// took over, but those
plugins were never created:

  • mattermost: dispatch mapping restored (_setup_mattermost still lives
    in hermes_cli/setup.py; the generic vars fallback lost its guided flow)
  • whatsapp: _setup_whatsapp restored (delegates to cmd_whatsapp); the
    platform had fallen through to a bare config.yaml hint
  • dingtalk, wecom: setup functions AND _PLATFORMS entries restored
    verbatim from e39b468^ — both platforms had vanished from the setup
    menu entirely (they only appear via plugin registration, which does
    not exist). Their adapters (gateway/platforms/{dingtalk,wecom}.py) and
    QR-auth helpers were never removed and still work.

feishu is intentionally left out — it is being restored on
dan/DAN-2143-fix-main-tests. wecom_callback remains missing (follow-up).

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

dizhaky and others added 2 commits July 17, 2026 12:51
…setup

The plugin-migration refactor (e39b468) removed these from the bespoke
setup dispatch claiming plugins/platforms/<name>/ took over, but those
plugins were never created:

- mattermost: dispatch mapping restored (_setup_mattermost still lives
  in hermes_cli/setup.py; the generic vars fallback lost its guided flow)
- whatsapp: _setup_whatsapp restored (delegates to cmd_whatsapp); the
  platform had fallen through to a bare config.yaml hint
- dingtalk, wecom: setup functions AND _PLATFORMS entries restored
  verbatim from e39b468^ — both platforms had vanished from the setup
  menu entirely (they only appear via plugin registration, which does
  not exist). Their adapters (gateway/platforms/{dingtalk,wecom}.py) and
  QR-auth helpers were never removed and still work.

feishu is intentionally left out — it is being restored on
dan/DAN-2143-fix-main-tests. wecom_callback remains missing (follow-up).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same incomplete plugin migration (e39b468): the wecom_callback
_PLATFORMS dict was deleted claiming a plugin took over, but no plugin
exists, so the platform was invisible in 'hermes gateway setup'. The
adapter (gateway/platforms/wecom_callback.py) and env-based config wiring
were never removed. Entry restored verbatim from e39b468^; it uses the
generic vars-based flow, so no dispatch mapping is needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dizhaky
dizhaky enabled auto-merge (squash) July 18, 2026 03:11

@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: 2839617a9e

ℹ️ 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 thread hermes_cli/gateway.py
client_id, client_secret = result
save_env_value("DINGTALK_CLIENT_ID", client_id)
save_env_value("DINGTALK_CLIENT_SECRET", client_secret)
save_env_value("DINGTALK_ALLOW_ALL_USERS", "true")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Don’t enable DingTalk open access by default

When the DingTalk wizard succeeds, this writes DINGTALK_ALLOW_ALL_USERS=true without an explicit user choice; the manual path repeats the same write below. gateway/run.py::_is_user_authorized treats that as a per-platform allow-all, while gateway/platforms/dingtalk.py defaults to no sender allowlist and DINGTALK_REQUIRE_MENTION=false, so a newly configured bot added to a group will process messages from any member immediately after setup. Please keep the deny-by-default pairing/allowlist flow unless the operator explicitly opts into open access.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
"key": "dingtalk",
"label": "DingTalk",
"emoji": "💬",
"token_var": "DINGTALK_CLIENT_ID",

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 Require the DingTalk secret before reporting success

With token_var set only to DINGTALK_CLIENT_ID, the generic fallback used by the manual path treats DINGTALK_CLIENT_SECRET as optional (_setup_standard_platform only aborts when the token var is blank), and _platform_status also reports configured as soon as the client ID exists. gateway/config.py only enables DingTalk when both ID and secret are present, so a user who enters an AppKey but skips AppSecret can finish setup/restart with a platform that never loads. Please validate both credentials before the setup is considered successful.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
"key": "wecom_callback",
"label": "WeCom Callback (Self-Built App)",
"emoji": "💬",
"token_var": "WECOM_CALLBACK_CORP_ID",

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 Require the WeCom callback secret before reporting success

This new generic setup entry makes only WECOM_CALLBACK_CORP_ID mandatory, so the wizard can save a Corp ID, skip WECOM_CALLBACK_CORP_SECRET, print the platform as configured, and offer to start/restart the gateway. However gateway/config.py only creates Platform.WECOM_CALLBACK when both Corp ID and Corp Secret are set, so that completed setup leaves WeCom Callback absent at runtime. Please require the secret (or provide a bespoke validator/status check) before reporting success.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
# mattermost moved into the plugin: setup_fn is registered by
# plugins/platforms/mattermost/adapter.py::register() and dispatched
# via the plugin path in _configure_platform().
"mattermost": _s._setup_mattermost,

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 Set allow-all when Mattermost setup promises open access

Routing Mattermost to _setup_mattermost makes the "leave empty for open access" path ineffective: that helper only prints the warning and never writes MATTERMOST_ALLOW_ALL_USERS or GATEWAY_ALLOW_ALL_USERS. The gateway then falls through _is_user_authorized with no allowlists and denies every Mattermost sender, so a user who follows the setup prompt gets a bot that appears configured but cannot be used until they manually edit auth settings.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
access_idx = prompt_choice(" How should unauthorized users be handled?", access_choices, 1)
if access_idx == 0:
save_env_value("WECOM_DM_POLICY", "open")
save_env_value("GATEWAY_ALLOW_ALL_USERS", "true")

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 Scope WeCom open access to WeCom only

When the WeCom wizard's open-access option is selected, this writes the global GATEWAY_ALLOW_ALL_USERS=true instead of the platform-specific WECOM_ALLOW_ALL_USERS=true. In installs with other platforms that rely on the default deny behavior and have no allowlist, opting WeCom into open access unexpectedly authorizes users on those platforms too.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
Comment on lines +4877 to +4879
{"name": "WECOM_CALLBACK_TOKEN", "prompt": "Callback Token", "password": True,
"help": "The Token from your WeCom callback configuration."},
{"name": "WECOM_CALLBACK_ENCODING_AES_KEY", "prompt": "Encoding AES Key", "password": True,

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 Require WeCom callback crypto fields before success

These callback Token and EncodingAESKey prompts are optional under _setup_standard_platform, so a user can skip them and still be told WeCom Callback is configured. The callback adapter constructs WXBizMsgCrypt for every incoming verification/message, and gateway/platforms/wecom_crypto.py raises when either value is missing or the AES key is not 43 chars, so WeCom's callbacks will be rejected with 400s even though setup completed.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
"help": "The Token from your WeCom callback configuration."},
{"name": "WECOM_CALLBACK_ENCODING_AES_KEY", "prompt": "Encoding AES Key", "password": True,
"help": "The EncodingAESKey from your WeCom callback configuration."},
{"name": "WECOM_CALLBACK_PORT", "prompt": "Callback server port (default: 8645)", "password": False,

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 Validate the WeCom callback port before saving

The generic prompt saves any non-empty WECOM_CALLBACK_PORT string, but gateway/config.py later does int(os.getenv("WECOM_CALLBACK_PORT", "8645")) without catching ValueError. If the operator types a non-numeric port during setup, the next gateway config load crashes before startup instead of falling back or showing a setup error.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
"help": "Your WeCom enterprise Corp ID."},
{"name": "WECOM_CALLBACK_CORP_SECRET", "prompt": "Corp Secret", "password": True,
"help": "The secret for your self-built application."},
{"name": "WECOM_CALLBACK_AGENT_ID", "prompt": "Agent ID", "password": False,

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 Require the WeCom callback agent ID before success

This Agent ID prompt is optional in the generic setup flow, but the callback adapter uses it for every reply as agentid in the WeCom message/send payload and falls back to 0 when it is blank. With Corp ID/secret plus callback crypto configured but no Agent ID, the gateway can receive callbacks yet all agent responses are rejected by WeCom, so setup should require a non-empty valid Agent ID before reporting the platform configured.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
"help": "The EncodingAESKey from your WeCom callback configuration."},
{"name": "WECOM_CALLBACK_PORT", "prompt": "Callback server port (default: 8645)", "password": False,
"help": "Port for the HTTP callback server."},
{"name": "WECOM_CALLBACK_ALLOWED_USERS", "prompt": "Allowed user IDs (comma-separated, or empty)", "password": False,

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 Scope WeCom Callback open access to callback only

Adding this allowlist field sends WeCom Callback through _setup_standard_platform; when the operator chooses its "Enable open access" option, that helper writes the global GATEWAY_ALLOW_ALL_USERS=true rather than WECOM_CALLBACK_ALLOW_ALL_USERS=true. On a multi-platform gateway, opting only WeCom Callback into open access therefore authorizes users on every other platform that has no allowlist.

Useful? React with 👍 / 👎.

Comment thread hermes_cli/gateway.py
_setup_standard_platform(dingtalk_platform)
return

result = dingtalk_qr_auth()

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 Avoid unpinned installs in DingTalk QR setup

Selecting the new default QR setup path calls dingtalk_qr_auth(), whose missing-qrcode fallback runs uv pip install qrcode / pip install qrcode without a pinned version. On hosts without the [dingtalk] extra this now performs an unpinned runtime install from the setup wizard, bypassing the repo's pinned qrcode==7.4.2 dependency and lockfile policy; use the pinned lazy-deps path or just show the manual link when the package is absent.

Useful? React with 👍 / 👎.

@dizhaky

dizhaky commented Jul 18, 2026

Copy link
Copy Markdown
Owner Author

Closing as superseded. The interactive setup for these platforms already landed in main via #93.

Main dispatches setup through _builtin_setup_fn() + the generic _setup_standard_platform() fallback, driven by the vars schema on each _PLATFORMS entry. Those picker entries (dingtalk, wecom, wecom_callback, mattermost, whatsapp) are all present in main (gateway.py:4702–4871), and main carries an explicit design note that these platforms intentionally use the generic vars-schema flow with no bespoke setup function needed.

This PR's approach — adding bespoke _setup_whatsapp() / _setup_dingtalk() / _setup_wecom() helpers — is the older, superseded design. Those functions aren't registered in the _builtin_setup_fn dispatch map on main, so merging them would only add unreachable dead code (and the conflicts reflect that divergence). No unique behavior is lost by closing.

@dizhaky dizhaky closed this Jul 18, 2026
auto-merge was automatically disabled July 18, 2026 03:27

Pull request was closed

@dizhaky
dizhaky deleted the claude/upbeat-pike-c717ff branch July 18, 2026 03:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant