Skip to content

feat(integrations): add the lfx-slack bundle with Web API actions on connections - #14962

Open
erichare wants to merge 9 commits into
feat/int-11-lfx-microsoftfrom
feat/int-12-lfx-slack
Open

feat(integrations): add the lfx-slack bundle with Web API actions on connections#14962
erichare wants to merge 9 commits into
feat/int-11-lfx-microsoftfrom
feat/int-12-lfx-slack

Conversation

@erichare

@erichare erichare commented Sep 5, 2026

Copy link
Copy Markdown
Member

feat(integrations): add the lfx-slack bundle with Web API actions on connections

Base: feat/int-11-lfx-microsoft (INT-11). That branch bases on feat/int-5-oauth-broker (#14935); retarget to release-1.13.0 once #14906..#14935 and INT-11 merge.

Restacked on INT-11

This branch was built independently from the INT-5 tip (5615cd03a3) and then merged with
feat/int-11-lfx-microsoft, which shares every bundle registration seam. Review this PR's own diff
against feat/int-11-lfx-microsoft, not against feat/int-5-oauth-broker
— the merge commit carries
the resolutions and its message lists them one by one. In short: INT-11's entry comes first in every
append-only list (pyproject.toml x3, bundle_profiles.json, release_inventory_contract.json,
migration_table.json, connection-oauth.mdx); the duplicated "Develop/connection-oauth" sidebar
entry was reduced to INT-11's copy inside Authentication and authorization, beside the Entra
runbook it links to; enterprise-hardened.lock.json was regenerated with
manage_bundle_profiles.py compile, not hand-merged; and uv.lock needed no re-resolution
(uv lock --offline and uv lock --check both accept it unchanged, 857 packages, nothing fetched).

Two problems only the combined tree can surface, both fixed in the merge commit:

  • scripts/ci/check_capability_manifests.py — added by this PR, generic over every bundle — reached
    lfx-microsoft's manifest for the first time and rejected it nine times. Eight are INT-11's
    deliberate offline_access deviation (Entra never echoes the scope and the resolver computes
    required - granted literally, so transcribing the matrix would fail every Microsoft resolution;
    already pinned by src/bundles/microsoft/tests/test_capabilities_manifest_contract.py); the ninth is
    the short "Microsoft 365" provider label the bundle ships everywhere against the matrix's longer
    one. Neither bundle's shipped behaviour was changed. Instead the checker gained a
    DELIBERATE_DEVIATIONS table recording the exact expected values, so any other drift still fails
    and a deviation that has since converged is reported as stale rather than silently accepted.
    Mutation-checked, and covered by six new tests.
  • INT-11's docs pages link to /bundles-microsoft, /entra-app-registration and /connection-oauth
    absolutely; those slugs exist only on the next version, so docs $ npm run build failed with four
    broken links. Converted to relative .mdx links — the same form this PR already had to use for
    /bundles-slack (see the note below). Worth folding back into INT-11 if that branch moves.

Summary

  • Adds src/bundles/slack (distribution lfx-slack) with the seven actions the INT-1 discovery gate froze in design/dedicated-integrations/matrices/slack.json: Slack: Search / Read Thread / Send Message / Create Canvas (as user) and Slack: Post Message / Add Reaction / List Channel Members (as app).
  • All seven run on the Slack Web API through slack_sdk, per decisions/substrate-slack.md (Option B) and the matrix's substrate_notes. slack_sdk and aiohttp are new dependencies; aiohttp is declared explicitly because AsyncWebClient imports it and cross-bundle-test.yml installs only declared deps.
  • capabilities.v1.json is lifted mechanically from the matrix (ids, display names, identities, required and conditional scopes, deployment contexts, component classes) and declares the two named auth profiles the connection contract requires: slack-user-oauth and slack-bot-install. Policy keys are integrations.slack.<user|bot>.<verb>.
  • Adds a Slack error normalizer. Slack answers HTTP 200 with {"ok": false, "error": ...}, so lfx's status-code-only fallback would have reported an expired token or a missing scope as provider-unavailable and the frontend's code-keyed reconnect/grant affordances would never fire. invalid_auth/token_expired/token_revoked/account_inactive/not_authedauth-expired; missing_scope (with needed) → scope-missing; ratelimited/HTTP 429 → rate-limited with Retry-After; not_allowed_token_type/channel_not_found/… → action-unsupported; everything else → provider-unavailable.
  • Adds an additive optional ResolvedCredential.identity (lfx) populated from the connection row's executing_identity (langflow-base). Slack user and bot tokens share scope names — chat:write is both a User Token Scope and a Bot Token Scope — so granted_scopes cannot tell them apart. A bot capability handed a user connection (or the reverse) now fails closed with connection-not-authorized before the first HTTP request. BUNDLE_API_VERSION stays 1; the changelog entry is required only because lfx/integrations is an in-scope surface.
  • An auth-expired rejection spends the one reactive re-resolve CredentialLease allows and retries once. That is how a rotated Slack token is picked up: Slack tokens do not expire unless the app opted into rotation, so a rejection is the only signal.
  • Runs the full INT-11 registration checklist: root pyproject.toml markers + uv.lock; bundle_profiles.json (enterprise-hardened) + recompiled enterprise-hardened.lock.json; release_inventory_contract.json for python-default and python-full, plus the source_roots entry test_contract_required_files_exist_in_sources needs; migration_table.json rows for the seven classes; the Slack sidebar group (the icon already existed); docs page, bundle list, graduated-install map, docs sidebar.
  • Adds scripts/ci/check_capability_manifests.py (+ tests), generic over every bundle that declares integrations: it proves each shipped capabilities.v1.json still agrees with its discovery-gate matrix. Extra capabilities and auth profiles are tolerated so TRG-5 can add its slack-app-token profile on top.
  • The Web API response each component memoizes is cleared in _pre_run_setup, the framework's per-build reset hook. Without that, a Slack action inside a Loop (or any rebuilt vertex — Graph._set_cache_to_vertices_in_cycle forces output.cache=False while Vertex.build reuses one custom_component) would run once and then report that first response for every later iteration: N green statuses, one message in the channel. Sharing between a component's two outputs within one build is unchanged.
  • The identity guard runs inside the integration_action span, so a fail-closed connection-not-authorized denial is counted in telemetry like any other integration error. It still fires before any HTTP request.
  • Registers docs/docs/Develop/connection-oauth.mdx in the docs sidebar — it was unreachable — and extends its Slack section with both redirect URL forms, the per-action scope table for each identity, and a worked two-registration LANGFLOW_CONNECTION_OAUTH_REGISTRATIONS example.

Verification

Bundle suite, run exactly the way .github/workflows/cross-bundle-test.yml does (a clean venv holding only in-repo lfx + the bundle + pytest), on both PR-matrix Python legs:

uv venv --python 3.13 && uv pip install ./src/lfx ./src/bundles/slack pytest pytest-asyncio tomli
lfx extension validate src/bundles/slack/src/lfx_slack
  -> validate: ok (8 file(s) scanned)
python -m pytest src/bundles/slack/tests -q -m "not api_key_required"
  -> 56 passed, 3 deselected

# same, --python 3.10
  -> validate: ok (8 file(s) scanned);  56 passed, 3 deselected

The 3 deselected are the opt-in live-workspace suite (api_key_required).

lfx package suite (isolated, from src/lfx):

uv sync --dev --extra otel
uv run --no-sync pytest tests/unit/integrations \
    tests/integration/extension/test_pilot_slack_upgrade.py \
    tests/unit/extension tests/unit/services/connection -q
  -> 747 passed, 2 skipped

(The 2 skips are test_pilot_slack_upgrade.py's distribution checks, which self-skip when lfx-slack is absent from the isolated lfx venv — the same way test_pilot_paddle_upgrade.py does.)

Backend and release tooling, from the repo root:

uv run --no-sync pytest scripts/ci/ -q
  -> 208 passed   (200 before the restack; +8 for the deviation-table tests)
uv run --no-sync pytest src/backend/tests/unit/api/v1/test_connections.py \
    src/backend/tests/unit/api/v1/test_connection_identity.py \
    src/backend/tests/unit/services/connection \
    src/backend/tests/unit/test_bundle_lfx_pin.py \
    src/backend/tests/unit/test_build_component_index.py \
    src/backend/tests/unit/test_lfx_bundles_extras.py -q
  -> 64 passed, 4 skipped
uv run --no-sync python scripts/ci/check_capability_matrices.py        -> Capability matrices are complete.
uv run --no-sync python scripts/ci/check_capability_manifests.py       -> agree with their matrices (2 checked)
uv run --no-sync python scripts/ci/check_execution_principal_matrix.py -> matrix is complete
uv run --no-sync python scripts/ci/manage_bundle_profiles.py check     -> Bundle profiles and locks passed
uv run --no-sync python scripts/ci/sync_bundle_lfx_pin.py 1.13.0       -> unchanged: slack
uv run --no-sync python scripts/ci/check_components_frozen.py          -> no additions beyond the frozen baseline
uv run --no-sync python scripts/migrate/check_bare_names.py            -> ok
uv run --no-sync python scripts/migrate/check_migration_append_only.py --base feat/int-11-lfx-microsoft
  -> ok (entries 1027, +28)
uv run --no-sync python scripts/migrate/check_bundle_api_changelog.py --base 5615cd03a3 -> ok (both bundles' entries present)
uv run --no-sync python scripts/ci/bundle_release_plan.py plan --base-ref 5615cd03a3   -> "status": "ready"
uv sync --frozen                                                       -> ok, no re-resolution
uv lock --check --offline                                              -> Resolved 857 packages

(The 4 backend skips are pre-existing and unrelated: test_build_component_index.py self-skips with "build_component_index.py script not found".)

The release-inventory rows were also checked against a real built wheel, since check_release_inventory.py needs an installed wheel shape (in an editable checkout it reports missing required_files for every bundle, lfx-openai and lfx-google included):

uv build --wheel src/bundles/slack
  -> entry_points.txt: [langflow.extensions] lfx-slack = lfx_slack
  -> all three python-default required_files present in the wheel

Frontend and docs:

src/frontend $ npx jest src/utils/__tests__/sidebarBundles.test.ts  -> 6 passed (4 Slack/base + 2 Microsoft)
docs $ npm run build   -> Generated static files; 0 broken links, and no broken anchor
                          reported on the `next` docs version  (re-run after the restack)

Ruff (check + format --check) is clean on every changed Python path; detect-secrets-hook is clean with no .secrets.baseline additions.

Notes for the reviewer

  • End-to-end runs still wait on INT-6. Graph.execution_principal defaults to ExecutionPrincipal.unknown(), and authorize_principal denies unknown for user and instance connections, so every Slack component run from the canvas, /api/v1/run, or a deployment fails closed until INT-6 stamps the principal. Only lfx run with LF_CONNECTION__SLACK__<NAME> works end to end today. INT-8 likewise has to ship the connection_ref renderer before the connection field is settable from the canvas; until then set it through tweaks or the API. The bundle is fully unit-tested against a fake resolver.
  • Ticket QA lines about pinned MCP are superseded. Per DECISIONS.md, INT-9 ships the generic pinned mode separately in 1.13 and its Slack sample stacks on this branch: it adds pin fields plus a recorded, clearly-synthetic tools/list fixture to one existing capability (slack.user.search is the natural target, and keeps its component_ref). This PR ships no MCP substrate, and substrate-slack.md / estimate.md are amended by INT-9's PR, not this one.
  • TRG-5 stacks on this branch and adds a third slack-app-token profile to the same capabilities.v1.json. The new manifest checker deliberately allows extra profiles and capabilities so that lands without a checker change.
  • SSRF. SLACK_API_BASE_URL is a module constant and no component exposes a URL, host, or proxy input, so there is no user-controllable request target. lfx.utils.ssrf_transport builds httpx clients with DNS pinning and AsyncWebClient speaks aiohttp, for which lfx ships no equivalent; removing the surface entirely is the stronger guarantee. Two tests pin it (the constant, and "no component declares a request-target input"). If we would rather add an aiohttp connector to lfx.utils.ssrf_transport, that is a BUNDLE_API-surface change and belongs in its own PR.
  • Backend locales/en.json is deliberately untouched. scripts/gp/extract_backend_strings.py walks lfx.components and reaches bundle components only through the lfx.components.<provider> compatibility shims that exist for components that moved out of the tree. lfx-slack is new and has no shim, and gp-backend-check.yml regenerates and auto-commits en.json on every PR touching src/bundles/**, so hand-written Slack keys would be deleted on the next run. paddle, confluent, valkey and nextplaid have no keys either.
  • Restack note (done). INT-11 added the identical "Develop/connection-oauth" entry to docs/sidebars.js. The restack keeps one copy — INT-11's, inside Authentication and authorization — so this PR no longer touches that part of the sidebar at all. Everything else this PR adds to a shared file is append-only and alphabetically placed.
  • docs/docs/Develop/connection-oauth.mdx is extended strictly by appending. The Slack redirect-URL and per-action scope material is a new trailing section, per the cross-ticket convention for this page; no existing text is edited.
  • The slack and microsoft rows in extensions-bundle-list.mdx link relatively on purpose. Every other row uses an absolute slug, but /bundles-slack and /bundles-microsoft exist only on the next docs version, so the absolute form fails the build: Docusaurus found broken links! - Broken link on source page path = /next/extensions-bundle-list. Verified by trying it. Normalize it only when 1.13 is cut and the slug exists in a released version.
  • Deviations from the matrix's schema.outputs, all deliberate: scalar rows (has_more, next_cursor, canvas_id) are folded into one Data output per component, because Langflow edges are typed and a bare bool/str output cannot be consumed downstream. The reactions.add input the matrix calls name is exposed as emoji_name, because Component.name is the registry-name override and an input called name would be silently shadowed by the class attribute; the Web API parameter is still sent as name.
  • The two matrix deviations above are now pinned by src/bundles/slack/tests/test_slack_matrix_schema.py, which compares the shipped components' input and output names against matrices/slack.json with the deviations listed explicitly and asserted exhaustive. check_capability_manifests.py cannot do this itself: the capability manifest carries no schema, only the matrix does.
  • src/backend/tests/unit/services/connection/test_oauth_providers.py now pins that the bundle's two auth profiles declare the same authorize and token URLs providers.endpoints hardcodes, so INT-8's picker and the broker cannot drift apart silently.
  • _base.py, _chat.py, _client.py sit at the package root, not in components/slack/: lfx extension validate scans the bundle directory and reports a shared abstract Component base there as build-method-missing.
  • Sample workspace IDs in fixtures and tests are deliberately non-hex (C0SLACKDEMO, not C0123456789) so detect-secrets does not read them as high-entropy strings. .secrets.baseline needed no new entries.
  • Not exercised: no live Slack workspace was available, so tests/test_slack_live.py has never run against real Slack. It is marked api_key_required, self-skips without LANGFLOW_SLACK_LIVE_USER_TOKEN / LANGFLOW_SLACK_LIVE_BOT_TOKEN / LANGFLOW_SLACK_LIVE_CHANNEL, and is deselected in CI. The hosted Langflow-owned Slack apps (confidential + a second PKCE app for Desktop) and the Marketplace listing that lifts the conversations.replies rate tier remain external dependencies.

Follow-ups (not in this PR)

  • EE oss-version re-pin once the INT stack merges, which also re-verifies enterprise-hardened.lock.json through scripts/check-oss-compat.sh. EE docs/connectors.md currently over-claims first-party Slack support and should be reconciled with these seven actions at the same time.
  • INT-7 consumes the declared policy_keys; INT-7/INT-8 deliver the Desktop hiding of bot actions by filtering on deployment_contexts. This PR only declares them.
  • Backend locales/en.json keys for the seven components. DECISIONS.md assigns the fix: include Google as a default partner bundle #14220 locale mirroring to INT-11; see the note above for why hand-writing them here would be undone by gp-backend-check.yml. Until INT-8's baseline lands, the Slack palette strings are English-only, as paddle's and confluent's are.
  • An lfx follow-up (not caused by this diff): in a full langflow install, python -c "import lfx_slack" raises ImportError from a partially initialized lfx.custom.custom_component.component, while import lfx_google succeeds. It reproduces with no Slack code at all (import lfx.io, lfx.schema.data; from lfx.custom.custom_component.component import Component) and does not affect the real loader path — load_installed_extensions reports lfx-slack ok, 7 components, 0 errors.

Post-review changes: 354709002e merges INT-11's fix to scripts/gp/extract_backend_strings.py — the extractor now also walks installed extension bundles through lfx.extension.load_installed_extensions() — which closes the "Backend locales/en.json keys for the seven components" follow-up above. locales/en.json conflicted on the merge and was resolved by re-running the generator rather than by hand-merging either side, so the seven Slack components' 101 rows are generated and the auto-bake job will keep them instead of deleting them. Nothing is removed and no value changes relative to the merged-in branch; --check is clean immediately after the run. src/bundles/slack/tests in the clean lfx-only venv is unchanged at 56 passed / 3 deselected.

erichare and others added 6 commits September 5, 2026 07:39
Slack is the first provider whose user and bot tokens share scope names --
chat:write is both a User Token Scope and a Bot Token Scope -- so a bundle
capability that must run as the app's bot user cannot tell from
granted_scopes whether it was handed a user-token connection. The connection
row already records executing_identity, but the resolver dropped it on the
floor when building ResolvedCredential, leaving Slack's own
not_allowed_token_type error as the only protection, after the request was
already sent.

Add an additive optional ResolvedCredential.identity and populate it in
DatabaseConnectionResolverService._resolved_from_row. The headless env
resolver leaves it None, which callers read as "the operator vouched for this
token". No existing field changed, so BUNDLE_API_VERSION stays 1; the
changelog entry is required because lfx/integrations is an in-scope surface.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Creates src/bundles/slack (distribution lfx-slack) with the seven actions the
INT-1 discovery gate froze in design/dedicated-integrations/matrices/slack.json:
four user-identity actions (search, read thread, send, create canvas) and three
bot-identity actions (post, add reaction, list channel members). All seven run
on the Slack Web API through slack_sdk's AsyncWebClient, per the accepted
substrate decision -- no MCP in this bundle.

capabilities.v1.json is lifted mechanically from the matrix: the same action
ids, display names, identities, required and conditional scopes, deployment
contexts and component classes, plus the two named auth profiles the connection
contract requires (slack-user-oauth, slack-bot-install) so a bot capability can
never resolve through a user-token connection by accident. Bot capabilities
declare no desktop context, because Slack desktop redirects may not request bot
scopes; the actual hiding is discovery's job (INT-7/INT-8), not the bundle's.

Two things needed care:

* Slack answers HTTP 200 with {"ok": false, "error": ...}, so lfx's
  status-code-only fallback would report an expired token or a missing scope as
  provider-unavailable. The bundle registers a Slack error normalizer that maps
  the ok:false codes onto auth-expired / scope-missing / rate-limited /
  action-unsupported, and an auth rejection spends the one reactive re-resolve
  the lease allows -- which is how a rotated Slack token is picked up, since
  Slack tokens otherwise never expire.
* User and bot scopes share names, so the components compare
  ResolvedCredential.identity and fail closed before the first request.

_base.py, _chat.py and _client.py sit at the package root rather than in the
bundle directory: `lfx extension validate` scans that directory and reports a
shared abstract Component base as build-method-missing.

Tests patch slack_sdk's lowest transport layer with recorded fixtures, so the
SDK's real request assembly, response parsing and error raising stay under
test while aiohttp is never touched. Sample workspace IDs are deliberately
non-hex (C0SLACKDEMO, not C0123456789) so detect-secrets does not read them as
high-entropy strings. The opt-in live-workspace suite is marked
api_key_required and self-skips without LANGFLOW_SLACK_LIVE_*.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Runs the same checklist lfx-google went through when it graduated to a
default-install bundle: root pyproject markers (deps, workspace source, member)
plus uv.lock; the enterprise-hardened bundle profile and its recompiled lock;
the python-default and python-full release-inventory rows, including the
source_roots entry test_contract_required_files_exist_in_sources needs to
resolve those required_files; migration-table rows for the seven component
classes; the Slack sidebar group (the Slack icon already existed); and the docs
pages, the bundle list, the graduated-install map and the docs sidebar.

Two seams the checklist does NOT need:

* component_index.json indexes lfx.components only, so bundle components never
  enter it and `make build_component_index` is a no-op here.
* Backend locales/en.json is regenerated from lfx.components on every PR that
  touches src/bundles/**, and reaches bundle components only through the
  lfx.components.<provider> compatibility shims that exist for components that
  MOVED out of the tree. lfx-slack is new and has no shim, so hand-written
  keys would be deleted by the next gp-backend-check run. Slack strings
  therefore stay untranslated for now, exactly as paddle, confluent, valkey and
  nextplaid do.

docs/docs/Develop/connection-oauth.mdx was never registered in the sidebar, so
the customer-owned Slack app guide the ticket asks for was unreachable. It is
now listed under Develop and carries the redirect URLs, the per-action scope
table for both identities, and a worked two-registration example. Links to the
new pages are relative, because absolute slugs resolve against the released
docs version, which does not have them yet.

scripts/ci/check_capability_manifests.py is new and generic over every bundle
that declares `integrations`: it proves each shipped capabilities.v1.json still
agrees with its discovery-gate matrix on ids, identity, scopes, deployment
contexts and component class. Nothing else stops those two from drifting, and a
scope present in only one of them is either unreviewed or never requested at
consent time. Extra capabilities and auth profiles are allowed so TRG-5 can add
its app-token profile on top.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
run_action memoized the Slack response on the component instance so a
component with two outputs (Messages plus Pagination) cost one call against
Slack's per-method rate tier. Nothing ever cleared it, and the graph reuses
one component instance across builds: Graph._set_cache_to_vertices_in_cycle
forces output.cache=False on every cycle vertex so its outputs recompute each
iteration, while Vertex.build keeps the same custom_component. A Slack write
action inside a Loop therefore posted once and then reported that first
response for every later iteration -- N green statuses, one message in the
channel.

Component._build_results calls _pre_run_setup once per build, so drop the memo
there. Sharing within one build is unchanged; freshness between builds is
restored. test_slack_rebuild.py covers both the framework hook and the public
build methods, and asserts the two-output case still costs one call.

Also move require_identity inside the integration_action span. The fail-closed
identity denial is the one an operator most wants counted, and outside the
context manager it emitted no integration_action telemetry at all. The guard
still runs before any HTTP request; SlackClient construction is inert.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three review follow-ups, no behaviour change.

check_capability_manifests.py compares ids, identity, scopes, contexts and
component_ref, but it cannot compare field names: the capability manifest
carries no schema, only the matrix does. test_slack_matrix_schema.py closes
that gap by comparing the shipped components' input and output names against
design/dedicated-integrations/matrices/slack.json, with the four deliberate
deviations listed explicitly (the emoji_name rename, and the three groups of
scalar outputs folded into one Data). The deviation lists are asserted
exhaustive, so amending the matrix later fails here until this file follows.

test_oauth_providers.py now pins that the bundle's two auth profiles declare
the same authorize and token URLs that providers.endpoints hardcodes. They
agree today; nothing stopped one side from drifting and sending a user to one
authorization server while the broker redeemed the code at another.

docs: connection-oauth.mdx's Slack redirect-URL and scope material moves to a
new trailing section, so this page stays strictly append-only for the other
integration branches that also extend it. bundles-slack.mdx links Data to
/data-types#json, the anchor the current docs version actually defines; #data
exists only as a raw <a id> in the pre-1.9 versioned copies and was the only
broken anchor the Docusaurus build reported on the next version.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Restack INT-12 (lfx-slack) onto INT-11 (lfx-microsoft) so the Slack PR
targets the Microsoft branch instead of the INT-5 tip. Both bundles were
built independently from 5615cd0 and touch the same registration seams,
so the conflicts were expected; both bundles are registered here.

Conflicts resolved, INT-11's entry first in every append-only list:

- pyproject.toml: lfx-microsoft then lfx-slack in the bundle dependency
  list, the uv workspace sources table, and the workspace members list.
- scripts/ci/bundle_profiles.json, scripts/ci/release_inventory_contract.json:
  both distributions, alphabetical where the surrounding list is sorted and
  append-ordered where it is not.
- src/lfx/src/lfx/extension/migration/migration_table.json: both row sets
  appended (991 -> 1027; +8 microsoft, +28 slack). Append-only against both
  the INT-11 tip and 5615cd0.
- docs/docs/Develop/connection-oauth.mdx: both trailing sections kept, the
  Microsoft 365 section first.
- docs/sidebars.js: both branches added the same "Develop/connection-oauth"
  entry. Kept INT-11's placement, inside "Authentication and authorization"
  beside the Entra runbook it links to, and dropped INT-12's duplicate.
- scripts/ci/bundle_profile_locks/enterprise-hardened.lock.json: not
  hand-merged. Regenerated with
  `manage_bundle_profiles.py compile --output-dir` after the other conflicts
  were resolved; the result is INT-11's lock plus the lfx-slack row and a new
  profile_digest.
- uv.lock: git's merge produced a lock `uv lock --offline` and
  `uv lock --check` both accept unchanged (857 packages, both bundles
  editable). No re-resolution was needed and nothing had to be fetched.

Two fixes the combined tree needs that neither branch could make alone:

- INT-12's new generic checker, scripts/ci/check_capability_manifests.py,
  reaches INT-11's manifest for the first time here and rejected it on nine
  counts. Eight are INT-11's deliberate `offline_access` deviation, which is
  load-bearing (Entra never echoes the scope, and the resolver computes
  `required - granted` literally, so transcribing the matrix would fail every
  Microsoft resolution) and is already pinned bundle-side; the ninth is the
  short "Microsoft 365" provider label the bundle ships everywhere against
  the matrix's longer one. Rather than change either bundle's shipped
  behaviour, the checker gained a DELIBERATE_DEVIATIONS table holding the
  exact expected values, so any other drift still fails and a deviation that
  has converged is reported as stale. Mutation-checked: dropping either entry
  reproduces the 8 and 1 failures.
- INT-11's docs link to /bundles-microsoft, /entra-app-registration and
  /connection-oauth absolutely; those slugs exist only on the `next` version,
  so `npm run build` failed with four broken links. Converted to relative
  .mdx links, the form INT-12 already had to use for /bundles-slack. The
  build now passes with zero broken links and no broken anchor on `next`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (1)
  • release-.*

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 47ea2282-42e8-4888-8187-cd90c849fed0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

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

@github-actions github-actions Bot added the enhancement New feature or request label Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions

This comment has been minimized.

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 55%
55.64% (84764/152331) 72.45% (12551/17322) 50.87% (2000/3931)

Unit Test Results

Tests Skipped Failures Errors Time
6644 0 💤 0 ❌ 0 🔥 22m 15s ⏱️

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Sep 5, 2026
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Sep 5, 2026
…anch

Takes INT-11's fix to scripts/gp/extract_backend_strings.py, which now also
walks installed extension bundles through lfx.extension.load_installed_extensions().

locales/en.json conflicted (both branches carried a bot regeneration of it)
and is resolved the only honest way: by re-running the extractor rather than
by hand-merging either side. That adds the 101 rows for this bundle's seven
Slack components, which the previous extractor could not see -- lfx-slack
ships no lfx/components/slack shim, and scripts/ci/check_bare_names.py would
reject one. Nothing is removed and no value changes relative to the merged-in
microsoft branch; --check is clean immediately after the run.
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Sep 5, 2026
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Build successful! ✅
Deploying docs draft.
Deploy successful! View draft

@codecov

codecov Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.21%. Comparing base (45e4ead) to head (3547090).

Additional details and impacted files

Impacted file tree graph

@@                      Coverage Diff                      @@
##           feat/int-11-lfx-microsoft   #14962      +/-   ##
=============================================================
- Coverage                      65.26%   65.21%   -0.05%     
=============================================================
  Files                           2519     2520       +1     
  Lines                         263172   263190      +18     
  Branches                       36824    39272    +2448     
=============================================================
- Hits                          171763   171649     -114     
- Misses                         89189    89321     +132     
  Partials                        2220     2220              
Flag Coverage Δ
backend 74.17% <ø> (-0.04%) ⬇️
frontend 62.36% <100.00%> (-0.07%) ⬇️
lfx 65.09% <100.00%> (+<0.01%) ⬆️

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

Files with missing lines Coverage Δ
...ckend/base/langflow/services/connection/service.py 58.56% <ø> (ø)
src/frontend/src/utils/styleUtils.ts 95.01% <100.00%> (+<0.01%) ⬆️
src/lfx/src/lfx/integrations/models.py 87.70% <100.00%> (+0.10%) ⬆️

... and 40 files with indirect coverage changes

🚀 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.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant