Skip to content

fix: require Feishu webhook authentication - #1638

Merged
serrrfirat merged 3 commits into
stagingfrom
fix/feishu-webhook-auth-staging
Mar 27, 2026
Merged

serrrfirat merged 3 commits into
stagingfrom
fix/feishu-webhook-auth-staging

Conversation

@serrrfirat

Copy link
Copy Markdown
Collaborator

Summary

  • reject unauthenticated Feishu webhooks unless the host already authenticated the request or the Feishu body token matches the configured verification token
  • inject and persist the Feishu verification token in runtime config and require it during setup
  • keep Feishu off the generic host-managed webhook-secret gate so legitimate body-token validation can run

Testing

  • cargo test --manifest-path channels-src/feishu/Cargo.toml
  • cargo test test_webhook_sig_plus_secret (currently blocked by an existing staging compile error in src/tunnel/mod.rs: GatewayConfig initializers are missing memory_layers, user_tokens, and workspace_read_scopes)

@github-actions github-actions Bot added scope: channel/wasm WASM channel runtime size: M 50-199 changed lines risk: medium Business logic, config, or moderate-risk modules contributor: experienced 6-19 merged PRs labels Mar 25, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the security and configuration of Feishu channel integration by enforcing webhook authentication. It introduces a mandatory verification token during setup and refines the webhook handling logic to ensure that Feishu's specific authentication requirements are met, preventing unauthenticated access while maintaining flexibility for host-level validation.

Highlights

  • Feishu Webhook Authentication: Feishu webhooks now explicitly require authentication. Unauthenticated requests will be rejected unless the host has already validated them or the Feishu body token matches the configured verification token.
  • Mandatory Verification Token: The Feishu verification token is now a required parameter during setup and is persisted in the runtime configuration.
  • Exclusion from Generic Host-Managed Secrets: Feishu webhooks have been excluded from the generic host-managed webhook-secret validation to allow for its specific body-token validation mechanism.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for Feishu webhook verification tokens. It makes the feishu_verification_token a required capability, adds it to the channel's configuration, and implements a new is_authenticated_webhook function to handle authentication logic based on this token or host-validated secrets. Host-managed webhook secrets are now explicitly disabled for the Feishu channel. The review comments suggest simplifying an if-let-else block for writing the verification token and address a design concern regarding hardcoding the "feishu" channel name for special authentication logic, which violates a rule and impacts maintainability.

Comment on lines +308 to +312
if let Some(ref verification_token) = config.verification_token {
let _ = channel_host::workspace_write(VERIFICATION_TOKEN_PATH, verification_token);
} else {
let _ = channel_host::workspace_write(VERIFICATION_TOKEN_PATH, "");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This if-let-else block can be simplified by using as_deref() and unwrap_or() to make the code more concise and readable.

        let token_to_write = config.verification_token.as_deref().unwrap_or("");
        let _ = channel_host::workspace_write(VERIFICATION_TOKEN_PATH, token_to_write);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 810cb18 — now uses config.verification_token.as_deref().unwrap_or(""), and further simplified in c6704b8 to use the same if let Some pattern as app_id/app_secret.

Comment thread src/channels/wasm/setup.rs Outdated
Comment on lines +392 to +396
if channel_name == "feishu" {
None
} else {
webhook_secret
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Hardcoding the channel name "feishu" to special-case its webhook authentication logic makes the code harder to maintain and violates Rule 9. Instead of hardcoding specific provider IDs, prefer checking for a common property (like a specific environment variable or a feature flag) that defines the group of providers needing this special handling. This approach improves maintainability and scalability.

References
  1. When implementing backward compatibility logic, scope it precisely to the intended cases. Instead of hardcoding specific provider IDs, prefer checking for a common property (like a specific environment variable) that defines the group of providers needing the compatibility logic.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 810cb18 — replaced the hardcoded "feishu" check with a generic managed_by_host field in the webhook capabilities schema (WebhookSchema.managed_by_host). Channels now opt out of host-managed secret validation declaratively via feishu.capabilities.json.

@zmanian zmanian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review: fix: require Feishu webhook authentication

Core auth logic is correct and the security improvement is real. One item to verify before merge.

Medium

  1. V2 event token location: FeishuEvent.token appears to only be populated during url_verification challenges. For Feishu Event Subscription v2.0, the verification token may be in event.header.token instead. If the top-level token is absent on normal v2 message events, this PR would reject all legitimate Feishu messages. Verify against Feishu's v2 event docs before merging.

  2. Hardcoded "feishu" channel name in host_managed_webhook_secret: Creates a Feishu-specific carve-out in generic WASM infrastructure. Consider having channels declare "host_managed_auth": false in capabilities instead.

Low

  1. Timing side-channel on token comparison: expected == provided is variable-time. Low practical risk over network, but since this is a security PR, constant-time comparison (e.g., subtle::ConstantTimeEq) would be the right call.

  2. Empty-string write when token absent: Consider skipping the write entirely, consistent with app_id/app_secret handling.

Info

  • Breaking change for existing instances with no verification token configured -- they'll reject all webhooks after upgrade. Correct behavior, but call out in release notes.
  • Test coverage is solid -- all 6 combinations of the auth matrix covered.

Approve once the v2 token location is verified.

@github-actions github-actions Bot added size: L 200-499 changed lines and removed size: M 50-199 changed lines labels Mar 25, 2026
@serrrfirat
serrrfirat requested a review from zmanian March 26, 2026 14:11
…secret

Address zmanian review nit #4: only write verification_token to workspace
when present, matching the if-let pattern used for app_id and app_secret.
Functionally identical (the auth check filters empty strings), but
consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@serrrfirat

Copy link
Copy Markdown
Collaborator Author

Addressing @zmanian's review

All items from your review have been addressed across commits 810cb18 and c6704b8:

Medium

  1. V2 event token location ✅ — Verified against Feishu Event Subscription v2.0 docs. The v2 event envelope places the verification token in header.token. The new request_verification_token() function checks event.header.token first (v2), then falls back to event.token (v1/url_verification). Both paths are covered by tests.

  2. Hardcoded "feishu" channel name ✅ — Replaced with a generic managed_by_host field in WebhookSchema. Channels now opt out of host-managed secret validation declaratively via capabilities JSON ("managed_by_host": false). Defaults to true for backwards compatibility.

Low

  1. Timing side-channel ✅ — Now uses subtle::ConstantTimeEq for token comparison.

  2. Empty-string write when token absent ✅ — Fixed in c6704b8 to use the same if let Some pattern as app_id/app_secret. Functionally identical (the auth check already filters empty strings via .filter(|token| !token.is_empty())), but consistent.

Note on CI

The test_webhook_sig_plus_secret integration test is blocked by a pre-existing staging compile error in src/tunnel/mod.rs (missing memory_layers, user_tokens, workspace_read_scopes fields in GatewayConfig). This is unrelated to this PR. All Feishu-specific tests pass (8/8).

@zmanian zmanian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-review: Feishu webhook authentication

All flagged concerns resolved:

  1. v2 event token -- Fixed: request_verification_token() checks event.header.token first (v2), falls back to event.token (v1). Two dedicated tests cover both paths.
  2. Empty-string write -- Fixed: Token filtered with .filter(|t| !t.is_empty()) before comparison.
  3. Constant-time comparison added: Uses subtle::ConstantTimeEq.
  4. managed_by_host capability flag: Clean design for channels that handle their own auth.

Approve. Ship it.

@serrrfirat
serrrfirat merged commit 30db07c into staging Mar 27, 2026
14 checks passed
@serrrfirat
serrrfirat deleted the fix/feishu-webhook-auth-staging branch March 27, 2026 07:49
DougAnderson444 pushed a commit to DougAnderson444/ironclaw that referenced this pull request Mar 29, 2026
* fix: require Feishu webhook authentication

* fix: handle Feishu v2 webhook token auth

* fix: skip empty verification token write, consistent with app_id/app_secret

Address zmanian review nit nearai#4: only write verification_token to workspace
when present, matching the if-let pattern used for app_id and app_secret.
Functionally identical (the auth check filters empty strings), but
consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
* fix: require Feishu webhook authentication

* fix: handle Feishu v2 webhook token auth

* fix: skip empty verification token write, consistent with app_id/app_secret

Address zmanian review nit nearai#4: only write verification_token to workspace
when present, matching the if-let pattern used for app_id and app_secret.
Functionally identical (the auth check filters empty strings), but
consistent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: experienced 6-19 merged PRs risk: medium Business logic, config, or moderate-risk modules scope: channel/wasm WASM channel runtime size: L 200-499 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants