Skip to content

feat(reports): add native Microsoft Teams alert notifications - #45508

Open
KristiDodaj wants to merge 29 commits into
apache:masterfrom
KristiDodaj:feature/teams-alerts
Open

KristiDodaj wants to merge 29 commits into
apache:masterfrom
KristiDodaj:feature/teams-alerts

Conversation

@KristiDodaj

@KristiDodaj KristiDodaj commented Oct 20, 2026 •

Copy link
Copy Markdown

SUMMARY

Add Microsoft Teams as an optional notification destination for attachment-free alerts.

Administrators configure a single tenant, bot credentials, and approved standard channels. Users select a destination in the alert editor. Each notification creates a new channel post containing the alert name, optional description, and optional link to Superset.

The integration is disabled by default behind ALERT_REPORT_TEAMS and uses the optional teams dependency extra. Authenticated installation callbacks maintain routing information. Removing the bot disables delivery until it is reinstalled.

Includes recipient validation, bounded retries, delivery error handling, setup documentation, and automated tests.

Initial scope excludes scheduled reports, private/shared channels, direct messages, file attachments, and interactive cards.

Related discussion: #45307

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Before: Microsoft Teams is not available as a notification destination.

After: Users can select an administrator-approved Teams destination and receive alert cards in its channel.

Teams destination selection

Selecting an approved Microsoft Teams destination in the Superset alert editor

Delivered alerts, including successful delivery after bot reinstallation

Separate alert posts delivered by Superset to the test Microsoft Teams channel

Credentials are configured server-side, not through an administrator UI.

TESTING INSTRUCTIONS

  1. Install the teams extra on the web server and Celery worker.
  2. Enable ALERT_REPORT_TEAMS and configure the tenant, bot credentials, and approved destinations.
  3. Apply the migration and configure the bot's HTTPS callback.
  4. Install the bot in an approved team.
  5. Create an alert with attachments disabled and select a Teams destination.
  6. Trigger two deliveries and confirm they appear as separate channel posts.
  7. Remove the bot and confirm delivery fails clearly. Reinstall it and confirm delivery recovers.

Validation:

  • 310 focused backend tests passed.
  • 175 frontend tests across five suites passed using a temporary local module mapping to resolve the shared dependency checkout.
  • Alembic reports one migration head. PostgreSQL migration upgrade, repeated upgrade, downgrade, and re-upgrade passed.
  • Changed-file formatting, linting, Mypy, feature-flag documentation sync, and workflow security checks passed. Custom Pylint passed in the Superset container.
  • The Netlify documentation preview deployed successfully.

Browser creation/editing coverage is provided by an opt-in test against a locally configured Superset instance. It skips when Teams is unconfigured. The local browser flow passed during validation.

Live delivery was tested separately using a Microsoft test tenant: Celery delivery to a non-default standard channel, separate root posts, delivery after web and worker restarts, and fresh removal/reinstallation callbacks with delivery failure and recovery.

ADDITIONAL INFORMATION

  • Has associated issue:
    Related discussion: Native Microsoft Teams notifications without Power Automate #45307
  • Required feature flags: ALERT_REPORTS, ALERT_REPORT_TEAMS
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@github-actions github-actions Bot added risk:db-migration PRs that require a DB migration api Related to the REST API doc Namespace | Anything related to documentation github_actions Pull requests that update GitHub Actions code labels Oct 20, 2026
@netlify

netlify Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit e921569
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6ae2d0dc7d2dd35b185ae1c5
😎 Deploy Preview https://deploy-preview-45508--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.31043% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.69%. Comparing base (2350348) to head (e921569).
⚠️ Report is 17 commits behind head on master.

Files with missing lines Patch % Lines
superset/integrations/teams/adapter.py 92.40% 11 Missing and 8 partials ⚠️
superset/integrations/teams/store.py 89.83% 4 Missing and 2 partials ⚠️
superset/views/base.py 77.77% 1 Missing and 1 partial ⚠️
...-frontend/src/features/alerts/AlertReportModal.tsx 98.24% 1 Missing ⚠️
superset/integrations/teams/api.py 98.75% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #45508      +/-   ##
==========================================
+ Coverage   84.63%   84.69%   +0.05%     
==========================================
  Files        3069     3080      +11     
  Lines      205446   206187     +741     
  Branches    48306    48449     +143     
