Skip to content

feat(gateway): add Microsoft Teams source#139

Merged
yordis merged 10 commits into
mainfrom
yordis/feat-ms-teams-source
Apr 29, 2026
Merged

feat(gateway): add Microsoft Teams source#139
yordis merged 10 commits into
mainfrom
yordis/feat-ms-teams-source

Conversation

@yordis
Copy link
Copy Markdown
Member

@yordis yordis commented Apr 28, 2026

  • Teams events need the same reliable ingress path as the other collaboration sources.
  • Graph subscriptions need edge validation so downstream consumers can rely on trusted notification flow.
  • Rich Teams notifications need to retain validation context for consumers that decrypt resource data.

@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 28, 2026

PR Summary

Medium Risk
Adds a new externally-facing webhook endpoint and validation logic, which could impact ingress reliability/security if misconfigured or if Graph payload shapes differ from assumptions.

Overview
Adds Microsoft Teams as a new trogon-gateway source, configurable via TROGON_SOURCE_MICROSOFT_TEAMS_CLIENT_STATE (and standard per-source stream/subject settings), and mounts a new /microsoft-teams/webhook route.

Introduces a new trogon-source-microsoft-teams crate that handles Graph subscription validation (validationToken), validates each notification’s clientState, then publishes the entire change-notification collection to NATS on {subject_prefix}.change_notification_collection with a deterministic NATS_MESSAGE_ID for deduplication; it also provisions a dedicated JetStream stream for the source.

Updates Docker/compose and gateway docs/examples, wires the new source into gateway config resolution, routing, and stream provisioning, and adds unit tests covering config validation and webhook publish behavior.

Reviewed by Cursor Bugbot for commit 0dc0451. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Warning

Rate limit exceeded

@yordis has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 30 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87e3b13d-133b-4b91-9742-3675dcf6fa34

📥 Commits

Reviewing files that changed from the base of the PR and between 9db8bed and 0dc0451.

📒 Files selected for processing (4)
  • devops/docker/compose/services/trogon-gateway/README.md
  • rsworkspace/crates/trogon-gateway/src/config.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/constants.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs

Walkthrough

Adds a new Microsoft Teams webhook source crate and integrates it into the Trogon gateway: configuration parsing, HTTP routing (POST /microsoft-teams/webhook), JetStream stream provisioning, client-state validation, and publishing logic with tests and docs updates.

Changes

Cohort / File(s) Summary
Configuration & Docs
devops/docker/compose/.env.example, devops/docker/compose/services/trogon-gateway/README.md, rsworkspace/crates/trogon-gateway/README.md
Adds Microsoft Teams env var examples and documentation for the /microsoft-teams/webhook route, required TROGON_SOURCE_MICROSOFT_TEAMS_CLIENT_STATE, and validationToken/notification behavior.
Workspace & Gateway Manifests
rsworkspace/Cargo.toml, rsworkspace/crates/trogon-gateway/Cargo.toml
Registers new trogon-source-microsoft-teams crate in workspace and adds it as a dependency to the gateway crate.
Gateway Config Parsing
rsworkspace/crates/trogon-gateway/src/config.rs
Adds sources.microsoft_teams resolution, validation (client_state, NATS tokens, durations), updates ResolvedConfig and has unit tests.
Gateway HTTP & Streams Integration
rsworkspace/crates/trogon-gateway/src/http.rs, rsworkspace/crates/trogon-gateway/src/streams.rs
Conditionally mounts the Teams router at /microsoft-teams, logs mount, adds provisioning call for Teams streams, and updates test fixtures/assertions.
Teams Source Crate Manifest
rsworkspace/crates/trogon-source-microsoft-teams/Cargo.toml
Adds new crate manifest with runtime and dev dependencies.
Teams Client State & Config
rsworkspace/crates/trogon-source-microsoft-teams/src/client_state.rs, .../src/config.rs, .../src/constants.rs
Introduces MicrosoftTeamsClientState (secret, SHA-256 constant-time match), MicrosoftTeamsConfig type, and constants (HTTP body max, NATS header keys).
Teams Public Surface & Server
rsworkspace/crates/trogon-source-microsoft-teams/src/lib.rs, .../src/server.rs
Exports crate modules and implements webhook server: Graph validationToken handling, notification parsing, clientState validation, subject/header formation, publishing to JetStream, unroutable handling, and comprehensive tests.

Sequence Diagram

sequenceDiagram
    actor Client as Microsoft Teams<br/>(Graph)
    participant Gateway as Trogon Gateway<br/>(HTTP Server)
    participant Handler as Teams Handler
    participant Validator as ClientState Validator
    participant Publisher as JetStream Publisher

    Client->>Gateway: POST /microsoft-teams/webhook (payload / ?validationToken)
    Gateway->>Handler: route to Teams handler
    Handler->>Handler: parse JSON notification collection
    Handler->>Validator: verify clientState (if required)
    alt validationToken query present
        Handler-->>Client: 200 OK (plain text validationToken)
    else clientState missing/invalid
        Validator-->>Handler: invalid
        Handler-->>Client: 401 Unauthorized
    else clientState valid
        Validator-->>Handler: valid
        Handler->>Handler: compute subject (prefix.resource_kind.change_type) or unroutable
        alt unroutable
            Handler->>Publisher: publish to <prefix>.unroutable (with reject header)
        else routable
            Handler->>Publisher: publish to <prefix>.<resource_kind>.<change_type> with headers
        end
        Publisher-->>Handler: publish result
        alt publish success
            Handler-->>Client: 202 Accepted
        else publish failure
            Handler-->>Client: 500 Internal Server Error
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

rust:coverage-baseline-reset

Poem

🐰 I hopped in with a secret key,
Graph tokens dancing, swift and free —
I guard the state in hashed delight,
Publish to streams through starry night,
Hooray for webhooks, carrots and bytes! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding Microsoft Teams as a new source to the gateway, which is the core objective of this PR.
Description check ✅ Passed The description is directly related to the changeset, explaining the business rationale for adding Teams support: reliable ingress, edge validation, and validation context retention.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/feat-ms-teams-source

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 21 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

badge

Code Coverage Summary

Details
Filename                                                                      Stmts    Miss  Cover    Missing
--------------------------------------------------------------------------  -------  ------  -------  ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
crates/trogon-source-incidentio/src/server.rs                                   343       0  100.00%
crates/trogon-source-incidentio/src/signature.rs                                369       0  100.00%
crates/trogon-source-incidentio/src/incidentio_signing_secret.rs                 67       0  100.00%
crates/trogon-source-incidentio/src/config.rs                                    16       0  100.00%
crates/trogon-source-incidentio/src/incidentio_event_type.rs                     62       0  100.00%
crates/acp-nats/src/nats/subjects/responses/cancelled.rs                         15       0  100.00%
crates/acp-nats/src/nats/subjects/responses/prompt_response.rs                   27       0  100.00%
crates/acp-nats/src/nats/subjects/responses/ext_ready.rs                         12       0  100.00%
crates/acp-nats/src/nats/subjects/responses/response.rs                          20       0  100.00%
crates/acp-nats/src/nats/subjects/responses/update.rs                            27       0  100.00%
crates/trogon-source-gitlab/src/config.rs                                        17       0  100.00%
crates/trogon-source-gitlab/src/signature.rs                                     28       0  100.00%
crates/trogon-source-gitlab/src/server.rs                                       397       0  100.00%
crates/acp-nats-server/src/main.rs                                              896      10  98.88%   96, 227-234, 433
crates/acp-nats-server/src/connection.rs                                        171      32  81.29%   76-83, 88-99, 115, 117-118, 123, 132-133, 138, 142, 146, 149, 157, 161, 164, 167-171, 207
crates/acp-nats-server/src/config.rs                                            137       9  93.43%   41, 50-61
crates/acp-nats-server/src/acp_connection_id.rs                                  45       0  100.00%
crates/acp-nats-server/src/transport.rs                                        1833     109  94.05%   277, 528, 546, 573, 627, 632, 651, 663, 782, 805-807, 859, 876-879, 974-977, 1051, 1054, 1057, 1066, 1070, 1073, 1076-1079, 1098, 1130-1133, 1141-1146, 1158-1162, 1166-1175, 1187-1188, 1206-1207, 1217, 1233-1237, 1265-1271, 1290-1292, 1297-1301, 1304-1309, 1319-1321, 1330, 1332-1333, 1415-1416, 1428-1429, 1449-1450, 1502-1518, 2214, 2257, 2309, 2364, 2376
crates/acp-nats/src/nats/extensions.rs                                            3       0  100.00%
crates/acp-nats/src/nats/parsing.rs                                             278       1  99.64%   151
crates/acp-nats/src/nats/mod.rs                                                  23       0  100.00%
crates/trogon-std/src/env/system.rs                                              17       0  100.00%
crates/trogon-std/src/env/in_memory.rs                                           73       0  100.00%
crates/acp-nats/src/jetstream/streams.rs                                        163       4  97.55%   206-208, 218
crates/acp-nats/src/jetstream/ext_policy.rs                                      26       0  100.00%
crates/acp-nats/src/jetstream/provision.rs                                       53       0  100.00%
crates/acp-nats/src/jetstream/consumers.rs                                       91       0  100.00%
crates/trogon-source-linear/src/signature.rs                                     54       1  98.15%   16
crates/trogon-source-linear/src/config.rs                                        17       0  100.00%
crates/trogon-source-linear/src/server.rs                                       386       0  100.00%
crates/acp-nats/src/telemetry/metrics.rs                                         53       0  100.00%
crates/acp-telemetry/src/signal.rs                                                7       1  85.71%   43
crates/acp-telemetry/src/lib.rs                                                 165      28  83.03%   28-34, 56-59, 94, 99, 104, 118-133, 170, 173, 176, 182
crates/acp-telemetry/src/log.rs                                                  67       1  98.51%   41
crates/acp-telemetry/src/trace.rs                                                30       3  90.00%   21-22, 30
crates/acp-telemetry/src/metric.rs                                               33       3  90.91%   28-29, 37
crates/acp-telemetry/src/service_name.rs                                         38       0  100.00%
crates/trogon-std/src/time/system.rs                                             31       0  100.00%
crates/trogon-std/src/time/mock.rs                                              125       0  100.00%
crates/trogon-source-github/src/signature.rs                                     61       0  100.00%
crates/trogon-source-github/src/config.rs                                        17       0  100.00%
crates/trogon-source-github/src/server.rs                                       328       0  100.00%
crates/trogon-nats/src/lease/provision.rs                                       177       0  100.00%
crates/trogon-nats/src/lease/renew.rs                                           234       7  97.01%   24-30
crates/trogon-nats/src/lease/lease_bucket.rs                                     19       0  100.00%
crates/trogon-nats/src/lease/renew_interval.rs                                   61       0  100.00%
crates/trogon-nats/src/lease/ttl.rs                                              73       0  100.00%
crates/trogon-nats/src/lease/acquire.rs                                           5       5  0.00%    9-14
crates/trogon-nats/src/lease/lease_config_error.rs                               11       0  100.00%
crates/trogon-nats/src/lease/release.rs                                           5       5  0.00%    8-12
crates/trogon-nats/src/lease/mod.rs                                             561      13  97.68%   180-193
crates/trogon-nats/src/lease/nats_kv_lease_config.rs                             26       0  100.00%
crates/trogon-nats/src/lease/lease_timing.rs                                     15       0  100.00%
crates/trogon-nats/src/lease/lease_key.rs                                        19       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_output.rs                  12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_request_permission.rs       12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_read_text_file.rs                12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_create.rs                  12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_kill.rs                    12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/fs_write_text_file.rs               12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_release.rs                 12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/session_update.rs                   12       0  100.00%
crates/acp-nats/src/nats/subjects/client_ops/terminal_wait_for_exit.rs           12       0  100.00%
crates/trogon-source-microsoft-teams/src/server.rs                              325       0  100.00%
crates/trogon-source-microsoft-teams/src/client_state.rs                         30       0  100.00%
crates/trogon-std/src/fs/mem.rs                                                 216      10  95.37%   61-63, 77-79, 132-134, 157
crates/trogon-std/src/fs/system.rs                                               92       0  100.00%
crates/acp-nats-stdio/src/main.rs                                               135      25  81.48%   56, 104-111, 117-119, 136, 165-184
crates/acp-nats-stdio/src/config.rs                                              66       0  100.00%
crates/acp-nats/src/config.rs                                                   203       0  100.00%
crates/acp-nats/src/jsonrpc.rs                                                    6       0  100.00%
crates/acp-nats/src/lib.rs                                                       69       0  100.00%
crates/acp-nats/src/req_id.rs                                                    39       0  100.00%
crates/acp-nats/src/pending_prompt_waiters.rs                                   134       0  100.00%
crates/acp-nats/src/ext_method_name.rs                                           68       0  100.00%
crates/acp-nats/src/session_id.rs                                                71       0  100.00%
crates/acp-nats/src/client_proxy.rs                                             186       0  100.00%
crates/acp-nats/src/acp_prefix.rs                                                50       0  100.00%
crates/acp-nats/src/in_flight_slot_guard.rs                                      32       0  100.00%
crates/acp-nats/src/error.rs                                                     82       0  100.00%
crates/acp-nats/src/agent/test_support.rs                                       267       0  100.00%
crates/acp-nats/src/agent/js_request.rs                                         283       0  100.00%
crates/acp-nats/src/agent/mod.rs                                                 65       0  100.00%
crates/acp-nats/src/agent/set_session_model.rs                                   67       0  100.00%
crates/acp-nats/src/agent/cancel.rs                                             101       0  100.00%
crates/acp-nats/src/agent/resume_session.rs                                      90       0  100.00%
crates/acp-nats/src/agent/load_session.rs                                        89       0  100.00%
crates/acp-nats/src/agent/ext_notification.rs                                    82       0  100.00%
crates/acp-nats/src/agent/close_session.rs                                       63       0  100.00%
crates/acp-nats/src/agent/fork_session.rs                                        94       0  100.00%
crates/acp-nats/src/agent/prompt.rs                                             471       0  100.00%
crates/acp-nats/src/agent/list_sessions.rs                                       47       0  100.00%
crates/acp-nats/src/agent/ext_method.rs                                          82       0  100.00%
crates/acp-nats/src/agent/new_session.rs                                         82       0  100.00%
crates/acp-nats/src/agent/initialize.rs                                          79       0  100.00%
crates/acp-nats/src/agent/logout.rs                                              49       0  100.00%
crates/acp-nats/src/agent/set_session_config_option.rs                           67       0  100.00%
crates/acp-nats/src/agent/authenticate.rs                                        49       0  100.00%
crates/acp-nats/src/agent/bridge.rs                                             123       4  96.75%   108-111
crates/acp-nats/src/agent/set_session_mode.rs                                    67       0  100.00%
crates/trogon-std/src/telemetry/http.rs                                         217       0  100.00%
crates/trogon-source-sentry/src/signature.rs                                     54       0  100.00%
crates/trogon-source-sentry/src/sentry_client_secret.rs                          17       0  100.00%
crates/trogon-source-sentry/src/server.rs                                       311       0  100.00%
crates/trogon-nats/src/auth.rs                                                  114       0  100.00%
crates/trogon-nats/src/client.rs                                                 22      22  0.00%    50-86
crates/trogon-nats/src/connect.rs                                                94       9  90.43%   22-23, 33, 60-65
crates/trogon-nats/src/nats_token.rs                                            157       0  100.00%
crates/trogon-nats/src/mocks.rs                                                 284       0  100.00%
crates/trogon-nats/src/subject_token_violation.rs                                17       0  100.00%
crates/trogon-nats/src/token.rs                                                   6       0  100.00%
crates/trogon-nats/src/messaging.rs                                             561       2  99.64%   144, 154
crates/trogon-source-telegram/src/server.rs                                     338       0  100.00%
crates/trogon-source-telegram/src/signature.rs                                   32       0  100.00%
crates/trogon-source-telegram/src/config.rs                                      17       0  100.00%
crates/trogon-source-slack/src/config.rs                                         17       0  100.00%
crates/trogon-source-slack/src/server.rs                                        863       0  100.00%
crates/trogon-source-slack/src/signature.rs                                      77       0  100.00%
crates/trogon-source-discord/src/gateway.rs                                     426       1  99.77%   137
crates/trogon-source-discord/src/config.rs                                      108       0  100.00%
crates/acp-nats/src/nats/subjects/commands/fork.rs                               15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_model.rs                          15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/resume.rs                             15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_mode.rs                           15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/prompt.rs                             15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/load.rs                               15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/set_config_option.rs                  15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/cancel.rs                             15       0  100.00%
crates/acp-nats/src/nats/subjects/commands/close.rs                              15       0  100.00%
crates/trogon-source-notion/src/server.rs                                       318       8  97.48%   92-96, 129-130, 149-150
crates/trogon-source-notion/src/signature.rs                                     56       1  98.21%   32
crates/trogon-source-notion/src/notion_verification_token.rs                     17       0  100.00%
crates/trogon-source-notion/src/notion_event_type.rs                             46       3  93.48%   47-49
crates/trogon-std/src/dirs/fixed.rs                                              80       0  100.00%
crates/trogon-std/src/dirs/system.rs                                             71       0  100.00%
crates/trogon-std/src/duration.rs                                                45       0  100.00%
crates/trogon-std/src/http.rs                                                    19       0  100.00%
crates/trogon-std/src/json.rs                                                    30       0  100.00%
crates/trogon-std/src/args.rs                                                    10       0  100.00%
crates/trogon-std/src/uuid.rs                                                     7       0  100.00%
crates/trogon-std/src/secret_string.rs                                           35       0  100.00%
crates/trogon-nats/src/telemetry/messaging.rs                                    82       0  100.00%
crates/acp-nats/src/nats/subjects/global/authenticate.rs                          6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext_notify.rs                            9       0  100.00%
crates/acp-nats/src/nats/subjects/global/initialize.rs                            6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_list.rs                          6       0  100.00%
crates/acp-nats/src/nats/subjects/global/logout.rs                                6       0  100.00%
crates/acp-nats/src/nats/subjects/global/session_new.rs                           6       0  100.00%
crates/acp-nats/src/nats/subjects/global/ext.rs                                   9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/prompt_wildcard.rs                9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_client.rs                     9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_session.rs                   12       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent.rs                      9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/global_all.rs                     9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_agent.rs                     15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_agent_ext.rs                  9       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/one_client.rs                    15       0  100.00%
crates/acp-nats/src/nats/subjects/subscriptions/all_session.rs                    9       0  100.00%
crates/trogon-gateway/src/http.rs                                               119       0  100.00%
crates/trogon-gateway/src/main.rs                                                 4       0  100.00%
crates/trogon-gateway/src/source_status.rs                                       28       0  100.00%
crates/trogon-gateway/src/streams.rs                                            148       0  100.00%
crates/trogon-gateway/src/config.rs                                            1780       0  100.00%
crates/trogon-service-config/src/lib.rs                                          92       0  100.00%
crates/acp-nats/src/client/fs_write_text_file.rs                                418       0  100.00%
crates/acp-nats/src/client/ext.rs                                               308       8  97.40%   163-172, 189-198
crates/acp-nats/src/client/terminal_kill.rs                                     290       0  100.00%
crates/acp-nats/src/client/mod.rs                                              2851       0  100.00%
crates/acp-nats/src/client/terminal_output.rs                                   206       0  100.00%
crates/acp-nats/src/client/terminal_wait_for_exit.rs                            378       0  100.00%
crates/acp-nats/src/client/request_permission.rs                                308       0  100.00%
crates/acp-nats/src/client/fs_read_text_file.rs                                 356       0  100.00%
crates/acp-nats/src/client/terminal_create.rs                                   274       0  100.00%
crates/acp-nats/src/client/ext_session_prompt_response.rs                       135       0  100.00%
crates/acp-nats/src/client/session_update.rs                                     55       0  100.00%
crates/acp-nats/src/client/terminal_release.rs                                  347       0  100.00%
crates/acp-nats/src/client/rpc_reply.rs                                          64       0  100.00%
crates/trogon-nats/src/jetstream/mocks.rs                                       670      32  95.22%   364-378, 384-392, 407-413, 427-430, 494-496
crates/trogon-nats/src/jetstream/publish.rs                                      64       0  100.00%
crates/trogon-nats/src/jetstream/stream_max_age.rs                               18       0  100.00%
crates/trogon-nats/src/jetstream/claim_check.rs                                 346       0  100.00%
crates/trogon-nats/src/jetstream/create_conflicts.rs                             24       0  100.00%
crates/trogon-source-twitter/src/server.rs                                      525       0  100.00%
crates/trogon-source-twitter/src/config.rs                                       17       0  100.00%
crates/trogon-source-twitter/src/signature.rs                                    69       0  100.00%
crates/acp-nats/src/nats/subjects/stream.rs                                      56       0  100.00%
crates/acp-nats/src/nats/subjects/mod.rs                                        362       0  100.00%
crates/acp-nats-agent/src/connection.rs                                        1270       1  99.92%   607
TOTAL                                                                         28465     358  98.74%

Diff against main

Filename                                                    Stmts    Miss  Cover
--------------------------------------------------------  -------  ------  --------
crates/acp-nats-server/src/transport.rs                         0      -4  +0.22%
crates/trogon-source-microsoft-teams/src/server.rs           +325       0  +100.00%
crates/trogon-source-microsoft-teams/src/client_state.rs      +30       0  +100.00%
crates/trogon-gateway/src/http.rs                              +9       0  +100.00%
crates/trogon-gateway/src/streams.rs                          +10       0  +100.00%
crates/trogon-gateway/src/config.rs                          +141       0  +100.00%
TOTAL                                                        +515      -4  +0.04%

Results for commit: 0dc0451

Minimum allowed coverage is 95%

♻️ This comment has been updated with latest results

Comment thread rsworkspace/crates/trogon-gateway/src/config.rs
Comment thread rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs Outdated
@yordis yordis force-pushed the yordis/feat-ms-teams-source branch 2 times, most recently from be5f9ec to f1b218a Compare April 28, 2026 17:07
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
rsworkspace/crates/trogon-gateway/src/config.rs (1)

328-342: Rename this to an explicit boundary type.

This struct is the untrusted confique input, but it shares the same name as the validated domain config returned later from resolve_microsoft_teams. Renaming it to something like MicrosoftTeamsConfigInput would make the one-way conversion boundary much clearer.

As per coding guidelines, "Untrusted input must use distinct *Input / *Wire / *Request types. Convert those boundary types into domain types exactly once."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/trogon-gateway/src/config.rs` around lines 328 - 342, The
struct MicrosoftTeamsConfig is the untrusted confique input but is named
identically to the validated domain config returned by resolve_microsoft_teams;
rename this input type to an explicit boundary name (e.g.,
MicrosoftTeamsConfigInput or MicrosoftTeamsConfigWire) and update all places
that construct or accept the unvalidated config (including the derive(Config)
declaration) so that resolve_microsoft_teams converts the new
MicrosoftTeamsConfigInput into the domain config exactly once, keeping the
domain config type name unchanged.
rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs (2)

390-412: Parse resource paths by segment instead of substring matching.

The contains("messages") / contains("teams") checks will also match opaque IDs or other path text, so the fallback router can classify some payloads under the wrong resource kind. Matching normalized path segments would keep routing deterministic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs` around lines
390 - 412, The current resource_kind_from_resource_path uses substring
contains(...) which can misclassify opaque IDs; change it to parse the path into
normalized segments and match exact segment names (e.g., split the input by '/'
and ignore empty segments, lowercase each segment) then check segment ==
"messages", "members", "channels", "chats", "recordings", "transcripts",
"presences", "onlinemeetings", "teams" and return the corresponding Some("...")
for the first exact match; update resource_kind_from_resource_path to iterate
segments (instead of contains) so routing is deterministic and not triggered by
substrings inside IDs.

28-33: Introduce a typed wire model for each notification instead of Vec<Value>.

Keeping the collection contents as raw serde_json::Value means extraction, mutation, and validation are spread across the handler. A NotificationWire type plus one conversion step would make the boundary explicit and simplify everything after deserialization.

As per coding guidelines, "Untrusted input must use distinct *Input / *Wire / *Request types. Convert those boundary types into domain types exactly once."

Also applies to: 209-219

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs` around lines
28 - 33, Replace the untyped Vec<Value> in ChangeNotificationCollection with a
concrete wire type (e.g., define a new struct NotificationWire /
NotificationWireInput that models the JSON fields you expect) and change
ChangeNotificationCollection.value: Vec<Value> -> Vec<NotificationWire>;
implement TryFrom<NotificationWire> (or a dedicated conversion function) to
convert/validate the wire type into your domain Notification type in a single
place, and update the code paths that deserialize/process notifications (the
handler that currently iterates over ChangeNotificationCollection.value) to
first deserialize into ChangeNotificationCollection, then convert each
NotificationWire -> Notification using the TryFrom/convert function; keep the
existing serde attributes (e.g., validation_tokens rename) intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rsworkspace/crates/trogon-gateway/README.md`:
- Around line 79-80: Update the README bullets so the default lists match the
actual defaults in rsworkspace/crates/trogon-gateway/src/config.rs: add
"twitter" to the TROGON_SOURCE_<SOURCE>_SUBJECT_PREFIX defaults and add "NOTION"
and "SENTRY" to the TROGON_SOURCE_<SOURCE>_STREAM_NAME defaults, ensuring the
exact casing/entries mirror those in config.rs for the symbols
TROGON_SOURCE_<SOURCE>_SUBJECT_PREFIX and TROGON_SOURCE_<SOURCE>_STREAM_NAME.

---

Nitpick comments:
In `@rsworkspace/crates/trogon-gateway/src/config.rs`:
- Around line 328-342: The struct MicrosoftTeamsConfig is the untrusted confique
input but is named identically to the validated domain config returned by
resolve_microsoft_teams; rename this input type to an explicit boundary name
(e.g., MicrosoftTeamsConfigInput or MicrosoftTeamsConfigWire) and update all
places that construct or accept the unvalidated config (including the
derive(Config) declaration) so that resolve_microsoft_teams converts the new
MicrosoftTeamsConfigInput into the domain config exactly once, keeping the
domain config type name unchanged.

