Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 0 additions & 143 deletions apps/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions apps/frontend/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ app.whenReady().then(() => {
autoBuildPath: validAutoBuildPath
});
agentManager.configure(settings.pythonPath, validAutoBuildPath);
// Also configure pythonEnvManager so venv is created with the right Python
Comment on lines 203 to +206

Choose a reason for hiding this comment

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

🟡 MEDIUM - Console.warn logging settings with filesystem paths
Agent: quality

Category: quality

Description:
console.warn() at lines 201-204 logs pythonPath and autoBuildPath settings. Contains filesystem paths but in Electron main process (not browser DevTools).

Suggestion:
Wrap with DEBUG environment check: if (process.env.DEBUG === '1' || process.env.DEBUG === 'true') { console.warn(...) }

Confidence: 65%
Rule: quality_avoid_console_in_production
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

if (settings.pythonPath) {
pythonEnvManager.configure(settings.pythonPath);
}
Copy link

Choose a reason for hiding this comment

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

Settings change doesn't update pythonEnvManager configuration

The PR adds pythonEnvManager.configure() at startup in index.ts but the corresponding call is missing from the SETTINGS_SAVE handler in settings-handlers.ts. When a user changes pythonPath via the UI, agentManager.configure() is called but pythonEnvManager.configure() is not. This creates inconsistent behavior where any venv created after a runtime settings change will use the old configured Python path (or auto-detection) instead of the newly configured one.

Fix in Cursor Fix in Web

}
} catch (error: unknown) {
// ENOENT means no settings file yet - that's fine, use defaults
Comment on lines 211 to 212

Choose a reason for hiding this comment

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

🔵 LOW - Error narrowing is acceptable but verbose
Agent: react

Category: quality

Description:
Error narrowing pattern for ENOENT check is correct for Node.js but verbose. This is a common pattern in Node.js and not incorrect.

Suggestion:
Consider a utility function isNodeError(e): e is NodeJS.ErrnoException for cleaner error handling across the codebase.

Confidence: 60%
Rule: ts_classify_http_errors_with_type_safe_narr
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Expand Down
5 changes: 5 additions & 0 deletions apps/frontend/src/main/ipc-handlers/settings-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getEffectiveVersion } from '../auto-claude-updater';
import { setUpdateChannel } from '../app-updater';
import { getSettingsPath, readSettingsFile } from '../settings-utils';
import { configureTools, getToolPath, getToolInfo } from '../cli-tool-manager';
import { pythonEnvManager } from '../python-env-manager';

const settingsPath = getSettingsPath();

Expand Down Expand Up @@ -176,6 +177,10 @@ export function registerSettingsHandlers(
// Apply Python path if changed
if (settings.pythonPath || settings.autoBuildPath) {
agentManager.configure(settings.pythonPath, settings.autoBuildPath);
// Also update pythonEnvManager so future venv creations use the new path
if (settings.pythonPath) {
pythonEnvManager.configure(settings.pythonPath);
}
}
Comment on lines 177 to 184

Choose a reason for hiding this comment

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

🔵 LOW - Incomplete comment - documents only pythonPath but handles both
Agent: documentation

Category: docs

Description:
Comment on line 177 states 'Apply Python path if changed' but condition on line 178 checks 'if (settings.pythonPath || settings.autoBuildPath)'. Code applies configuration for BOTH settings when either is provided, not just pythonPath.

Suggestion:
Update comment to accurately reflect both conditions: '// Apply Python path and/or autoBuild path if either changed'

Confidence: 75%
Rule: ts_jsdoc_description_mismatch
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray


// Configure CLI tools if any paths changed
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/main/python-detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ function getPythonVersion(pythonCmd: string): string | null {
* @param pythonCmd - The Python command to validate
* @returns Validation result with status, version, and message
*/
function validatePythonVersion(pythonCmd: string): {
export function validatePythonVersion(pythonCmd: string): {
valid: boolean;
version?: string;
message: string;
Expand Down
63 changes: 59 additions & 4 deletions apps/frontend/src/main/python-env-manager.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { spawn, execSync, ChildProcess } from 'child_process';
import { spawn, execSync, execFileSync, ChildProcess } from 'child_process';
import { existsSync, readdirSync } from 'fs';
import path from 'path';
import { EventEmitter } from 'events';
import { app } from 'electron';
import { findPythonCommand, getBundledPythonPath } from './python-detector';
import { findPythonCommand, getBundledPythonPath, validatePythonPath, parsePythonCommand, validatePythonVersion } from './python-detector';

export interface PythonEnvStatus {
ready: boolean;
Expand Down Expand Up @@ -40,6 +40,39 @@ export class PythonEnvManager extends EventEmitter {
private initializationPromise: Promise<PythonEnvStatus> | null = null;
private activeProcesses: Set<ChildProcess> = new Set();
private static readonly VENV_CREATION_TIMEOUT_MS = 120000; // 2 minutes timeout for venv creation
// User-configured Python path from settings (takes priority over auto-detection)
private configuredPythonPath: string | null = null;

/**
* Configure the Python path from user settings.
* This should be called before initialize() to ensure the user's preferred Python is used.
* @param pythonPath - The user-configured Python path from settings
* @returns true if path was accepted, false if rejected (will use auto-detection)
*/
configure(pythonPath?: string): boolean {
if (!pythonPath) {
return false;
}

// Step 1: Validate path security (no shell injection, valid executable)
const pathValidation = validatePythonPath(pythonPath);
if (!pathValidation.valid || !pathValidation.sanitizedPath) {
console.error(`[PythonEnvManager] Invalid Python path rejected: ${pathValidation.reason}`);
return false;
}

// Step 2: Validate Python version meets 3.10+ requirement
const versionValidation = validatePythonVersion(pathValidation.sanitizedPath);
if (!versionValidation.valid) {
console.error(`[PythonEnvManager] Python version rejected: ${versionValidation.message}`);
this.emit('error', `Configured Python version is too old: ${versionValidation.message}`);
return false;
}

this.configuredPythonPath = pathValidation.sanitizedPath;
console.log(`[PythonEnvManager] Configured Python path: ${this.configuredPythonPath} (${versionValidation.version})`);
return true;
}

/**
* Get the path where the venv should be created.
Expand Down Expand Up @@ -181,11 +214,33 @@ if sys.version_info >= (3, 12):
}

Choose a reason for hiding this comment

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

🟡 MEDIUM - Magic number: timeout value 15000 without named constant
Agent: quality

Category: quality

Description:
Hardcoded timeout value 15000 (milliseconds) is a magic number. While VENV_CREATION_TIMEOUT_MS constant exists on line 42 for venv creation (120000ms), this different timeout for dependency checking lacks a named constant.

Suggestion:
Extract to named class constant: private static readonly DEPS_CHECK_TIMEOUT_MS = 15000;

Confidence: 70%
Rule: qual_magic_numbers_js
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray


/**
Comment on lines 214 to 216

Choose a reason for hiding this comment

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

🟡 MEDIUM - Error silently swallowed without logging
Agent: react

Category: quality

Description:
catch block in checkDepsInstalled() silently returns false without logging. Makes debugging difficult when dependency checks fail unexpectedly.

Suggestion:
Add error logging: catch (error) { console.warn('[PythonEnvManager] Failed to check deps:', error); return false; }

Confidence: 80%
Rule: ts_log_errors_instead_of_failing_silently
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

* Find Python 3.10+ (bundled or system).
* Find Python 3.10+ (configured, bundled, or system).
Comment on lines 214 to +217

Choose a reason for hiding this comment

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

🟡 MEDIUM - execSync with shell string interpolation
Agent: security

Category: security

Description:
Uses execSync with shell string interpolation on venvPython. While venvPython is constructed from internal paths, using shell execution with string interpolation is a defense-in-depth concern. The checkScript string is also interpolated.

Suggestion:
Use execFileSync with shell: false. Pass checkScript as a file or use simpler inline command: execFileSync(venvPython, ['-c', checkScript], {shell: false, ...})

Confidence: 65%
Rule: node_avoid_command_injection
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

* Uses the shared python-detector logic which validates version requirements.
* Priority: bundled Python (packaged apps) > system Python
* Priority: user-configured > bundled Python (packaged apps) > system Python
*/
private findSystemPython(): string | null {
// 1. First check user-configured Python path (from settings)
if (this.configuredPythonPath) {
try {
// Verify the configured path actually works and resolve it to a full path
// Use execFileSync with shell: false for security (defense-in-depth)
const [command, args] = parsePythonCommand(this.configuredPythonPath);
const pythonPath = execFileSync(command, [...args, '-c', 'import sys; print(sys.executable)'], {
stdio: 'pipe',
timeout: 5000,
windowsHide: true,
shell: false // Explicitly disable shell for security
}).toString().trim();

console.log(`[PythonEnvManager] Using user-configured Python: ${pythonPath}`);
return pythonPath;
} catch (err) {
console.error(`[PythonEnvManager] User-configured Python failed, falling back to auto-detection:`, err);
// Fall through to auto-detection
}
Comment on lines +237 to +240

Choose a reason for hiding this comment

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

🟡 MEDIUM - Error fallback behavior not explicit
Agent: react

Category: quality

Description:
Error from user-configured Python path is caught and logged, then silently falls through to auto-detection. Control flow could be clearer.

Suggestion:
Make fallback explicit: Add comment 'Continue to auto-detection below' or refactor to explicit return of fallback call.

Confidence: 60%
Rule: ts_re_throw_or_return_errors_to_propagate_f
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

}
Copy link

Choose a reason for hiding this comment

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

User-configured Python path bypasses version requirement check

The findSystemPython() method is documented to find "Python 3.10+" but the user-configured Python path bypasses version validation. The configure() method calls validatePythonPath() which checks security and that the path is a valid Python executable, but does not verify it meets the minimum version requirement (3.10+). Meanwhile, findPythonCommand() used for bundled/system Python does validate the version via validatePythonVersion(). This allows users to configure Python 2.x or 3.9, creating a venv that will fail later when claude-agent-sdk (which requires 3.10+) is used.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link

Choose a reason for hiding this comment

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

User-configured Python path bypasses version requirement check

The findSystemPython() method is documented to find "Python 3.10+" but the user-configured Python path bypasses version validation. The configure() method calls validatePythonPath() which checks security and that the path is a valid Python executable, but does not verify it meets the minimum version requirement (3.10+). Meanwhile, findPythonCommand() used for bundled/system Python does validate the version via validatePythonVersion(). This allows users to configure Python 2.x or 3.9, creating a venv that will fail later when claude-agent-sdk (which requires 3.10+) is used.

Additional Locations (1)

Fix in Cursor Fix in Web


// 2. Auto-detect Python
const pythonCmd = findPythonCommand();
if (!pythonCmd) {
return null;
Comment on lines +230 to 246

Choose a reason for hiding this comment

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

🟡 MEDIUM - Magic number: timeout 5000 appears twice without constant
Agent: quality

Category: quality

Description:
Hardcoded timeout value 5000ms appears at lines 217 and 248 without a named constant. Makes maintenance harder if timeout needs adjustment.

Suggestion:
Extract to named constant: private static readonly PYTHON_DETECTION_TIMEOUT_MS = 5000; Use at both locations.

Confidence: 70%
Rule: qual_magic_numbers_js
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Choose a reason for hiding this comment

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

🟡 MEDIUM - execSync with shell string interpolation
Agent: security

Category: security

Description:
Uses execSync with pythonCmd interpolated into command string. While pythonCmd comes from findPythonCommand() which returns known-safe values, using execSync with shell execution and string concatenation is a defense-in-depth concern.

Suggestion:
Use parsePythonCommand() (already available in imports) and execFileSync with shell: false:
const [cmd, args] = parsePythonCommand(pythonCmd);
const pythonPath = execFileSync(cmd, [...args, '-c', 'import sys; print(sys.executable)'], {shell: false, ...}).toString().trim();

Confidence: 70%
Rule: node_avoid_command_injection
Review ID: 4568f414-7fe1-4e1e-b775-42705dca77eb
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

Expand Down