chore: back port the new workflow updates from 1.12 - #14581
Conversation
* fix(a11y): admin and auth pages accessibility - Wrap /login/admin and /admin content in a <main> landmark - Add accessible names to admin controls: search, clear, active/superuser toggles, row edit/delete, back button - Fix New User modal label associations (explicit htmlFor on checkbox fields) - Bind /login/admin username/password inputs so the placeholder overlay clears once text is entered - Constrain the active/superuser toggle focus ring to the checkbox instead of spanning the full cell - Make the clear-search control a real focusable button (was a div onClick) - Add /admin and /login/admin a11y specs, IBM baselines for remaining framework-level debt, and a clear-search keyboard test - Add i18n keys admin.backButton and admin.clearSearch across all locales - Move baselineFolder to tests/a11y/baselines * fix(a11y): resolve admin/auth violations, fix modal password field, add dark scans Resolve the a11y debt that was previously baselined for the /admin page and harden the auth surfaces: - Toggle controls (active/superuser): convert to proper toggle buttons (aria-label + aria-pressed threaded to the trigger) and render the inner CheckBoxDiv as presentational, so a checkbox role is no longer nested inside an interactive button (IBM aria_descendant_valid, WCAG 1.3.1/4.1.2). - Row action icons (edit/delete): size each trigger to >=24x24 CSS px so they meet WCAG 2.5.8 target size and no longer trip target_spacing_sufficient. - Delete all three admin IBM baselines now that the violations are fixed. - New User modal: the password/confirm fields hand-rolled a raw input with the visibility toggle stuffed into the label. Replace with the shared InputComponent password primitive (eye toggle inside the input, keyboard operable, aria-label + aria-pressed), matching the login/signup surfaces; move validation to the getRequiredFieldError pattern. - Dark-mode coverage: run every auth state in both light and dark and add a dark new-user-modal scan. This surfaced insufficient error-text contrast in dark mode (~3.9:1); fix .field-invalid/.label-invalid to use the brighter accent-red so form errors meet WCAG AA 4.5:1. * fix(frontend): restore name attr on new user password inputs InputComponent lost the name attribute that Radix Form.Control asChild previously injected, breaking Playwright selectors input[name=password] and input[name=confirmpassword] in the New User modal. --------- Co-authored-by: Eric Hare <ericrhare@gmail.com>
* feat: add IBM Accessibility Level 1 validation tracker and compliance guide - Introduced a manual validation tracker for IBM Level 1 accessibility, detailing validation methods and criteria. - Added a comprehensive engineering compliance guide aligned with IBM Equal Access Toolkit v7.3, covering essential accessibility requirements and best practices. - The tracker complements existing automated checks and serves as a shared checklist for UI validation. * feat(a11y): add IBM Accessibility Level 1 criteria and validation tracker - Introduced a comprehensive guide for IBM Accessibility Level 1 compliance, detailing essential requirements aligned with the IBM Equal Access Toolkit v7.3. - Added a manual validation tracker to facilitate UI accessibility checks, complementing existing automated tools. - Updated README to include references to the new criteria and tracker documents, emphasizing their role in the accessibility testing process. * feat(a11y): introduce a11y-spec-authoring skill for Playwright accessibility scans - Added a new skill for authoring Playwright accessibility scan spec files, aimed at enhancing IBM Equal Access compliance for Langflow frontend features and routes. - Updated the README to include guidance on using the new skill and its integration with existing a11y testing workflows. - Enhanced the IBM Level 1 criteria documentation to clarify the scope and application of accessibility requirements. * docs(a11y): update README for improved accessibility testing guidance - Revised the README to enhance clarity on Langflow's accessibility testing processes, including a detailed overview of scanning methods and their purposes. - Added sections for quick start and workflow for adding a11y coverage, making it easier for contributors to understand how to implement accessibility tests. - Updated references to IBM Level 1 compliance documents, ensuring users have access to the necessary resources for effective a11y validation. * feat: enhance accessibility and localization in knowledge base components - Introduced RadixAriaControlsFix component to manage aria-controls attributes for better accessibility in popovers and dialogs. - Updated CrashErrorComponent to use semantic <main> tag for improved structure. - Added new localization keys for various actions and navigation in multiple languages, enhancing user experience. - Implemented aria-labels for buttons and interactive elements to ensure compliance with accessibility standards. - Improved accessibility in FilesPanel and StepReview components by adding descriptive aria-labels for better screen reader support. * chore: update secrets baseline with new line numbers for hashed secrets in es.json - Adjusted line numbers for multiple hashed secrets in the .secrets.baseline file to reflect changes in the src/frontend/src/locales/es.json file. - Ensured that all entries are correctly aligned with their respective line numbers for better tracking and management of secrets. * feat(a11y): introduce a11y-spec-authoring skill and enhance accessibility testing - Added a new skill for authoring Playwright accessibility scan spec files, aimed at improving coverage for Langflow frontend features and routes. - Created a centralized JSON file for managing accessibility rule suppressions, ensuring clarity on which rules are framework-owned and cannot be fixed at the feature level. - Updated existing accessibility test specifications to utilize the new ignore rules, streamlining the process of identifying actionable issues versus suppressed ones. - Enhanced documentation for accessibility testing workflows, including detailed instructions on capturing all relevant UI states during scans. - Improved the HTML report generation to clearly distinguish between actionable and suppressed accessibility issues, aiding developers in focusing on necessary fixes. * feat(a11y): implement feature-specific accessibility rule suppression for Knowledge Bases - Introduced a new JSON file, `knowledge-bases-ignore-rules.json`, to centralize accessibility rule suppressions specific to the Knowledge Bases feature. - Updated relevant test specifications to import the new feature-specific ignore rules, enhancing clarity on which rules are framework-owned and cannot be fixed at the feature level. - Modified the HTML report generation to reflect KB-specific suppressions, ensuring that only relevant findings are greyed out while actionable issues remain visible. - Enhanced documentation to guide other features in creating their own ignore rules as needed, promoting consistency in accessibility testing practices. * chore: update secrets baseline and adjust line numbers for hashed secrets in pt.json - Updated line numbers for multiple hashed secrets in the .secrets.baseline file to reflect changes in the src/frontend/src/locales/pt.json file. - Modified the generated_at timestamp for consistency. - Changed version field in Structured Data Analysis Agent configuration to null. - Improved CSS variable definitions for better accessibility compliance. * feat(a11y): enhance keyboard navigation and accessibility in Knowledge Bases * feat(a11y): implement per-scan accessibility rule suppression and reporting - Added `writeA11yIgnoreSidecar` function to persist applied ignore rules for each scan, enabling precise reporting of suppressed rules. - Updated HTML report generation to read from the new sidecar files, ensuring only relevant rules are greyed out based on individual scan configurations. - Enhanced documentation to clarify the management of suppression rules and their impact on accessibility reporting. * refactor(a11y): streamline accessibility rule handling and update UI components - Removed the `writeA11yIgnoreSidecar` function and associated logic for managing suppressed rules, simplifying the accessibility reporting process. - Updated accessibility scan calls in tests to remove references to ignored rules, ensuring a more straightforward evaluation of violations. - Enhanced UI components in `MetadataEditor` and `StepConfiguration` with improved focus styles for better accessibility compliance. - Deleted outdated accessibility tracking documentation and related files to reflect the current testing strategy. * feat(a11y): add frontend accessibility check skill and enhance UI components - Introduced a new skill for conducting accessibility checks on frontend components, detailing when to use it and how to implement tests with Jest and Playwright. - Updated `RadixAriaControlsFix` to improve ARIA label handling for input-less lists. - Enhanced `DBProviderInput` and `ModelInputComponent` to include labels for better accessibility. - Modified `StepConfiguration` and `StepReview` components to manage menu containers for accessibility compliance. - Improved `MetadataCombobox` to use a plain input for search functionality, ensuring better ARIA compliance. * feat(knowledgeBase): implement row actions for knowledge base table - Added `KnowledgeBaseRowActions` component to handle actions for each row in the knowledge base table, including ingesting files, viewing chunks, stopping ingestion, and deleting entries. - Enhanced accessibility by ensuring dropdown menus and tooltips are properly managed within the main content area. - Utilized `useLayoutEffect` to resolve the menu container dynamically, improving the user experience and compliance with accessibility standards. * feat(a11y): enhance Radix components for improved accessibility - Integrated `useInertForAriaHiddenElements` in `RadixAriaControlsFix` to manage focusable controls under `aria-hidden` elements, ensuring compliance with accessibility standards. - Updated `SelectContent` to accept a `container` prop for better portal management, allowing content to be rendered within the main landmark. - Modified `SourceChunksPage` to dynamically set the select container, improving the accessibility of portaled content. * refactor(a11y): clean up comments and improve code clarity - Removed outdated comments from `RadixAriaControlsFix`, `DBProviderInput`, and `ModelInputComponent` to enhance code readability. - Streamlined focus management in `KnowledgeBasesTab` and `SourceChunksPage` by eliminating unnecessary comments related to accessibility. - Updated styles in `ag-theme-shadcn.css` and `index.css` for better focus visibility and consistency across components. * refactor(a11y): remove frontend accessibility check skill and enhance Radix component focus management - Deleted the `frontend-a11y-check` skill documentation to streamline the project. - Improved focus management in `RadixAriaControlsFix` by optimizing the handling of ARIA attributes and tabindex for better accessibility compliance. - Updated `KnowledgeBasesTab` to ensure proper typing for keyboard event handling, enhancing type safety and clarity. * feat(a11y): enhance accessibility in various components - Added "aria-label" props to DBProviderInput, ModelInputComponent, and related components to improve screen reader support. - Updated localization files to include new keys for knowledge base and chunk metadata labels, enhancing accessibility for non-English users. - Implemented focus management improvements in KnowledgeBaseUploadModal and DeleteConfirmationModal to ensure proper focus restoration after modal closure. - Enhanced MetadataEditor and ChunksMetadataFilter components with appropriate ARIA attributes for better accessibility compliance. - Improved accessibility in KnowledgeBasesTab by adding ARIA labels to search inputs and buttons. These changes aim to ensure compliance with WCAG standards and improve the overall user experience for assistive technology users. * fix(locales): add missing commas in translation files for consistency Added trailing commas to the "knowledge.chunksMetadataValueLabel" entries in the localization files for German, English, Spanish, French, Japanese, Portuguese, and Simplified Chinese to ensure proper JSON formatting and consistency across all language files. * fix(a11y): enhance keyboard navigation for actions in knowledge base table - Updated the actions column header to be accessible and named for assistive technologies. - Implemented keyboard handling to open the row actions menu when the actions cell is focused, improving usability for keyboard users. - Adjusted tabindex management for empty body rows to ensure focus remains accessible. - Added tests to verify accessibility features and keyboard interactions in the knowledge base table. This commit addresses WCAG 2.1 compliance and enhances the overall accessibility of the knowledge base interface. * fix(a11y): update test ID for OpenAI text embedding option in accessibility tests Modified the test ID for the OpenAI text embedding option in the knowledge bases accessibility test to ensure accurate visibility checks. This change enhances the reliability of the accessibility tests for the embedding dropdown. * chore: regenerate secrets baseline * chore: update .gitignore and enhance IBM Level 1 audit skill documentation - Added .cursor/settings.local.json to .gitignore for personal settings. - Revised the description and workflow of the ibm-a11y-level1-audit skill to clarify its default behavior and remediation process. - Updated related skills references and progress checklist to reflect changes in auditing and fixing accessibility issues. --------- Co-authored-by: Eric Hare <ericrhare@gmail.com>
* test(models): define provider policy contracts * feat(models): extend provider registry contract * feat(models): enforce provider visibility policy * fix(models): address provider policy review feedback
* Remove lfx-bundles from default Langflow install
* chore: wake ci
* Move lfx-bundles tests out of backend integration
* test: skip lfx-bundles unit tests when absent
* test: adjust bundle-dependent coverage
* test: relax optional bundle frontend checks
* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]
* chore: trigger CI
* test: fix optional bundle CI drift
* test: stub optional opensearch dependency
* test: stub optional google drive client
* test: share optional google client stub
* test: stub optional groq client
* test: stub optional google genai client
* test: remove redundant unguarded FAISS vectorstore test straggler
The FAISS component moved to the lfx-bundles distribution, and this PR
stops installing lfx-bundles by default. The copy under
tests/unit/components/vectorstores/test_faiss_vector_store_component.py
imported the deprecation shim path (lfx.components.FAISS.faiss) at module
level without an importorskip guard, so pytest collection errored with
"ModuleNotFoundError: No module named 'lfx_bundles'" and failed the
Python 3.14 Group 5 unit-test job.
Its sibling under tests/unit/components/bundles/faiss/ is the canonical,
guarded copy: it importorskips lfx_bundles, imports the real
lfx_bundles.faiss.faiss module, and is a strict superset (adds the
allow_dangerous_deserialization security-default regressions). Deleting
the straggler removes the duplicate and the collection failure with zero
coverage loss.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: guard KB ingestion Ollama embedding tests behind langchain_ollama
The two TestKBIngestionHelperBuildEmbeddings Ollama cases exercise the real
EmbeddingModelComponent (no mock), which imports langchain_ollama at build
time. langchain-ollama is only an optional extra and reached CI transitively
via lfx-bundles; with bundles removed from the default install it is absent,
so both tests failed with 'Could not import langchain_ollama' and fail-fast
red-ed the whole Python 3.14 Group 2 split.
Add pytest.importorskip('langchain_ollama') to those two tests (matching the
convention in test_chatollama_component.py) so they skip cleanly when the
optional dep is missing. The four sibling tests in the class mock the
component and stay unaffected.
* fix: document optional bundle requirements
* style: format lfx bundle shims
* test: guard git SSRF tests behind optional bundle
* test: guard connector SSRF tests behind optional bundle
* chore: regenerate artifacts after rebase
* [autofix.ci] apply automated fixes
* [autofix.ci] apply automated fixes (attempt 2/3)
* fix: stabilize lean bundle CI
* test: skip faiss without optional bundles
* fix: ship optional starters with lfx-bundles
* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]
* chore: retrigger ci
* chore: record component index conflict resolution
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: make the 1.11 core runtime self-contained * test: define langflow-core distribution contract * feat: add langflow-core distribution * feat: add langflow-core container image * feat: ship the langflow-core distribution * fix: support Python 3.10 in core distribution tests * fix: address langflow-core review feedback * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * feat: make langflow-core the shared distribution base * docs: put information in one place and include uv * docs: align core dependency guidance * fix: allow first core release CLI gate to skip * docs: fix relative links * docs: defer user guidance to documentation PR * fix: align provider CI with optional bundles --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Mendon Kissling <59585235+mendonk@users.noreply.github.com>
refactor: enhance accessibility and styling in various components - Updated StringReader component to improve styling with min-width and leading adjustments. - Added keyboard event handling in TableComponent to prevent double activation of dialogs. - Enhanced SessionView component with new keyboard event handling for cell selection. - Improved TextModal styling for better alignment and readability. - Added aria-label to TextEditorArea for improved accessibility. - Introduced accessibility tests for HeaderMessagesComponent and messagesPage to ensure compliance. These changes aim to enhance user experience and accessibility across the application.
* chore: bump release versions to 1.12.0 * fix: address version bump review feedback * test: cover sdk dependency pin variants
* ci: add release inventory gates * chore: trigger CI
* test: define scoped authorization visibility contract * feat: add scoped authorization visibility prefilter
* feat: automate bundle release planning * fix: address bundle release review feedback
* fix: complete shared resource access (LE-1828) * test: cover structured unscoped list visibility * fix: honor structured visibility for unscoped resources * test: align memory guards with share-aware lookup * fix: address shared resource authorization review
* feat: enhance accessibility and internationalization for AlertDisplayArea and Button components - Added `useTranslation` for internationalization in `AlertDisplayArea`, providing an aria-label for better accessibility. - Updated `Button` component to include `aria-busy` attribute during loading and ensured the accessible name is preserved with a visually hidden label. - Enhanced accessibility tests for both components to verify the presence of roles and attributes. * Enhance Button Component Accessibility and Behavior - Updated button styles to include aria-disabled and aria-busy attributes, ensuring focus retention during loading states. - Implemented logic to prevent activation of button clicks and key presses while loading, improving user experience. - Added tests to verify button behavior during loading, including focus retention and click prevention. - Introduced a new test suite for button functionality, covering various interaction scenarios. These changes aim to improve accessibility and usability of the button component in the UI. * fix(mcp): stabilize Tool Mode activation (#14188) * fix(mcp): stabilize tool mode activation * fix(frontend): prevent stale tool mode refresh * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes --------- Co-authored-by: Eric Hare <ericrhare@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* feat(authz): complete release 1.12 RBAC deliverables * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix(ci): align bundle releases and LFX clean-flow tests * fix: address CodeRabbit release findings --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix: include Google as a default partner bundle * chore: auto-bake note keys and regenerate backend locales/en.json [skip ci] * chore: wake CI * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: address Google bundle review findings * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- 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>
# Conflicts: # .github/workflows/cross-platform-test.yml # .github/workflows/docker-build-v2.yml # .github/workflows/release_nightly.yml # .secrets.baseline # scripts/ci/test_release_workflow.py
… sync (#14104) * fix(rbac): pass owner id to deployment crud layer and close shared-access gaps - Pass row_owner_id through list/count/sync so credentials and attachments stay in the provider-account owner namespace while user_id remains the listing actor - Use deployment_row.user_id for shared delete cleanup; confirmed zero rows → 404; unconfirmed DELETE rowcount → 500 - Keep shared update rollback in the deployment owner namespace - Add apply_owned_or_visible_prefilter so scoped API keys with a concrete visible-id set do not auto-include owned deployments (owner override still unions via restrict_to_owned_or_visible) - Document None vs [] at the deployment list prefilter call site - Enforce flow:deploy before provider mutation on create, update (added versions), and snapshot replacement via ensure_flows_permission - Authorize deployment:create before existing-resource provider get/create - Add route, CRUD, listing, and guard coverage for the above * fix(rbac): sync deployment guard retries in each flow owner's namespace Guard-retry was syncing with the actor user_id, so shared deleters/movers could not reconcile the owner's deployments. Resolve owners from the flow rows and sync per owner instead. * docs: clarify correctness of owner derivation in deployment guard sync * fix(rbac): scope deployment guard repair to authorized flows --------- Co-authored-by: Eric Hare <ericrhare@gmail.com>
* feat(authz): complete release 1.12 contracts * docs: fix versioned image profile links * fix: address release completion review feedback
* fix: graduate Azure and Ollama bundles * chore: auto-bake note keys and regenerate backend locales/en.json [skip ci] * chore: wake CI --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix: normalize MCP resource flow IDs * fix: address MCP resource review feedback
…14256) * fix: populate name and description on starter-projects API response GET /api/v1/starter-projects/ returned a null top-level name for every template, making it impossible to select a template by name. The name is not recoverable elsewhere in the response, so the endpoint was unusable for programmatic template selection. get_starter_projects_dump() called Graph.dump() with no arguments, and the starter project builders construct Graph(start=..., end=...) without flow_name, so Graph.dump() never wrote the name key at all. description failed the same way. Pass the canonical name and description, sourced from the matching starter_projects/*.json files, into dump(). Also stop stringifying endpoint_name unconditionally: str(None) produced the literal string "None" instead of null. GraphDump is total=False, so omitting the key when it is None matches how name and description are already handled, and no caller reads endpoint_name off a dump() result. The existing tests asserted only the status code and that the result was a list, so no field was ever inspected. Add assertions that names are present and unique, descriptions are present, and endpoint_name is never the string "None". Fixes #14255 * refactor: co-locate starter project metadata and assert canonical values Address review feedback on #14256. Declare each starter project builder alongside its name and description so reordering cannot pair a graph with the wrong metadata, replacing the positional zip between two separate lists. Tighten the regression test to compare the full name-to-description mapping and the expected project count, so a wrong name, a wrong description, or a swapped association now fails rather than passing on any unique non-empty strings.
…e canvas (#14258) * fix: render flows whose nodes have no position instead of crashing the canvas Flows whose `data.nodes` lack a `position` crashed the canvas with a full-page error boundary. The auto-layout fallback that exists for exactly this case (`needsLayout` + `getLayoutedNodes`) was broken in two independent ways. 1. `getLayoutedNodes` passed `id: undefined` to ELK — for edges (`id: e.id`) and for ports derived from absent handles (`id: e.sourceHandle`). ELK rejected the graph with `JsonImportException: Id must be a string or an integer: 'null'`, so the layout failed for precisely the flows that needed it. Both id sources had to be fixed; repairing either alone still threw. Handle-less ports are now dropped (their edges fall back to the always-present node-id port) and edges without an id get a stable synthetic one. A failed layout now falls back to a deterministic grid rather than leaving nodes unpositioned. 2. `processFlows` iterates with `forEach(async …)`, which discards the returned promise, so it returns before the layout resolves and `useApplyFlowToCanvas` hands position-less nodes straight to React Flow — whose `getNodePositionWithOrigin` dereferences `node.position.x` unguarded. This crashed even when ELK succeeded. `processDataFromFlow` now seeds deterministic positions synchronously before awaiting ELK, so no node can reach React Flow without one. `needsLayout` also now rejects non-numeric and NaN coordinates, not just an absent `position`. A payload with this shape is served by `GET /api/v1/starter-projects/`, whose nodes have no `position` and whose edges have no `id`/`sourceHandle`/ `targetHandle`; POSTing one to `/api/v1/flows/` and opening it reproduced the crash. Position-less flows can also arrive from hand-written JSON, older exports, and third-party tooling. * fix: treat non-finite coordinates as needing layout, cover ELK rejection Addresses review feedback on #14258. `needsLayout` used a typeof + NaN check, which let `Infinity` through: it is a number and is not NaN, so a node with an infinite coordinate skipped the synchronous seeding and could still reach React Flow as an unusable position. `Number.isFinite` does not coerce, so it subsumes the typeof check while also rejecting NaN and ±Infinity. Also adds the missing error-path coverage for the ELK fallback: the previous tests only exercised successful layouts, never the catch branch. The new test mocks elk.layout to reject and asserts getLayoutedNodes resolves to the deterministic grid rather than propagating. Both tests fail without their corresponding fix.
…4272) remove_agentic_mcp_server called update_server without delete=True under a comment claiming "Empty config removes the server". That has never been true: the flag-less call is a full replace, so users who had the langflow-agentic server were left with an empty-config row, and users who never had it gained a brand-new empty-config row (the create path runs when no row exists) — a broken entry in their MCP servers list either way. The same behavior existed under the old file-based store (the entry was set to {}). Pass delete=True so the row is actually removed. For users without the server, update_server raises HTTPException, which the existing per-user except/continue block already handles. The helper currently has no callers (the agentic-experience disable path was never wired up), so nothing ships the broken behavior today; this fixes the latent utility and pins the semantics with tests before anyone wires it up.
…ama base url from components (#14236) * add default fallback to instantiation.py and removed default ollama base URL from components * chore: auto-bake note keys and regenerate backend locales/en.json [skip ci] * update to rerun tests * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: align Ollama starter project defaults * fix: ignore transient component template metadata --------- 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> Co-authored-by: Eric Hare <ericrhare@gmail.com>
fix(tracing): detach spans from missing parents
…14511) * fix: let the caller own the flow span so a run's spans nest under it async_start is an async generator, so a span it opens cannot be made current: the context token would be attached and detached across the generator's suspension points and leak into whatever task resumed it. A span that is not current cannot parent anything, so every span produced during the run sat beside the flow span instead of under it. Under HTTP that means siblings of the server span; with no ambient span, a separate trace entirely. The callers are coroutines and thread entry points, which have no such problem, so the span moves to them and async_start takes open_flow_span=False. Converted: the agentic assistant (both coordinator consumers, the served path), the lfx CLI, lfx run, preload, and Graph.start. The flag defaults to True, so a caller that has not been converted still gets a span rather than silently none. Those runs keep the flat shape they have today. The mistake the flag makes possible is deferring and then not opening one, which is silent, so async_start warns when it is told the caller owns the span and no span is current. It warns rather than raising, because telemetry must never take a run down. The nesting test in test_mcp_tool_span.py was an xfail and is now a real assertion. Its counterpart is kept, asserting the detached span cannot parent, so the reason the span had to move does not get lost. Verified: a span opened mid-run parents to the caller's flow span, an unconverted caller still emits exactly one flow span, and deferring with no caller span emits none. 752 passed across graph, mcp and execution; the two catalog-policy failures there fail identically with these changes stashed. * fix: pass the event manager to async_start by keyword async_start takes (inputs, max_iterations, config, event_manager). The sync start forwarded the event manager positionally, so it landed in config and __apply_config subscripted it. That happens on the worker thread start spawns, so nothing reaches the caller: the exception is logged there and the generator finishes empty. A run that produces no results and no error is the worst shape for this, so the regression test asserts on the results rather than on not raising. Measured before and after on a ChatInput -> ChatOutput graph: start(event_manager=...) 0 results -> 3 results Pre-existing rather than introduced here; release-1.12.0 has the same call without the keyword. Fixed on this branch because it is the line this PR already changes. config is applied by start itself before the thread, so it is deliberately not forwarded again. Found by CodeRabbit on this PR. * fix: carry the caller context into the worker thread Graph.start hands the run to a worker thread, and a thread starts with an empty context. So the flow span opened in there found no current span and began a brand-new trace: measured, the caller's span and flow.execute came back with different trace ids and no parent and no link between them. A caller's span and the run it started were two unrelated traces in the operator's APM, which is the correlation this branch exists to provide. Copy the context and run the thread body inside it. The same copy carries the protocol and client contextvars, which are set at the entry point for exactly this reason. The caller's span is still recording while the generator is consumed, so the flow span parents to it normally. A caller that abandons the generator early leaves a dead parent, which flow_execution_span already handles by linking instead of parenting. The regression test asserts on the trace id rather than the parent alone: a parent could be satisfied by a span that happened to nest under something else in the worker. Red before this with two different traces. Found by CodeRabbit on this PR. * test: give the stand-in graph the flow span the caller now opens This branch moved the flow span out of async_start and into the callers, so _run_graph_with_events opens graph.flow_execution_span() itself. The coordinator test drives it with a dataclass stand-in that has no such method, and the AttributeError is swallowed by the broad except around that block, so the coordinator was never reached. The failure read as 'the coordinator was not used' (assert 0 == 1) rather than 'the stand-in is missing a method', which is the more expensive kind of red. Verified it fails at this branch's head before my commits and passes on release-1.12.0, so it came in with the span move rather than with the keyword and context fixes. src/backend/tests/unit/agentic: 1621 passed. The one remaining failure there, test_execute_named_assistant_flow_is_graceful_not_500, reproduces on release-1.12.0 untouched. * fix: let a failed sync run reach both the caller and the span The worker caught ValueError inside the flow span scope and let everything else escape the thread entirely. Two different wrong outcomes from one block. Measured before, on a cyclic graph hitting max_iterations, which is where async_start raises a raw ValueError: raised_to_caller=ValueError flow spans exported=0 The handler sat inside the span scope, so the consumer raised the moment the exception was queued, the generator was abandoned, thread.join never ran and the worker never finished ending the span. The run failed and the operator's APM has nothing at all for it. And on a component failure, which arrives wrapped as ComponentBuildError and so missed the ValueError handler completely: raised_to_caller=None span status=error It propagated out of the worker, died with the thread, and the caller read the end-of-stream sentinel and saw a clean finish. A run that failed returned no error to a synchronous caller. Nothing is caught inside the scope now. The failure leaves the span, the span records it, and a worker-boundary handler enqueues every Exception rather than just ValueError. The consumer already re-raises whatever it finds, so the caller gets what a synchronous call should have given it. The None sentinel is still written in the finally, after the exception, so the caller reads the error first. Regression covers both kinds and both halves, and each fails without the fix for its own reason: the ValueError case on 0 spans, the other on the caller receiving nothing. Found by erichare in review.
…4543) Menus rendered inline rather than in a portal live inside React Flow's node element, which listens for arrow and selection keys on that element itself. Radix consumes those keys for its own roving focus but lets them keep bubbling, so one arrow press both navigates the menu and moves the node. Stop the keys React Flow reserves at the content element, at the two shared primitives instead of the ten call sites that use them.
* feat(api): add id-keyed project upsert endpoint
Add PUT /api/v1/projects/{project_id} so a project can be created or updated
at a caller-specified UUID, mirroring PUT /api/v1/flows/{flow_id}. Returns 201
on create and 200 on update, 404 for another user's project, and 409 on a name
collision on both paths (POST keeps auto-renaming). Sending flows_list or
components_list to an existing project is rejected with 400 rather than
silently dropped, since membership is derived from the flows themselves.
Extract the POST and PATCH handler bodies into _new_project and
_apply_project_update so the new route reuses the existing MCP registration,
auth-settings and flow-move side effects instead of duplicating them.
Also fix two pre-existing bugs surfaced by exercising the shared update core:
renaming a project onto a name its owner already uses returned 500 with the
failing SQL statement and bound parameters in the response body, because
handle_mcp_server_rename swallows the IntegrityError raised by the post-rename
autoflush and leaves the session needing rollback. The collision is now checked
before the row is mutated and returns 409, and the fallback 500 goes through
sanitize_database_error like the read and delete handlers. This changes PATCH's
status for that case from 500 to 409.
* fix(api): scope project-update flow queries to the owner and sanitize 500s
Address review feedback on the project upsert endpoint.
Scope both the in-project flow rollup and the default-folder lookup in
_apply_project_update to the project owner. Every user gets their own folder
named DEFAULT_FOLDER_NAME, so the unscoped .first() could resolve to a
different user's folder and hand ensure_flow_moves_allowed a foreign
destination to authorize the move against. The excluded rows were already
moved back into the project by the following statement, so the end state was
unaffected, but the guard was evaluating the wrong folder. get_default_folder_id
scopes the same lookup by user_id; this matches it.
Route the remaining write-path 500s through sanitize_database_error, which the
read and delete handlers already use: the fetch failure in update_project, the
fallback in create_project, and upsert_project's non-409 fallback, which
returned _handle_unique_constraint_error's detail of str(exc) — the SQL
statement plus its bound parameters — for any error that is not a unique
violation. The helper's 409 mapping is preserved for a unique violation that
arrives wrapped in another exception type.
The read endpoints keep their unsanitized details; they are outside this
change.
* fix(api): make unique-constraint mapping backend-agnostic and leak-free
_handle_unique_constraint_error only recognized SQLite's "UNIQUE constraint
failed" text, so on PostgreSQL every unique violation fell through to a 500
whose detail was str(exc) — the failing statement plus its bound parameters.
PUT /flows/{flow_id} answered a name or endpoint-name conflict that way on the
one backend a cross-instance sync actually runs on.
Detect the violation by SQLSTATE 23505 off the driver exception (sqlstate on
psycopg3, pgcode on psycopg2) and fall back to message text for SQLite. Pick
the detail from a marker table keyed on both what SQLite prints (columns:
"flow.endpoint_name") and what PostgreSQL prints (constraint names:
"unique_flow_name"); every constraint involved is named in the models. Sanitize
the non-violation 500, keeping the 500 return itself because update_flow reads
it as "not a conflict" rather than raising it.
This also fixes the composite-key parse: "UNIQUE constraint failed:
flow.user_id, flow.name" split on the dot and reported " flow must be unique".
Flow and project conflicts now name the field, and a primary-key collision --
two concurrent upserts at the same id -- is no longer reported as a name
conflict.
projects.py drops the bespoke IntegrityError branch that worked around all of
the above, and PATCH now maps its constraint backstop through the same helper
as PUT so both verbs answer a concurrent rename with 409 instead of diverging.
Sanitize the three remaining read-handler 500s, and drop an always-truthy
`if project_results:` guard on a ScalarResult.
Covers the helper with direct unit tests: the suite runs only SQLite, so the
PostgreSQL branch has no integration coverage.
* Add authz endpoint matrix json
…ter a rename (#14544) Nodes and edges are tab stops but render no focus styling, so a keyboard user traverses nine invisible stops with no idea where they are. React Flow clears the outline on both and leaves the indicator to the app; restore one using the app-wide focus token. Committing a project rename unmounts the focused input without moving focus, dropping it to <body> and forcing a tab from the top of the page. Hand focus back to the project's nav item, but only when it was actually lost.
…#14556) * fix(test): run the bundle-guarded tests that CI was silently skipping Since #13869 made lfx-bundles opt-in, 36 backend/lfx test files (378 test functions) carry pytest.importorskip("lfx_bundles") -- and nothing in CI installed the metapackage, so none of them ever executed. The backend suite installs with a plain `uv sync`; cross-bundle-test.yml runs only each bundle's own tests/ directory. Closes #14554. Bundle component tests move to the bundle (10 files) Relocated to src/bundles/lfx-bundles/tests/, where cross-bundle-test.yml runs them. That job now installs [all-no-torch] (the same aggregate langflow[bundles] resolves, so it stays torch-free) plus respx/pytest-timeout, and the bundle gains a [tool.pytest.ini_options] with asyncio_mode and registered markers. The extras install deliberately sits in the test step, not setup, so the contract smoke keeps asserting graceful degradation without extras. Bundle suite: 15 passed -> 132 passed, 29 skipped (skips are credential-gated only: QIANFAN_AK/SK, COMETAPI_KEY). Security tests become bundle-free (new test_bundle_ssrf_wiring.py) The SSRF guards live in shared lfx.utils.ssrf_* helpers whose behaviour is already covered in lfx/tests/unit/utils/; what the skipped tests uniquely proved is that each provider *wires* the guard in. That is now asserted statically over the in-repo provider sources -- parsed, never imported -- so it runs in every default install: guard imported, guard actually called (an unused import lints clean while leaving the request open), and no raw httpx sink. A registry test fails if a new module uses an ssrf_safe_ helper without being listed. Precedent: test_bundle_shims.py, test_migration_table_completeness.py. Verified by mutation: deleting deepseek's guard import and restoring the raw httpx.get call fails two independent assertions. The behavioural versions move to the bundle, so both layers exist. Stragglers get a lane instead of a move (8 files) altk/chroma/cometapi/cuga/elastic/langwatch/youtube inherit tests/base.py's version-compatibility harness (tests.constants + tests.integration.utils), which is langflow-specific and cannot follow them into the bundle's lfx-only venv -- one imports langflow directly. New python_test.yml job installs `uv sync --extra bundles` and runs the guarded files, discovered by grep so a newly guarded test joins automatically. It asserts lfx_bundles actually imported afterwards, so the job cannot go green by skipping everything again. Ollama split out of the SSRF file, as in #14553: it graduated to lfx-ollama (a default dependency, absent from the bundle venv), so those two tests stay in the backend suite where they run for real. * fix(ci): split backend and lfx guarded runs; bump lfx-bundles; address review The new bundle-guarded job failed on both Python legs with ImportPathMismatchError: ('tests.conftest', '.../src/backend/tests/conftest.py', '.../src/lfx/tests/conftest.py') Both trees ship a top-level `tests` package, so collecting them in one pytest run collides on tests.conftest. Split into two invocations, the lfx one from src/lfx -- the same separation the existing Unit Tests / LFX Tests jobs use, and what `make lfx_tests` does. The lfx step also needs its own install: the lfx venv does not carry lfx-bundles, and src/lfx/tests/conftest.py refuses to run when langflow IS installed, so it gets lfx + the in-repo bundle and nothing else. Verified in a matching venv (lfx + lfx_bundles present, langflow absent): the two guarded lfx files go from skipped to 10 passed. Also swapped mapfile for a `while read` loop -- mapfile needs bash 4+, and runs-on is a workflow input, so the runner shell is not guaranteed to have it (macOS bash 3.2 does not). Moved the lfx_bundles import assertion ahead of the test run: after the run it cannot prevent a green report from a fully-skipped suite, which is the failure being fixed. Bundle release plan gate: adding [tool.pytest.ini_options] counts as a releasable source change, so lfx-bundles goes 1.1.10 -> 1.1.11 via `bundle_release_plan.py update` (root pin + uv.lock synced by the tool). CodeRabbit review: - cross-bundle-test.yml deselects `-m "not api_key_required"`. Registering the marker never skipped anything; the tests self-skipped on missing env vars, so the marker's "not run in CI" contract was aspirational. Now enforced: 132 passed, 1 skipped, 28 deselected. - bundle-guarded-tests gets `permissions: contents: read` and checkout `persist-credentials: false`, matching cross-bundle-test.yml. Test Docker Images failed on the same run with "runner has received a shutdown signal" -- infrastructure, unrelated to this change. * fix(ci): harden bundle-guarded discovery and match api-key policy Follow-up to review feedback on the guarded-test scan, plus one bug the suggestion surfaced while being verified. Discovery is now quote-agnostic and .py-only: grep -rlE --include='*.py' "pytest\.importorskip\([[:space:]]*['\"]lfx_bundles" - ['\"] so a single-quoted importorskip is not missed. A guarded test the scan overlooks is the exact bug this job exists to catch, so a partial pattern defeats it. - POSIX grep -E rather than rg: runs-on is an input to this workflow (including self-hosted and an ARM64 ephemeral runner), so ripgrep is not guaranteed. - --include='*.py' after hitting a real failure locally: grep -r also reads __pycache__/*.pyc, where the docstring text survives compilation, so the scan matched a .pyc and handed pytest a path it could not collect ("ERROR: not found: .../test_ssrf_guarded_ollama_components...pyc"). A fresh CI checkout has no __pycache__, so this would only have bitten on a reused runner or locally. Verified by extracting the command from the YAML and running it against fixtures covering double-quoted, single-quoted, whitespace, and unguarded files. That also caught my first escaping attempt being wrong -- [\'\\"] terminates the shell string early -- which reading the diff alone would not have shown. Both pytest invocations now pass -m "not api_key_required", matching `make unit_tests`, which the main backend job already uses. Running the guarded files without it executed three live-API altk tests that the rest of CI deselects by policy; this job should not be the only one making real provider calls. Those three remain deliberately excluded rather than silently skipped -- a different thing from the import-skip this PR fixes. * fix(ci): drop --timeout from the lfx guarded-test run The backend leg passed; the lfx leg died with pytest: error: unrecognized arguments: --timeout=300 pytest-timeout is not in lfx's dev group (pytest, pytest-asyncio, pytest-cov), and `make lfx_tests` does not pass a timeout either. The backend step keeps the flag -- the root project does have pytest-timeout. My earlier local check masked this: the venv I verified against had pytest-timeout hand-installed, which CI does not do. Re-verified in a venv built exactly as the job builds it (lfx dev deps + the in-repo bundle, no pytest-timeout, no langflow), running the step's command extracted straight from the YAML: 2 files discovered, 10 passed.
add bob context file to .gitignore
* chore(deps): bump datasets to 5.0.1 Mend flags datasets 4.8.5. The declared range (>2.14.7,<6.0.0) already permitted 5.x; the lock had simply gone stale, so this is a lock-only re-resolution with no transitive churn. datasets is an optional extra with no first-party import in Langflow. * chore(deps): upgrade react-router-dom to v7.18.2 The three react-router advisories Mend reports against 6.30.4 have no fix in the 6.x line -- CVE-2026-53669 and CVE-2026-53666 are patched only in 7.18.0, and CVE-2026-53668 (react-router-dom 6.30.2-6.30.4) has no 6.x patch at all. 7.18.2 also covers GHSA-qwww-vcr4-c8h2. The migration surface is small: Langflow uses createBrowserRouter with createRoutesFromElements and no loaders, actions, fetchers, defer(), or json(), so the v7 future flags that gate behavior changes do not apply. The only v6-specific code was a test that opted into v7_relativeSplatPath and v7_startTransition explicitly -- both are v7 defaults, so the prop is dropped. react-router v7 reads TextEncoder at module load and jsdom does not expose it, which broke 14 suites at import time; polyfilled next to the existing crypto/URL shims in jest.setup.js. Verified: tsc --noEmit is byte-identical to the v6 baseline (284 pre-existing errors, zero new), vite build succeeds, and all 587 jest suites / 6421 tests pass. * fix(frontend): keep flow events posted just before mount visible react-router v7 renders route updates in a transition, so the flow page can paint before useFlowEvents remounts with the new flow id. The hook seeded its `since` cursor with Date.now() at mount and the events API only returns events strictly newer than `since`, so anything posted in that window was dropped for good: the poll kept re-sending the same cursor and never saw the event. That is what shard 38 hit here. The trace shows the test's POST landing ~0.2-0.5s before the hook mounted on the new flow, so the agent banner never appeared -- deterministic, 8/8 attempts, while the same shard passed at the base commit. Seed the cursor 10s in the past instead, and let the server's `settled` flag decide what to do with what turns up: on the catch-up poll, events for a flow that has already settled advance the cursor but stay silent, so finished work does not flash a banner or trigger the settle-driven flow refetch. * test(frontend): wait for the new flow to load before pressing "/" Second fallout from the router bump, same shape as the flow-events one: the blank-flow click creates a flow and navigates, and under v7 the new canvas mounts well after the click resolves -- 1.3s later in the failing trace, which is 0.2s AFTER the test pressed "/". The wait that was supposed to cover this does not: `sidebar-search-input` is present on the flow we are LEAVING too, so it resolved against the outgoing page. Focus went to that sidebar, the new flow's page then remounted, and the input the assertion polls was a different, unfocused one -- "inactive", 8/8 attempts. It passed at the base commit and was already failing here before the flow-events fix (run 1 attempt 1, rescued by the job-level retry). Wait for the GET of the flow in the URL to land instead, so the test is on the page it thinks it is on before it touches the keyboard.
…14560) fix(a11y): name the knowledge-base provider picker from its canvas field label ParameterRenderComponent spreads ariaLabelledBy into every widget, but DBProviderInputComponent never read it, so the provider combobox on the canvas fell back to its own generic aria-label and a screen reader user never heard which field they were on. Forward it through to the trigger, and emit only one of the two names: aria-labelledby already wins over aria-label, so setting both strands a name nothing reads. Modal callers pass aria-label with no field label to reference and keep their existing behavior.
Alembic reflected every table in the database and reported each one absent from SQLModel.metadata as a remove_table diff, so `alembic check` aborted startup with "There's a mismatch between the models and the database" whenever a user pointed a vector store or any other tool at Langflow's own database. The tables LangChain's PGVector creates (langchain_pg_collection, langchain_pg_embedding) are the common trigger; Langflow's own Postgres knowledge base backend creates the same two. Add an include_name filter so autogenerate only considers tables Langflow owns. Drift inside those tables is still detected, and tables present in the models but missing from the database are still reported, so `alembic revision --autogenerate` keeps working. Fixes #9117
* ci: harden nightly builds and test reliability
* chore: satisfy bundle release contracts
* ci: align reusable workflow permissions
* ci: address CodeRabbit review on nightly hardening
Shard calculation: `playwright test --list | wc -l` counted the
"Listing tests:" header and "Total:" footer, so every suite was
over-sharded by two tests' worth of runners, and a grep matching no test
made Playwright exit non-zero and kill the step under `set -euo
pipefail`. Parse the "Total:" line and fall back to a single shard.
Least privilege: py_autofix.yml had no permissions block at all, so it
ran on default token scopes; autofix-ci uploads a diff artifact and the
autofix.ci App applies it with its own credentials, so contents:read is
enough — this matches js_autofix.yml. Read-only checkouts in the docker
nightly, storybook deploy, and extension-migration gates no longer
persist the token into the workspace.
SQLite reflection noise: the composite-FK PRAGMA warning was filtered
inline in alembic/env.py only, so both autogenerate comparisons in
test_migration_execution.py still emitted it. Fold it into
filter_known_sqlite_reflection_warnings() and apply that at both call
sites.
Live smoke isolation: playwright.live.config.ts shared port 7860 with
the blocking suite and set reuseExistingServer: true. Playwright only
applies `env` to servers it starts, so a leftover blocking-suite backend
was reused with OPENAI_BASE_URL still pointed at the loopback fixture —
the "live" provider check could pass without touching a real provider.
Give it a dedicated port, database, and no server reuse.
Also: memoizedNodeToolbarComponent listed updateNodeCode but calls
handleUpdateCode, pinning the toolbar to stale templates and edges; the
loopback fixture rewrote headers on a late streaming failure and died of
an unhandled ERR_HTTP_HEADERS_SENT; cleanAllFlows threw after
successfully deleting exactly MAX_DELETIONS flows; cleanOldFolders
confirmed deletion by text order instead of the modal test id.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(ci): resolve zero-flake test regressions
* fix(ci): close zero-flake acceptance gaps
* fix(ci): run base CLI checks in uv environment
* fix(ci): close remaining release acceptance races
* fix(ci): align bundle versions with moved release base
* fix(ci): stabilize release Playwright persistence
* fix(ci): stabilize PSD file component setup
* fix(ci): eliminate remaining Playwright fixture races
* fix(ci): close final Playwright readiness races
* fix(ci): close remaining Playwright races
* fix(e2e): target current RetrievalQA handles
* ci: make the Playwright report gate survive partial re-runs
The report gate could not go green after a "re-run failed jobs": blob
report artifacts are named per attempt, but a partial re-run only
re-executes the failed shards, so the shards that passed the first time
keep their attempt-1 names. Downloading only
`blob-report-<os>-*-attempt-${{ github.run_attempt }}` therefore found 1
of 70 reports on attempt 2 and the strict count check failed the run.
Download every attempt instead and resolve the newest attempt per shard,
so a partial re-run converges on exactly one report per shard. The count
check now also names the shards it is missing rather than dumping the
whole download tree.
Two supporting fixes:
- Add `timeout-minutes` to the shard job and to the browser-install
steps. Shard 59 of run 31775314581 hung in `playwright install
--with-deps` (apt-get) and was only killed by GitHub's 6-hour job
ceiling, which is what starved the gate in the first place. Successful
shards finish in 4-9 minutes.
- Gate the merged-JSON upload on the merge having actually run. It was
`if: always()` with `if-no-files-found: error`, so every gate
short-circuit produced a second, misleading red X. The JSON still
uploads when the report checker finds failures.
* ci: stop re-downloading Playwright browsers on every shard
The browser cache has never worked. PLAYWRIGHT_BROWSERS_PATH was
relative, so it resolved against each step's working directory: the
install runs from src/frontend and wrote to src/frontend/ms-playwright,
while actions/cache archived <workspace>/ms-playwright and logged "Path
Validation Error ... no cache is being saved". Every one of the 70
shards therefore re-downloaded Chromium and re-ran apt on every run.
Making the path absolute fixes both halves at once.
Dropping `--with-deps` on Linux fixes the rest. On the hosted image
every library Chromium links against is already present — apt's own
summary was "0 upgraded, 9 newly installed", and all 9 were CJK/X11 font
packages, 21MB pulled from one mirror by 70 shards at once. That is what
timed out shard 45 after 10 minutes here, and shard 59 after six hours
before this branch added a timeout. Fonts affect glyph rendering, not
whether Chromium starts, and the cache-hit path skips them regardless.
The install now retries three times with backoff.
Also bumps lfx-bundles 1.1.11 -> 1.1.12 via `bundle_release_plan.py
update`: release-1.12.0 shipped 1.1.11 in the meantime, so this branch's
lfx-bundles changes had landed on a version already published. The plan
now validates as "ready".
* fix(ci): pin main-page waits to the route just navigated to
Two shards failed after merging release-1.12.0, both on mainpage_title
straight after a route change — the react-router v7 deferred-render
behaviour that the base's own keyboardComponentSearch fix was chasing:
- fileUploadComponent: `waitForSelector('[data-testid="mainpage_title"]')`
matched the outgoing page's heading, so the one-shot `textContent()`
read returned "Toggle SidebarStarter Project" instead of "Files". A
one-shot read has no retry, so the value is whatever was mounted at
that instant.
- bulk-actions: `expect(mainpage_title).toBeVisible()` after `goto("/")`
timed out at the default 5s with "element(s) not found". A full goto
reboots the app, which is more than 5s of CI.
Both now go through waitForMainPageReady, which asserts on the heading
*text* with a retrying matcher when the caller names the destination, and
allows TIMEOUTS.standard rather than the 5s default.
Verified: biome (pinned 2.1.1) clean, and tsc clean over all four touched
spec/helper files. Note tsconfig.json's `include` is an explicit allowlist
that covers none of them, so `tsc -p tsconfig.json` silently skips these
specs — they were checked via a temporary config.
* fix(ci): fit the canvas before asserting nodes in twoEdges
The report gate's only remaining complaint was one flaky test. Its first
attempt failed on
getByText('Knowledge', { exact: true }).first()
locator resolved to <span data-testid="node-name">Knowledge</span>
unexpected value "hidden"
so the node was mounted but outside the viewport: the spec asserted node
visibility straight after opening the Vector Store RAG template, before
any fit_view. Whether a given node lands inside the initial viewport is
luck, which is exactly the shape of a flake that passes on retry.
Now waits for the editor and fits the view first. numberOfZoomOut: 0
keeps the visual state unchanged for the rest of the test, and the
existing fit_view further down re-fits regardless.
Pre-existing flake, not merge fallout -- this branch had never touched
the spec. Not reproducible locally (it needs the full e2e stack and only
fails intermittently), so CI is the verification.
* fix(ci): scope default flow names in general-bugs-shard-3836
Shard 70 failed its first attempt in awaitBootstrapTest with "Creating a
new flow returned 400". That is the race
route-test-scoped-default-flow-names.ts already documents: the product
derives "New Flow (n)" from a client-side inventory snapshot, so two
shards can pick the same suffix before either POST commits and the loser
violates the unique (user_id, name) constraint.
This spec does not exercise naming, so it takes the same beforeEach hook
ten other specs already use.
Not a regression from the release-1.12.0 merge: the same spec passed on
its first attempt in the previous run, which already carried the merged
flows.py unique-constraint mapper.
The retry of that run failed differently — img[alt$="chain.png"] never
rendered within 100s — which this does not address. That assertion passed
in the previous run, so it is being left as an observation rather than
guessed at.
* ci: let the report gate warn on flaky instead of failing
The gate failed on any test that retried to green. In practice the suite
carries a background flake rate of roughly 1-3 specs per run out of 445,
and the set is different every run -- three consecutive runs of this
branch produced completely disjoint flaky sets (twoEdges;
general-bugs-3836; then messages.a11y + globalVariables + Travel Planning
Agent). Four targeted fixes all held and none reappeared, but new ones
kept surfacing, so a zero-tolerance gate blocks whichever PR is unlucky
rather than signalling a real regression.
inspectPlaywrightReport now returns the flaky list instead of throwing on
it, and throws only for tests that ended red or top-level reporter
errors. When a real failure is present the flaky entries are still
included in the message, so context is not lost. The CLI prints flakes as
a warning and reports the count on success.
Verified against the real merged report from run 31831257298, the one
that failed this gate: it now exits 0 and logs its 3 flakes
(445 tests). Unit tests updated to the new contract, 11/11 passing.
Note for nightlies: nightly_build.yml alerts Slack when the Windows
frontend test_status is "failed", so a flake-only Windows run no longer
raises that alert -- consistent with treating flakes as non-blocking.
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…099) (#14579) Three defects found while testing the IdP support lane. BUG-01 — revoking a role assignment left its provenance rows behind on SQLite. ``authz_role_assignment_grant.assignment_id`` declares ``ondelete="CASCADE"``, but SQLite ignores foreign keys unless ``PRAGMA foreign_keys=ON`` is issued per connection, which Langflow never does. Declaring the ORM relationship makes SQLAlchemy issue the child deletes itself, so every delete path cascades identically on SQLite and PostgreSQL. ``all, delete`` deliberately omits ``delete-orphan``: grant rows are created by setting ``assignment_id`` directly, and ``delete-orphan`` would reject those as unparented at flush time. BUG-03 — LE-2109 called for a short-lived cache so bearer-path group reconciliation does not run on every request. It was never implemented, so each authenticated request opened a transaction, took the authorization plugin's policy locks and appended a ``directory_membership:reconcile`` audit row. One QA session left 183 of them; a single page load produced 16. A reconciliation that verified the stored state already matched the claim is now remembered for ``LANGFLOW_EXTERNAL_AUTH_GROUP_RECONCILE_INTERVAL_SECONDS`` (default 60, 0 disables), keyed by the exact directory state it verified, so any change in the group set, claim state or resolved user still reconciles immediately. A pass that changed something is not cached until a confirming pass runs, so a pending post-commit propagation retry is never hidden behind the cache. BUG-02 (partial) — a deadlocked reconciliation was reported to the caller as ``401 {"detail":"Token authentication failed"}``. A transaction rolled back as a deadlock victim never judged the credential, so it is now raised as ``AuthBackendUnavailableError`` and answered with a retryable ``503`` (``Retry-After: 1``) — ``1013`` on websockets — instead of blaming a token that was never rejected. It also short-circuits the remaining credential fallbacks rather than replaying them into the same outage. The lock-ordering defect itself lives in the authorization plugin and is fixed there.
…ssion check (#14523) * refactor(frontend): expose the pending half of the flow permission gate useIsFlowReadOnly conflates two states: the query is still resolving, and the user is denied. Controls that invoke a gated mutation need to tell them apart to disable themselves only while the answer is in flight and to name the reason correctly. Adds useIsFlowPermissionPending next to it, reading the same provider so both predicates can never disagree. No behaviour change on its own. * fix(frontend): gate sidebar component items on the pending permission check The add path already refused to run while the permission query resolved, but the item stayed draggable, double-clickable and kept an enabled add button, so the click was discarded with nothing reported. The row now carries the same not-allowed affordance it already uses for placement constraints, and the add button is disabled for that window. A constraint violation is a verdict and still hides the button; a pending check is transient, so it only suspends it and the control keeps its place. Refs LE-2176 * fix(frontend): gate New Custom Component on the pending permission check Same discarded-click window as the component items, on the sidebar footer button. It already had a disabled channel wired to the component-types load, so the pending permission state joins it. Because the button opts out of the base class with unstyled, the disabled look is spelled out at the call site — without it the control would block the click while still looking exactly like a working one. Refs LE-2176 * test(frontend): cover the add affordance during the pending permission check Splits the two halves of the gate on the hook, then asserts on both add surfaces that the control refuses the click visibly instead of discarding it, and that a placement constraint still wins the reason when both apply. Checked against the base: 5 of the 8 item assertions and 3 of the 4 button assertions fail without the fix; the rest are the resolved-state controls and the constraint regression guard. Refs LE-2176 * test(frontend): add e2e guard for the discarded add click Holds the permission response open so the window is deterministic instead of racing a round trip that is milliseconds wide on localhost, then asserts the control is unavailable during it and that the same single click adds a node once the answer arrives. Asserts the request actually happened: without that the test would pass vacuously on any build where the editor stops querying permissions. Refs LE-2176 * test(frontend): poll the intercepted permission request instead of reading it once The counter is incremented by the route handler on the Node side, while the visibility assertion it follows resolves on the browser side. Nothing orders the two, so on a loaded runner the guard could read zero and fail a test that is otherwise correct. Addresses the CodeRabbit review on #14523. * fix(frontend): dim the custom component button for both refusal reasons The button was disabled by the component-types load and by the pending permission check, but only the second one dimmed it. Same control looking refused for one cause and working for the other reads as a bug, and the load case fires on every flow open, so it is the more frequently hit half. Hoists the condition so disabled and the disabled look cannot diverge. Addresses I1 of the review on #14523. * fix(frontend): refuse the add affordance for denied write, not just in flight The gate the add path uses is read-only, which is true both while the permission answer travels and, permanently, when it denies write. Gating the controls on the pending half alone left a read-only collaborator with a fully interactive sidebar whose every add is discarded, with nothing reported — the same defect, except it never resolves. Both surfaces now key off useIsFlowReadOnly, the exact predicate that refuses the click, and useIsFlowPermissionPending only picks which reason to show: still checking, or read-only access. A placement constraint keeps hiding the add button; the permission cases only disable it, so a denied user still sees the layout everyone else does. Addresses I2 of the review on #14523. --------- Co-authored-by: Eric Hare <ericrhare@gmail.com>
|
Important Review skippedToo many files! This PR contains 1801 files, which is 1501 over the limit of 300. To get a review, reduce the PR to 300 files or fewer by splitting it into smaller PRs or changing its base branch. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (1801)
You can disable this status message by setting the |
|
✅ Migration Validation Passed All migrations follow the Expand-Contract pattern correctly. |
✅ Test Coverage AdvisorNo source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉
|
|
Build successful! ✅ |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #14581 +/- ##
==========================================
+ Coverage 64.91% 64.96% +0.04%
==========================================
Files 2454 2456 +2
Lines 250995 251004 +9
Branches 34982 34940 -42
==========================================
+ Hits 162932 163054 +122
+ Misses 85999 85885 -114
- Partials 2064 2065 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
…(main) (#14586) fix(ci): assert the base console script the 1.12 line actually ships Ports #14584 to main. main inherited the stale `langflow-base` assertion from #14571 when the back-merge (#14581) paired it with release-1.12.0's post-#14339 pyproject, where the base wheel declares `langflow`: # src/backend/base/pyproject.toml [project.scripts] langflow = "langflow.langflow_launcher:main" Both branches have to carry this. The nightly tag push only succeeds while main and the release branch have identical .github/workflows content -- GitHub screens App-token pushes for workflow changes and GITHUB_TOKEN cannot carry `workflows`, so any drift re-breaks create-nightly-tag. Taken as release-1.12.0's copy of the file verbatim rather than re-applying the edit, so the two branches are byte-identical by construction.
This branch is the back-merge. Its tip
51cd93670ais a true two-parent merge commit (b1b0ce1a50+0a2d167ade) preserving all 186 commits ofrelease-1.12.0history individually. Squashing or rebasing destroys exactly the thing this PR exists to preserve.Why now: the nightly build is broken
The 2026-08-15 nightly (run 31853074951) failed 3/3 attempts at
create-nightly-tag→ Commit tag:GitHub screens every push made with a GitHub App token (including
GITHUB_TOKEN) for changes under.github/workflows, and that screen fails closed when it runs out of time.GITHUB_TOKENcannot carryworkflows, so the tag push is rejected outright.The screen's cost tracks how far the tagged release branch has drifted from the default branch:
mainmainv1.12.0.dev24v1.12.0.dev25v1.12.0.dev26v1.12.0.dev27d65b98f (#14540, ci: harden nightly builds and test reliability) rewrote 49 workflow files on
release-1.12.0only. The first nightly after it landed is the one that broke.This merge drops the workflow delta from 52 files to 1, which puts the screen back inside its budget.
Verification
release-1.12.0main's #14571 fix)maingainsrelease-1.12.0fully containedmainfully contained (fast-forward)No conflicts.
main's sole unique commit (b1b0ce1, #14571) auto-merged correctly and is preserved.Follow-ups
maininherits ci: harden nightly builds and test reliability #14540's hardenednightly_build.yml, so the hardcodedref: release-1.12.0is replaced by theresolve-release-branchjob — no more hand-editing each release.v1.12.0.dev27out.release-1.12.0still carried the pre-fix(ci): assert the base wheel's real console script name #14571 assertion; forward-ported separately.create-nightly-tagcheckout would make the tag push independent of drift — worth doing as defense in depth.🤖 Generated with Claude Code