Commit Graph

18146 Commits

Author SHA1 Message Date
48c2e19d23 fix(security): deny server secrets/DB within the local-file-access boundary
restrict_local_file_access confined reads to config_dir, but config_dir IS
the storage dir AND holds the server-managed secrets as siblings of the
per-flow upload subdirs: secret_key (Fernet master key), private_key.pem /
public_key.pem (JWT signing keys), and the SQLite DB (save_db_in_config_dir).
A tenant File-component input of "<flow>/../secret_key" routed through
build_full_path (no '..' check) resolved back to <config_dir>/secret_key,
passed the is_relative_to(config_dir) boundary, and was read -- disclosing the
key that decrypts every tenant's stored credentials. The control thus failed
its own stated goal under the very multi-tenant mode it adds.

enforce_local_file_access now denies the exact config_dir locations of
secret_key / private_key.pem / public_key.pem and the sqlite DB derived from
database_url (including the -wal / -shm / -journal sidecars that hold the same
row data, and the async sqlite+aiosqlite:/// + ?query URL forms), even though
they resolve inside the boundary. Matched at exact location only, not by
basename, so a tenant upload that merely shares a reserved name inside a flow
subdir stays readable. Fails safe on non-sqlite / empty / unavailable settings.

Known limitation (tracked separately): this does not scope reads per tenant,
so cross-tenant reads of <config_dir>/<other_flow_id>/<file> uploads remain
possible and need per-user/per-flow scoping in a follow-up.

Tests: reserved file blocked, traversal-to-reserved blocked, DB + WAL/SHM/
journal sidecars blocked, async+query URL blocked, same-named upload in a flow
subdir still allowed.
2026-06-16 13:16:31 -04:00
1707415a85 fix(security): clarify connector SSRF errors and document hardening toggles
Address PR-review findings on the connector SSRF wrapper and docs:
- validate_connector_url_for_ssrf: raise a clear, actionable error for a
  scheme-less / host-less connector URL (e.g. Milvus "host:19530") instead
  of the shared validator's confusing "Invalid URL scheme ''". The message
  tells the operator to use an explicit http(s) scheme and notes that
  allowlisting alone does not permit a scheme-less host (the format gate
  runs before the allowlist check). Only fires when host validation would
  actually run (global SSRF on); stays a no-op otherwise.
- Document the DNS-rebinding residual in the wrapper docstring: connectors
  hand the URL to third-party clients that re-resolve DNS at connect time
  and expose no pinned-IP hook (would break TLS SNI), so unlike api_request
  this guard is validate-then-connect. Literal-IP targets (metadata,
  RFC1918) are blocked identically.
- Docs: add a "Multi-tenant component hardening" section covering
  LANGFLOW_BLOCK_CODE_INTERPRETER_COMPONENTS and
  LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS, recommended alongside
  LANGFLOW_ALLOW_CUSTOM_COMPONENTS=false.
- Tests: add TestConnectorURLValidation (disabled no-op, metadata blocked,
  scheme-less clear-error, no-op when global SSRF off).
2026-06-16 13:16:31 -04:00
63ec82e6a5 fix(security): address review findings on security-hardening PR
- Log (instead of silently swallowing) settings-read failures in the
  fail-open enable-switch helpers so a security control silently
  disabling is observable: restrict_local_file_access and
  connector_ssrf_validation_enabled gates.
- Log when get_all() skips a GENERIC variable holding ciphertext
  (likely a CREDENTIAL row relabeled GENERIC) instead of dropping it
  silently.
- Remove unreachable non-http/https scheme branch in SSRF validators
  (_validate_url_scheme already raises) and fix the misleading comment
  claiming such schemes are "not subject to SSRF protection".
- Close the unbalanced paren in the WebSearch SSRF-blocked message.
- Correct getenvvar comment: only LANGFLOW_*/LFX_* are prefix-matched;
  AWS protection is specific names, not an AWS_* glob.
- Fix three code-execution denylist comments to point at the real
  exec sites (get_function, LocalPythonInterpreter, external
  agents.ds_star executor).
- Correct LANGFLOW_SSRF_PROTECTION_ENABLED docs default (True, not False).
- Add symlink-escape containment tests for enforce_local_file_access
  (the docstring promises symlink resolution; previously untested).
2026-06-16 13:16:31 -04:00
b80ac66f62 fix(security): harden review-found gaps in the multi-tenant security commits
Follow-up to 6e4ec5ae3f / 1cdc3052f6 / c31eeb81f7 from an extensive PR review.
Fixes real defects in those commits and adds opt-in SSRF for connector components.
No backwards-incompatible default behavior: all host-blocking SSRF is opt-in, and
local/private hosts keep working out of the box.

Defect fixes (always active; only affect abuse/abnormal inputs, not legit flows):
- MCP stdio: close a command-injection bypass where a tenant packs the whole payload
  into `command` with empty `args` (e.g. "bash -c '<payload>'"). The validator now
  tokenizes the command, and MCPServerConfig delegates to the shared
  validate_mcp_stdio_config (single source of truth).
- Code-exec block list: add the missing "Python Code Structured" display-name alias
  and the PythonFunction component so a hash-valid node can't bypass the block.
- Env-var fallback: route the remaining tenant-controlled os.getenv sites through
  safe_getenv (VariableService, credentials, knowledge-base sources), harden the
  GetEnvVar component, and expand the infra-secret denylist.
- web_search + Home Assistant: allow_redirects=False so a 3xx can't bypass the SSRF guard.
- git: enforce the scheme allowlist regardless of the SSRF toggle; confine the Local
  repo_path under LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS.
- api_request: reduce the Content-Disposition filename to a basename (no path traversal).

Opt-in connector SSRF (new LANGFLOW_CONNECTOR_SSRF_VALIDATION_ENABLED, default off):
- New validate_connector_url_for_ssrf / validate_connector_database_url_for_ssrf wrappers
  that no-op unless the flag is set, so connectors keep reaching localhost/private hosts
  by default. When enabled they defer to LANGFLOW_SSRF_PROTECTION_ENABLED / _ALLOWED_HOSTS.
- Applied to vector stores (chroma/clickhouse/qdrant/elasticsearch/opensearch/milvus/
  supabase/upstash/weaviate), the SQL Database components, glean, astradb_cql, model
  discovery (litellm/huggingface/xai/deepseek/groq/watsonx), Ollama (chat + embeddings),
  LM Studio, Home Assistant, and the MCP HTTP-mode URL.
- The SQL local-file dialect restriction stays on its own LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS
  toggle, independent of the connector flag.

Local file-access confinement (no-op unless LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS=true):
CSV/JSON/OpenAPI agents + save_file write.

Docs: document LANGFLOW_CONNECTOR_SSRF_VALIDATION_ENABLED + a multi-tenant recommendation
in api-keys-and-authentication.mdx. Re-export the MCP constants from langflow.api.v2.schemas
for backwards compatibility.
2026-06-16 13:16:20 -04:00
aeb3c0f560 fix(security): close 5 multi-tenant RCE, code-exec, and SSRF holes
Five more critical issues for multi-tenant deployments where tenants use all core
components + curated trusted custom components but cannot author custom ones.
All distinct from the issues fixed in 6e4ec5ae3f and 1cdc3052f6.

1. MCP stdio flow-embedded command execution (RCE): a tenant-built flow can embed an
   MCP stdio config (command/args/env) directly in the MCPTools component value, which
   reached `bash -c "exec <command>"` with no validation -- the MCPServerConfig allowlist
   only ran at the REST /api/v2/mcp/servers layer, never in the flow-execution path, and
   mcp_servers_locked / allow_custom_components=False do not cover it. New single-source
   lfx.base.mcp.security (constants + validate_mcp_stdio_config) enforced at the update_tools
   sink and the legacy deactivated/mcp_stdio sink; MCPServerConfig now imports the shared
   constants/helper so the two enforcement points cannot drift. MCP HTTP/SSE url is now
   SSRF-validated too.

2. Code-agent components bypass the code-interpreter lockdown: CodeActAgentSmolagents
   (smolagents LocalPythonExecutor) and OpenDsStarAgent (bare exec) run LLM-generated
   Python in-process but were absent from CODE_EXECUTION_COMPONENT_TYPES, so
   LANGFLOW_BLOCK_CODE_INTERPRETER_COMPONENTS=true did not block them. Added both class
   names + display-name aliases.

3. Git components clone arbitrary tenant URLs: GitExtractor/GitLoader pass repository_url
   /clone_url to git clone -> ext:: remote-helper RCE, file://+local-path file read,
   leading-'-' option injection, internal-host SSRF. Add validate_git_repository_url
   (always blocks remote helpers + option injection; blocks local-file clones under SSRF
   or local-file restriction; SSRF-validates network hosts incl. scp-like).

4. Home Assistant reflective SSRF -> cloud-metadata credential theft: List States (GET)
   and Control (POST) fetch f"{base_url}/api/.." and reflect the body to the tenant; a
   trailing '#' reaches the IMDS credential path. Route base_url through
   validate_url_for_ssrf before the request.

5. Model-provider base_url SSRF in build-config discovery: Ollama/LM Studio fetch a
   tenant-set base_url (even on field edit, no flow run) with no SSRF guard. Validate
   before each fetch. (Consistent with the existing url.py hard-block posture: local model
   servers need LANGFLOW_SSRF_ALLOWED_HOSTS or SSRF disabled.)

Tests: 220 lfx + 121 backend tests pass; ruff clean.
2026-06-16 13:15:20 -04:00
8e20dbdcc1 fix(security): close 4 multi-tenant secret-leak, SSRF, and file-read holes
Four more critical issues for multi-tenant deployments where tenants use all core
components but cannot author custom ones:

1. Variable Credential->Generic type-confusion: PATCH /variables flipping a credential
   row's type to Generic without a value left the Fernet ciphertext in place; get_all
   then decrypted it and returned plaintext via GET /variables, exposing the server's
   shared provider keys. Reject the transition (write path) and never decrypt a
   Fernet-token value labeled Generic (read path).

2. SQL Database components (sql_executor, langchain sql/sql_database) accepted arbitrary
   connection URIs -> SSRF to internal DBs and sqlite:////abs/path local file
   read/write. Add validate_database_url_for_ssrf: host validated against SSRF blocked
   ranges (default-on), local-file dialects blocked under LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS
   so single-tenant sqlite keeps working.

3. Web Search RSS/web fetches used bare requests.get with no SSRF guard (cloud-metadata
   cred theft). Route the RSS URL and result-link fetches through validate_url_for_ssrf.

4. File/Directory/JSON-to-Data/CSV-to-Data read arbitrary server files via uncontained
   resolve_path. Add LANGFLOW_RESTRICT_LOCAL_FILE_ACCESS (default off) +
   enforce_local_file_access, confining resolved paths to the storage data dir at every
   read sink. resolve_path itself is unchanged so persistence-dir components are unaffected.
2026-06-16 13:15:20 -04:00
885ecc832d fix(security): harden multi-tenant code-exec and env-var leak surfaces
Three critical issues for multi-tenant deployments where users may not author
custom components:

1. Code-execution core components (Python Interpreter/REPL, Python Code
   Structured tool, Smart Transform) are official, so their class-code hash is
   valid and they pass the allow_custom_components=False policy, yet they execute
   arbitrary user Python from their input fields. Add the
   LANGFLOW_BLOCK_CODE_INTERPRETER_COMPONENTS setting (default off), enforced in
   flow_validation at the Graph.from_payload choke point with recursion into
   nested flows so all build paths are covered.

2. LambdaFilterComponent evaluated an LLM-generated lambda with full builtins
   (prompt-injection -> RCE). Reject escape gadgets via validate_code_safety and
   eval with safe_builtins() (reuses python_repl_security).

3. The global-variable -> env-var fallback did os.getenv(<tenant-supplied name>),
   letting any tenant read LANGFLOW_SECRET_KEY / DATABASE_URL etc. Add
   env_var_security.safe_getenv with a reserved-name denylist and apply it at all
   fallback sites in lfx and langflow.
2026-06-16 13:14:53 -04:00
72f86c96eb ci: gate backend tests by Python changes (#13614)
* ci: gate backend tests by Python changes

* fix(ci): update test conditions to include docs-only path filter

* Update .github/workflows/ci.yml

Co-authored-by: Adam-Aghili <149833988+Adam-Aghili@users.noreply.github.com>

---------

Co-authored-by: Adam-Aghili <149833988+Adam-Aghili@users.noreply.github.com>
2026-06-15 18:35:30 +00:00
bb930e2ffe docs: build docker from source (#13041)
* docs-add-build-from-source-and-refresh

* peer review

* peer-review

* peer-review

* peer-review
2026-06-15 17:16:28 +00:00
ca29afab5c fix(frontend): restore Inspection Panel access to hidden advanced fields (1.11.0) (#13626)
fix(frontend): restore Inspection Panel access to hidden advanced fields

Fields that were both advanced=True and listed in HIDDEN_FIELDS became
unreachable from the Inspection Panel: hidden from the node body (advanced)
and removed from the panel (HIDDEN_FIELDS), leaving no edit path. This
affected every HIDDEN_FIELDS entry, originally reported for Chat Input/Output
Store Messages (should_store_message).

Keep HIDDEN_FIELDS out of the default advanced view (the #12473 declutter
intent) but stop filtering them out of edit-fields mode, so users can surface
and edit them via the visibility toggle. Also drop the stale Agent verbose
entry (removed from the component via drop = {verbose}) while keeping the
still-live format_instructions and output_schema hidden. i18n the two
remaining hardcoded panel strings.

Fixes #13595
2026-06-15 16:51:46 +00:00
de06b9176a fix(frontend): duplicate tooltip + raw i18n key on collapsed sidebar nav (1.11.0) (#13652)
fix(frontend): remove duplicate tooltip and raw i18n key on collapsed sidebar nav

The floating canvas control nav (shown when the sidebar is collapsed)
rendered two tooltips per icon: a native `title` attribute on
ControlButton plus the styled ShadTooltip. On top of that,
MemoizedComponents passed the raw i18n key (`item.tooltip`) as the
tooltip text instead of running it through `t()`, so the ShadTooltip
exposed strings like `sidebar.nav.bundles` while the native title showed
the bare id (`bundles`).

- CanvasControlButton: drop the native `title` (the duplicate tooltip);
  keep accessibility via `aria-label`. The ShadTooltip is the single
  visual tooltip. This also removes the redundant native tooltip from the
  zoom/fit/lock control buttons.
- MemoizedComponents: translate the nav tooltip with `t(item.tooltip)`.

Adds an isolated CanvasControlButton regression test asserting no native
`title` and that the label is surfaced via aria-label + ShadTooltip.
2026-06-15 14:44:37 +00:00
02319696dc feat: add docs feedback components (#13627)
* add-docs-page-feedback-component

* make-buttons-same-size
2026-06-12 18:03:54 +00:00
3e3a24e353 fix: fail fast when Redis job queue backend is unreachable (#13456)
* fix: fail fast when Redis job queue backend is unreachable

When LANGFLOW_JOB_QUEUE_TYPE=redis is set but Redis is not reachable,
Langflow booted normally and then raised a raw redis ConnectionError as
a 500 on the first flow execution, with no clear cause.

Probe Redis at startup (bounded retry) and abort boot with an actionable
error when it stays unreachable, mirroring the existing external-cache
connectivity check. Translate a later Redis outage on the build and
ownership paths into a clean HTTP 503 via a typed
JobQueueBackendUnavailableError instead of a raw stack trace.

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]

* [autofix.ci] apply automated fixes

* fix: address review - probe redis pre-start, redact credentials, cancel orphaned build

- is_connected() now probes with a temporary client when the service has
  not started yet: the startup fail-fast in initialize_services() runs
  before the per-worker start() creates the client, so it previously
  rejected every redis boot, healthy or not
- connection_target redacts URL userinfo so credentials never reach
  server logs or the HTTP 503 detail
- build_flow cancels the just-started build (best-effort) when owner
  registration fails, instead of leaving an unreachable build running
- register_job_owner only records the local owner after the Redis write
  succeeds, so a failed write cannot leave same-worker ownership checks
  passing while other workers see the job as unowned

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-06-12 17:13:55 +00:00
538bcf3845 feat: docs page copy-as-markdown keyboard shortcut (#13628)
* add-copy-page-keyboard-shortcut

* peer-review
2026-06-12 16:58:50 +00:00
415323ec6d docs: migrate code blocks to native Prism and restyle API reference pages (#13299)
* docs: migrate code blocks from CodeSnippet to native Prism

Replace the custom CodeSnippet component (@code-hike/lighter) with
Docusaurus's native @theme/CodeBlock across all MDX files (current and
versioned docs). Add bash to additionalLanguages and swizzle
prism-include-languages.js to add custom token highlighting for shell
commands and flags. Remove @code-hike/mdx dependency.

* docs: improve inline code styling

Darken inline code background, increase horizontal padding to 0.4em,
fix vertical alignment, and remove border in light mode.

* docs: address PR review — fix code slice regression and CSS/regex polish

- Inline RecursiveCharacterTextSplitter inputs and methods as literal
  code blocks in concepts-components.mdx (current + 1.8.0 + 1.9.0),
  restoring the focused slices lost when migrating from CodeSnippet
- Scope bash-plain Prism regex to unambiguous CLI subcommands only,
  removing generic bash builtins (run, add, get, set, start, stop, etc.)
- Merge duplicate .theme-code-block CSS rules into a single declaration

* fix(docs): prevent horizontal scroll on API docs pages

The Redoc two-column layout (sidebar 300px + api-content 1300px)
totals 1600px, expanding .main-wrapper beyond narrower viewports
because it has overflow:visible. Clips at .main-wrapper using the
html.plugin-redoc class that Docusaurus adds on API pages only.

* fix(docs): API docs sidebar and layout fixes

- Disable Redoc built-in search (disableSearch: true)
- Pin sidebar top to navbar height (top: 60px) so it never hides behind navbar
- Remove hardcoded #111 background from dark mode sidebar

* fix(docs): render markdown correctly in API docs descriptions

The _clean_descriptions function was converting newlines to <br> tags,
mixing HTML with Markdown. CommonMark stops parsing Markdown headings
(###) inside HTML blocks, causing them to appear as literal text in Redoc.

Replace the <br> conversion with a simple strip() so descriptions remain
pure Markdown and Redoc renders headings, lists, and code blocks correctly.

* feat(docs): align API docs colors with Langflow brand

- Set primaryColor to #F471B5 (Langflow pink)
- Add HTTP method badge colors matching Langflow palette
- Set schema.linesColor and requireLabelColor to brand pink
- Set inline code color to pink, headers to #e3e3e3
- Set sidebar background to #18181b (matches frontend dark bg)
- Set rightPanel background to #0d0d0f, codeBlock to #161618
- Refactor: move color config from CSS to theme.theme where safe
- Remove dead search input CSS (search disabled via disableSearch:true)
- Consolidate duplicate .menu-content rules

* wip(docs): API docs styling — colors, components, light/dark themes

* fix(docs): fix Response samples h3 title padding and refactor HTTP method button CSS

* feat(docs): add sidebar dark background, active item styles, and right panel color adjustments

* fix(docs): add sidebar borders and remove operation divider border

* fix(docs): fix expanded response background and align dark/light theme colors

* refactor(docs): standardize selectors, comments and remove duplicate rules in redocusaurus.css

* refactor(docs): apply PR review — CSS custom properties, version pin, dom version comments, fix overflow

* fix(docs): fix Redocly badge visibility covered by sidebar background

* fix(docs): extend sidebar border-right to Redocly badge area

* refactor(docs): replace hardcoded #ffffff label color with --redoc-text-label variable

* fix(docs): lighten inline code background in API docs dark theme

Redoc's default typography.code.backgroundColor (rgba(38, 50, 56, 0.05))
is nearly invisible over the dark background. Override it with
rgba(255, 255, 255, 0.05) in dark theme only, excluding pre > code so
code sample blocks stay unaffected.

* feat(docs): align docs primary pink with API spec brand color

Use #f471b5 (API spec primaryColor) as --ifm-color-primary in dark theme
and #e44fa0 (slightly darkened for contrast on white) in light theme.
Remove dark-theme pink overrides in sidebar.css (#ff6ad0 CTA and
hsla(329, 55%, 68%) active TOC link) — they compensated for the old
muted pink and are redundant now that the primary itself is bright.

* feat(docs): lighten dark theme text colors for better readability

Bump body text (#a8a8b0 -> #bcbcc4), headings (#cdcdd4 -> #dcdce2)
and sidebar menu (#8a8a92 -> #9c9ca4) one step brighter.

* chore(docs): add IBM Equal Access accessibility-checker setup

Add accessibility-checker as devDependency with aceconfig.js (policy
IBM_Accessibility, JSON reports in docs/a11y-results/, gitignored).
Scan with: npx achecker <url> against a built docs site.

* fix(docs): WCAG AA contrast and ARIA fixes across docs and API reference

Validated with IBM Equal Access scans (light theme): home, quickstart and
component pages at 0 violations; /api from 3382 down to 167 (all remaining
are Redoc-internal DOM: schema table headers, svg/select labels).

Docs site:
- Light primary pink #d11074 — passes 4.5:1 on white and inline-code bg
- Light Prism palette darkened per-token to pass 4.5:1 on #f9f9fd
- TabItem swizzled to give tabpanels an accessible name (aria-label)
- codeBlockA11y client module: scrollable code blocks get role=region +
  unique label; non-scrollable ones lose the needless tabindex

API reference (Redocusaurus):
- redocA11y client module: role=main on api-content, role=navigation on
  sidebar — fixes 1924 aria_content_in_landmark violations
- HTTP method badges and response chips darkened to pass with white text
- Light-theme overrides: accessible pink #cd1072 for links, required
  markers, constraint chips, schema tree lines; darker grays for utility
  buttons and type labels (incl. 0.7-opacity wrapper fix)
- Sidebar active/hover items use regular text color, method badges keep
  their own colors; expandable property names match non-expandable ones

* fix(docs): WCAG AA contrast fixes for dark theme

Validated with IBM Equal Access scans in dark mode (temporary
colorMode.defaultMode flip during scanning): home, quickstart and
component pages at 0 violations; /api matches light at 167 remaining
(all Redoc-internal DOM: table headers, svg/select labels).

- Code block comments/line numbers #4a5060 -> #798197 (4.56:1 on #18181a)
- Redoc dark sample tokens: boolean/null #e95c59, number #5392b8
- Status-code tabs: lift docusaurus-theme-redoc's #303846 !important
  selected-tab rule with a higher-specificity override
- oneOf variant buttons: dark text in both themes (their white/pink
  backgrounds are theme-independent)
- redocA11y client module: patch response chip colors (success green /
  error red) to dark-accessible variants when data-theme=dark — a single
  Redoc theme color cannot pass on both light and dark derived
  backgrounds, and status is only distinguishable by computed color

* fix(docs): resolve remaining Redoc-internal accessibility violations

Extend the redocA11y client module with semantic patches for Redoc DOM
the theme cannot reach (validated: 0 IBM Equal Access violations on all
scanned pages in both light and dark themes):

- Decorative svg chevrons/arrows: aria-hidden=true (svg_graphics_labelled)
- Content-type dropdowns: aria-label (input_label_exists)
- Schema field tables (2-col name|description layout, no <th> anywhere):
  role=presentation — content reads in DOM order; role=rowheader on <td>
  is invalid ARIA inside a native table (table_headers_exists/related)
- Semantic patches run on the next animation frame after DOM changes so
  Redoc's lazy-rendered operations are covered immediately; the heavier
  color patch stays debounced

* ci(docs): gate docs accessibility with IBM Equal Access scans

Add test-docs-accessibility job to docs_test.yml (rides the existing
docs/** path filter from ci.yml): build + scan 4 representative pages
(home, quickstart, component page, /api) in light theme, then flip
colorMode.defaultMode to dark, rebuild and scan again.

- scripts/a11y-ci.sh: serves the build and runs npx achecker per page
  with one retry to absorb Redoc lazy-render timing flakes; any real
  violation fails the job (failLevels: violation)
- aceconfig.js: pin ruleArchive to 19May2026 so IBM rule updates don't
  break CI without a deliberate bump

* ci(docs): fix Chrome sandbox launch on Ubuntu 24.04 runners

Ubuntu 24.04 restricts unprivileged user namespaces via AppArmor, which
prevents puppeteer's Chrome (used by the IBM checker) from starting its
sandbox. Re-enable them with the documented sysctl workaround instead of
weakening the browser with --no-sandbox.

* fix(docs): align response status code with description text

Redoc sets vertical-align: top and a smaller line-height on the status
code <strong> inside response buttons, leaving "200" visually higher
than "Successful Response". Align both to the shared text baseline.

* refactor(docs): apply PR review feedback

- redocA11y: match only real Redoc routes (/api, /api/workflow) — a bare
  startsWith("/api") also matched docs pages like /api-request and
  leaked one body MutationObserver per navigation
- codeBlockA11y: also observe the hidden attribute — Docusaurus tabs
  toggle panels via hidden (no childList mutation), so scrollable blocks
  inside an initially hidden tab were never re-evaluated for tabindex
- Extract Prism themes to src/prismThemes.js (docusaurus.config.js was
  past the 600-line red flag)
- concepts-components.mdx (current + 1.9.0 + 1.8.0): comment pointing
  hardcoded snippets to recursive_character.py to mitigate drift

Validated: clean build + IBM Equal Access scans 4/4 passing.

* replace-openapi-file-with-1.10

* migrate-prism-changes-to-1.10-version

* a11y-script-dont-block

---------

Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
2026-06-12 13:58:04 +00:00
29140c06f0 fix(ci): resolve validate-version output in release-lfx changelog link (1.11.0) (#13612)
fix(ci): resolve validate-version output in release-lfx changelog link

The create-release job references
needs.validate-version.outputs.current_version in its generated release
notes (the Full Changelog compare link), but validate-version was not in
the job's needs array, so the expression evaluated empty and the link
rendered as compare/v...lfx-vX.Y.Z (broken base).

Add validate-version to the create-release needs. This adds no real
serialization: create-release already waits on release-lfx, which
transitively requires validate-version via run-tests, and the job's
always() if-condition is unaffected.

Flagged by actionlint: property "validate-version" is not defined in
object type {build-docker, release-lfx}.
2026-06-10 08:42:28 -07:00
dea7b09257 fix(ci): create GitHub releases on the dispatched v-prefixed tag (1.11.0) (#13607)
fix(ci): create GitHub releases on the dispatched v-prefixed tag

The create_release job passed the bare version (v stripped) as the
release tag with no commit target, so when that tag did not exist
GitHub minted a new lightweight tag at the default-branch HEAD -- the
wrong commit, still carrying the previous version (main only adopts a
release's version via the post-release back-merge). Every release since
1.8.2 shipped a stray bare tag (1.8.2, 1.8.3, 1.9.0-1.9.6, 1.10.0)
pointing at a previous-version commit, and the GitHub release had to be
manually re-pointed to the real vX.Y.Z tag after each release.

- create_release now attaches the release to inputs.release_tag for
  stable releases; pre-releases keep their computed tag (e.g.
  1.10.0rc1) but it is minted at the release commit via 'commit:'.
- release-lfx.yml pins the minted lfx-v* tag to github.sha instead of
  the default branch.

The validate-tag-format guard (#12847) only blocks at dispatch time;
create_release was re-creating the very duplicates it guards against.
2026-06-10 08:41:41 -07:00
84c3bbebcd fix(ci): scope nightly migration-test pre-releases to the langflow stack (1.11.0) (#13604)
fix(ci): scope nightly migration-test pre-releases to the langflow stack

The previous fix (#13599) added a global --prerelease=allow, which let
UNRELATED dependencies resolve to alphas: on nightly run 27274206250
the stable->nightly upgrade pulled pydantic 2.14.0a1 + pydantic-yaml
1.6.1a1, and the pydantic alpha breaks langchain-core at import time
(RunnablePassthrough pydantic ValidationError), failing the nightly
boot right after a successful install. Clean installs were fine - only
this upgrade path resolved the alpha combo.

Scope pre-release eligibility to the langflow lockstep stack instead:
uv accepts a pre-release when the package's own requirement carries a
pre-release marker, but not via transitive pins, and the nightly chain
is langflow -> langflow-base -> lfx -> langflow-sdk with exact ==devN
pins. Request each directly; langflow-sdk versions independently
(0.2.0.devN), so an explicit .dev0 floor marks it eligible while lfx's
exact pin selects the version. The 'latest' branch gets the same
treatment via .dev0 floors on all four.

Verified by dry-run against PyPI: langflow/langflow-base/lfx at
1.11.0.dev2 + langflow-sdk 0.2.0.dev2 resolve with pydantic staying at
stable 2.13.4.
2026-06-10 07:19:36 -07:00
75e01157fe fix(ci): allow pre-releases when pinning the nightly in migration validation (1.11.0) (#13600)
fix(ci): allow pre-releases when pinning the nightly in migration validation

Migration Test: pip/venv (stable -> nightly) failed deterministically on
nightly run 27260425158 (twice, including a rerun):

  hint: langflow-base was requested with a pre-release marker (e.g.,
  langflow-base==1.11.0.dev1), but pre-releases weren't enabled
  (try: --prerelease=allow)

This is the first nightly publishing as a canonical .devN pre-release
of the langflow distribution (nightly -> stable bundle cutover). The
'latest' branch of the upgrade step already passes --prerelease=allow,
but the pinned-version branches do not. uv implicitly allows the
pre-release for the directly requested ==X.Y.Z.devN pin, yet langflow's
metadata pins langflow-base==X.Y.Z.devN transitively, and uv rejects
transitive pre-releases unless they are enabled - so the install fails
after the stable uninstall, sinking the migration test.

Add --prerelease=allow to both pinned-version install lines.
2026-06-10 04:50:26 -07:00
0555eeced1 fix(test): gate models.dev background refresh out of tests (#13596)
Integration tests failed twice in nightly run 27260425158 with pyleak
EventLoopBlockError - first Integration Tests 3.14, then 3.12 on the
rerun, each time in a different test. The blocking stack points at
refresh_models_dev_periodically: every app boot unconditionally starts
a lifespan task that immediately fetches https://models.dev/api.json,
so the request lands mid-test in whatever test happens to be running.
Under pyleak's asyncio debug instrumentation the fetch blocked the loop
0.797s against a 0.2s threshold. Whichever test draws the short straw
flakes - which is why it looked transient and moved between versions.

Add a LANGFLOW_MODELS_DEV_REFRESH env gate (default unchanged: enabled)
and disable it session-wide in the backend test conftest. Tests fall
back to the bundled static model lists, which is also deterministic.

Verified: with the gate set, app boot makes zero models.dev requests;
the previously failing integration test passes.
2026-06-10 04:36:38 -07:00
086e38898d fix(ci): anchor langflow-base version extraction in nightly docker build (1.11.0) (#13592)
fix(ci): anchor langflow-base version extraction in nightly docker build

The first nightly on the 1.11 workspace (tag v1.11.0.dev0, run
27253229568) failed in Build Nightly Base Package within seconds:
'Base version format is incorrect'. The extraction (uv tree, grep
langflow-base unanchored, awk field 3, first line) broke because uv
tree now prints the langflow-base workspace-root line
('langflow-base v1.11.0.dev0', two fields) before any dependency line
('langflow-base[complete] v1.11.0.dev0' under the langflow root, three
fields), so the first match yields an empty field 3 and the format
check exits 1. uv tree's stderr is discarded, which made the real
cause invisible in CI.

Anchor to the root line and take field 2 instead - the exact pattern
the langflow (main package) extraction in this same file already uses,
which is why the main-package builds passed on the same tag. Verified
both extractions print 1.11.0.dev0 against a local checkout of
v1.11.0.dev0.
2026-06-10 00:25:55 -07:00
d065523493 fix(test): raise spawn-child join timeout in test_multi_process_visibility (#13588)
The test spawns a child via multiprocessing spawn context, which
cold-imports the full langflow package (plus coverage's multiprocessing
hooks in CI) before appending a single event. The 10s join timeout is
routinely exceeded on a loaded CI runner sharing 4 vCPUs with a second
xdist worker: in nightly run 27253229568 (Unit Tests - Python 3.12 -
Group 5) the test failed all 12 executions (5 reruns x 2 step attempts),
each rerun exactly 10s apart - the join deadline, not a product bug.

Raise the liveness bound to 60s (join returns immediately when the
child exits, so the passing case is unaffected) and kill the child on
timeout so a hung spawn can't leak into later tests.
2026-06-09 23:13:35 -07:00
17447920f9 fix(ci): rebalance backend test splits with measured durations + raise unit-test step timeout (#13583)
Unit Tests - Python 3.12 - Group 3 has been failing at 98-99% on the
nightly: the job hits the nick-fields/retry 40-minute per-attempt timeout
and pytest is SIGTERM'd mid-test, so it looks like one flaky last test
when it is actually a deterministic timeout (and the internal retry plus
run-level retries can never succeed).

Root cause is twofold:

1. .test_durations was last regenerated ~May 2025 and covered only 2,219
   of ~9,500 current unit tests, so pytest-split weighted 77% of the
   suite at the 0.73s average. The expensive client-fixture tests
   (test_webhook.py, test_login.py - each pays a full create_app +
   lifespan boot per test, 60-120s late in a CI run) clustered into
   group 3's tail, making it ~8-10 minutes slower than its siblings
   (33:15 on 3.13, >40min on 3.12 which is additionally slowed by
   astrapy disabling SSL connection reuse on Python 3.12.0-11).
   The weekly store_pytest_durations workflow that should refresh the
   file has been dying at the 6-hour GitHub job limit every week (serial
   full-suite run no longer fits), so the file silently froze.

   This regenerates the file from real per-test wall-clock measured in
   the passing Python 3.13 nightly jobs (run 27246228762 attempt 1, all
   5 groups, parsed from the -vv xdist logs: per-worker start-to-start
   deltas). 9,508 tests now have measured durations; old entries are
   kept where no new measurement exists. Simulated least_duration
   split goes from one outlier group to 5 even groups (~24.6 min each)
   with the >50s tests spread 1-2 per group instead of 7 in one.

2. timeout_minutes 40 -> 50 gives headroom for matrix-cell variance
   (3.12 runs ~20% slower than 3.13) so a slightly slow cell degrades
   gracefully instead of burning 2x40min and failing the whole run.

Follow-ups (not in this PR): fix store_pytest_durations to run with
xdist or split groups so it fits the 6h limit; investigate the in-worker
degradation that makes client-fixture boots cost 8-12s early in a run
but 60-120s after ~30 minutes.
2026-06-09 21:28:02 -07:00
ee659ca38c fix(bundles): floor lfx pin at the minor line's .dev0 so nightlies resolve
The first 1.11.0.dev0 nightly failed its "Test Langflow Main CLI" step:
the fork bump's sync_bundle_lfx_pin.py re-synced every bundle floor to
lfx>=1.11.0, and PEP 440 sorts the nightly's 1.11.0.dev0 BELOW 1.11.0,
so the workspace-built bundles (whose metadata shadows the satisfiable
PyPI lfx-arxiv 0.1.1 during `uv pip install dist/*.whl`) reject the
branch's own lfx while langflow-base pins it exactly — unresolvable.

Floor at lfx>=X.Y.0.dev0,<(X+1).0.0 instead: X.Y.0.dev0 is the lowest
version PEP 440 admits in the minor line, so every devN / rcN / final
satisfies the floor while older lines and the next major stay excluded.
This closes the NIGHTLY.md activation-gate hole structurally — future
minor forks re-sync to a floor their own nightlies already satisfy.

- sync_bundle_lfx_pin.py: lfx_floor_spec emits the .dev0 floor
- port_bundle.py: mirrored _current_lfx_floor kept in step
- bundle pyprojects restamped via the script (arxiv/docling/duckduckgo/ibm)
- test_bundle_lfx_pin.py expectations updated (20/20 passing)
- NIGHTLY.md gate section annotated with the post-activation fix

uv.lock is unaffected (workspace lfx is recorded as an editable source
with no specifier — which is also why uv sync/lock passed in the same
job). The release.yml RC floor-relax sed still matches the new form;
now redundant but harmless. No bundle version bump needed: published
0.1.1 floors >=1.10.0.rc0, satisfiable by the whole 1.11 line.
2026-06-09 18:02:43 -07:00
7a784515e0 fix(lfx): restamp component index version after 1.11.0 fork bump (#13574)
The release-1.11.0 fork bumped lfx to 1.11.0 but left component_index.json's version field at 1.10.0. _read_component_index fails closed on exact version mismatch, so the bundled registry loads as None and the upgrade-gate tests fail (UpgradeFlowError: 'bundled component registry is empty or missing') across the LFX test matrix. That failure blocks the nightly's release-nightly-build job, so no canonical 1.11.0.devN is published and check-nightly-status blocks CI everywhere.

Surgical restamp: version -> 1.11.0 and recomputed sha256 (same orjson OPT_SORT_KEYS hashing and OPT_SORT_KEYS|OPT_INDENT_2 serialization as scripts/build_component_index.py). Entries unchanged. Verified the reader validation passes and the three failing tests go green.
2026-06-09 15:18:21 -07:00
fb64e45e75 chore: bump version to 1.11.0 2026-06-09 13:29:01 -07:00
13a937c5b7 feat(ci): nightly → stable bundles via canonical pre-releases + decision record [gated] (#13528)
* docs: record nightly→stable bundle cutover plan (gated on lfx 1.10.0)

Add src/bundles/NIGHTLY.md documenting why langflow-nightly currently
renames the bundles (lfx and lfx-nightly ship the same lfx/ import, so a
stable bundle would co-install both and collide) and the deferred cutover
(Approach A: canonical pre-releases; B: lfx as a bundle extra), gated on
stable lfx 1.10.0 being published to PyPI.

Also expand two docstrings in scripts/ci/update_lfx_version.py to state
the deeper install-conflict reason, not just the resolve failure. No
behavior change.

* feat(ci): nightly Approach A — canonical pre-releases, drop nightly bundles [DRAFT/gated] (#13529)

feat(ci): nightly Approach A — canonical pre-releases, drop nightly bundles

DRAFT reference implementation of the nightly→stable-bundle cutover documented
in src/bundles/NIGHTLY.md. Publishes the nightly under CANONICAL package names as
.devN pre-releases instead of separate *-nightly distributions, so the stable
lfx-* bundles resolve against a single canonical lfx (no dual-lfx install
collision) and no nightly bundle packages are produced.

- tag scripts (pypi/lfx/sdk_nightly_tag.py): count .devN against the canonical
  PyPI histories instead of the *-nightly projects
- update scripts: stop renaming to *-nightly; set .devN versions; re-pin
  inter-package deps to exact canonical dev versions; delete the bundle
  rename/repin (update_lfx_dep_in_bundles, rename_bundles_for_nightly)
- release_nightly.yml: publish canonical pre-releases; remove bundle build,
  dist-nightly-bundles artifact, publish-nightly-bundles job + its gate; verify
  canonical names; main wheel glob dist/langflow-*.whl
- nightly_build.yml: drop the bundle git-add in the tag commit
- NIGHTLY.md: Approach A marked implemented + activation gate + A1/A2 follow-ups

Held as DRAFT: do not activate until stable lfx 1.10.0 is published AND the
nightly base is the next minor (release-1.11.0). A 1.10.0.devN core sorts below
1.10.0 and would fail the bundles' >=1.10.0 floor. Stacked on #13528.

(.secrets.baseline: incidental line-number shifts for the two workflows + prune
of pre-existing stale Pokédex Agent.json entries.)

* docs(ci): drop internal 'Approach A' label from nightly cutover comments

Comment- and docstring-only change across scripts/ci/* and the two nightly
workflows; no logic change. The two workflow edits stay single-line so
.secrets.baseline line numbers are unaffected. src/bundles/NIGHTLY.md keeps
its A/B decision-record framing intentionally.

* feat(ci): make nightly consumers work with canonical pre-releases

Follow-ups from the nightly cutover that are part of its blast radius (the
nightly now publishes canonical `.devN` pre-releases, not `*-nightly`
distributions):

- version.py: derive the "Nightly" label from the `.dev` version marker, since
  the canonical `langflow`/`langflow-base` distribution matches first in the
  lookup. Keeps the startup banner and telemetry `package` field identifying
  nightlies. Adds a canonical-dev test; updates the base-dev assertion.
- ci.yml check-nightly-status: query the canonical `langflow` project and pick
  the latest `.devN` release date instead of `langflow-nightly`'s `.info.version`.
- db-migration-validation.yml: install the nightly as `langflow[postgresql]==<dev>`
  (pre-release) instead of `langflow-nightly[...]`; verify via version("langflow").
- src/lfx/README.md: nightly install is `uv pip install --pre lfx`.
- NIGHTLY.md: rewrite the follow-ups section (these are addressed; Docker image,
  A2 meta-package, and website docs remain deferred by design).

The `langflowai/langflow-nightly` Docker image name is intentionally unchanged.

* fix(ci): correct nightly verify uv tree parsing + stale base-dep regex

Addresses review of #13528:

- release_nightly.yml LFX verify: `uv tree | grep lfx | head -n1` matches the
  bundle `lfx-ibm` first → 'Name lfx-ibm does not match lfx'. Root the tree with
  `uv tree --package lfx` so the first line is the lfx package itself.
- release_nightly.yml base verify: under canonical naming `langflow-base` prints
  as a top-level `langflow-base v<ver>` line, so the old $2/$3 field parse read
  name="v0.10.0" and version="". Use `uv tree --package langflow-base` and $1/$2.
- update_lf_base_dependency.py update_base_dep: regex only accepted ~=/==, so its
  CLI entry point couldn't match the current root dep `langflow-base[complete]>=0.10.0`.
  Add >= (parity with update_uv_dependency.py). The active nightly path uses
  update_uv_dependency.py and was unaffected.

* docs(nightly): point NIGHTLY.md status at the activation gate, not draft state

Per review of #13528: this file ships inside #13528 (#13529 was folded in), so
the 'stacked on prep #13528' + 'held as a draft' framing is stale and misleading.
Reword the status block to state the real guard is the activation gate (stable
lfx 1.10.0 published AND next-minor base), not merge/draft state. Also reword the
follow-ups heading 'decide before un-drafting' -> 'decide before activating'.
2026-06-09 13:23:55 -07:00
0195a132e2 Merge release-1.10.0 into main
Non-squash union back-merge, ahead of cutting release-1.11.0 / release-1.10.1.
- Preserves main's settings-mixin refactor (#13141): release-1.10.0's 40 new
  settings ported into the per-group mixins, verified field-for-field and
  behaviorally against release's monolith.
- Keeps main's model-handling (#13191, auto-merged).
- CI workflows, docling deps, component index, starter projects, AGENTS.md,
  .secrets.baseline resolved to release-1.10.0. main: 1.9.6 -> 1.10.0.
2026-06-09 13:16:48 -07:00
8ee3493bb7 fix(observability): make grafana-loki reference stack instructions work end to end (#13454)
The reference stack README pointed LANGFLOW_LOG_FILE and LANGFLOW_LOG_DIR at
different directories, so following it produced an empty Grafana dashboard:
Langflow wrote to one path while Promtail scraped another. It also documented a
stdout-scrape alternative the shipped Promtail config does not implement.

Make the two paths consistent, require an absolute log path, correct the stdout
note, and add a no-Langflow smoke test that writes a sample record and confirms
it reaches Loki.
2026-06-09 17:14:46 +00:00
9690e69e86 fix(security): remove the disabled Python Code Structured tool component (#13560)
* fix(security): remove the disabled Python Code Structured tool component

Follow-up to #13538, which neutered PythonCodeStructuredTool to a
non-executable stub "for one release cycle, full removal later." This
completes that removal.

- Delete the component and its registration in lfx.components.tools.
- Drop its entry from the component index (num_components 355 -> 354,
  sha256 recomputed surgically) and from stable_hash_history.json.
- Remove its 18 i18n keys from every locale file.
- Replace the dedicated stub unit test with a removal test in
  test_dynamic_import_integration.py.
- Add a regressions entry to regressions/1.10.x.yaml.

The unauthenticated public-build RCE fix (report H1-3754930) is
unaffected: PythonCodeStructuredTool stays in
CODE_EXECUTION_COMPONENT_TYPES, so build_public_tmp still rejects any
saved or crafted flow that carries the type. instantiate_class execs the
node's stored `code` field regardless of whether the class still exists,
so the type-name block -- not the class -- is what closes the path.

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

* docs: document removal

* docs: typo

* Apply suggestion from @mendonk

Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
2026-06-09 10:16:36 -07:00
d7804149d8 docs: LF assistant ampersand and dot selectors (#13544)
* docs-lf-assistant-dot-selector

* docs-add-lfx-matrix-to-1.10-version
2026-06-09 13:04:49 +00:00
2524604a19 fix(ci): make Biome lint non-blocking for release workflow calls (correct implementation using allow-failure input)
- Revert invalid continue-on-error syntax on reusable workflow uses: job
- Add allow-failure input to ci.yml lint-frontend call
- Define allow-failure input parameter in lint-js.yml workflow_call
- Implement conditional exit-code swallow in lint-js.yml when allow-failure=true
- When release=true, Biome errors are non-blocking for release pipeline
- When release=false/unset, Biome failures block PR merge (existing ci_success gate)
2026-06-08 17:22:21 -04:00
801edf3bab Revert "fix(ci): make Biome lint non-blocking for release workflow calls (#13547)"
This reverts commit a1adb1aa6f.
2026-06-08 17:21:24 -04:00
a1adb1aa6f fix(ci): make Biome lint non-blocking for release workflow calls (#13547)
When ci.yml is called from release.yml (inputs.release == true), a
Biome failure was blocking all downstream publish and docker jobs via
needs.ci.result == 'success'. Biome was already excluded from the
ci_success gate for PR merges, but the reusable CI workflow itself
could still fail when the lint job errored.

Add continue-on-error: ${{ inputs.release == true }} to lint-frontend
so Biome failures are informational-only during release runs, while
remaining visible (and blocking ci_success) on regular PRs.
2026-06-08 17:04:51 -04:00
6610091697 fix(bundles): republish lfx-* at 0.1.1 with corrected pin + relax lfx floor for RC builds (#13542)
* fix(bundles): bump lfx-* bundles to 0.1.1 to republish with corrected lfx pin

The published 0.1.0 artifacts on PyPI carry stale lfx pins from before the lfx 0.5.0->1.10.0 version realignment:

- lfx-arxiv, lfx-duckduckgo: lfx>=0.5.0,<0.6.0 (hard-broken; the <0.6.0 cap can never resolve lfx 1.10.0)
- lfx-docling, lfx-ibm: lfx>=0.5.0 (uncapped floor/cap mismatch)

The source pin was already corrected to lfx>=1.10.0,<2.0.0 in #13516, but the bundles were never re-published. PyPI versions are immutable, so shipping the fix requires a version bump. Bump all four to 0.1.1 so the Release Bundles workflow cuts fresh wheels carrying the correct pin. Root pyproject keeps its >=0.1.0 floors (satisfied by 0.1.1); only the bundle dist versions and their uv.lock stamps change.

* fix(release): relax bundle lfx floor for pre-release builds + idempotent bundle publish

The RC pre-release run builds lfx as 1.10.0rc0, but bundles floor lfx at >=1.10.0. Under PEP 440 a pre-release sorts below the final, so 1.10.0rc0 fails >=1.10.0 and the cross-platform install test cannot resolve the bundle wheels against the RC lfx wheel.

build-base/build-main/build-lfx already rewrite their inter-package deps to the pre-release version when pre_release=true; build-bundles was the only release artifact missing that step. Add it: when pre_release=true, rewrite each bundle's lfx floor to the exact pre-release version, keeping the wide <2.0.0 BUNDLE_API cap. Stable source stays at >=1.10.0 -- only RC wheels are relaxed, at build time, so no source churn or re-tag.

Also make publish-bundles tolerate 'already exists' duplicate wheels on rerun, matching release_bundles.yml.
2026-06-08 13:18:56 -07:00
fa14076dec fix(security): block code-execution components on unauthenticated public flow builds (#13538)
* fix(security): block code-execution components on unauthenticated public flow builds (H1-3754930)

PythonCodeStructuredTool exec()'d its attacker-controlled `tool_code` field at
flow-build time. Because a PUBLIC flow can be built with no authentication via
POST /api/v1/build_public_tmp/{flow_id}/flow, that sink was reachable as an
unauthenticated server-side RCE — and other components (Python Interpreter/REPL,
Smart Transform) execute code on the same path, so removing one component alone
would not close the gap.

- Harden the public build path: build_public_tmp now rejects flows containing
  code-execution components via validate_public_flow_no_code_execution(). The
  check keys on the node `type`, so it holds regardless of the stored component
  `code`, and is enforced ONLY on the unauthenticated public path —
  authenticated /build is unchanged.
- Neuter PythonCodeStructuredTool to a non-executable compatibility stub: all
  exec()/eval() sinks removed; build_tool returns a tool that raises a
  deprecation error. The component stays registered with identical
  display_name/inputs so saved flows still load and locale keys don't change.
  It will be fully removed in a future release.

component_index.json (code_hash) is regenerated by autofix.ci.

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

* [autofix.ci] apply automated fixes

* fix: validate_public_flow_no_code_execution

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-08 18:57:22 +00:00
4339011b6d docs: lfx compatibility matrix and lfx serve updates (#13518)
* docs-add-existing-changes

* fix-combining-of-glyphs

* docs-lfx-compatibility

* peer-review
2026-06-08 18:26:12 +00:00
2411d8036e docs: build OpenAPI spec and cut version 1.10 (#13537)
* build-api

* bump-version-to-1.10

* fix-broken-links
2026-06-08 18:25:14 +00:00
60afa18f05 fix: serialize DataFrames in tool mode to prevent pandas truncation (#13504)
* fix: serialize DataFrames in tool mode to prevent pandas truncation

When Memory Base or Knowledge components are wired as agent tools, the DataFrame
result was returned directly without serialization. LangChain would then stringify
this for the agent observation using pandas' default repr, which truncates all
cells to 50 characters (display.max_colwidth=50), inserting "...".

This breaks the F3 agent use case where agents need to reliably recall facts from
memory. The agent receives truncated content and cannot see the full text.

The fix serializes DataFrames through the existing serialize() function, which
converts them to list[dict] format with full, untruncated content. This maintains
consistency with how other result types (Message, Data, etc.) are handled in tool mode.

- Affects: Memory Base and Knowledge components used as agent tools
- Does not affect: Component-to-component wiring or normal (non-tool) execution
- Testing: Added tests verifying DataFrames serialize to list[dict] with complete content

Improved MB GUI component  description

* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]

* [autofix.ci] apply automated fixes

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-08 15:25:02 +00:00
0087ed895c chore: remove aws scripts (#13534)
remove aws scripts
2026-06-08 15:21:33 +00:00
7ad65e83df docs: add code agents and file processing components (#13285)
* add-code-agents-and-file-ingestion-components

* docs: add release note for code agents

* Apply suggestions from code review

Co-authored-by: April I. Murphy <36110273+aimurphy@users.noreply.github.com>

---------

Co-authored-by: April I. Murphy <36110273+aimurphy@users.noreply.github.com>
2026-06-08 15:14:47 +00:00
ba16577079 docs: JSON logging structure and grafana integration (#13251)
* initial-cherry-pick

* docs-move-config-to-logging

* update-logging paths-and-clarify-behavior

* fix-other-relative-link

* peer-review
2026-06-08 14:21:27 +00:00
c1f7054cd1 fix: Remove getenvvar component and update locales (#13521)
* refactor: remove getenvvar component and update locales

* test: add test for GetEnvVar component removal and update component index

---------

Co-authored-by: Janardan S Kavia <janardanskavia@Janardans-MacBook-Pro.local>
2026-06-05 20:30:22 +00:00
b08442a330 fix: standardize playground code block + container backgrounds on shadcn tokens (#13520)
fix: use shadcn canvas colors for playground code blocks and chat-bg for the container

Standardize the playground tool-call surfaces on shadcn theme tokens so
they swap correctly between light and dark mode:

- Code blocks (SimplifiedCodeTabComponent) use bg-canvas: light grey
  (#F4F4F5) / dark black (#000) so they stand out as the code surface.
- The 'Called tool' container (ContentBlockDisplay) uses bg-background so
  it matches the chat background in both themes instead of inverting to
  solid black in dark mode (it was bg-primary-foreground).

Previously the container and code blocks were both bg-primary-foreground,
which rendered the whole section black in dark mode with no contrast.
2026-06-05 19:04:46 +00:00
922c6f2e34 docs: gunicorn worker configuration (#13511)
* docs-add-gunicorn-config

* docs-env-vars-gunicorn-configuration

* align-links-with-title

* fix-links

* mismatched-timeout-values

* Apply suggestions from code review

Co-authored-by: April I. Murphy <36110273+aimurphy@users.noreply.github.com>

* peer-review

---------

Co-authored-by: April I. Murphy <36110273+aimurphy@users.noreply.github.com>
2026-06-05 18:02:34 +00:00
0d9f9112ef perf(telemetry): batched off-pool writer for transactions + vertex_builds (#13126)
* perf(telemetry): batched off-pool writer for transactions + vertex_builds

Adds TelemetryWriterService that buffers transaction and vertex_build rows
in memory and drains them in batched INSERTs via a dedicated AsyncEngine
(pool_size=1 for SQLite, 2 for Postgres, max_overflow=0). Retention is
amortized in a 60s sweeper instead of running on every insert.

Producers (log_transaction, log_vertex_build) enqueue instead of opening
a DB session, so telemetry traffic no longer competes with the
request-handling pool. Falls back to the legacy direct-write path via
LANGFLOW_TELEMETRY_WRITER_ENABLED=false.

Durability: in-flight rows spill to a diskcache.Deque per PID on shutdown
and are restored on next startup; orphan PID directories left by crashed
workers are adopted.

* perf(telemetry): tighten error handling and add coverage

Review feedback from pr-review-toolkit + silent-failure-hunter:

- Retention sweep snapshots the dirty-flow sets before commit and only
  clears them after it lands; a crashed sweep no longer drops the flows on
  the floor, so per-flow caps cannot drift unboundedly.
- Producer fall-through is no longer silent. transaction_service and
  log_vertex_build each log a one-shot WARNING when telemetry_writer_enabled
  is True but the writer is not running.
- Lifespan startup failure now logs ERROR instead of WARNING — if the user
  opted into the writer and it didn't come up, that's an error.
- Shutdown drain timeout no longer suppressed silently: logs a WARNING with
  pending row count + a hint to raise telemetry_writer_shutdown_drain_s.
- Writer's flush loop catches asyncio.CancelledError separately and
  re-prepends the in-flight batch to the buffer so teardown's disk spill
  catches it.
- After 6 consecutive batch failures the writer emits a loud ERROR with
  buffer depths so operators see sustained data-loss risk.

Added tests:
- test_sanitization_survives_writer_round_trip
- test_retention_failure_preserves_dirty_flows
- test_in_flight_batch_returned_on_cancel

* perf(telemetry): address copilot review

- _restore_from_disk + _adopt_orphan_outboxes now route through _enqueue so a
  large disk-spilled or orphan outbox can't bypass telemetry_writer_max_queue
  and OOM the process. Oldest rows are dropped and counted via the existing
  dropped_transactions / dropped_vertex_builds counters.
- chmod 0o700 the outbox root + per-PID directory so sanitized-but-still-
  sensitive payloads aren't exposed cross-user on multi-tenant hosts.
  Suppressed on platforms where chmod is a no-op (Windows).
- Added test_adopt_orphan_outboxes_honors_max_queue.

The remaining two copilot notes (private API access to DatabaseService and
diskcache.Cache.close) were also flagged by the in-tree review; tracking
separately. The "diskcache not declared" note is a false positive — the
dependency is at src/backend/base/pyproject.toml:76.

* perf(telemetry): address coderabbit review

- Sweeper hands off dirty sets via capture-and-clear so concurrent
  flushes during a retention pass aren't wiped by the post-commit
  subtract; failure path restores the snapshot.
- Stress README uses a concrete Postgres DSN matching the docker
  example instead of an unset env var.
- Test PID-probe loops bounded via a shared helper with pytest.fail
  fallback.

* perf(telemetry): swap diskcache outbox for stdlib sqlite (CVE-2025-69872)

Replaces the diskcache.Deque-backed spill outbox with a stdlib sqlite3
outbox (WAL mode, JSON payloads in TEXT). diskcache 5.6.3 has
CVE-2025-69872 (pickle deserialization RCE for an attacker with write
access to the cache dir), no fixed version released, and was never
declared as a dependency — import failed on Python 3.10.

The replacement is encapsulated in a small _Outbox helper that owns the
connection, schema, JSON codec, and lifecycle. The codec uses tagged
wrappers for datetime and UUID so SQLAlchemy's typed columns accept
restored payloads on the way back out.

Hardening informed by a survey of OTel collector, Fluent Bit, Vector,
Prometheus remote_write, Datadog agent, Logstash, and Filebeat:

- Per-PID outbox dirs now stamp an owner.json (hostname + Linux boot_id
  or time()-monotonic() proxy). Adoption only proceeds when host+boot
  match; cross-host or pre-owner-file dirs are logged and skipped so a
  recycled PID after a container restart cannot pull in a stranger's
  spill data.
- PRAGMA synchronous=FULL on the spill connection so the shutdown
  commit hits the platter (NORMAL only fsyncs on WAL checkpoint, which
  may never run if the process exits immediately after commit).
- Spill honors telemetry_writer_max_queue with drop-oldest, matching
  the producer-side overflow policy so a backlogged buffer at shutdown
  can neither stall teardown nor fill disk.
- append_all encodes payloads up front and only clears the deque after
  the transaction commits — no more partial-drain on mid-flight SQLite
  failure. drain collapses to a single DELETE FROM outbox after the
  SELECT.
- Exception handlers at the spill/restore/adopt boundaries narrowed to
  (sqlite3.Error, OSError) so genuinely unexpected exceptions
  propagate rather than being silently logged.

Tests cover: cross-host orphan skipped, missing-owner orphan skipped,
spill cap drops oldest, and a realistic UUID+datetime payload
surviving spill → restore → SQLAlchemy INSERT.

* [autofix.ci] apply automated fixes

* fix(telemetry): name wait_for inner tasks so pyleak can filter

Integration tests using @pyleak_marker were flagging an inner asyncio
task created by the telemetry writer's `wait_for(Event.wait(), ...)`
loops. The wrapper task is auto-named (Task-N) and lands mid-await
across the test boundary, so pyleak counts it as leaked. The writer
itself shuts down cleanly via teardown; the "leak" is a pattern
mismatch with pyleak's per-test snapshot model, not a real lifecycle
bug.

Wrap Event.wait() in an explicitly named task (`telemetry-writer-tick`,
`telemetry-writer-backoff`, `telemetry-sweeper-tick`) via a small
_wait_or_shutdown helper, and extend pyleak_marker with a task_name_filter
that excludes `telemetry-*` from leak detection. CI was green on earlier
commits in this branch only because the diskcache import error
prevented the writer from starting at all — fixing the import surfaced
this latent pyleak collision.

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* test(telemetry): disable writer in tests so reads see writes synchronously

* perf(telemetry): age out cross-host orphan outboxes on shared volumes

A pod on a shared PV (NFS/RWX) cannot adopt rows from a dead pod on a
different host because the dead pod's hostname doesn't match. Without a
janitor those directories accumulate forever. Add an owner-file mtime
heartbeat from the sweeper plus a prune pass that deletes cross-host
outboxes whose owner file hasn't been touched within
telemetry_writer_orphan_max_age_s (default 1h). Same-host orphans still
flow through the existing adoption path.

* perf(telemetry): add byte-aware flush + drop strategy

Today the writer bounds memory by row count only, so a worker logging fat
vertex_build artifacts can hold tens of MB per row and silently dwarf the
configured max_queue. Add a size_strategy switch ('count' | 'bytes' |
'either', default 'count' for parity) with two byte thresholds:

- batch_size_bytes (256KB) caps per-flush INSERT size when bytes apply
- max_queue_bytes (200MB) drops oldest by bytes when bytes apply

Parallel sizes deques mirror the payload buffers so accounting stays
consistent across drain, spill, restore, and the cancel/retry rollback.
Single rows above the byte budget are still emitted (no row is refused);
operators get dropped_*_bytes counters alongside dropped_*.

* test(telemetry): tighten byte-strategy assertions and cover end-to-end paths

Address gaps in the byte-aware strategy tests:
- pin exact dropped counts and remaining buffer state for the drop-by-bytes
  case (was 'greater than zero')
- compute exact drain count from encoded size (was a 1-4 range)
- round-trip bytes through spill+restore to verify size deque is rebuilt
- round-trip bytes through orphan adoption for the same reason
- exercise the sweeper loop end-to-end to confirm heartbeat + prune are
  wired in (previously only unit-tested in isolation)

Clarify in the settings docs that the byte caps measure encoded JSON size,
not Python in-memory footprint.

* ref: updates to telemetry writer PR (#13294)

* fix(telemetry-writer): harden error handling and add missing test coverage

Critical:
- teardown() now re-raises CancelledError after awaiting the writer task so the
  asyncio cancellation chain propagates correctly on lifespan task kill
- suppress(OSError) on owner file write replaced with explicit error log so
  operators know when disk-spilled rows will not be recoverable on restart

High / important:
- Escalation threshold check changed from == to >= so the error log fires on
  every failure past the threshold, not just the 6th
- Dead `except OSError` on time.time() - time.monotonic() changed to
  `except Exception` since time functions cannot raise OSError
- Removed redundant `from uuid import UUID` inside _run_retention_pass (already
  imported at module top)
- Orphan directory cleanup: replaced blanket suppress(OSError) with per-child
  suppress so ENOTEMPTY on an individual rmdir doesn't abort the whole loop and
  leave the parent directory leaking silently; outer failure now logs at debug

Tests (3 new):
- test_retention_sweep_caps_vertex_builds_per_vertex: inserts 8 builds for a
  single vertex with max_per_vertex=3 so the per-vertex DELETE subquery
  actually executes (previous test used 8 distinct vertex IDs, bypassing it)
- test_either_strategy_trips_on_bytes_first: verifies bytes can be the first
  trigger under 'either' strategy (previous test only covered the count-first path)
- test_writer_retries_on_batch_failure: injects 2 flush failures then success;
  confirms failed_batches increments, rows are preserved in the buffer, and
  flushed_rows reflects the final successful write

* ci: add stress-tests job to nightly build pipeline

Wires the stress-tests workflow into nightly so telemetry write stress
tests run automatically. Also gates release-nightly-build and
slack-notification on stress-tests result so a stress regression blocks
the nightly release and surfaces in Slack.

* ci: run stress tests in nightly without blocking release

Stress tests are informational for now — a failure is visible in the
workflow run and Slack but does not gate the nightly release or build.

* fix(telemetry-writer): address PR review on cancelled teardown and nightly stress tests

- Add the stress-tests.yml reusable workflow (was untracked, so the
  nightly stress-tests job could never resolve)
- Notify Slack on stress-tests failure (add to slack-notification gate
  and FAILED_JOB detection as non-blocking)
- Run sweeper cancel, disk spill, and engine dispose in a finally so a
  cancelled teardown() still persists the in-memory buffer
- Add tests for the cancelled-teardown spill path and the >= escalation
  threshold; drop the misleading wait-loop in the retry test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jordan Frazier <122494242+jordanrfrazier@users.noreply.github.com>
2026-06-05 17:32:47 +00:00
d3ee447e31 fix(canvas): anchor new note bottom-center to cursor on placement (#13441)
* fix(canvas): anchor new note bottom-center to cursor on placement

* improve notes component

* [autofix.ci] apply automated fixes

* improve testcases

---------

Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local>
Co-authored-by: Olayinka Adelakun <olayinkaadelakun@mac.war.can.ibm.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-05 17:18:16 +00:00
283cc018a8 fix: slider value lost when adjusting before the node is selected (#13515)
* fix: commit slider value before node selection consumes the interaction

Sliders inside React Flow nodes (e.g. the URL component's Depth field) lost
the value the user set when the node was not yet selected. React Flow selects
a node on click and pans/drags it on pointer down, while Radix drives the
slider with the same pointer events. The interactive SliderPrimitive.Root had
no React Flow isolation, so the first interaction on an unselected node was
consumed by node selection: the slider reacted visually but the chosen value
reverted or snapped to wherever the pointer landed.

Stop pointer/click propagation on the slider root and add React Flow's
nodrag/nopan/noflow/nowheel opt-out classes (matching the slider's value-text
input). Radix composes the handlers, so value setting is unaffected.

Adds a regression test asserting slider pointer-down/click do not bubble to
the node wrapper while unrelated children still do.

* Update src/frontend/src/components/core/parameterRenderComponent/components/sliderComponent/__tests__/slider-node-selection.test.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* [autofix.ci] apply automated fixes

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-06-05 16:25:56 +00:00
e12086f257 docs: lfx readme and lfx mcp (#13010)
* docs-add-readmes-from-outdated-branch

* docs-add-sessionid-value

* add-example-from-support

* peer-review
2026-06-05 16:06:54 +00:00
183cdd82cf fix: add ssrf protection to url component (#13488)
* fix: add ssrf protection to url component

add ssrf protection to url component

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes (attempt 3/3)

* chore: address ruff errors

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* chore: update starter projects and component_index

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* fix: url component sync and async

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Eric Hare <ericrhare@gmail.com>
2026-06-05 15:42:24 +00:00