diff --git a/lib/crewai/src/crewai/cli/cli.py b/lib/crewai/src/crewai/cli/cli.py index ad1923b28..b0483d570 100644 --- a/lib/crewai/src/crewai/cli/cli.py +++ b/lib/crewai/src/crewai/cli/cli.py @@ -27,7 +27,7 @@ from crewai.cli.tools.main import ToolCommand from crewai.cli.train_crew import train_crew from crewai.cli.triggers.main import TriggersCommand from crewai.cli.update_crew import update_crew -from crewai.cli.utils import build_env_with_tool_repository_credentials, read_toml +from crewai.cli.utils import build_env_with_all_tool_credentials, read_toml from crewai.memory.storage.kickoff_task_outputs_storage import ( KickoffTaskOutputsSQLiteStorage, ) @@ -48,24 +48,18 @@ def crewai() -> None: @click.argument("uv_args", nargs=-1, type=click.UNPROCESSED) def uv(uv_args: tuple[str, ...]) -> None: """A wrapper around uv commands that adds custom tool authentication through env vars.""" - env = os.environ.copy() try: - pyproject_data = read_toml() - sources = pyproject_data.get("tool", {}).get("uv", {}).get("sources", {}) - - for source_config in sources.values(): - if isinstance(source_config, dict): - index = source_config.get("index") - if index: - index_env = build_env_with_tool_repository_credentials(index) - env.update(index_env) - except (FileNotFoundError, KeyError) as e: + # Verify pyproject.toml exists first + read_toml() + except FileNotFoundError as e: raise SystemExit( "Error. A valid pyproject.toml file is required. Check that a valid pyproject.toml file exists in the current directory." ) from e except Exception as e: raise SystemExit(f"Error: {e}") from e + env = build_env_with_all_tool_credentials() + try: subprocess.run( # noqa: S603 ["uv", *uv_args], # noqa: S607 diff --git a/lib/crewai/src/crewai/cli/install_crew.py b/lib/crewai/src/crewai/cli/install_crew.py index aa10902aa..9e897416a 100644 --- a/lib/crewai/src/crewai/cli/install_crew.py +++ b/lib/crewai/src/crewai/cli/install_crew.py @@ -2,6 +2,8 @@ import subprocess import click +from crewai.cli.utils import build_env_with_all_tool_credentials + # Be mindful about changing this. # on some environments we don't use this command but instead uv sync directly @@ -13,7 +15,14 @@ def install_crew(proxy_options: list[str]) -> None: """ try: command = ["uv", "sync", *proxy_options] - subprocess.run(command, check=True, capture_output=False, text=True) # noqa: S603 + + # Inject tool repository credentials so uv can authenticate + # against private package indexes (e.g. crewai tool repository). + # Without this, `uv sync` fails with 401 Unauthorized when the + # project depends on tools from a private index. + env = build_env_with_all_tool_credentials() + + subprocess.run(command, check=True, capture_output=False, text=True, env=env) # noqa: S603 except subprocess.CalledProcessError as e: click.echo(f"An error occurred while running the crew: {e}", err=True) diff --git a/lib/crewai/src/crewai/cli/run_crew.py b/lib/crewai/src/crewai/cli/run_crew.py index e2b942512..6f031f245 100644 --- a/lib/crewai/src/crewai/cli/run_crew.py +++ b/lib/crewai/src/crewai/cli/run_crew.py @@ -1,11 +1,10 @@ from enum import Enum -import os import subprocess import click from packaging import version -from crewai.cli.utils import build_env_with_tool_repository_credentials, read_toml +from crewai.cli.utils import build_env_with_all_tool_credentials, read_toml from crewai.cli.version import get_crewai_version @@ -56,19 +55,7 @@ def execute_command(crew_type: CrewType) -> None: """ command = ["uv", "run", "kickoff" if crew_type == CrewType.FLOW else "run_crew"] - env = os.environ.copy() - try: - pyproject_data = read_toml() - sources = pyproject_data.get("tool", {}).get("uv", {}).get("sources", {}) - - for source_config in sources.values(): - if isinstance(source_config, dict): - index = source_config.get("index") - if index: - index_env = build_env_with_tool_repository_credentials(index) - env.update(index_env) - except Exception: # noqa: S110 - pass + env = build_env_with_all_tool_credentials() try: subprocess.run(command, capture_output=False, text=True, check=True, env=env) # noqa: S603 diff --git a/lib/crewai/src/crewai/cli/utils.py b/lib/crewai/src/crewai/cli/utils.py index a23bdc85a..ad8f5897e 100644 --- a/lib/crewai/src/crewai/cli/utils.py +++ b/lib/crewai/src/crewai/cli/utils.py @@ -484,8 +484,12 @@ def get_flows(flow_path: str = "main.py") -> list[Flow[Any]]: if flow_instances: break - except Exception: # noqa: S110 - pass + except Exception as e: + import logging + + logging.getLogger(__name__).debug( + f"Could not load tool repository credentials: {e}" + ) return flow_instances @@ -549,6 +553,31 @@ def build_env_with_tool_repository_credentials( return env +def build_env_with_all_tool_credentials() -> dict[str, Any]: + """ + Build environment dict with credentials for all tool repository indexes + found in pyproject.toml's [tool.uv.sources] section. + + Returns: + dict: Environment variables with credentials for all private indexes. + """ + env = os.environ.copy() + try: + pyproject_data = read_toml() + sources = pyproject_data.get("tool", {}).get("uv", {}).get("sources", {}) + + for source_config in sources.values(): + if isinstance(source_config, dict): + index = source_config.get("index") + if index: + index_env = build_env_with_tool_repository_credentials(index) + env.update(index_env) + except Exception: # noqa: S110 + pass + + return env + + @contextmanager def _load_module_from_file( init_file: Path, module_name: str | None = None