From 7dd86119b1afdb9e22f88a22dd4e7635dbc16c27 Mon Sep 17 00:00:00 2001 From: "omer.roth" Date: Thu, 28 May 2026 15:21:51 +0300 Subject: [PATCH 1/4] CM-65133 upgrade and fix new issues --- cycode/cli/apps/mcp/mcp_command.py | 6 +- poetry.lock | 70 +++++++------------ pyproject.toml | 3 +- .../test_commit_range_documents.py | 32 ++++----- 4 files changed, 49 insertions(+), 62 deletions(-) diff --git a/cycode/cli/apps/mcp/mcp_command.py b/cycode/cli/apps/mcp/mcp_command.py index adfc0a3f..2967dea1 100644 --- a/cycode/cli/apps/mcp/mcp_command.py +++ b/cycode/cli/apps/mcp/mcp_command.py @@ -8,6 +8,7 @@ import uuid from typing import Annotated, Any, Optional +import anyio import typer from pathvalidate import sanitize_filepath from pydantic import Field @@ -65,7 +66,7 @@ def _get_current_executable() -> str: return 'cycode' -async def _run_cycode_command(*args: str, timeout: int = _DEFAULT_RUN_COMMAND_TIMEOUT) -> dict[str, Any]: +async def _run_cycode_command(*args: str) -> dict[str, Any]: """Run a cycode command asynchronously and return the parsed result. Args: @@ -78,6 +79,7 @@ async def _run_cycode_command(*args: str, timeout: int = _DEFAULT_RUN_COMMAND_TI verbose = ['-v'] if _is_debug_mode() else [] cmd_args = [_get_current_executable(), *verbose, '-o', 'json', *list(args)] _logger.debug('Running Cycode CLI command: %s', ' '.join(cmd_args)) + timeout = _DEFAULT_RUN_COMMAND_TIMEOUT try: process = await asyncio.create_subprocess_exec( @@ -238,7 +240,7 @@ async def _cycode_scan_tool( try: if paths: - missing = [p for p in paths if not os.path.exists(p)] + missing = [p for p in paths if not anyio.Path(p).exists()] if missing: return json.dumps({'error': f'Paths not found on disk: {missing}'}, indent=2) diff --git a/poetry.lock b/poetry.lock index eab3b4da..55ffb9da 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "altgraph" @@ -27,25 +27,23 @@ files = [ [[package]] name = "anyio" -version = "4.11.0" +version = "4.12.1" description = "High-level concurrency and networking framework on top of asyncio or Trio" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version >= \"3.10\"" files = [ - {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, - {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, + {file = "anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c"}, + {file = "anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" -sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -trio = ["trio (>=0.31.0)"] +trio = ["trio (>=0.31.0) ; python_version < \"3.10\"", "trio (>=0.32.0) ; python_version >= \"3.10\""] [[package]] name = "arrow" @@ -339,7 +337,6 @@ files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {test = "sys_platform == \"win32\""} [[package]] name = "coverage" @@ -554,11 +551,11 @@ description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main", "test"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] -markers = {main = "python_version == \"3.10\"", test = "python_version < \"3.11\""} [package.dependencies] typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} @@ -743,7 +740,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.3.6" +jsonschema-specifications = ">=2023.03.6" referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -1715,30 +1712,30 @@ files = [ [[package]] name = "ruff" -version = "0.11.7" +version = "0.15.14" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.11.7-py3-none-linux_armv6l.whl", hash = "sha256:d29e909d9a8d02f928d72ab7837b5cbc450a5bdf578ab9ebee3263d0a525091c"}, - {file = "ruff-0.11.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:dd1fb86b168ae349fb01dd497d83537b2c5541fe0626e70c786427dd8363aaee"}, - {file = "ruff-0.11.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d3d7d2e140a6fbbc09033bce65bd7ea29d6a0adeb90b8430262fbacd58c38ada"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4809df77de390a1c2077d9b7945d82f44b95d19ceccf0c287c56e4dc9b91ca64"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3a0c2e169e6b545f8e2dba185eabbd9db4f08880032e75aa0e285a6d3f48201"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49b888200a320dd96a68e86736cf531d6afba03e4f6cf098401406a257fcf3d6"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2b19cdb9cf7dae00d5ee2e7c013540cdc3b31c4f281f1dacb5a799d610e90db4"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64e0ee994c9e326b43539d133a36a455dbaab477bc84fe7bfbd528abe2f05c1e"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bad82052311479a5865f52c76ecee5d468a58ba44fb23ee15079f17dd4c8fd63"}, - {file = "ruff-0.11.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7940665e74e7b65d427b82bffc1e46710ec7f30d58b4b2d5016e3f0321436502"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:169027e31c52c0e36c44ae9a9c7db35e505fee0b39f8d9fca7274a6305295a92"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:305b93f9798aee582e91e34437810439acb28b5fc1fee6b8205c78c806845a94"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a681db041ef55550c371f9cd52a3cf17a0da4c75d6bd691092dfc38170ebc4b6"}, - {file = "ruff-0.11.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:07f1496ad00a4a139f4de220b0c97da6d4c85e0e4aa9b2624167b7d4d44fd6b6"}, - {file = "ruff-0.11.7-py3-none-win32.whl", hash = "sha256:f25dfb853ad217e6e5f1924ae8a5b3f6709051a13e9dad18690de6c8ff299e26"}, - {file = "ruff-0.11.7-py3-none-win_amd64.whl", hash = "sha256:0a931d85959ceb77e92aea4bbedfded0a31534ce191252721128f77e5ae1f98a"}, - {file = "ruff-0.11.7-py3-none-win_arm64.whl", hash = "sha256:778c1e5d6f9e91034142dfd06110534ca13220bfaad5c3735f6cb844654f6177"}, - {file = "ruff-0.11.7.tar.gz", hash = "sha256:655089ad3224070736dc32844fde783454f8558e71f501cb207485fe4eee23d4"}, + {file = "ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108"}, + {file = "ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b"}, + {file = "ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553"}, + {file = "ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6"}, + {file = "ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902"}, + {file = "ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826"}, + {file = "ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f"}, ] [[package]] @@ -1799,19 +1796,6 @@ files = [ {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, ] -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -groups = ["main"] -markers = "python_version >= \"3.10\"" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - [[package]] name = "sse-starlette" version = "3.0.2" @@ -2056,4 +2040,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.9" -content-hash = "ac37763cb9b582d1997853c1347edfdb05566fa225adf304685ecce66989fc67" +content-hash = "2164dccfdb5e79b74dbd41c228d9eda616302439ea15bda54a3da7d7c985fd40" diff --git a/pyproject.toml b/pyproject.toml index 1b43757b..a91546dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ pydantic = ">=2.11.5,<3.0.0" pathvalidate = ">=3.3.1,<4.0.0" tomli-w = ">=1.0.0,<2.0.0" tomli = {version = ">=2.0.0,<3.0.0", python = "<3.11"} +anyio = ">=4.0.0, <4.13.0" [tool.poetry.group.test.dependencies] mock = ">=4.0.3,<4.1.0" @@ -65,7 +66,7 @@ pyinstaller = {version=">=6.0.0,<7.0.0", python=">=3.9,<3.15"} dunamai = ">=1.26.1,<1.27.0" [tool.poetry.group.dev.dependencies] -ruff = "0.11.7" +ruff = "0.15.14" [tool.pytest.ini_options] log_cli = true diff --git a/tests/cli/files_collector/test_commit_range_documents.py b/tests/cli/files_collector/test_commit_range_documents.py index 0b96a0e2..999e0e0c 100644 --- a/tests/cli/files_collector/test_commit_range_documents.py +++ b/tests/cli/files_collector/test_commit_range_documents.py @@ -67,7 +67,7 @@ def test_returns_head_when_repository_has_commits(self) -> None: def test_returns_empty_tree_hash_when_repository_has_no_commits(self) -> None: """Test that an empty tree hash is returned when the repository has no commits.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, repo): result = get_safe_head_reference_for_diff(repo) expected_empty_tree_hash = consts.GIT_EMPTY_TREE_OBJECT assert result == expected_empty_tree_hash @@ -343,7 +343,7 @@ def test_diff_with_bare_repository(self) -> None: def test_diff_with_no_paths(self) -> None: """Test behavior when the diff has neither a_path nor b_path.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, repo): class MockDiff: def __init__(self) -> None: @@ -409,7 +409,7 @@ class TestGetDefaultBranchesForMergeBase: def test_environment_variable_override(self) -> None: """Test that the environment variable takes precedence.""" with ( - temporary_git_repository() as (temp_dir, repo), + temporary_git_repository() as (_temp_dir, repo), patch.dict(os.environ, {consts.CYCODE_DEFAULT_BRANCH_ENV_VAR_NAME: 'custom-main'}), ): branches = _get_default_branches_for_merge_base(repo) @@ -418,7 +418,7 @@ def test_environment_variable_override(self) -> None: def test_git_symbolic_ref_success(self) -> None: """Test getting default branch via git symbolic-ref.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo with a git interface that returns origin/main mock_repo = Mock() mock_repo.git.symbolic_ref.return_value = 'refs/remotes/origin/main' @@ -429,7 +429,7 @@ def test_git_symbolic_ref_success(self) -> None: def test_git_symbolic_ref_with_master(self) -> None: """Test getting default branch via git symbolic-ref when it's master.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo with a git interface that returns origin/master mock_repo = Mock() mock_repo.git.symbolic_ref.return_value = 'refs/remotes/origin/master' @@ -440,7 +440,7 @@ def test_git_symbolic_ref_with_master(self) -> None: def test_git_remote_show_fallback(self) -> None: """Test fallback to git remote show when symbolic-ref fails.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo where symbolic-ref fails but the remote show succeeds mock_repo = Mock() mock_repo.git.symbolic_ref.side_effect = Exception('symbolic-ref failed') @@ -459,7 +459,7 @@ def test_git_remote_show_fallback(self) -> None: def test_both_git_methods_fail_fallback_to_hardcoded(self) -> None: """Test fallback to hardcoded branches when both Git methods fail.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo where both Git methods fail mock_repo = Mock() mock_repo.git.symbolic_ref.side_effect = Exception('symbolic-ref failed') @@ -474,7 +474,7 @@ def test_both_git_methods_fail_fallback_to_hardcoded(self) -> None: def test_no_duplicates_in_branch_list(self) -> None: """Test that duplicate branches are not added to the list.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo that returns main (which is also in fallback list) mock_repo = Mock() mock_repo.git.symbolic_ref.return_value = 'refs/remotes/origin/main' @@ -486,7 +486,7 @@ def test_no_duplicates_in_branch_list(self) -> None: def test_env_var_plus_git_detection(self) -> None: """Test combination of environment variable and git detection.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): mock_repo = Mock() mock_repo.git.symbolic_ref.return_value = 'refs/remotes/origin/develop' @@ -500,7 +500,7 @@ def test_env_var_plus_git_detection(self) -> None: def test_malformed_symbolic_ref_response(self) -> None: """Test handling of malformed symbolic-ref response.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (_temp_dir, _repo): # Create a mock repo that returns a malformed response mock_repo = Mock() mock_repo.git.symbolic_ref.return_value = 'malformed-response' @@ -845,7 +845,7 @@ def _make_linear_history(self, repo: Repo, base_dir: str) -> tuple[str, str, str def test_two_dot_linear_history(self) -> None: """For 'A..C', expect (A,C) in linear history.""" with temporary_git_repository() as (temp_dir, repo): - a, b, c = self._make_linear_history(repo, temp_dir) + a, _b, c = self._make_linear_history(repo, temp_dir) parsed_from, parsed_to, separator = parse_commit_range(f'{a}..{c}', temp_dir) assert (parsed_from, parsed_to, separator) == (a, c, '..') @@ -853,7 +853,7 @@ def test_two_dot_linear_history(self) -> None: def test_three_dot_linear_history(self) -> None: """For 'A...C' in linear history, expect (A,C).""" with temporary_git_repository() as (temp_dir, repo): - a, b, c = self._make_linear_history(repo, temp_dir) + a, _b, c = self._make_linear_history(repo, temp_dir) parsed_from, parsed_to, separator = parse_commit_range(f'{a}...{c}', temp_dir) assert (parsed_from, parsed_to, separator) == (a, c, '...') @@ -861,7 +861,7 @@ def test_three_dot_linear_history(self) -> None: def test_open_right_linear_history(self) -> None: """For 'A..', expect (A,HEAD=C).""" with temporary_git_repository() as (temp_dir, repo): - a, b, c = self._make_linear_history(repo, temp_dir) + a, _b, c = self._make_linear_history(repo, temp_dir) parsed_from, parsed_to, separator = parse_commit_range(f'{a}..', temp_dir) assert (parsed_from, parsed_to, separator) == (a, c, '..') @@ -869,7 +869,7 @@ def test_open_right_linear_history(self) -> None: def test_open_left_linear_history(self) -> None: """For '..C' where HEAD==C, expect (HEAD=C,C).""" with temporary_git_repository() as (temp_dir, repo): - a, b, c = self._make_linear_history(repo, temp_dir) + _a, _b, c = self._make_linear_history(repo, temp_dir) parsed_from, parsed_to, separator = parse_commit_range(f'..{c}', temp_dir) assert (parsed_from, parsed_to, separator) == (c, c, '..') @@ -877,7 +877,7 @@ def test_open_left_linear_history(self) -> None: def test_single_commit_spec(self) -> None: """For 'A', expect (A,HEAD=C).""" with temporary_git_repository() as (temp_dir, repo): - a, b, c = self._make_linear_history(repo, temp_dir) + a, _b, c = self._make_linear_history(repo, temp_dir) parsed_from, parsed_to, separator = parse_commit_range(a, temp_dir) assert (parsed_from, parsed_to, separator) == (a, c, '..') @@ -935,7 +935,7 @@ def test_parse_all_for_empty_remote_scenario_with_two_commits(self) -> None: def test_parse_all_with_empty_repository_returns_none(self) -> None: """Test that '--all' returns None when repository has no commits.""" - with temporary_git_repository() as (temp_dir, repo): + with temporary_git_repository() as (temp_dir, _repo): # Empty repository with no commits parsed_from, parsed_to, separator = parse_commit_range('--all', temp_dir) # Should return None, None, None when HEAD doesn't exist From 6f01812c563b0ac6662eea0e12b4ad3fa748cd60 Mon Sep 17 00:00:00 2001 From: "omer.roth" Date: Thu, 28 May 2026 15:27:53 +0300 Subject: [PATCH 2/4] CM-65133 ignore ruff rule --- cycode/cli/apps/mcp/mcp_command.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cycode/cli/apps/mcp/mcp_command.py b/cycode/cli/apps/mcp/mcp_command.py index 2967dea1..f9744a77 100644 --- a/cycode/cli/apps/mcp/mcp_command.py +++ b/cycode/cli/apps/mcp/mcp_command.py @@ -65,8 +65,8 @@ def _get_current_executable() -> str: return 'cycode' - -async def _run_cycode_command(*args: str) -> dict[str, Any]: +# ruff: disable[ASYNC109] +async def _run_cycode_command(*args: str, timeout: int = _DEFAULT_RUN_COMMAND_TIMEOUT) -> dict[str, Any]: """Run a cycode command asynchronously and return the parsed result. Args: @@ -79,7 +79,6 @@ async def _run_cycode_command(*args: str) -> dict[str, Any]: verbose = ['-v'] if _is_debug_mode() else [] cmd_args = [_get_current_executable(), *verbose, '-o', 'json', *list(args)] _logger.debug('Running Cycode CLI command: %s', ' '.join(cmd_args)) - timeout = _DEFAULT_RUN_COMMAND_TIMEOUT try: process = await asyncio.create_subprocess_exec( @@ -109,7 +108,7 @@ async def _run_cycode_command(*args: str) -> dict[str, Any]: return {'error': f'Command timeout after {timeout} seconds'} except Exception as e: return {'error': f'Failed to run command: {e!s}'} - +# ruff: enable[ASYNC109] def _sanitize_file_path(file_path: str) -> str: """Sanitize file path to prevent path traversal and other security issues. From 92dfd3e7c5182b8be90dcc48ccd9913d49983632 Mon Sep 17 00:00:00 2001 From: "omer.roth" Date: Thu, 28 May 2026 15:40:30 +0300 Subject: [PATCH 3/4] CM-65133 formatting --- cycode/cli/apps/mcp/mcp_command.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cycode/cli/apps/mcp/mcp_command.py b/cycode/cli/apps/mcp/mcp_command.py index f9744a77..9be62252 100644 --- a/cycode/cli/apps/mcp/mcp_command.py +++ b/cycode/cli/apps/mcp/mcp_command.py @@ -65,6 +65,7 @@ def _get_current_executable() -> str: return 'cycode' + # ruff: disable[ASYNC109] async def _run_cycode_command(*args: str, timeout: int = _DEFAULT_RUN_COMMAND_TIMEOUT) -> dict[str, Any]: """Run a cycode command asynchronously and return the parsed result. @@ -108,8 +109,11 @@ async def _run_cycode_command(*args: str, timeout: int = _DEFAULT_RUN_COMMAND_TI return {'error': f'Command timeout after {timeout} seconds'} except Exception as e: return {'error': f'Failed to run command: {e!s}'} + + # ruff: enable[ASYNC109] + def _sanitize_file_path(file_path: str) -> str: """Sanitize file path to prevent path traversal and other security issues. From 2f87a53cb99782f8d8acb67e9a96e8072485b5b5 Mon Sep 17 00:00:00 2001 From: "omer.roth" Date: Thu, 28 May 2026 15:45:34 +0300 Subject: [PATCH 4/4] CM-65133 added await to anyio path check --- cycode/cli/apps/mcp/mcp_command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cycode/cli/apps/mcp/mcp_command.py b/cycode/cli/apps/mcp/mcp_command.py index 9be62252..517f514f 100644 --- a/cycode/cli/apps/mcp/mcp_command.py +++ b/cycode/cli/apps/mcp/mcp_command.py @@ -243,7 +243,7 @@ async def _cycode_scan_tool( try: if paths: - missing = [p for p in paths if not anyio.Path(p).exists()] + missing = [p for p in paths if not await anyio.Path(p).exists()] if missing: return json.dumps({'error': f'Paths not found on disk: {missing}'}, indent=2)