==========================================
+ Hits       173879   174624     +745     
+ Misses      28277    28265      -12     
- Partials     3290     3298       +8     
Flag Coverage Δ
hive 34.45% <20.70%> (-0.09%) ⬇️
javascript 80.85% <99.22%> (+0.04%) ⬆️
mysql 52.41% <28.61%> (-0.14%) ⬇️
postgres 52.42% <28.61%> (-0.14%) ⬇️
presto 36.17% <20.70%> (-0.10%) ⬇️
python 87.78% <95.73%> (+0.05%) ⬆️
sqlite 52.18% <28.61%> (-0.14%) ⬇️
unit 82.53% <95.58%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions Bot added the requires:rebase Requires rebasing on top of current master label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Possible DB migration conflict

@KristiDodaj the base branch master picked up a new database migration under superset/migrations/ after this PR was opened, and this PR adds or modifies migration files too. Alembic migrations form a single linear chain, so if both branch off the same parent revision, merging this PR as-is could leave the migration history with two heads instead of one, which makes superset db upgrade fail with Multiple head revisions are present.

To check and, if needed, fix this:

  1. Rebase this branch onto the latest master.
  2. Run superset db heads. If it lists more than one revision, you have a conflict.
  3. In your new migration's script, update down_revision (and the Revises comment) to point at the other head instead, so the chain has a single head again.

See Merging DB Migrations in the contributing guide for a worked example.

@github-actions github-actions Bot added i18n Namespace | Anything related to localization requires:rebase Requires rebasing on top of current master and removed requires:rebase Requires rebasing on top of current master labels Oct 22, 2026
@github-actions github-actions Bot removed the requires:rebase Requires rebasing on top of current master label Oct 23, 2026
@KristiDodaj
KristiDodaj marked this pull request as ready for review October 23, 2026 14:48
try:
destination = config.get_destination(recipient["target"])
except ValueError:
raise TeamsRecipientValidationError(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These Teams validation messages (here, the "A configured Teams destination key is required" and "Invalid Teams recipient configuration" ones above, and the duplicate-key message in commands/report/base.py) are plain English and flow straight into the 422 response and the editor's error toast. A non-English user saving an alert whose Teams destination was removed will see "Teams destination is not approved" untranslated, while the neighbouring report validators wrap theirs in _(). Should these go through gettext (and into messages.pot) like the rest of the report validation errors?

return InvokeResponse(status=result.status)

try:
server = HttpServer(adapter, messaging_endpoint=EVENTS_PATH)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A new HttpServer is built for every callback, so (assuming the SDK's validator builds its JWKS client per instance) none of the signing-key cache or refresh cooldown carries over between requests. An unauthenticated caller who posts a well-formed JWT with any kid then triggers a blocking fetch of the Bot Framework key set inside the Flask worker on every request, and if the egress IP gets throttled, legitimate installation events fail key lookup with a 401 and are never recorded (Teams does not redeliver). The tests monkeypatch the signing-key lookup, so this isn't exercised. Does the SDK cache keys across HttpServer instances, or should the server/validator be kept per process?

)
missing_sdk = MagicMock(side_effect=AssertionError("must not check SDK"))
monkeypatch.setattr(destinations, "is_teams_sdk_installed", missing_sdk)
monkeypatch.setitem(sys.modules, "superset.integrations.teams.adapter", None)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

register_teams_api and base are imported at the top of this test, before sys.modules is blocked here. If a module-level import microsoft_teams were added to api.py or destinations.py, those modules would already be loaded with the SDK present, so this test would still pass in CI while a deployment without the optional extra fails at startup. Could this run the disabled-Teams startup in a fresh interpreter (or import the modules after the block) and assert the callback still returns 404?

@github-actions github-actions Bot removed the requires:rebase Requires rebasing on top of current master label Oct 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Related to the REST API dependencies:python doc Namespace | Anything related to documentation github_actions Pull requests that update GitHub Actions code i18n Namespace | Anything related to localization risk:db-migration PRs that require a DB migration size/XXL utsc2026 UTSC 2026 course contributions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants