crewai-cli 1.14.8a3.dev20260624__tar.gz → 1.14.8a5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/PKG-INFO +2 -2
  2. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/pyproject.toml +1 -1
  3. crewai_cli-1.14.8a5/src/crewai_cli/__init__.py +1 -0
  4. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/experimental/skills/main.py +29 -1
  5. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/pyproject.toml +1 -1
  6. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/declarative_flow/pyproject.toml +1 -1
  7. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/pyproject.toml +1 -1
  8. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/tool/pyproject.toml +1 -1
  9. crewai_cli-1.14.8a5/tests/skills/test_safe_extract.py +140 -0
  10. crewai_cli-1.14.8a3.dev20260624/src/crewai_cli/__init__.py +0 -1
  11. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/.gitignore +0 -0
  12. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/README.md +0 -0
  13. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/add_crew_to_flow.py +0 -0
  14. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/__init__.py +0 -0
  15. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/constants.py +0 -0
  16. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/main.py +0 -0
  17. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/__init__.py +0 -0
  18. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/auth0.py +0 -0
  19. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/base_provider.py +0 -0
  20. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/entra_id.py +0 -0
  21. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/keycloak.py +0 -0
  22. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/okta.py +0 -0
  23. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/providers/workos.py +0 -0
  24. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/token.py +0 -0
  25. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/authentication/utils.py +0 -0
  26. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/checkpoint_cli.py +0 -0
  27. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/checkpoint_tui.py +0 -0
  28. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/cli.py +0 -0
  29. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/command.py +0 -0
  30. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/config.py +0 -0
  31. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/constants.py +0 -0
  32. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/create_crew.py +0 -0
  33. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/create_flow.py +0 -0
  34. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/create_json_crew.py +0 -0
  35. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/crew_chat.py +0 -0
  36. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/crew_run_tui.py +0 -0
  37. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/deploy/__init__.py +0 -0
  38. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/deploy/archive.py +0 -0
  39. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/deploy/main.py +0 -0
  40. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/deploy/validate.py +0 -0
  41. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/enterprise/__init__.py +0 -0
  42. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/enterprise/main.py +0 -0
  43. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/evaluate_crew.py +0 -0
  44. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/experimental/__init__.py +0 -0
  45. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/experimental/skills/__init__.py +0 -0
  46. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/git.py +0 -0
  47. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/install_crew.py +0 -0
  48. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/kickoff_flow.py +0 -0
  49. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/memory_tui.py +0 -0
  50. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/organization/__init__.py +0 -0
  51. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/organization/main.py +0 -0
  52. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/plot_flow.py +0 -0
  53. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/plus_api.py +0 -0
  54. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/provider.py +0 -0
  55. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/py.typed +0 -0
  56. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/remote_template/__init__.py +0 -0
  57. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/remote_template/main.py +0 -0
  58. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/replay_from_task.py +0 -0
  59. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/reset_memories_command.py +0 -0
  60. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/run_crew.py +0 -0
  61. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/run_declarative_flow.py +0 -0
  62. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/settings/__init__.py +0 -0
  63. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/settings/main.py +0 -0
  64. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/shared/__init__.py +0 -0
  65. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/shared/token_manager.py +0 -0
  66. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/task_outputs.py +0 -0
  67. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/AGENTS.md +0 -0
  68. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/__init__.py +0 -0
  69. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/.gitignore +0 -0
  70. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/README.md +0 -0
  71. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/__init__.py +0 -0
  72. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/config/agents.yaml +0 -0
  73. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/config/tasks.yaml +0 -0
  74. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/crew.py +0 -0
  75. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/knowledge/user_preference.txt +0 -0
  76. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/main.py +0 -0
  77. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/skills/.gitkeep +0 -0
  78. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/tools/__init__.py +0 -0
  79. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/crew/tools/custom_tool.py +0 -0
  80. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/declarative_flow/.gitignore +0 -0
  81. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/declarative_flow/README.md +0 -0
  82. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/declarative_flow/flow.yaml +0 -0
  83. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/.gitignore +0 -0
  84. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/README.md +0 -0
  85. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/__init__.py +0 -0
  86. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/crews/content_crew/config/agents.yaml +0 -0
  87. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/crews/content_crew/config/tasks.yaml +0 -0
  88. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/crews/content_crew/content_crew.py +0 -0
  89. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/main.py +0 -0
  90. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/skills/.gitkeep +0 -0
  91. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/tools/__init__.py +0 -0
  92. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/flow/tools/custom_tool.py +0 -0
  93. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/tool/.gitignore +0 -0
  94. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/tool/README.md +0 -0
  95. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/tool/src/{{folder_name}}/__init__.py +0 -0
  96. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/templates/tool/src/{{folder_name}}/tool.py +0 -0
  97. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/tools/__init__.py +0 -0
  98. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/tools/main.py +0 -0
  99. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/train_crew.py +0 -0
  100. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/triggers/__init__.py +0 -0
  101. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/triggers/main.py +0 -0
  102. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/tui_picker.py +0 -0
  103. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/update_crew.py +0 -0
  104. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/user_data.py +0 -0
  105. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/utils.py +0 -0
  106. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/src/crewai_cli/version.py +0 -0
  107. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/__init__.py +0 -0
  108. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/__init__.py +0 -0
  109. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/__init__.py +0 -0
  110. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/test_auth0.py +0 -0
  111. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/test_entra_id.py +0 -0
  112. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/test_keycloak.py +0 -0
  113. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/test_okta.py +0 -0
  114. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/providers/test_workos.py +0 -0
  115. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/test_auth_main.py +0 -0
  116. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/authentication/test_utils.py +0 -0
  117. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/deploy/__init__.py +0 -0
  118. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/deploy/test_archive.py +0 -0
  119. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/deploy/test_deploy_main.py +0 -0
  120. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/deploy/test_validate.py +0 -0
  121. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/enterprise/__init__.py +0 -0
  122. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/enterprise/test_main.py +0 -0
  123. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/experimental/__init__.py +0 -0
  124. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/experimental/skills/__init__.py +0 -0
  125. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/experimental/skills/test_main.py +0 -0
  126. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/organization/__init__.py +0 -0
  127. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/organization/test_main.py +0 -0
  128. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/skills/__init__.py +0 -0
  129. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_cli.py +0 -0
  130. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_click_compatibility.py +0 -0
  131. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_config.py +0 -0
  132. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_constants.py +0 -0
  133. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_create_crew.py +0 -0
  134. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_create_flow.py +0 -0
  135. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_crew_run_tui.py +0 -0
  136. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_crew_test.py +0 -0
  137. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_flow_commands.py +0 -0
  138. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_git.py +0 -0
  139. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_install_crew.py +0 -0
  140. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_kickoff_flow.py +0 -0
  141. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_plus_api.py +0 -0
  142. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_run_crew.py +0 -0
  143. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_run_declarative_flow.py +0 -0
  144. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_settings_command.py +0 -0
  145. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_token_manager.py +0 -0
  146. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_train_crew.py +0 -0
  147. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_utils.py +0 -0
  148. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/test_version.py +0 -0
  149. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/tools/__init__.py +0 -0
  150. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/tools/test_main.py +0 -0
  151. {crewai_cli-1.14.8a3.dev20260624 → crewai_cli-1.14.8a5}/tests/triggers/test_main.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: crewai-cli
3
- Version: 1.14.8a3.dev20260624
3
+ Version: 1.14.8a5
4
4
  Summary: CLI for CrewAI — scaffold, run, deploy and manage AI agent crews.
5
5
  Project-URL: Homepage, https://crewai.com
6
6
  Project-URL: Documentation, https://docs.crewai.com
@@ -10,7 +10,7 @@ Requires-Python: <3.14,>=3.10
10
10
  Requires-Dist: appdirs~=1.4.4
11
11
  Requires-Dist: certifi
12
12
  Requires-Dist: click<9,>=8.1.7
13
- Requires-Dist: crewai-core==1.14.8a3.dev20260624
13
+ Requires-Dist: crewai-core==1.14.8a5
14
14
  Requires-Dist: cryptography>=42.0
15
15
  Requires-Dist: httpx~=0.28.1
16
16
  Requires-Dist: packaging>=23.0
@@ -8,7 +8,7 @@ authors = [
8
8
  ]
9
9
  requires-python = ">=3.10, <3.14"
10
10
  dependencies = [
11
- "crewai-core==1.14.8a3.dev20260624",
11
+ "crewai-core==1.14.8a5",
12
12
  "click>=8.1.7,<9",
13
13
  "pydantic>=2.11.9,<2.13",
14
14
  "pydantic-settings~=2.10.1",
@@ -0,0 +1 @@
1
+ __version__ = "1.14.8a5"
@@ -378,12 +378,40 @@ class SkillCommand(BaseCommand, PlusAPIMixin):
378
378
 
379
379
 
380
380
  def _safe_extractall(tf: tarfile.TarFile, dest: Path) -> None:
381
- """Path-traversal-safe extraction for Python < 3.12."""
381
+ """Path-traversal-safe extraction for Python versions without tar filters.
382
+
383
+ Validates both the member's own path and, for symlink/hardlink members,
384
+ the link target. Without the link-target check a malicious archive can
385
+ plant a symlink that escapes ``dest`` (e.g. ``link -> /home/user/.ssh``)
386
+ followed by a regular member written *through* that link
387
+ (``link/authorized_keys``), escaping ``dest`` even though every member
388
+ name resolves inside it. This mirrors the protection that
389
+ ``tarfile.extractall(..., filter="data")`` provides when available.
390
+ """
382
391
  dest_resolved = dest.resolve()
383
392
  for member in tf.getmembers():
384
393
  member_path = (dest / member.name).resolve()
385
394
  if not member_path.is_relative_to(dest_resolved):
386
395
  raise ValueError(f"Blocked path traversal attempt: {member.name!r}")
396
+ if not (member.isfile() or member.isdir() or member.issym() or member.islnk()):
397
+ raise ValueError(f"Blocked unsupported tar member: {member.name!r}")
398
+ if member.issym() or member.islnk():
399
+ link_target = member.linkname
400
+ # Absolute link targets always escape the destination.
401
+ if os.path.isabs(link_target):
402
+ raise ValueError(
403
+ f"Blocked link target escaping destination: "
404
+ f"{member.name!r} -> {link_target!r}"
405
+ )
406
+ # Hardlink names are relative to the archive root; symlink
407
+ # targets are relative to the member's own directory.
408
+ anchor = dest if member.islnk() else (dest / member.name).parent
409
+ resolved_target = (anchor / link_target).resolve()
410
+ if not resolved_target.is_relative_to(dest_resolved):
411
+ raise ValueError(
412
+ f"Blocked link target escaping destination: "
413
+ f"{member.name!r} -> {link_target!r}"
414
+ )
387
415
  tf.extractall(dest) # noqa: S202
388
416
 
389
417
 
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
5
5
  authors = [{ name = "Your Name", email = "you@example.com" }]
6
6
  requires-python = ">=3.10,<3.14"
7
7
  dependencies = [
8
- "crewai[tools]==1.14.8a3"
8
+ "crewai[tools]==1.14.8a5"
9
9
  ]
10
10
 
11
11
  [project.scripts]
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
5
5
  authors = [{ name = "Your Name", email = "you@example.com" }]
6
6
  requires-python = ">=3.10,<3.14"
7
7
  dependencies = [
8
- "crewai[tools]==1.14.8a3"
8
+ "crewai[tools]==1.14.8a5"
9
9
  ]
10
10
 
11
11
  [build-system]
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
5
5
  authors = [{ name = "Your Name", email = "you@example.com" }]
6
6
  requires-python = ">=3.10,<3.14"
7
7
  dependencies = [
8
- "crewai[tools]==1.14.8a3"
8
+ "crewai[tools]==1.14.8a5"
9
9
  ]
10
10
 
11
11
  [project.scripts]
@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10,<3.14"
7
7
  dependencies = [
8
- "crewai[tools]==1.14.8a3"
8
+ "crewai[tools]==1.14.8a5"
9
9
  ]
10
10
 
11
11
  [tool.crewai]
@@ -0,0 +1,140 @@
1
+ """Regression tests for path-traversal-safe archive extraction.
2
+
3
+ Guards against symlink/hardlink-based path traversal in the fallback used on
4
+ Python versions without tarfile extraction filters. The filtered path relies on
5
+ `tarfile.extractall(..., filter="data")`; the fallback must provide the same
6
+ protection by validating link targets, not just member names.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import io
12
+ import tarfile
13
+ from pathlib import Path
14
+
15
+ import pytest
16
+
17
+ from crewai_cli.experimental.skills.main import _safe_extractall
18
+
19
+
20
+ def _tar_from_members(build) -> tarfile.TarFile:
21
+ """Build an in-memory tar archive via `build(tf)` and return it for reading."""
22
+ buf = io.BytesIO()
23
+ with tarfile.open(fileobj=buf, mode="w") as tf:
24
+ build(tf)
25
+ buf.seek(0)
26
+ return tarfile.open(fileobj=buf, mode="r")
27
+
28
+
29
+ def test_blocks_symlink_escaping_destination(tmp_path: Path) -> None:
30
+ """A symlink whose target escapes dest, plus a file written through it,
31
+ must be rejected before anything is extracted."""
32
+ outside = tmp_path / "outside"
33
+ outside.mkdir()
34
+ dest = tmp_path / "dest"
35
+ dest.mkdir()
36
+
37
+ def build(tf: tarfile.TarFile) -> None:
38
+ link = tarfile.TarInfo("link")
39
+ link.type = tarfile.SYMTYPE
40
+ link.linkname = str(outside) # absolute path outside dest
41
+ tf.addfile(link)
42
+ payload = b"pwned"
43
+ info = tarfile.TarInfo("link/evil.txt")
44
+ info.size = len(payload)
45
+ tf.addfile(info, io.BytesIO(payload))
46
+
47
+ with _tar_from_members(build) as tf:
48
+ with pytest.raises(ValueError, match="escaping destination"):
49
+ _safe_extractall(tf, dest)
50
+
51
+ assert not (outside / "evil.txt").exists()
52
+
53
+
54
+ def test_blocks_relative_symlink_escaping_destination(tmp_path: Path) -> None:
55
+ """A relative symlink (../..) that escapes dest is also rejected."""
56
+ dest = tmp_path / "dest"
57
+ dest.mkdir()
58
+
59
+ def build(tf: tarfile.TarFile) -> None:
60
+ link = tarfile.TarInfo("sub/link")
61
+ link.type = tarfile.SYMTYPE
62
+ link.linkname = "../../outside" # escapes dest from sub/
63
+ tf.addfile(link)
64
+
65
+ with _tar_from_members(build) as tf:
66
+ with pytest.raises(ValueError, match="escaping destination"):
67
+ _safe_extractall(tf, dest)
68
+
69
+
70
+ def test_blocks_hardlink_escaping_destination(tmp_path: Path) -> None:
71
+ """A hardlink whose target escapes dest is rejected."""
72
+ dest = tmp_path / "dest"
73
+ dest.mkdir()
74
+
75
+ def build(tf: tarfile.TarFile) -> None:
76
+ link = tarfile.TarInfo("escape")
77
+ link.type = tarfile.LNKTYPE
78
+ link.linkname = "../outside.txt" # escapes archive root
79
+ tf.addfile(link)
80
+
81
+ with _tar_from_members(build) as tf:
82
+ with pytest.raises(ValueError, match="escaping destination"):
83
+ _safe_extractall(tf, dest)
84
+
85
+
86
+ def test_blocks_special_tar_member(tmp_path: Path) -> None:
87
+ """Special tar members such as FIFOs are rejected."""
88
+ dest = tmp_path / "dest"
89
+ dest.mkdir()
90
+
91
+ def build(tf: tarfile.TarFile) -> None:
92
+ fifo = tarfile.TarInfo("pipe")
93
+ fifo.type = tarfile.FIFOTYPE
94
+ tf.addfile(fifo)
95
+
96
+ with _tar_from_members(build) as tf:
97
+ with pytest.raises(ValueError, match="unsupported tar member"):
98
+ _safe_extractall(tf, dest)
99
+
100
+
101
+ def test_allows_benign_relative_symlink(tmp_path: Path) -> None:
102
+ """A symlink that stays within dest is permitted."""
103
+ dest = tmp_path / "dest"
104
+ dest.mkdir()
105
+
106
+ def build(tf: tarfile.TarFile) -> None:
107
+ payload = b"hi"
108
+ info = tarfile.TarInfo("real.txt")
109
+ info.size = len(payload)
110
+ tf.addfile(info, io.BytesIO(payload))
111
+ link = tarfile.TarInfo("alias.txt")
112
+ link.type = tarfile.SYMTYPE
113
+ link.linkname = "real.txt" # stays inside dest
114
+ tf.addfile(link)
115
+
116
+ with _tar_from_members(build) as tf:
117
+ _safe_extractall(tf, dest)
118
+
119
+ assert (dest / "real.txt").read_bytes() == b"hi"
120
+ assert (dest / "alias.txt").is_symlink()
121
+ assert (dest / "alias.txt").readlink() == Path("real.txt")
122
+
123
+
124
+ def test_allows_benign_archive(tmp_path: Path) -> None:
125
+ """An ordinary archive of regular files extracts correctly."""
126
+ dest = tmp_path / "dest"
127
+ dest.mkdir()
128
+
129
+ def build(tf: tarfile.TarFile) -> None:
130
+ for name, body in (("SKILL.md", b"# skill"), ("scripts/run.py", b"print(1)")):
131
+ payload = body
132
+ info = tarfile.TarInfo(name)
133
+ info.size = len(payload)
134
+ tf.addfile(info, io.BytesIO(payload))
135
+
136
+ with _tar_from_members(build) as tf:
137
+ _safe_extractall(tf, dest)
138
+
139
+ assert (dest / "SKILL.md").read_bytes() == b"# skill"
140
+ assert (dest / "scripts" / "run.py").read_bytes() == b"print(1)"
@@ -1 +0,0 @@
1
- __version__ = "1.14.8a3.dev20260624"