In `@rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs`:
- Around line 390-412: The current resource_kind_from_resource_path uses
substring contains(...) which can misclassify opaque IDs; change it to parse the
path into normalized segments and match exact segment names (e.g., split the
input by '/' and ignore empty segments, lowercase each segment) then check
segment == "messages", "members", "channels", "chats", "recordings",
"transcripts", "presences", "onlinemeetings", "teams" and return the
corresponding Some("...") for the first exact match; update
resource_kind_from_resource_path to iterate segments (instead of contains) so
routing is deterministic and not triggered by substrings inside IDs.
- Around line 28-33: Replace the untyped Vec<Value> in
ChangeNotificationCollection with a concrete wire type (e.g., define a new
struct NotificationWire / NotificationWireInput that models the JSON fields you
expect) and change ChangeNotificationCollection.value: Vec<Value> ->
Vec<NotificationWire>; implement TryFrom<NotificationWire> (or a dedicated
conversion function) to convert/validate the wire type into your domain
Notification type in a single place, and update the code paths that
deserialize/process notifications (the handler that currently iterates over
ChangeNotificationCollection.value) to first deserialize into
ChangeNotificationCollection, then convert each NotificationWire -> Notification
using the TryFrom/convert function; keep the existing serde attributes (e.g.,
validation_tokens rename) intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 80d9b551-336b-4b85-9de4-2fb313279d28

📥 Commits

Reviewing files that changed from the base of the PR and between e2b7c43 and f1b218a.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • devops/docker/compose/.env.example
  • devops/docker/compose/services/trogon-gateway/README.md
  • rsworkspace/Cargo.toml
  • rsworkspace/crates/trogon-gateway/Cargo.toml
  • rsworkspace/crates/trogon-gateway/README.md
  • rsworkspace/crates/trogon-gateway/src/config.rs
  • rsworkspace/crates/trogon-gateway/src/http.rs
  • rsworkspace/crates/trogon-gateway/src/streams.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/Cargo.toml
  • rsworkspace/crates/trogon-source-microsoft-teams/src/client_state.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/config.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/constants.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/lib.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs

Comment thread rsworkspace/crates/trogon-gateway/README.md Outdated
@yordis yordis force-pushed the yordis/feat-ms-teams-source branch 2 times, most recently from 0e7aedd to 9e730bd Compare April 28, 2026 17:52
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/feat-ms-teams-source branch from 9e730bd to 9cfae59 Compare April 28, 2026 18:22
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Comment thread rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs Outdated
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 480f37c. Configure here.

Comment thread rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs Outdated
yordis added 3 commits April 28, 2026 17:47
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rsworkspace/crates/trogon-gateway/README.md (1)

42-61: ⚠️ Potential issue | 🟡 Minor

Keep incidentio in the top-level gateway docs.

The route table, required-setting table, and sample TOML now list Teams/Notion/Sentry, but incidentio is still missing from all three. That leaves this README out of sync with rsworkspace/crates/trogon-gateway/src/config.rs and devops/docker/compose/services/trogon-gateway/README.md, which both still document the source.

📝 Suggested doc fix
 | Twitter/X | `/twitter/webhook` |
 | GitLab | `/gitlab/webhook` |
+| incident.io | `/incidentio/webhook` |
 | Linear | `/linear/webhook` |
 | Microsoft Teams | `/microsoft-teams/webhook` |
 | Notion | `/notion/webhook` |
 | Sentry | `/sentry/webhook` |
@@
 | Twitter/X | `TROGON_SOURCE_TWITTER_CONSUMER_SECRET` |
 | GitLab | `TROGON_SOURCE_GITLAB_WEBHOOK_SECRET` |
+| incident.io | `TROGON_SOURCE_INCIDENTIO_SIGNING_SECRET` |
 | Linear | `TROGON_SOURCE_LINEAR_WEBHOOK_SECRET` |
 | Microsoft Teams | `TROGON_SOURCE_MICROSOFT_TEAMS_CLIENT_STATE` |
 | Notion | `TROGON_SOURCE_NOTION_VERIFICATION_TOKEN` |
 | Sentry | `TROGON_SOURCE_SENTRY_CLIENT_SECRET` |
@@
 [sources.gitlab]
 webhook_secret = "gitlab-secret"
 
+[sources.incidentio]
+signing_secret = "whsec_..."
+
 [sources.linear]
 webhook_secret = "linear-secret"

Also applies to: 129-136

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rsworkspace/crates/trogon-gateway/README.md` around lines 42 - 61, The README
is missing the incidentio source entries—update the route table, the "Source
enablement" required-setting table, and the sample TOML to include incidentio so
the docs match rsworkspace/crates/trogon-gateway/src/config.rs and
devops/docker/compose/services/trogon-gateway/README.md; specifically add an
incidentio row in the route table (e.g., `/incidentio/webhook`), add the
corresponding required env var name for incidentio in the "Source enablement"
table (the same variable used by config.rs), and include the incidentio settings
in the sample TOML block so all three doc locations list incidentio
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rsworkspace/crates/trogon-gateway/src/config.rs`:
- Around line 328-342: Rename the local unvalidated struct MicrosoftTeamsConfig
to a boundary/input type (e.g., MicrosoftTeamsConfigInput) and update all places
that construct or reference it (including resolve_microsoft_teams and the other
occurrences called out around lines 969-1053) so that the validated domain type
trogon_source_microsoft_teams::MicrosoftTeamsConfig remains distinct; update
struct name in the #[derive(Config)] definition and change any variable
bindings, function parameters, and conversions that map this input type into the
validated trogon_source_microsoft_teams::MicrosoftTeamsConfig to use the new
MicrosoftTeamsConfigInput name to make the input→domain conversion explicit.

In `@rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs`:
- Around line 219-223: The loop currently early-returns a server error on the
first failing publish which causes a 500 even when prior notifications
succeeded; change the logic in the loop over notifications that calls
publish_notification(&state, notification, &metadata).await so it does not
return immediately on status.is_server_error(). Instead, collect
per-notification outcomes (e.g., a boolean or Vec of statuses), continue
publishing remaining notifications, and after the loop decide the HTTP response:
if all succeeded return success (200/202), if some succeeded and some failed
return a multi-status/partial success (207 or 202 with a per-item report), and
only return a 500 if none succeeded; ensure publish_notification and any
downstream publish_event/idempotency behavior are preserved.
- Around line 97-100: The current change_type_token implementation only ensures
the string is a valid NATS token but does not verify it is a known Graph
changeType; update it to parse/convert the incoming boundary string into a
domain value object (e.g., a new ChangeType enum or struct) and return
RejectReason::InvalidChange for any unrecognized values instead of accepting
arbitrary strings; then build the NatsToken from the canonical domain value
(e.g., ChangeType::as_str()) so the routing code that uses change_type_token
(and the publish path around the former routing at lines ~249-265) only ever
sees validated, domain-specific change types. Ensure conversion is done once at
the boundary in change_type_token (or an explicit from_wire/from_input helper)
and propagate the domain type (or its canonical string) to downstream routing.

---

Outside diff comments:
In `@rsworkspace/crates/trogon-gateway/README.md`:
- Around line 42-61: The README is missing the incidentio source entries—update
the route table, the "Source enablement" required-setting table, and the sample
TOML to include incidentio so the docs match
rsworkspace/crates/trogon-gateway/src/config.rs and
devops/docker/compose/services/trogon-gateway/README.md; specifically add an
incidentio row in the route table (e.g., `/incidentio/webhook`), add the
corresponding required env var name for incidentio in the "Source enablement"
table (the same variable used by config.rs), and include the incidentio settings
in the sample TOML block so all three doc locations list incidentio
consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6299f13f-74a7-4870-95ab-3925d9a9079e

📥 Commits

Reviewing files that changed from the base of the PR and between f1b218a and 9db8bed.

⛔ Files ignored due to path filters (1)
  • rsworkspace/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • devops/docker/compose/.env.example
  • devops/docker/compose/services/trogon-gateway/README.md
  • rsworkspace/Cargo.toml
  • rsworkspace/crates/trogon-gateway/Cargo.toml
  • rsworkspace/crates/trogon-gateway/README.md
  • rsworkspace/crates/trogon-gateway/src/config.rs
  • rsworkspace/crates/trogon-gateway/src/http.rs
  • rsworkspace/crates/trogon-gateway/src/streams.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/Cargo.toml
  • rsworkspace/crates/trogon-source-microsoft-teams/src/client_state.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/config.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/constants.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/lib.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs
✅ Files skipped from review due to trivial changes (6)
  • rsworkspace/crates/trogon-gateway/Cargo.toml
  • rsworkspace/Cargo.toml
  • devops/docker/compose/.env.example
  • rsworkspace/crates/trogon-source-microsoft-teams/Cargo.toml
  • rsworkspace/crates/trogon-source-microsoft-teams/src/lib.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/config.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • rsworkspace/crates/trogon-gateway/src/http.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/client_state.rs
  • rsworkspace/crates/trogon-source-microsoft-teams/src/constants.rs
  • rsworkspace/crates/trogon-gateway/src/streams.rs

Comment thread rsworkspace/crates/trogon-gateway/src/config.rs
Comment thread rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs Outdated
Comment thread rsworkspace/crates/trogon-source-microsoft-teams/src/server.rs Outdated
yordis added 3 commits April 28, 2026 23:35
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/feat-ms-teams-source branch from c1ca26c to ed76de1 Compare April 29, 2026 04:40
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the yordis/feat-ms-teams-source branch from ed76de1 to 0dc0451 Compare April 29, 2026 05:00
@yordis yordis merged commit c4455d4 into main Apr 29, 2026
7 checks passed
@yordis yordis deleted the yordis/feat-ms-teams-source branch April 29, 2026 06:08
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