-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Fix: Add frontend and backend component image builds to release workflow #10218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix: Add frontend and backend component image builds to release workflow #10218
Conversation
Previously, API keys from one user account could be used to execute flows owned by other users. This happened because the flow retrieval function only validated user ownership when looking up flows by endpoint name, but not when using flow UUIDs. This commit adds user ownership validation for UUID-based flow lookups by checking the user_id in the database query. Now when a flow is retrieved by ID, it also verifies that the requesting user owns that flow. Additionally, updated the flow execution endpoints to pass the API key user's ID through to the flow retrieval function. Returns 404 for both non-existent flows and unauthorized access attempts to avoid leaking information about which flows exist. Added comprehensive test coverage including: - Tests verifying cross-account access is properly blocked - Tests confirming legitimate same-account access still works - Tests for both simplified and webhook execution endpoints Fixes langflow-ai#10202
…ty-10202 Fix API key cross-account access vulnerability
- Add build-frontend-backend-components job to docker-build-v2.yml - Build langflow-frontend and langflow-backend images on main releases - Support both Docker Hub and GitHub Container Registry - Include multi-architecture support (amd64/arm64) - Respect pre-release flag for proper tagging - Add retry logic and propagation delays for reliability Fixes langflow-ai#10215
WalkthroughAdds a new ARM64 GitHub Actions job to build/push frontend/backend images. Implements user-ownership validation in flow lookups and updates run/webhook endpoints to pass user_id. Adds unit tests, validation scripts, and extensive documentation explaining the security fix and IDE warnings. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant API as API Endpoint (run/webhook)
participant Auth as API Key Auth
participant Helper as get_flow_by_id_or_endpoint_name(...)
participant DB as DB
Client->>API: POST /api/v1/run/{flow_id_or_name}
API->>Auth: Validate API key -> get user_id
API->>Helper: Resolve(flow_id_or_name, user_id)
alt UUID or endpoint name
Helper->>DB: SELECT Flow WHERE id/name AND user_id
DB-->>Helper: Flow or None
end
alt Flow found
API-->>Client: 200 Run initiated
else Not found or not owned
API-->>Client: 404
end
sequenceDiagram
autonumber
actor Client
participant API as API Endpoint (webhook)
participant Auth as Webhook Auth
participant Helper as get_flow_by_id_or_endpoint_name(...)
participant DB as DB
Client->>API: POST /api/v1/webhook/{flow_id_or_name}
API->>Auth: Authenticate webhook -> user_id
API->>Helper: Resolve(flow_id_or_name, user_id)
Helper->>DB: Scoped lookup by user_id
alt Found
API-->>Client: 200 Webhook processed
else Not found/not owned
API-->>Client: 404
end
sequenceDiagram
autonumber
participant GH as GitHub Actions
participant Buildx as Docker Buildx
participant DHub as Docker Hub
participant GHCR as GHCR
GH->>GH: build-frontend-backend-components (matrix 4x)
GH->>Buildx: Setup builder
GH->>DHub: Login
GH->>GHCR: Login
GH->>Buildx: Build+Push frontend/backend (amd64, arm64)
par Registries
Buildx->>DHub: Push tags
Buildx->>GHCR: Push tags
end
GH-->>GH: Wait/Retry for propagation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 error, 1 warning)
✅ Passed checks (7 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/backend/base/langflow/api/v1/endpoints.py (1)
323-366: Update docstring to describeflow_id_or_name.Ruff is failing (D417) because the
simplified_run_flowdocstring no longer documents the newly addedflow_id_or_nameparameter. Please add an argument description so the style check passes.- flow (FlowRead | None): The flow to execute, loaded via dependency + flow_id_or_name (str): Identifier (UUID or endpoint name) used to look up the flow
🧹 Nitpick comments (4)
PR_DESCRIPTION_FRONTEND_FIX.md (1)
195-195: Minor markdown formatting: Use heading instead of bold emphasis.The bold text "Ready for Review! 🚀" could be formatted as a heading for better document structure.
Apply this diff:
-**Ready for Review! 🚀** +## Ready for Review! 🚀WARNINGS_EXPLAINED.md (1)
52-52: Add language specifiers to fenced code blocks.Several fenced code blocks lack language specifiers, which improves syntax highlighting and accessibility.
For example, at line 52:
-``` +```text Import "fastapi" could not be resolvedSimilarly, update other code blocks with appropriate language identifiers (text, bash, etc.) based on their content.
Also applies to: 61-61, 70-70, 82-82, 110-110, 121-121, 212-212
IDE_ERRORS_EXPLAINED.md (1)
13-13: Add language specifiers to fenced code blocks.Fenced code blocks should specify their language for better rendering and accessibility.
Apply language identifiers based on content:
- Shell commands →
bash- Plain text output →
text- Python code →
pythonExample at line 13:
-``` +```text Import "fastapi" could not be resolvedAlso applies to: 25-25, 67-67, 82-82, 120-120, 131-131, 196-196
QUICK_START.md (1)
9-12: Use a proper Markdown heading instead of bold text.markdownlint (MD036) is complaining because the TL;DR section uses emphasis to mimic a heading. Switching to a real heading keeps the style checker happy and matches the rest of the document.
-**Problem:** User A's API key could execute User B's flows ❌ -**Solution:** Added user ownership validation ✅ -**Impact:** No breaking changes, fixes critical security issue -**Status:** Ready for review and merge +### Problem +User A's API key could execute User B's flows ❌ + +### Solution +Added user ownership validation ✅ + +### Impact +No breaking changes, fixes critical security issue + +### Status +Ready for review and merge[Based on static analysis hints]
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
.github/workflows/docker-build-v2.yml(1 hunks)FIX_COMPLETE.md(1 hunks)IDE_ERRORS_EXPLAINED.md(1 hunks)PR_DESCRIPTION.md(1 hunks)PR_DESCRIPTION_FRONTEND_FIX.md(1 hunks)QUICK_START.md(1 hunks)SECURITY_FIX_10202.md(1 hunks)SUMMARY.md(1 hunks)WARNINGS_EXPLAINED.md(1 hunks)run_validation.sh(1 hunks)src/backend/base/langflow/api/v1/endpoints.py(4 hunks)src/backend/base/langflow/helpers/flow.py(1 hunks)src/backend/tests/unit/test_api_key_cross_account_security.py(1 hunks)validate_fix.py(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
{src/backend/**/*.py,tests/**/*.py,Makefile}
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code
Files:
src/backend/base/langflow/api/v1/endpoints.pysrc/backend/base/langflow/helpers/flow.pysrc/backend/tests/unit/test_api_key_cross_account_security.py
src/backend/tests/unit/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
Test component integration within flows using create_flow, build_flow, and get_build_events utilities
Files:
src/backend/tests/unit/test_api_key_cross_account_security.py
src/backend/tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
src/backend/tests/**/*.py: Unit tests for backend code must be located in the 'src/backend/tests/' directory, with component tests organized by component subdirectory under 'src/backend/tests/unit/components/'.
Test files should use the same filename as the component under test, with an appropriate test prefix or suffix (e.g., 'my_component.py' → 'test_my_component.py').
Use the 'client' fixture (an async httpx.AsyncClient) for API tests in backend Python tests, as defined in 'src/backend/tests/conftest.py'.
When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.
Each test in backend Python test files should have a clear docstring explaining its purpose, and complex setups or mocks should be well-commented.
Test both sync and async code paths in backend Python tests, using '@pytest.mark.asyncio' for async tests.
Mock external dependencies appropriately in backend Python tests to isolate unit tests from external services.
Test error handling and edge cases in backend Python tests, including using 'pytest.raises' and asserting error messages.
Validate input/output behavior and test component initialization and configuration in backend Python tests.
Use the 'no_blockbuster' pytest marker to skip the blockbuster plugin in tests when necessary.
Be aware of ContextVar propagation in async tests; test both direct event loop execution and 'asyncio.to_thread' scenarios to ensure proper context isolation.
Test error handling by mocking internal functions using monkeypatch in backend Python tests.
Test resource cleanup in backend Python tests by using fixtures that ensure proper initialization and cleanup of resources.
Test timeout and performance constraints in backend Python tests using 'asyncio.wait_for' and timing assertions.
Test Langflow's Messag...
Files:
src/backend/tests/unit/test_api_key_cross_account_security.py
🧬 Code graph analysis (3)
src/backend/base/langflow/api/v1/endpoints.py (5)
src/backend/base/langflow/services/database/models/user/model.py (1)
UserRead(62-72)src/backend/base/langflow/services/auth/utils.py (2)
api_key_security(44-89)get_webhook_user(262-336)src/backend/base/langflow/services/database/models/flow/model.py (1)
FlowRead(221-225)src/backend/base/langflow/helpers/flow.py (1)
get_flow_by_id_or_endpoint_name(280-301)src/backend/tests/conftest.py (1)
flow(544-560)
src/backend/base/langflow/helpers/flow.py (3)
src/lfx/src/lfx/custom/custom_component/custom_component.py (2)
user_id(189-192)flow_id(195-196)src/backend/base/langflow/services/database/models/flow/model.py (1)
Flow(186-212)src/backend/tests/conftest.py (1)
flow(544-560)
src/backend/tests/unit/test_api_key_cross_account_security.py (5)
src/backend/base/langflow/services/auth/utils.py (1)
get_password_hash(344-346)src/backend/base/langflow/services/database/models/user/model.py (1)
UserRead(62-72)src/backend/base/langflow/services/deps.py (1)
get_db_service(127-136)src/backend/base/langflow/services/database/service.py (1)
with_session(187-198)src/backend/tests/conftest.py (3)
logged_in_headers(495-501)active_user(457-491)flow(544-560)
🪛 actionlint (1.7.7)
.github/workflows/docker-build-v2.yml
505-505: label "langflow-ai-arm64-40gb" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2022", "windows-2019", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "ubuntu-20.04", "macos-latest", "macos-latest-xl", "macos-latest-xlarge", "macos-latest-large", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xl", "macos-14-xlarge", "macos-14-large", "macos-14", "macos-13-xl", "macos-13-xlarge", "macos-13-large", "macos-13", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file
(runner-label)
545-545: shellcheck reported issue in this script: SC2086:info:3:14: Double quote to prevent globbing and word splitting
(shellcheck)
545-545: shellcheck reported issue in this script: SC2086:info:3:26: Double quote to prevent globbing and word splitting
(shellcheck)
552-552: shellcheck reported issue in this script: SC2086:info:3:54: Double quote to prevent globbing and word splitting
(shellcheck)
552-552: shellcheck reported issue in this script: SC2086:info:5:86: Double quote to prevent globbing and word splitting
(shellcheck)
🪛 GitHub Actions: Ruff Style Check
src/backend/base/langflow/api/v1/endpoints.py
[error] 324-324: D417 Missing argument description in the docstring for simplified_run_flow: flow_id_or_name.
🪛 GitHub Check: Ruff Style Check (3.13)
src/backend/tests/unit/test_api_key_cross_account_security.py
[failure] 130-132: Ruff (D205)
src/backend/tests/unit/test_api_key_cross_account_security.py:130:5: D205 1 blank line required between summary line and description
[failure] 92-99: Ruff (D415)
src/backend/tests/unit/test_api_key_cross_account_security.py:92:5: D415 First line should end with a period, question mark, or exclamation point
[failure] 92-99: Ruff (D205)
src/backend/tests/unit/test_api_key_cross_account_security.py:92:5: D205 1 blank line required between summary line and description
[failure] 81-81: Ruff (RET504)
src/backend/tests/unit/test_api_key_cross_account_security.py:81:12: RET504 Unnecessary assignment to flow before return statement
[failure] 69-69: Ruff (ARG001)
src/backend/tests/unit/test_api_key_cross_account_security.py:69:80: ARG001 Unused function argument: second_user
[failure] 59-59: Ruff (ARG001)
src/backend/tests/unit/test_api_key_cross_account_security.py:59:70: ARG001 Unused function argument: active_user
[failure] 43-44: Ruff (S110)
src/backend/tests/unit/test_api_key_cross_account_security.py:43:5: S110 try-except-pass detected, consider logging the exception
[failure] 1-5: Ruff (D415)
src/backend/tests/unit/test_api_key_cross_account_security.py:1:1: D415 First line should end with a period, question mark, or exclamation point
validate_fix.py
[failure] 1-1: Ruff (EXE001)
validate_fix.py:1:1: EXE001 Shebang is present but file is not executable
🪛 markdownlint-cli2 (0.18.1)
WARNINGS_EXPLAINED.md
52-52: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
61-61: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
70-70: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
82-82: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
110-110: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
121-121: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
212-212: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
IDE_ERRORS_EXPLAINED.md
52-52: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
61-61: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
70-70: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
82-82: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
110-110: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
121-121: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
212-212: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
QUICK_START.md
184-184: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
PR_DESCRIPTION_FRONTEND_FIX.md
195-195: Emphasis used instead of a heading
(MD036, no-emphasis-as-heading)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: Lint Backend / Run Mypy (3.10)
- GitHub Check: Lint Backend / Run Mypy (3.12)
- GitHub Check: Lint Backend / Run Mypy (3.13)
- GitHub Check: Lint Backend / Run Mypy (3.11)
- GitHub Check: Run Frontend Tests / Determine Test Suites and Shard Distribution
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
- GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
- GitHub Check: Test Starter Templates
- GitHub Check: Optimize new Python code in this PR
- GitHub Check: Update Starter Projects
🔇 Additional comments (3)
src/backend/base/langflow/helpers/flow.py (1)
285-291: LGTM! Security fix correctly implemented.The UUID-based lookup now properly validates user ownership by filtering on both
Flow.idandFlow.user_id. This prevents cross-account access while maintaining backward compatibility whenuser_idis not provided.run_validation.sh (1)
1-164: LGTM! Comprehensive validation script.The script provides thorough validation across multiple dimensions:
- Python syntax compilation
- Security fix presence verification
- Test coverage checks
- Code quality validation
- Git repository status
The output formatting is clear, and exit codes are properly handled.
FIX_COMPLETE.md (1)
1-263: Excellent comprehensive documentation.This document provides thorough coverage of:
- Problem analysis and fix implementation
- Verification steps with multiple options
- Complete checklists for code, testing, and documentation
- Clear next steps for deployment
The documentation quality is professional and will be valuable for reviewers and future maintainers.
| - name: Get version | ||
| id: version | ||
| run: | | ||
| version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//') | ||
| echo "Using version: $version" | ||
| echo version=$version >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Quote shell variables to prevent word splitting.
The version extraction step has unquoted variables that shellcheck flags.
Apply this diff:
- name: Get version
id: version
run: |
- version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
+ version="$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')"
echo "Using version: $version"
- echo version=$version >> $GITHUB_OUTPUT
+ echo "version=$version" >> "$GITHUB_OUTPUT"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Get version | |
| id: version | |
| run: | | |
| version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//') | |
| echo "Using version: $version" | |
| echo version=$version >> $GITHUB_OUTPUT | |
| - name: Get version | |
| id: version | |
| run: | | |
| version="$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')" | |
| echo "Using version: $version" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" |
🧰 Tools
🪛 actionlint (1.7.7)
545-545: shellcheck reported issue in this script: SC2086:info:3:14: Double quote to prevent globbing and word splitting
(shellcheck)
545-545: shellcheck reported issue in this script: SC2086:info:3:26: Double quote to prevent globbing and word splitting
(shellcheck)
🤖 Prompt for AI Agents
.github/workflows/docker-build-v2.yml around lines 543 to 548: the shell step
that extracts and echoes version uses unquoted variable expansions which can
cause word-splitting and break on versions with spaces; update the script to
always quote variable usages (e.g., "$version" and when writing to GITHUB_OUTPUT
use echo "version=$version" >> "$GITHUB_OUTPUT") and ensure command
substitutions are assigned safely (e.g., version="$(uv tree 2>/dev/null | grep
'^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')" ) so all
expansions are quoted consistently.
| - name: Set component tags | ||
| id: tags | ||
| run: | | ||
| version="${{ steps.version.outputs.version }}" | ||
| if [[ "${{ inputs.pre_release }}" == "true" ]]; then | ||
| echo "tags=${{ matrix.image_name }}:${version}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "tags=${{ matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >> $GITHUB_OUTPUT | ||
| fi |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Quote shell variables in tag computation.
The tag computation step has unquoted variables that could cause issues with word splitting.
Apply this diff:
- name: Set component tags
id: tags
run: |
version="${{ steps.version.outputs.version }}"
if [[ "${{ inputs.pre_release }}" == "true" ]]; then
- echo "tags=${{ matrix.image_name }}:${version}" >> $GITHUB_OUTPUT
+ echo "tags=${{ matrix.image_name }}:${version}" >> "$GITHUB_OUTPUT"
else
- echo "tags=${{ matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >> $GITHUB_OUTPUT
+ echo "tags=${{ matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >> "$GITHUB_OUTPUT"
fi📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - name: Set component tags | |
| id: tags | |
| run: | | |
| version="${{ steps.version.outputs.version }}" | |
| if [[ "${{ inputs.pre_release }}" == "true" ]]; then | |
| echo "tags=${{ matrix.image_name }}:${version}" >> $GITHUB_OUTPUT | |
| else | |
| echo "tags=${{ matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Set component tags | |
| id: tags | |
| run: | | |
| version="${{ steps.version.outputs.version }}" | |
| if [[ "${{ inputs.pre_release }}" == "true" ]]; then | |
| echo "tags=${{ matrix.image_name }}:${version}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "tags=${{ matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >> "$GITHUB_OUTPUT" | |
| fi |
🧰 Tools
🪛 actionlint (1.7.7)
552-552: shellcheck reported issue in this script: SC2086:info:3:54: Double quote to prevent globbing and word splitting
(shellcheck)
552-552: shellcheck reported issue in this script: SC2086:info:5:86: Double quote to prevent globbing and word splitting
(shellcheck)
🤖 Prompt for AI Agents
.github/workflows/docker-build-v2.yml around lines 550 to 558: the tag
computation echoes unquoted expansions and redirects to an unquoted
$GITHUB_OUTPUT which can cause word-splitting/globbing issues; replace the echo
lines with a safe construction that quotes variables and the redirection target,
e.g. use printf 'tags=%s\n' "${{ matrix.image_name }}:${version}" >>
"$GITHUB_OUTPUT" for the pre_release branch and printf 'tags=%s\n' "${{
matrix.image_name }}:${version},${{ matrix.image_name }}:latest" >>
"$GITHUB_OUTPUT" for the else branch so all expansions and the output file are
properly quoted.
| """Test for API Key Cross-Account Security Issue #10202 | ||
| This test reproduces the security vulnerability where an API key from one account | ||
| can be used to execute flows from another account. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the module docstring punctuation/spacing to satisfy Ruff.
Ruff (D415/D205) fails because the first line lacks terminal punctuation and there’s no blank line between the summary and body. Tweaking the docstring keeps linting green.
-"""Test for API Key Cross-Account Security Issue #10202
-
-This test reproduces the security vulnerability where an API key from one account
-can be used to execute flows from another account.
-"""
+"""Test for API Key Cross-Account Security Issue #10202.
+
+This test reproduces the security vulnerability where an API key from one account
+can be used to execute flows from another account.
+"""📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| """Test for API Key Cross-Account Security Issue #10202 | |
| This test reproduces the security vulnerability where an API key from one account | |
| can be used to execute flows from another account. | |
| """ | |
| """Test for API Key Cross-Account Security Issue #10202. | |
| This test reproduces the security vulnerability where an API key from one account | |
| can be used to execute flows from another account. | |
| """ |
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 1-5: Ruff (D415)
src/backend/tests/unit/test_api_key_cross_account_security.py:1:1: D415 First line should end with a period, question mark, or exclamation point
🤖 Prompt for AI Agents
In src/backend/tests/unit/test_api_key_cross_account_security.py around lines 1
to 5, the module docstring lacks terminal punctuation on the summary line and is
missing a blank line between the one-line summary and the body; update the
docstring so the first line ends with a period (or other appropriate
punctuation) and insert a blank line before the longer description so the
summary/body separation conforms to Ruff's D415/D205 rules.
| # Clean up | ||
| try: | ||
| async with db_manager.with_session() as session: | ||
| user_to_delete = await session.get(User, user.id) | ||
| if user_to_delete: | ||
| await session.delete(user_to_delete) | ||
| await session.commit() | ||
| except Exception: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the blanket try/except in teardown.
The bare try/except: pass trips Ruff (S110) and masks real cleanup failures. Let exceptions surface (or log them explicitly) so we notice issues during teardown.
- # Clean up
- try:
- async with db_manager.with_session() as session:
- user_to_delete = await session.get(User, user.id)
- if user_to_delete:
- await session.delete(user_to_delete)
- await session.commit()
- except Exception:
- pass
+ # Clean up
+ async with db_manager.with_session() as session:
+ user_to_delete = await session.get(User, user.id)
+ if user_to_delete:
+ await session.delete(user_to_delete)
+ await session.commit()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # Clean up | |
| try: | |
| async with db_manager.with_session() as session: | |
| user_to_delete = await session.get(User, user.id) | |
| if user_to_delete: | |
| await session.delete(user_to_delete) | |
| await session.commit() | |
| except Exception: | |
| pass | |
| # Clean up | |
| async with db_manager.with_session() as session: | |
| user_to_delete = await session.get(User, user.id) | |
| if user_to_delete: | |
| await session.delete(user_to_delete) | |
| await session.commit() |
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 43-44: Ruff (S110)
src/backend/tests/unit/test_api_key_cross_account_security.py:43:5: S110 try-except-pass detected, consider logging the exception
🤖 Prompt for AI Agents
In src/backend/tests/unit/test_api_key_cross_account_security.py around lines 36
to 44, the teardown code uses a bare try/except that suppresses all exceptions;
remove the blanket try/except so cleanup errors surface to the test runner, or
replace it with a specific catch that logs the exception and re-raises (e.g.,
catch Exception as e, log with logger.exception(...) then raise) to avoid
silently masking failures during teardown.
| async def first_user_api_key(client: AsyncClient, logged_in_headers, active_user): | ||
| """Create an API key for the first user.""" | ||
| api_key_data = ApiKeyCreate(name="first-user-api-key") | ||
| response = await client.post("api/v1/api_key/", json=api_key_data.model_dump(), headers=logged_in_headers) | ||
| assert response.status_code == 200, response.text | ||
| data = response.json() | ||
| return data["api_key"] # Return the unmasked API key | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop the unused active_user fixture parameter.
Ruff flags active_user as unused (ARG001). Since logged_in_headers already depends on active_user, we can remove it from this fixture’s signature.
-async def first_user_api_key(client: AsyncClient, logged_in_headers, active_user):
+async def first_user_api_key(client: AsyncClient, logged_in_headers):📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def first_user_api_key(client: AsyncClient, logged_in_headers, active_user): | |
| """Create an API key for the first user.""" | |
| api_key_data = ApiKeyCreate(name="first-user-api-key") | |
| response = await client.post("api/v1/api_key/", json=api_key_data.model_dump(), headers=logged_in_headers) | |
| assert response.status_code == 200, response.text | |
| data = response.json() | |
| return data["api_key"] # Return the unmasked API key | |
| async def first_user_api_key(client: AsyncClient, logged_in_headers): | |
| """Create an API key for the first user.""" | |
| api_key_data = ApiKeyCreate(name="first-user-api-key") | |
| response = await client.post( | |
| "api/v1/api_key/", | |
| json=api_key_data.model_dump(), | |
| headers=logged_in_headers, | |
| ) | |
| assert response.status_code == 200, response.text | |
| data = response.json() | |
| return data["api_key"] # Return the unmasked API key |
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 59-59: Ruff (ARG001)
src/backend/tests/unit/test_api_key_cross_account_security.py:59:70: ARG001 Unused function argument: active_user
🤖 Prompt for AI Agents
In src/backend/tests/unit/test_api_key_cross_account_security.py around lines 59
to 66, the fixture function first_user_api_key includes an unused parameter
active_user which Ruff flags ARG001; remove active_user from the function
signature so the fixture only accepts (client: AsyncClient, logged_in_headers),
leaving logged_in_headers to continue to depend on active_user, and run tests to
ensure no other references to active_user in this function remain.
| async def second_user_flow(client: AsyncClient, second_user_logged_in_headers, second_user): | ||
| """Create a flow owned by the second user.""" | ||
| # Create a simple flow | ||
| flow_data = { | ||
| "name": "Second User Flow", | ||
| "description": "A flow belonging to the second user", | ||
| "data": {"nodes": [], "edges": []}, | ||
| } | ||
|
|
||
| response = await client.post("api/v1/flows/", json=flow_data, headers=second_user_logged_in_headers) | ||
| assert response.status_code == 201, response.text | ||
| flow = response.json() | ||
| return flow | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tidy up the fixture signature and return value.
second_user is unused (ARG001) and the extra assignment triggers RET504. Removing the unused dependency and returning the JSON payload directly satisfies Ruff.
-async def second_user_flow(client: AsyncClient, second_user_logged_in_headers, second_user):
+async def second_user_flow(client: AsyncClient, second_user_logged_in_headers):
@@
- flow = response.json()
- return flow
+ return response.json()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def second_user_flow(client: AsyncClient, second_user_logged_in_headers, second_user): | |
| """Create a flow owned by the second user.""" | |
| # Create a simple flow | |
| flow_data = { | |
| "name": "Second User Flow", | |
| "description": "A flow belonging to the second user", | |
| "data": {"nodes": [], "edges": []}, | |
| } | |
| response = await client.post("api/v1/flows/", json=flow_data, headers=second_user_logged_in_headers) | |
| assert response.status_code == 201, response.text | |
| flow = response.json() | |
| return flow | |
| async def second_user_flow(client: AsyncClient, second_user_logged_in_headers): | |
| """Create a flow owned by the second user.""" | |
| # Create a simple flow | |
| flow_data = { | |
| "name": "Second User Flow", | |
| "description": "A flow belonging to the second user", | |
| "data": {"nodes": [], "edges": []}, | |
| } | |
| response = await client.post("api/v1/flows/", json=flow_data, headers=second_user_logged_in_headers) | |
| assert response.status_code == 201, response.text | |
| return response.json() |
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 81-81: Ruff (RET504)
src/backend/tests/unit/test_api_key_cross_account_security.py:81:12: RET504 Unnecessary assignment to flow before return statement
[failure] 69-69: Ruff (ARG001)
src/backend/tests/unit/test_api_key_cross_account_security.py:69:80: ARG001 Unused function argument: second_user
🤖 Prompt for AI Agents
In src/backend/tests/unit/test_api_key_cross_account_security.py around lines 69
to 82, the fixture function second_user_flow declares an unused parameter
second_user and assigns response.json() to a local variable before returning it;
remove the unused second_user parameter from the function signature and
eliminate the intermediate assignment by returning response.json() directly
(i.e., change signature to accept only client and second_user_logged_in_headers
and return await client.post(...).json() or call response.json() directly in the
return).
| """Test that reproduces the security vulnerability: | ||
| - User 1 creates an API key | ||
| - User 2 creates a flow | ||
| - User 1's API key should NOT be able to execute User 2's flow | ||
| EXPECTED BEHAVIOR: This should fail with a 403 or 404 error | ||
| CURRENT BEHAVIOR: This succeeds (security vulnerability) | ||
| """ | ||
| # Get the flow ID from second user | ||
| flow_id = second_user_flow["id"] | ||
|
|
||
| # Try to run second user's flow with first user's API key | ||
| headers = {"x-api-key": first_user_api_key} | ||
| payload = { | ||
| "input_value": "test message", | ||
| "input_type": "chat", | ||
| "output_type": "chat", | ||
| "tweaks": {}, | ||
| "stream": False, | ||
| } | ||
|
|
||
| response = await client.post(f"/api/v1/run/{flow_id}", json=payload, headers=headers) | ||
|
|
||
| # This SHOULD fail with 403 (Forbidden) or 404 (Not Found) | ||
| # But currently it will succeed (status 200), which is the security issue | ||
| assert response.status_code in [403, 404], ( | ||
| f"Security Issue: User 1's API key was able to execute User 2's flow! " | ||
| f"Expected 403 or 404, got {response.status_code}. " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjust test docstrings to pass Ruff’s docstring rules.
Ruff (D415/D205) fires because the first line doesn’t end with punctuation and there’s no blank line after the summary. Adding a period and blank line to each test docstring fixes the warnings.
- """Test that reproduces the security vulnerability:
+ """Test that reproduces the security vulnerability.
+
- User 1 creates an API key
@@
- """Test that a user's API key CAN execute their own flows (legitimate use case).
+ """Test that a user's API key CAN execute their own flows (legitimate use case).
+
@@
- """Test that a user cannot retrieve another user's flow details using their API key."""
+ """Test that a user cannot retrieve another user's flow details using their API key."""(Add a blank line after each summary line as shown above.)
Also applies to: 125-152, 156-171
🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 92-99: Ruff (D415)
src/backend/tests/unit/test_api_key_cross_account_security.py:92:5: D415 First line should end with a period, question mark, or exclamation point
[failure] 92-99: Ruff (D205)
src/backend/tests/unit/test_api_key_cross_account_security.py:92:5: D205 1 blank line required between summary line and description
🤖 Prompt for AI Agents
In src/backend/tests/unit/test_api_key_cross_account_security.py around lines 92
to 119, the test docstring summary line lacks terminal punctuation and is
missing a blank line after the one-line summary, triggering Ruff D415/D205;
update the docstring by ending the first summary line with a period and
inserting a blank line between the summary and the rest of the docstring body.
Apply the same fixes to the other affected ranges (lines 125-152 and 156-171) so
each test docstring has a punctuated first line and a following blank line.
| @@ -0,0 +1,89 @@ | |||
| #!/usr/bin/env python3 | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the script executable.
The shebang is present but the file lacks execute permissions.
Run this command to fix:
chmod +x validate_fix.py🧰 Tools
🪛 GitHub Check: Ruff Style Check (3.13)
[failure] 1-1: Ruff (EXE001)
validate_fix.py:1:1: EXE001 Shebang is present but file is not executable
🤖 Prompt for AI Agents
validate_fix.py lines 1-1: the script has a shebang but is not executable; make
the file executable by updating its permissions (e.g., give the owner execute
permission) so the script can be run directly from the shell.
|
When will this get merged? I faced this issue now a couple of times. |



🐛 Problem Description
Issue: #10215 - Missing langflow-frontend Docker Image for Version 1.6.4
When Langflow releases a new version (like 1.6.4), the corresponding
langflowai/langflow-frontendDocker image is not being published to Docker Hub. This creates a version mismatch problem for users who rely on the separate frontend image, particularly those using the langflow-ide Helm chart.Current Situation
langflowai/langflow) gets published successfullylangflowai/langflow-ep) gets published successfullylangflowai/langflow-all) gets published successfullylangflowai/langflow-frontend) is NOT being publishedlangflowai/langflow-backend) is NOT being publishedImpact
Users deploying Langflow using the Helm chart that depends on separate frontend/backend images cannot upgrade to the latest versions. The last available frontend image on Docker Hub is still
1.5.1, while the main Langflow release is at1.6.4.🔍 Root Cause Analysis
The issue stems from the migration to the new
docker-build-v2.ymlworkflow:Old Workflow (
docker-build.yml): Included abuild_componentsjob that built separate frontend/backend imagesNew Workflow (
docker-build-v2.yml): Focused on building the main images but did not include the component build job - this was an oversight during workflow refactoringResult: When releases are triggered, only the main images get built, leaving the frontend and backend component images un-updated.
✨ The Fix
Added a new job
build-frontend-backend-componentsto.github/workflows/docker-build-v2.ymlthat:Key Features
release_type == 'main'andpush_to_registry == truelangflowai/langflow-backend(Docker Hub)langflowai/langflow-frontend(Docker Hub)ghcr.io/langflow-ai/langflow-backend(GitHub Container Registry)ghcr.io/langflow-ai/langflow-frontend(GitHub Container Registry)linux/amd64andlinux/arm64platformslatest(e.g.,1.6.4andlatest)1.6.4)langflowimage to be built first🧪 Testing Strategy
Validation Performed
yaml.safe_load()How to Test (Post-Merge)
When the next Langflow release is triggered:
📋 Expected Outcome
After this PR is merged and the next release is triggered:
Docker Hub Images
langflowai/langflow-frontend:<version>+latestlangflowai/langflow-backend:<version>+latestGHCR Images
ghcr.io/langflow-ai/langflow-frontend:<version>+latestghcr.io/langflow-ai/langflow-backend:<version>+latestArchitecture Support
linux/amd64andlinux/arm64📝 Checklist
docker-build-v2.yml🔗 Related
Fixes #10215
📚 Additional Notes
docker-build.ymlworkflowThanks to @Vasyl-Prokopenko for reporting this issue and providing clear details about the impact on Helm chart deployments! Once merged, the next Langflow release will automatically publish the frontend and backend component images. 🚀
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores