Skip to content

docs(integrations): headless connection resolver and deployment reference (INT-13) - #14954

Open
erichare wants to merge 7 commits into
feat/int-5-oauth-brokerfrom
feat/int-13-headless-reference
Open

docs(integrations): headless connection resolver and deployment reference (INT-13)#14954
erichare wants to merge 7 commits into
feat/int-5-oauth-brokerfrom
feat/int-13-headless-reference

Conversation

@erichare

@erichare erichare commented Sep 5, 2026

Copy link
Copy Markdown
Member

docs(integrations): headless connection resolver and deployment reference (INT-13)

Base: feat/int-5-oauth-broker (#14935) · Branch: feat/int-13-headless-reference · One PR.

Summary

  • New page docs/docs/Lfx/lfx-connections.mdx — the headless half of the connection contract, which had no documentation anywhere: how provider/name becomes LF_CONNECTION__<PROVIDER>__<NAME>, the bare-token and JSON wire formats and the fields they refuse, the lfx run pre-flight and its exact error text, per-request injection under lfx serve, implementing a BaseConnectionResolverService without Langflow's database, the sanitized error-code table, and the required_connections a project deployment artifact declares. Registered in the LFX sidebar.
  • Runnable samples under docs/docs/Lfx/samples/connections/ — the page embeds them verbatim with raw-loader and the lfx tests execute the same files, so the page cannot document code that does not run:
    • connection_action_component.py — a ConnectionRefInput action that resolves a lease and returns account and scopes, never a token, plus the flow lfx run and lfx serve load.
    • env_resolver_host.py — environment-backed resolution through both injection channels, and the JSON credential builder.
    • secret_manager_resolver.py — a generic callable-backed SecretManagerConnectionResolver plus MountedSecretsConnectionResolver, a dependency-free implementation over a mounted secrets directory (Kubernetes/Docker secrets), with AWS and Vault adapters shown in comments. No new dependencies.
    • lfx.toml and serve_request.sh — the registration and the request shape.
  • CI coveragetest_reference_samples.py (19 tests), test_serve_app_connections.py (4 tests driving the real serve app), and two drift tests that pin the page to the code: the error-code table against INTEGRATION_ERROR_CODES, and the manifest example against a manifest build_project_artifact actually produces (key sets and the schema_version 4 rule are read off the builder's output, not restated). serve_request.sh is executed too: a test runs it with a curl stub and resolves both request bodies through the env resolver, and a second test refuses any literal timestamp under the samples directory, so no sample can ship an expiry that goes stale.
  • Cross-links and gaps filledlfx-run.mdx (connection pre-flight and missing-connection text), lfx-serve.mdx (global_vars, --no-env-fallback, --reset-environ, none of which were documented under docs/), deployment-wxo.mdx (the watsonx Orchestrate connection-variable naming rule), configuration-global-variables.mdx (LANGFLOW_REQUEST_VARIABLES, the LF_CONNECTION__* family, and the distinction between LANGFLOW_FALLBACK_TO_ENV_VAR and --no-env-fallback), environment-variables.mdx pointer, lfx-devops-sdk.mdx see-also, a new ## Headless connection resolution section appended to connection-oauth.mdx (a heading naming its subject, so the later INT/TRG tickets appending to that file do not all land on one generic ## See also), src/lfx/PLUGGABLE_SERVICES.md and src/lfx/lfx.toml.example (connection_resolver_service, which both omitted).
  • No runtime code changes. The only non-docs, non-test edit is one [tool.ruff.lint.per-file-ignores] entry so the samples (loaded by path, not a package) do not trip INP001.
  • docs/sidebars.js gains exactly one entry, this page's. docs/docs/Develop/connection-oauth.mdx is still an orphan in the sidebar — it belongs to feat(integrations): broker delegated OAuth connections #14935, and registering it from here would collide with that PR (a doc listed twice in one sidebar is a Docusaurus error). It is reachable through the links this PR adds; feat(integrations): broker delegated OAuth connections #14935 should add its own sidebar line.

What the documentation deliberately does not promise

Each of these is stated in the page as current behavior, and pinned by a test where testable:

  • lfx serve has no connection pre-flight and no machine-readable error code. A missing connection surfaces when the component awaits its lease, as HTTP 500 whose result is ConnectionUnresolvedError's sanitized message. The serve test asserts on that text. A typed sanitized error event for serve is still owed by INT-2 (contract section 11); this PR documents what ships.
  • --no-env-fallback is lfx serve-only. For lfx run only --check-variables and the exact-key / x-langflow-global-var-* env lookups are documented.
  • LANGFLOW_REQUEST_VARIABLES is a serve/TRM channel, not an lfx run one. VariableService honors the blob at resolution time, but validate_connection_refs_for_env reads only graph.context['request_variables'] and env keys, so a credential carried only in that blob passes at runtime and fails the default pre-flight. Called out in a :::note; the fix belongs in feat(integrations): add lfx connection resolution contract #14919.
  • required_connections is informational for deployment tooling today. Verified in the EE and CP trees: langflow_ctl/lfpkg.py SUPPORTED_SCHEMA_VERSIONS = frozenset({1, 2, 3}) refuses a v4 artifact, and the control plane's checkVariableAvailability handles variable names only. Stated plainly rather than implied away.
  • TRM/WXO. "TRM" is the watsonx Orchestrate tool runtime that calls POST /flows/{id}/run with global_vars (src/lfx/src/lfx/cli/runtime_variables.py, src/lfx/src/lfx/services/variable/request_scope.py). The page documents that a wxO connection variable must be named exactly ConnectionRef.env_key(), and that explicit keys beat the LANGFLOW_REQUEST_VARIABLES blob. No repository test exercises a live TRM; confirming it end to end is an INT-14 checklist item.
  • Host/resolver table. EE serving mode runs the full backend and therefore resolves through DatabaseConnectionResolverService, not EnvConnectionResolver; the page says which host runs which resolver so the env-injection guidance is not read as applying to that plane.

Verification

Run from src/lfx in its isolated environment (uv sync --dev --extra otel), and from the repo root for the backend test.

cd src/lfx && uv run --no-sync pytest tests/unit/services/connection tests/unit/cli/test_serve_app_connections.py tests/unit/integrations -q
  73 passed (23 new: 19 reference-sample + 4 serve)

cd src/lfx && uv run --no-sync pytest tests/unit/cli -q
  1173 passed, 3 xfailed, 2 xpassed in 112.51s   (the xfail/xpass are pre-existing)

uv run --no-sync pytest src/backend/tests/unit/services/deployment_artifacts/ -q
  59 passed (1 new: test_docs_manifest_example.py)

uv run --no-sync ruff check <changed paths>      All checks passed!
uv run --no-sync ruff format --check <changed paths>   11 files already formatted
uv run --no-sync detect-secrets-hook --baseline .secrets.baseline <changed paths>   exit 0, baseline unmodified
uv run --no-sync python scripts/ci/{check_execution_principal_matrix,check_capability_matrices,check_authz_endpoint_matrix,check_components_frozen}.py   all OK
uv run --no-sync python scripts/migrate/check_bundle_api_changelog.py --base origin/feat/int-5-oauth-broker
  ok: no in-scope BUNDLE_API surface files changed (so no changelog line is owed)

cd docs && npm run build
  SUCCESS, exit 0, zero broken links (docs_test.yml equivalent); the built
  lfx-connections page renders all five embedded samples

Not exercised: a live watsonx Orchestrate run, and any multi-worker demonstration of request-scope isolation (test_serve_env_isolation_integration.py is CI-skipped). Neither is reachable from this repository's test environment.

Reviewers

Requesting the lfx owner and the serving-plane maintainers for the QA item "Serving owners review the documentation"; the host/resolver table and the EE/CP consumer caveat are the parts that need their sign-off.

Post-review changes

  • c908d58 fixes the LFX Tests - Python 3.10 CI failure: test_reference_samples.py imported tomllib unguarded (stdlib only from 3.11); it now falls back to tomli, matching lfx/extension/manifest.py and lfx/services/config_discovery.py. No CodeRabbit review was posted (auto-review is disabled for non-release-* base branches).

erichare and others added 6 commits September 5, 2026 07:39
INT-13 documents the headless half of the connection contract, which had no
page at all: how a handle becomes an LF_CONNECTION__* key, what the bare-token
and JSON wire formats permit and refuse, how lfx run pre-flights a missing
connection, how lfx serve injects one per request, how a host registers its own
BaseConnectionResolverService without Langflow's database, and what a project
deployment artifact declares in required_connections.

The samples under docs/docs/Lfx/samples/connections are the page's source of
truth: the page embeds them verbatim with raw-loader and the lfx tests execute
the same files, so the documentation cannot describe code that does not run.
They cover a connection-backed action component, environment-backed resolution
through both injection channels, a secret-manager resolver (generic callable
plus a dependency-free mounted-secrets implementation), the lfx.toml
registration, and the serve request shape.

connection-oauth.mdx was orphaned from the sidebar since it was added; it is
registered here so the two connection pages form a navigable pair.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The reference samples are code operators copy into production, so CI executes
them rather than only rendering them. The lfx suites load each sample by path
and assert the invariants that make it safe as well as the behavior it
demonstrates: the headless-operator deny floor, the refusal of refresh tokens
and other long-lived secrets, typed auth-expired and scope-missing failures,
the mounted-secrets path-containment check, and fail-closed lfx.toml
registration.

test_serve_app_connections.py drives the real serve app with the sample flow so
the documented request shape is exercised end to end: a request-scoped
credential resolves, an absent one surfaces as a 500 carrying the sanitized
"could not be resolved" text (lfx serve has no pre-flight and no machine
readable error code today), an ambient environment value loses under
--no-env-fallback, and a request scope does not leak into the next request.

Two drift tests pin the page to the code it describes: the error-code table
against INTEGRATION_ERROR_CODES, and the artifact manifest example against
ProjectArtifactRequiredConnection and the schema_version 4 rule.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…y paths

The headless reference is only useful where a reader already is. lfx-run gains
the connection pre-flight behavior and the exact ConnectionUnresolvedError text;
lfx-serve documents global_vars, --no-env-fallback and --reset-environ, which
had no documentation anywhere under docs/; deployment-wxo names the
LF_CONNECTION__<PROVIDER>__<NAME> variable a watsonx Orchestrate connection must
carry; configuration-global-variables introduces LANGFLOW_REQUEST_VARIABLES and
the LF_CONNECTION__* family and separates LANGFLOW_FALLBACK_TO_ENV_VAR from
--no-env-fallback, which are different switches.

PLUGGABLE_SERVICES.md and lfx.toml.example gain the connection_resolver_service
entry they were missing, including the fail-closed rules and the deny floor a
host implementation must apply.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
docusaurus.config.js sets onBrokenLinks to "throw", and the docs site builds the
released version snapshots alongside `next`. An absolute slug link such as
/lfx-connections resolves inside a released version too, where the page does not
exist, so `npm run build` failed on five links. Relative .mdx links are resolved
per version, which is the convention the rest of docs/docs already uses for
cross-directory references.

Verified with a full `cd docs && npm ci && npm run build`: SUCCESS, zero broken
links (the remaining broken-anchor warnings are pre-existing, in the 1.9.0 and
1.10.0 snapshots).

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

Two pieces of shipped reference material were wrong, and neither test caught it.

The project-artifact manifest example omitted the `name` key that
`deployment_artifacts/builder.py` emits in every `flows[]` entry, so an operator
who modelled a manifest reader on the page would reject every real .lfpkg. The
drift test asserted the doc's key sets against hardcoded literals, so it agreed
with the wrong shape; it now builds a real connection-referencing artifact with
the builder and compares the documented key sets against the manifest that build
produces. Removing the `name` line from the page fails the test.

serve_request.sh hardcoded `expires_at: "2026-01-01T00:00:00+00:00"`, already in
the past, so the copy-pasteable JSON-credential request failed with auth-expired
on every attempt. The expiry is now computed at send time from an overridable
TTL. It was the one sample no test executed, so two tests close that gap: one
runs the script with a curl stub and resolves both request bodies through the
env resolver, the other refuses any literal timestamp under the samples
directory, since that is the class of defect that goes stale silently.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- sidebars.js keeps only this ticket's own entry. `Develop/connection-oauth`
  belongs to the PR that introduced the page (#14935); registering it here too
  would collide with that PR and list one doc twice in one sidebar, which
  Docusaurus rejects. The page stays reachable through the links this PR adds.
- The section appended to connection-oauth.mdx now has a heading naming its
  subject instead of a generic "See also", so the later tickets that append to
  the same file do not all land on the same heading.
- LANGFLOW_REQUEST_VARIABLES is a JSON-encoded string, not a nested object:
  runtime_variables.py json.loads() the value and logs-and-drops anything that
  is not a string containing an object. Both pages now say so.
- The appended global-variables heading gets the blank line the rest of the file
  uses.
- sample_loader fails loudly when docs/ is present but the samples are not.
  Skipping all seventeen sample tests on a moved directory is the opposite of
  the drift protection they exist for; an sdist-only tree without docs/ still
  skips.

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: c43058ee-19f8-4c26-bc22-99018d2eb702

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 documentation Improvements or additions to documentation 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.65% (84754/152292) 72.47% (12552/17320) 50.95% (2000/3925)

Unit Test Results

Tests Skipped Failures Errors Time
6641 0 💤 0 ❌ 0 🔥 22m 9s ⏱️

The lfx reference-sample test parsed the sample ``lfx.toml`` with a bare
``import tomllib``, which is stdlib only from 3.11, so the LFX Tests -
Python 3.10 job failed with ModuleNotFoundError. Use the same guarded
import the rest of lfx uses (manifest.py, config_discovery.py); lfx
already depends on tomli unconditionally, so the fallback always resolves.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation and removed documentation Improvements or additions to documentation 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

@github-actions github-actions Bot added documentation Improvements or additions to documentation and removed documentation Improvements or additions to documentation labels Sep 5, 2026
@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 66.71%. Comparing base (5615cd0) to head (c908d58).

Additional details and impacted files

Impacted file tree graph

@@                     Coverage Diff                     @@
##           feat/int-5-oauth-broker   #14954      +/-   ##
===========================================================
+ Coverage                    65.63%   66.71%   +1.07%     
===========================================================
  Files                         2519     2526       +7     
  Lines                       263230   263493     +263     
  Branches                     39299    36899    -2400     
===========================================================
+ Hits                        172771   175787    +3016     
+ Misses                       88239    85488    -2751     
+ Partials                      2220     2218       -2     
Flag Coverage Δ
backend 73.59% <ø> (-0.60%) ⬇️
frontend 64.97% <ø> (+1.93%) ⬆️
lfx 65.12% <ø> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 343 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.

@github-actions github-actions Bot added documentation Improvements or additions to documentation and removed documentation Improvements or additions to documentation labels Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant