Skip to content

Conversation

@Sahilbhatane
Copy link
Collaborator

@Sahilbhatane Sahilbhatane commented Dec 10, 2025

Related Issue

Closes #269

Summary

Implemented parallel task execution system for Cortex that enables concurrent execution of independent installation steps, providing 2-3x speedup for complex multi-step installations.

Key Features Implemented

1. Core Parallel Execution Engine (install_parallel.py)

  • Async task execution with dependency graph resolution
  • Intelligent task scheduling based on dependencies
  • Concurrent execution of independent tasks (up to 4 workers)
  • Comprehensive error handling and timeout management
  • Security validation with dangerous command pattern detection
  • Real-time progress tracking with start/end times and duration metrics

2. CLI Integration (cli.py)

  • Added --parallel flag to cortex install command
  • Integrated parallel execution into existing installation workflow
  • Maintained backward compatibility with sequential execution (default)
  • Code quality improvements:
  • Removed unused imports (subprocess, validate_installation_id, ValidationError)
  • Fixed type safety issues (None checks before error handling)
  • Moved inline imports to module level (shutil, traceback, urllib.request)
  • Cleaned up unused parser variables

3. Comprehensive Test Suite (test_parallel_install.py)

  • 13 test cases covering all scenarios (100% passing)
  • Test coverage includes:
  • Parallel vs sequential execution performance
  • Dependency order enforcement
  • Failure handling and task skipping
  • Diamond dependency graphs
  • Timeout handling
  • Log callback functionality
  • Edge cases (empty commands, invalid inputs)

test as user

# Sequential execution (default)
cortex install docker --execute

# Parallel execution (new feature)
cortex install docker --execute --parallel

Files Changed: 4 files -

  • New Files: 2 (install_parallel.py, test_parallel_install.py)
  • Test Coverage: 13/13 tests passing
  • Code Quality: All linting errors fixed, type-safe implementation

Checklist

  • Tests pass (pytest tests/)
  • PR title format: [#XX] Description
  • MVP label added if closing MVP issue

#video
https://drive.google.com/file/d/1GIzYu3dzfB0w2S_LU3lH7SgXsZAUCx2s/view?usp=sharing

Summary by CodeRabbit

  • New Features
    • Added a --parallel option to the install command enabling parallel installs with dependency-aware scheduling and per-task status, timing, output, and logging.
  • Bug Fixes
    • Validation errors now only print when an error message is present.
  • Tests
    • Added comprehensive tests for parallel execution, dependencies, timeouts, failure propagation, logging, and task metadata.
  • Chores
    • Added security pattern definitions, updated dependencies, and removed a CI workflow.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings December 10, 2025 13:46
@Sahilbhatane Sahilbhatane added the MVP Killer feature sprint label Dec 10, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a dependency-aware asyncio-based parallel installer and a CLI flag --parallel; introduces task/status dataclasses, unsafe-command validation, timeouts, per-task logging, and tests validating parallelism, dependencies, failures, and timeouts.

Changes

Cohort / File(s) Summary
CLI integration
cortex/cli.py
Added --parallel flag, updated CortexCLI.install(..., parallel: bool = False), and wired CLI to call the parallel path while preserving the sequential fallback.
Parallel execution framework
cortex/install_parallel.py
New module: TaskStatus enum, ParallelTask dataclass, run_single_task() (async subprocess via threadpool, safety checks, timeout, logging) and run_parallel_install() (dependency-aware scheduler, parallel execution, stop-on-error, returns (all_success, tasks)).
Validators
cortex/validators.py
Added DANGEROUS_PATTERNS (list of regex strings) used to block unsafe commands.
Coordinator update
cortex/coordinator.py
Replaced in-file dangerous-patterns with import from cortex.validators (no behavior change beyond source of patterns).
Tests
tests/installer/__init__.py, tests/installer/test_parallel_install.py
New test package and comprehensive tests covering parallel execution, dependency graphs, failure propagation, timeouts, descriptions, logs, and task metadata.
Dependencies
requirements.txt
Added PyYAML>=6.0.0.
CI workflow
.github/workflows/codeql.yml
Removed CodeQL workflow file.

Sequence Diagram(s)

sequenceDiagram
    actor User as CLI User
    participant CLI as cortex/cli.py\n(CortexCLI.install)
    participant Parallel as cortex/install_parallel.py\n(run_parallel_install)
    participant Scheduler as Scheduler\n(task graph)
    participant Worker as Worker\n(threadpool subprocess)
    participant Log as Log Callback

    User->>CLI: run "cortex install --parallel"
    CLI->>CLI: parse args, build commands/descriptions
    CLI->>Parallel: run_parallel_install(commands, descriptions, deps)
    Parallel->>Scheduler: build task graph & validate commands
    loop while tasks remain
        Scheduler->>Scheduler: select ready tasks (deps satisfied)
        par execute ready tasks
            Scheduler->>Worker: schedule run_single_task(task)
            Worker->>Log: emit "Starting task"
            Worker->>Worker: execute subprocess (threadpool, timeout)
            Worker->>Log: emit "Finished/Failed task"
            Worker->>Scheduler: report status (SUCCESS/FAILED)
        end
        alt failure + stop_on_error
            Scheduler->>Scheduler: mark dependents SKIPPED
        end
    end
    Parallel->>CLI: return (all_success, tasks[])
    CLI->>User: print summary, exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on:
    • concurrency/scheduling correctness in cortex/install_parallel.py (ready-task detection, dependency handling, skip/cancel logic),
    • timeout and subprocess error handling in run_single_task(),
    • safety validation using DANGEROUS_PATTERNS,
    • reliability/flakiness of timing-based tests in tests/installer/test_parallel_install.py.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • dhvll

Poem

🐰 Hopping through tasks with nimble feet,

Commands aligned, each dependency neat,
Async carrots fetched in parallel light,
Timeouts guarded, logs glowing bright,
A rabbit cheers — installs take flight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive All changes are directly related to implementing parallel task execution. The PyYAML dependency addition and removal of the CodeQL workflow appear to be necessary supporting changes but may warrant clarification. Clarify why PyYAML was added (not mentioned in requirements) and explain the CodeQL workflow removal to ensure these are intentional scope changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main change: adding parallel task execution capabilities to the installation system for multi-step installs.
Description check ✅ Passed The PR description is comprehensive and mostly complete, with a clear summary of implemented features, test coverage, file changes, and a completed checklist following the template.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #269: parallel task execution with dependency graph resolution, concurrent execution of independent tasks, real-time progress tracking, and CLI --parallel flag exposure.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
tests/installer/test_parallel_install.py (2)

16-24: Consider using sys.executable instead of hard-coded python

These tests shell out to "python -c ...", which can be brittle on systems where the interpreter is only exposed as python3 or via a venv path. Using sys.executable (quoted appropriately) would make the tests more robust across environments. Same applies to other commands in this file.


236-257: Unused tasks variable in log callback test

In test_log_callback_called, the unpacked tasks result is never used:

success, tasks = await run_parallel_install(...)

This triggers Ruff/Sonar warnings. Rename to _tasks or _ to signal intentional discard:

-            success, tasks = await run_parallel_install(
+            success, _tasks = await run_parallel_install(
                 commands,
                 timeout=10,
                 log_callback=log_callback
             )
cortex/cli.py (1)

115-301: CortexCLI.install is very large; consider extracting helpers

Static analysis flags very high cognitive complexity here. The method now handles:

  • Validation, API key selection, and interpreter setup
  • History bookkeeping
  • Dry-run vs execute
  • Sequential and parallel execution flows, each with their own logging and error handling

Longer term, consider splitting into helpers (e.g. _plan_install, _run_parallel, _run_sequential) to make future changes around dependency-aware parallelism less painful.

cortex/install_parallel.py (2)

73-81: Minor: static f-string for error message

task.error = f"Command blocked: matches dangerous pattern"

Since there are no placeholders, this doesn’t need to be an f-string:

-            task.error = f"Command blocked: matches dangerous pattern"
+            task.error = "Command blocked: matches dangerous pattern"

This also silences Ruff’s F541 warning.


82-97: Use get_running_loop() instead of get_event_loop() in async context

Inside an async function, asyncio.get_running_loop() is the preferred API:

-        loop = asyncio.get_event_loop()
+        loop = asyncio.get_running_loop()

This is more future-proof against changes in event-loop policy and matches current asyncio best practices.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1c17ea and ef7f8cc.

📒 Files selected for processing (4)
  • cortex/cli.py (8 hunks)
  • cortex/install_parallel.py (1 hunks)
  • tests/installer/__init__.py (1 hunks)
  • tests/installer/test_parallel_install.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
tests/installer/test_parallel_install.py (1)
cortex/install_parallel.py (4)
  • run_parallel_install (131-253)
  • ParallelTask (20-35)
  • TaskStatus (11-16)
  • duration (32-35)
cortex/install_parallel.py (1)
tests/installer/test_parallel_install.py (1)
  • log_callback (242-243)
cortex/cli.py (3)
cortex/validators.py (1)
  • validate_install_request (72-99)
cortex/coordinator.py (2)
  • execute (252-299)
  • InstallationCoordinator (65-350)
cortex/install_parallel.py (1)
  • run_parallel_install (131-253)
🪛 GitHub Check: SonarCloud Code Analysis
tests/installer/test_parallel_install.py

[warning] 245-245: Replace the unused local variable "tasks" with "_".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAQFNR_PctvIblpk&open=AZsIhAQFNR_PctvIblpk&pullRequest=288

cortex/install_parallel.py

[warning] 220-220: Remove this unnecessary list() call on an already iterable object.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpj&open=AZsIhAP6NR_PctvIblpj&pullRequest=288


[failure] 88-88: Use an async subprocess call in this async function instead of a synchronous one.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpf&open=AZsIhAP6NR_PctvIblpf&pullRequest=288


[failure] 38-38: Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpd&open=AZsIhAP6NR_PctvIblpd&pullRequest=288


[failure] 131-131: Refactor this function to reduce its Cognitive Complexity from 69 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblph&open=AZsIhAP6NR_PctvIblph&pullRequest=288


[warning] 38-38: Remove this "timeout" parameter and use a timeout context manager instead.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpc&open=AZsIhAP6NR_PctvIblpc&pullRequest=288


[warning] 193-193: Remove this unnecessary list() call on an already iterable object.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpi&open=AZsIhAP6NR_PctvIblpi&pullRequest=288


[warning] 135-135: Remove this "timeout" parameter and use a timeout context manager instead.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpg&open=AZsIhAP6NR_PctvIblpg&pullRequest=288


[warning] 76-76: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAP6NR_PctvIblpe&open=AZsIhAP6NR_PctvIblpe&pullRequest=288

cortex/cli.py

[failure] 115-115: Refactor this function to reduce its Cognitive Complexity from 103 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAKmNR_PctvIblpb&open=AZsIhAKmNR_PctvIblpb&pullRequest=288


[failure] 235-235: Define a constant instead of duplicating this literal "Installation failed" 4 times.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAKmNR_PctvIblpa&open=AZsIhAKmNR_PctvIblpa&pullRequest=288

🪛 Ruff (0.14.8)
tests/installer/test_parallel_install.py

245-245: Unpacked variable tasks is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

cortex/install_parallel.py

76-76: f-string without any placeholders

Remove extraneous f prefix

(F541)


88-88: subprocess call with shell=True identified, security issue

(S602)


122-122: Do not catch blind exception: Exception

(BLE001)


157-157: Avoid specifying long messages outside the exception class

(TRY003)

cortex/cli.py

200-200: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


252-252: Do not catch blind exception: Exception

(BLE001)


255-255: Use explicit conversion flag

Replace with conversion flag

(RUF010)

⏰ 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). (1)
  • GitHub Check: Agent
🔇 Additional comments (6)
tests/installer/__init__.py (1)

1-1: Package marker is fine

Simple docstring-only __init__ cleanly declares the tests package; no issues here.

tests/installer/test_parallel_install.py (1)

13-322: Parallel install tests give strong behavioral coverage

The suite exercises timing, dependency ordering (including diamond graphs), failure propagation, timeouts, empty inputs, per-task metadata, and log callbacks against the public run_parallel_install API. This is a solid baseline for the new parallel executor.

cortex/cli.py (2)

188-257: Parallel branch error handling and history updates look consistent with sequential path

The new parallel execution branch mirrors the sequential flow by:

  • Printing a clear success message and total duration on success.
  • Updating InstallationHistory with SUCCESS/FAILED and including an error message where available.
  • Emitting rollback/history hints for the user.

This keeps user-visible behavior and history records consistent between modes. The inline parallel_log_callback integration with cx_print also looks good.


115-176: Parallel install path lacks dependency tracking for sequenced operations

The install method calls run_parallel_install without a dependency graph or ordering constraints. This risks incorrect execution order for multi-step installations where later steps depend on earlier ones completing first (e.g., apt update before apt install, or service configuration before service start).

Unless CommandInterpreter.parse filters commands to return only truly independent steps, the --parallel flag should either:

  • Pass an explicit dependency graph via the dependencies parameter to preserve required ordering, or
  • Implement conservative defaults that only parallelize clearly safe groupings

Current behavior treats all commands as independent, which is unsafe for typical system installations.

cortex/install_parallel.py (2)

19-35: Task model and duration tracking are well structured

ParallelTask cleanly encapsulates per-task metadata (status, output, timing), and duration() provides a simple derived metric for higher-level reporting. This structure aligns well with how the CLI and tests consume task data.


58-71: Dangerous-command patterns duplicated from sequential path

run_single_task defines its own DANGEROUS_PATTERNS list. The sequential InstallationCoordinator already uses a global DANGEROUS_PATTERNS set for exactly this purpose. Duplicating the patterns here risks the two paths drifting over time, so parallel installs might allow commands that sequential installs would block (or vice versa), weakening your safety guarantees.

It would be better to centralize these patterns, for example by importing the existing constant or moving them to a shared module used by both coordinator and parallel executor.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a parallel task execution system for Cortex installations, enabling concurrent execution of independent installation steps. The implementation introduces a new async-based parallel execution engine alongside the existing sequential coordinator, with CLI integration via a --parallel flag.

Key Changes

  • New async parallel execution engine (install_parallel.py) with dependency graph resolution, concurrent task execution (max 4 workers), and security validation matching the sequential coordinator
  • CLI integration adds --parallel flag to the install command while maintaining backward compatibility with sequential execution as the default
  • Comprehensive test suite with 13 test cases covering parallel execution, dependency handling, failure scenarios, and edge cases

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 16 comments.

File Description
cortex/install_parallel.py New parallel execution engine with async task scheduling, dependency resolution, security validation, and timeout handling
cortex/cli.py Added --parallel flag support, integrated parallel execution path, cleaned up unused imports and improved None-checking in error handling
tests/installer/test_parallel_install.py Comprehensive test suite covering parallel execution, dependency ordering, failure handling, timeouts, and integration scenarios
tests/installer/__init__.py Package initialization file for installer tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Sahilbhatane Sahilbhatane self-assigned this Dec 10, 2025
@Sahilbhatane Sahilbhatane linked an issue Dec 11, 2025 that may be closed by this pull request
8 tasks
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (7)
cortex/validators.py (1)

12-26: Good consolidation of dangerous patterns; consider strengthening the rm -rf pattern.

Centralizing DANGEROUS_PATTERNS in validators.py is a good approach for maintainability. However, the rm -rf pattern at line 14 might miss some dangerous variants:

  • rm -rf /* (the pattern expects a space before / or *, but /* is a single token)
  • rm -rf ~ or rm -rf $HOME

Consider a more comprehensive pattern:

 DANGEROUS_PATTERNS = [
-    r'rm\s+-rf\s+[/\*]',
+    r'rm\s+-rf\s+(/|~|\*|\$)',
     r'rm\s+--no-preserve-root',

Also consider adding >>\s*/etc/ for append redirects if that's a concern.

tests/installer/test_parallel_install.py (1)

15-38: Consider using pytest-asyncio for cleaner async tests.

The current pattern of wrapping async code in asyncio.run() works, but using pytest-asyncio with @pytest.mark.asyncio decorator would be more idiomatic and reduce boilerplate:

import pytest

@pytest.mark.asyncio
async def test_parallel_runs_faster_than_sequential(self):
    """Verify that parallel execution is faster for independent tasks."""
    commands = [...]
    success, tasks = await run_parallel_install(commands, timeout=10)
    # assertions...

This would require adding pytest-asyncio to dev dependencies.

cortex/cli.py (2)

188-191: Move parallel execution imports to module level.

The asyncio and run_parallel_install imports are done inline within the conditional block. While this works, it's generally better practice to have imports at the module level for clarity and to avoid repeated import overhead if the function is called multiple times.

Add these imports at the top of the file with other imports:

import asyncio
from cortex.install_parallel import run_parallel_install

Then remove lines 190-191.


252-256: Consider catching more specific exceptions.

The broad Exception catch is flagged by static analysis. While it's acceptable for a top-level error boundary, you could improve error reporting by catching more specific exceptions first.

+                except asyncio.CancelledError:
+                    if install_id:
+                        history.update_installation(install_id, InstallationStatus.FAILED, "Operation cancelled")
+                    self._print_error("Parallel execution cancelled")
+                    return 130
                 except Exception as e:
                     if install_id:
                         history.update_installation(install_id, InstallationStatus.FAILED, str(e))
-                    self._print_error(f"Parallel execution failed: {str(e)}")
+                    self._print_error(f"Parallel execution failed: {e!s}")
                     return 1
cortex/install_parallel.py (3)

103-117: Consider catching subprocess.TimeoutExpired explicitly.

The subprocess.run() call can raise subprocess.TimeoutExpired if the internal timeout fires before the asyncio timeout. While the generic Exception handler will catch it, explicit handling would provide clearer error messages consistent with coordinator.py.

     except asyncio.TimeoutError:
         task.status = TaskStatus.FAILED
         task.error = f"Command timed out after {timeout} seconds"
         task.end_time = time.time()
         if log_callback:
             log_callback(f"Finished {task.name} (failed)", "error")
         return False
     
+    except subprocess.TimeoutExpired:
+        task.status = TaskStatus.FAILED
+        task.error = f"Command timed out after {timeout} seconds"
+        task.end_time = time.time()
+        if log_callback:
+            log_callback(f"Finished {task.name} (failed)", "error")
+        return False
+
     except Exception as e:

176-176: Consider making max_workers configurable.

The thread pool is hardcoded to 4 workers. For systems with more cores or when running many independent tasks, this could be a bottleneck. Consider exposing this as a parameter with a sensible default.

 async def run_parallel_install(
     commands: List[str],
     descriptions: Optional[List[str]] = None,
     dependencies: Optional[Dict[int, List[int]]] = None,
     timeout: int = 300,
     stop_on_error: bool = True,
-    log_callback: Optional[Callable] = None
+    log_callback: Optional[Callable] = None,
+    max_workers: int = 4
 ) -> tuple:
     ...
-    executor = concurrent.futures.ThreadPoolExecutor(max_workers=4)
+    executor = concurrent.futures.ThreadPoolExecutor(max_workers=max_workers)

120-141: Improve docstring return type annotation.

The docstring states the return type as tuple but should be more specific to match best practices and aid IDE tooling. A previous review also flagged this.

     Returns:
-        tuple[bool, List[ParallelTask]]: Success status and list of all tasks
+        Tuple[bool, List[ParallelTask]]: (all_success, task_list) where all_success
+            is True if no tasks failed, and task_list contains all ParallelTask objects.
     """

And update the return type hint:

-) -> tuple:
+) -> Tuple[bool, List[ParallelTask]]:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef7f8cc and e96966f.

📒 Files selected for processing (7)
  • .github/workflows/codeql.yml (0 hunks)
  • cortex/cli.py (8 hunks)
  • cortex/coordinator.py (1 hunks)
  • cortex/install_parallel.py (1 hunks)
  • cortex/validators.py (1 hunks)
  • requirements.txt (1 hunks)
  • tests/installer/test_parallel_install.py (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/codeql.yml
🧰 Additional context used
🧬 Code graph analysis (2)
tests/installer/test_parallel_install.py (3)
src/sandbox_executor.py (1)
  • success (52-54)
cortex/logging_system.py (1)
  • error (219-221)
cortex/coordinator.py (1)
  • duration (36-39)
cortex/install_parallel.py (6)
cortex/cli.py (1)
  • status (620-675)
cortex/logging_system.py (1)
  • error (219-221)
cortex/coordinator.py (1)
  • duration (36-39)
tests/installer/test_parallel_install.py (1)
  • log_callback (237-238)
src/sandbox_executor.py (2)
  • failed (57-59)
  • success (52-54)
src/progress_tracker.py (1)
  • cancel (464-500)
🪛 Ruff (0.14.8)
cortex/cli.py

200-200: String contains ambiguous (INFORMATION SOURCE). Did you mean i (LATIN SMALL LETTER I)?

(RUF001)


252-252: Do not catch blind exception: Exception

(BLE001)


255-255: Use explicit conversion flag

Replace with conversion flag

(RUF010)

cortex/install_parallel.py

77-77: subprocess call with shell=True identified, security issue

(S602)


111-111: Do not catch blind exception: Exception

(BLE001)


146-146: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (9)
cortex/coordinator.py (1)

12-14: LGTM!

Clean refactor to import DANGEROUS_PATTERNS from the shared validators module instead of defining it locally. This ensures consistent security validation across both sequential and parallel execution paths.

tests/installer/test_parallel_install.py (1)

1-9: LGTM! Comprehensive test coverage for parallel execution.

The test suite covers key scenarios including dependency ordering, failure propagation, timeout handling, and diamond dependency graphs. The use of python -c commands makes tests cross-platform compatible.

cortex/cli.py (3)

213-219: Good fix for duration calculation.

The duration calculation now properly handles None values using generator expressions with default=None and explicit is not None checks. This addresses the previous review feedback about incorrect handling when end_time could be 0 or None.


892-898: Underscore prefix addresses unused variable warnings.

The parser variables are now prefixed with _ to indicate they're intentionally unused. This is a common Python convention and addresses the static analysis warnings from previous reviews.


905-905: LGTM! --parallel flag properly integrated.

The --parallel flag is correctly added to the install subparser and properly passed through to the install() method.

cortex/install_parallel.py (3)

10-10: Good use of shared DANGEROUS_PATTERNS.

Importing DANGEROUS_PATTERNS from the centralized validators module ensures consistent security validation and addresses the previous review feedback about code duplication.


69-86: Good timeout handling with dual timeout approach.

The implementation correctly uses both subprocess.run(..., timeout=timeout) for the process itself and asyncio.wait_for(..., timeout=timeout + 5) for the async wrapper. The comment about shell=True addresses the previous review feedback. The 5-second buffer for asyncio overhead is reasonable.


194-205: Good deadlock/cycle detection implementation.

This addresses the critical issue from previous reviews about potential infinite loops when tasks have unresolvable dependencies. The implementation correctly detects when no progress can be made and marks remaining tasks as skipped.

requirements.txt (1)

12-12: No action needed—PyYAML is already used in the codebase.

PyYAML is imported and used in src/config_manager.py and cortex/user_preferences.py, making it a legitimate dependency. Adding PyYAML>=6.0.0 to requirements.txt is appropriate even though it's not imported directly by the changed files in this PR.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
cortex/cli.py (5)

181-188: install method complexity grows; consider extracting helpers

Adding the parallel: bool flag and upfront validate_install_request call is correct, but CortexCLI.install is now very large (as Sonar notes). Consider extracting helpers (e.g. _run_install_sequential, _run_install_parallel, _record_install_success/failure) to reduce cognitive complexity and make future changes safer.


242-247: Sequential vs parallel execution share duplicated failure-handling logic

The sequential and parallel branches both construct error messages, update InstallationHistory, and print very similar “Installation failed” output. This duplication is what Sonar is flagging and makes changes error-prone. Consider centralizing this into a small helper that takes install_id and an optional error_msg, updates history, and prints the common messaging.

+    def _handle_install_failure(self, history, install_id, error_msg: str | None = None):
+        message = error_msg or "Installation failed"
+        if install_id:
+            history.update_installation(install_id, InstallationStatus.FAILED, message)
+            print(f"\n📝 Installation recorded (ID: {install_id})")
+            print(f"   View details: cortex history show {install_id}")
+        self._print_error("Installation failed")
+        if error_msg:
+            print(f"  Error: {error_msg}", file=sys.stderr)

Then call _handle_install_failure(...) from both the parallel and sequential failure paths.

Also applies to: 324-366


545-546: Avoid unconditional tracebacks in CLI error path

Printing a full traceback for edit_pref errors can be noisy for users and may leak internal details. Since you already have a verbose mode, consider gating the traceback on self.verbose (or logging it instead).

-        except Exception as e:
-            self._print_error(f"Failed to edit preferences: {str(e)}")
-            traceback.print_exc()
+        except Exception as e:
+            self._print_error(f"Failed to edit preferences: {str(e)}")
+            if self.verbose:
+                traceback.print_exc()

576-601: Tighten Ollama/config/history status checks (unused var and f-string nits)

The Ollama and config/history status additions are useful; a few small cleanups will also satisfy the static analysis hints:

  • Drop the unused resp binding from urlopen.
  • Remove f-strings where no interpolation occurs.
-        ollama_host = os.environ.get('OLLAMA_HOST', 'http://localhost:11434')
-        try:
-            req = urllib.request.Request(f"{ollama_host}/api/tags", method='GET')
-            with urllib.request.urlopen(req, timeout=2) as resp:
-                cx_print(f"Ollama: [bold]Running[/bold] ({ollama_host})", "success")
-        except Exception:
-            cx_print(f"Ollama: [bold]Not running[/bold]", "info")
-            cx_print("  Start: ollama serve", "info")
+        ollama_host = os.environ.get('OLLAMA_HOST', 'http://localhost:11434')
+        try:
+            req = urllib.request.Request(f"{ollama_host}/api/tags", method="GET")
+            with urllib.request.urlopen(req, timeout=2):
+                cx_print(f"Ollama: [bold]Running[/bold] ({ollama_host})", "success")
+        except Exception:
+            cx_print("Ollama: [bold]Not running[/bold]", "info")
+            cx_print("  Start: ollama serve", "info")
@@
-        config_path = os.path.expanduser('~/.cortex/config.json')
+        config_path = os.path.expanduser("~/.cortex/config.json")
         if os.path.exists(config_path):
             cx_print(f"Config: {config_path}", "info")
         else:
-            cx_print(f"Config: Not created yet", "info")
+            cx_print("Config: Not created yet", "info")
@@
-        history_path = os.path.expanduser('~/.cortex/history.db')
+        history_path = os.path.expanduser("~/.cortex/history.db")
         if os.path.exists(history_path):
             cx_print(f"History: {history_path}", "info")
         else:
-            cx_print(f"History: Not created yet", "info")
+            cx_print("History: Not created yet", "info")

680-681: --parallel flag wiring is correct; optional UX tweak with --execute

The CLI correctly plumbs --parallel into CortexCLI.install(..., parallel=args.parallel), and the flag only has effect when --execute is set (since the parallel/sequential branch is under if execute:). Behavior is safe; if you want to make it clearer to users, you could either mention in the help text that --parallel only applies with --execute, or enforce that combination via argparse (e.g., documenting or validating in install).

Also applies to: 737-737

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e96966f and 0c2c28b.

📒 Files selected for processing (1)
  • cortex/cli.py (10 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cortex/cli.py (2)
cortex/coordinator.py (2)
  • execute (238-285)
  • InstallationCoordinator (51-336)
cortex/install_parallel.py (1)
  • run_parallel_install (120-269)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py

[failure] 181-181: Refactor this function to reduce its Cognitive Complexity from 101 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAKmNR_PctvIblpb&open=AZsIhAKmNR_PctvIblpb&pullRequest=288


[failure] 301-301: Define a constant instead of duplicating this literal "Installation failed" 4 times.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsIhAKmNR_PctvIblpa&open=AZsIhAKmNR_PctvIblpa&pullRequest=288


[warning] 583-583: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsNK1Y5fMeRJ4F2fFX_&open=AZsNK1Y5fMeRJ4F2fFX_&pullRequest=288


[warning] 580-580: Remove the unused local variable "resp".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsNK1Y5fMeRJ4F2fFX-&open=AZsNK1Y5fMeRJ4F2fFX-&pullRequest=288


[warning] 594-594: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsNK1Y5fMeRJ4F2fFYA&open=AZsNK1Y5fMeRJ4F2fFYA&pullRequest=288


[warning] 600-600: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZsNK1Y5fMeRJ4F2fFYB&open=AZsNK1Y5fMeRJ4F2fFYB&pullRequest=288

🔇 Additional comments (3)
cortex/cli.py (3)

65-71: API key error handling now avoids blank error lines

Conditionally printing the validation error only when error is non-empty prevents empty “Error:” lines while preserving existing behavior. This looks good.


254-287: Parallel execution integration and duration calculation look correct

The asyncio.run(run_parallel_install(...)) integration, logging callback, and None-safe duration calculation via max_end/min_start are coherent and handle the earlier edge cases (no end_time/start_time) without producing bogus durations. The branch correctly only uses total_duration on success.


694-701: Preferences subcommands and parser wiring line up with implementation

The check-pref and edit-pref subparsers, including the validate action, align with the methods implemented on CortexCLI and make those flows reachable from the CLI. Argument shapes look consistent with how check_pref and edit_pref use them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

MVP Killer feature sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parallel Task Execution for Multi-Step Installs Batch Operations & Parallel Execution

1 participant