-
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
shell kwarg #13
shell kwarg #13
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
name: Run Build Tests | ||
on: | ||
push: | ||
branches: | ||
- master | ||
pull_request: | ||
branches: | ||
- dev | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build_tests: | ||
strategy: | ||
max-parallel: 2 | ||
matrix: | ||
python-version: [3.8, 3.9, "3.10", "3.11" ] | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Setup Python | ||
uses: actions/setup-python@v4 | ||
with: | ||
python-version: ${{ matrix.python-version }} | ||
- name: Install Build Tools | ||
run: | | ||
python -m pip install build wheel | ||
- name: Install System Dependencies | ||
run: | | ||
sudo apt-get update | ||
sudo apt install python3-dev swig libssl-dev | ||
- name: Build Source Packages | ||
run: | | ||
python setup.py sdist | ||
- name: Build Distribution Packages | ||
run: | | ||
python setup.py bdist_wheel | ||
- name: Install skill | ||
run: | | ||
pip install . |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,66 @@ | ||||||||||||||||||||||||||
name: Run UnitTests | ||||||||||||||||||||||||||
on: | ||||||||||||||||||||||||||
pull_request: | ||||||||||||||||||||||||||
branches: | ||||||||||||||||||||||||||
- dev | ||||||||||||||||||||||||||
paths-ignore: | ||||||||||||||||||||||||||
- 'version.py' | ||||||||||||||||||||||||||
- 'examples/**' | ||||||||||||||||||||||||||
- '.github/**' | ||||||||||||||||||||||||||
- '.gitignore' | ||||||||||||||||||||||||||
- 'LICENSE' | ||||||||||||||||||||||||||
- 'CHANGELOG.md' | ||||||||||||||||||||||||||
- 'MANIFEST.in' | ||||||||||||||||||||||||||
- 'README.md' | ||||||||||||||||||||||||||
- 'scripts/**' | ||||||||||||||||||||||||||
push: | ||||||||||||||||||||||||||
branches: | ||||||||||||||||||||||||||
- master | ||||||||||||||||||||||||||
paths-ignore: | ||||||||||||||||||||||||||
- 'version.py' | ||||||||||||||||||||||||||
- 'examples/**' | ||||||||||||||||||||||||||
- '.github/**' | ||||||||||||||||||||||||||
- '.gitignore' | ||||||||||||||||||||||||||
- 'LICENSE' | ||||||||||||||||||||||||||
- 'CHANGELOG.md' | ||||||||||||||||||||||||||
- 'MANIFEST.in' | ||||||||||||||||||||||||||
- 'README.md' | ||||||||||||||||||||||||||
- 'scripts/**' | ||||||||||||||||||||||||||
workflow_dispatch: | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
jobs: | ||||||||||||||||||||||||||
unit_tests: | ||||||||||||||||||||||||||
strategy: | ||||||||||||||||||||||||||
matrix: | ||||||||||||||||||||||||||
python-version: [3.9, "3.10" ] | ||||||||||||||||||||||||||
runs-on: ubuntu-latest | ||||||||||||||||||||||||||
steps: | ||||||||||||||||||||||||||
- uses: actions/checkout@v2 | ||||||||||||||||||||||||||
- name: Set up python ${{ matrix.python-version }} | ||||||||||||||||||||||||||
uses: actions/setup-python@v2 | ||||||||||||||||||||||||||
with: | ||||||||||||||||||||||||||
python-version: ${{ matrix.python-version }} | ||||||||||||||||||||||||||
- name: Install System Dependencies | ||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
sudo apt-get update | ||||||||||||||||||||||||||
sudo apt install python3-dev | ||||||||||||||||||||||||||
python -m pip install build wheel | ||||||||||||||||||||||||||
- name: Install core repo | ||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
pip install . | ||||||||||||||||||||||||||
- name: Install test dependencies | ||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
pip install pytest pytest-timeout pytest-cov | ||||||||||||||||||||||||||
- name: Install System Dependencies | ||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
sudo apt-get update | ||||||||||||||||||||||||||
- name: Install ovos dependencies | ||||||||||||||||||||||||||
Comment on lines
+54
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove duplicate system dependencies step This step is redundant as it duplicates the system dependencies installation from lines 43-47, but without actually installing any packages. Remove these lines as they are already covered by the previous system dependencies installation step. - - name: Install System Dependencies
- run: |
- sudo apt-get update 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
pip install ovos-plugin-manager | ||||||||||||||||||||||||||
- name: Run unittests | ||||||||||||||||||||||||||
run: | | ||||||||||||||||||||||||||
pytest --cov=ovos-skill-cmd --cov-report xml test | ||||||||||||||||||||||||||
- name: Upload coverage | ||||||||||||||||||||||||||
env: | ||||||||||||||||||||||||||
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}} | ||||||||||||||||||||||||||
uses: codecov/codecov-action@v2 | ||||||||||||||||||||||||||
Comment on lines
+61
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Update Codecov action version The Codecov action should be updated to the latest version for better security and features. Apply this diff: env:
CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}
- uses: codecov/codecov-action@v2
+ uses: codecov/codecov-action@v3 📝 Committable suggestion
Suggested change
🧰 Tools🪛 actionlint66-66: the runner of "codecov/codecov-action@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue (action) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
recursive-include locale * | ||
include *.txt |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -53,12 +53,13 @@ def initialize(self): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def run(self, message): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
script = message.data.get('Script') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
script = self.alias.get(script, script) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
args = script.split(' ') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
shell = self.settings.get('shell', True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security: Reconsider defaulting Setting Suggested fix: - shell = self.settings.get('shell', True)
+ shell = self.settings.get('shell', False) Consider adding a warning log when shell=True is enabled: if shell:
LOG.warning("Shell execution enabled - ensure command input is trusted") |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
args = script.split(' ') if shell else script | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LOG.info(f'Running {args}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+57
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve command argument handling The current implementation has several issues:
Consider using - args = script.split(' ') if shell else script
+ import shlex
+ args = script if shell else shlex.split(script)
- LOG.info(f'Running {args}')
+ LOG.info(f'Running command: {script} (shell={shell})') 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if self.uid and self.gid: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subprocess.Popen(args, preexec_fn=set_user(self.uid, self.gid)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subprocess.Popen(args, preexec_fn=set_user(self.uid, self.gid), shell=shell) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LOG.info(f'Running {args}') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subprocess.Popen(args) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
subprocess.Popen(args, shell=shell) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+61
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improve subprocess execution and error handling Several improvements needed for safer subprocess execution:
Suggested improvements: - subprocess.Popen(args, preexec_fn=set_user(self.uid, self.gid), shell=shell)
- else:
- subprocess.Popen(args, shell=shell)
+ process = subprocess.Popen(
+ args,
+ shell=shell,
+ preexec_fn=lambda: set_user(self.uid, self.gid),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True
+ )
+ else:
+ process = subprocess.Popen(
+ args,
+ shell=shell,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ text=True
+ )
+ try:
+ stdout, stderr = process.communicate(timeout=60)
+ if process.returncode != 0:
+ LOG.error(f"Command failed with exit code {process.returncode}")
+ LOG.error(f"stderr: {stderr}")
+ else:
+ LOG.debug(f"Command output: {stdout}")
+ except subprocess.TimeoutExpired:
+ process.kill()
+ LOG.error("Command timed out after 60 seconds") 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
except Exception: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
LOG.exception('Could not run script ' + script) |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -5,7 +5,7 @@ | |||||
|
||||||
# Define package information | ||||||
SKILL_CLAZZ = "CmdSkill" # Make sure it matches __init__.py class name | ||||||
URL = "https://github.com/OVOSHatchery/ovos-skill-cmd" | ||||||
URL = "https://github.com/OpenVoiceOS/ovos-skill-cmd" | ||||||
AUTHOR = "forslund" | ||||||
EMAIL = "" | ||||||
LICENSE = "Apache2.0" | ||||||
|
@@ -37,7 +37,7 @@ def get_requirements(requirements_filename: str = "requirements.txt"): | |||||
|
||||||
# Function to find resource files | ||||||
def find_resource_files(): | ||||||
resource_base_dirs = ("locale", "ui") | ||||||
resource_base_dirs = ("locale") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix syntax error in resource_base_dirs tuple definition. The current definition Apply this fix: - resource_base_dirs = ("locale")
+ resource_base_dirs = ("locale",) # Note the comma to make it a single-element tuple 📝 Committable suggestion
Suggested change
|
||||||
base_dir = abspath(dirname(__file__)) | ||||||
package_data = ["*.json"] | ||||||
for res in resource_base_dirs: | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,13 @@ | ||||||||||||||
import unittest | ||||||||||||||
from ovos_plugin_manager.skills import find_skill_plugins | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class TestPlugin(unittest.TestCase): | ||||||||||||||
@classmethod | ||||||||||||||
def setUpClass(self): | ||||||||||||||
self.skill_id = "ovos-skill-cmd.openvoiceos" | ||||||||||||||
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect usage of The Apply this fix: @classmethod
def setUpClass(self):
- self.skill_id = "ovos-skill-cmd.openvoiceos"
+ cls.skill_id = "ovos-skill-cmd.openvoiceos" 📝 Committable suggestion
Suggested change
|
||||||||||||||
|
||||||||||||||
def test_find_plugin(self): | ||||||||||||||
plugins = find_skill_plugins() | ||||||||||||||
self.assertIn(self.skill_id, list(plugins)) | ||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import unittest | ||
from os.path import dirname | ||
|
||
from ovos_plugin_manager.skills import find_skill_plugins | ||
from ovos_utils.messagebus import FakeBus | ||
from ovos_workshop.skill_launcher import PluginSkillLoader, SkillLoader | ||
from ovos_skill_cmd import CmdSkill | ||
|
||
|
||
class TestSkillLoading(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(self): | ||
self.skill_id = "ovos-skill-cmd.openvoiceos" | ||
self.path = dirname(dirname(__file__)) | ||
|
||
def test_from_class(self): | ||
bus = FakeBus() | ||
skill = CmdSkill() | ||
skill._startup(bus, self.skill_id) | ||
self.assertEqual(skill.bus, bus) | ||
self.assertEqual(skill.skill_id, self.skill_id) | ||
|
||
def test_from_plugin(self): | ||
bus = FakeBus() | ||
for skill_id, plug in find_skill_plugins().items(): | ||
if skill_id == self.skill_id: | ||
skill = plug() | ||
skill._startup(bus, self.skill_id) | ||
self.assertEqual(skill.bus, bus) | ||
self.assertEqual(skill.skill_id, self.skill_id) | ||
break | ||
else: | ||
raise RuntimeError("plugin not found") | ||
|
||
Comment on lines
+23
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor duplicate plugin search logic. The plugin search logic is duplicated in + def _find_plugin(self):
+ for skill_id, plug in find_skill_plugins().items():
+ if skill_id == self.skill_id:
+ return plug
+ raise RuntimeError("plugin not found")
+
def test_from_plugin(self):
bus = FakeBus()
- for skill_id, plug in find_skill_plugins().items():
- if skill_id == self.skill_id:
- skill = plug()
- skill._startup(bus, self.skill_id)
- self.assertEqual(skill.bus, bus)
- self.assertEqual(skill.skill_id, self.skill_id)
- break
- else:
- raise RuntimeError("plugin not found")
+ plug = self._find_plugin()
+ skill = plug()
+ skill._startup(bus, self.skill_id)
+ self.assertEqual(skill.bus, bus)
+ self.assertEqual(skill.skill_id, self.skill_id) Also applies to: 42-54 |
||
def test_from_loader(self): | ||
bus = FakeBus() | ||
loader = SkillLoader(bus, self.path) | ||
loader.load() | ||
self.assertEqual(loader.instance.bus, bus) | ||
self.assertEqual(loader.instance.root_dir, self.path) | ||
|
||
def test_from_plugin_loader(self): | ||
bus = FakeBus() | ||
loader = PluginSkillLoader(bus, self.skill_id) | ||
for skill_id, plug in find_skill_plugins().items(): | ||
if skill_id == self.skill_id: | ||
loader.load(plug) | ||
break | ||
else: | ||
raise RuntimeError("plugin not found") | ||
|
||
self.assertEqual(loader.skill_id, self.skill_id) | ||
self.assertEqual(loader.instance.bus, bus) | ||
self.assertEqual(loader.instance.skill_id, self.skill_id) | ||
Comment on lines
+16
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add cleanup and negative test cases. Consider these improvements to make the tests more robust:
Example additions: def tearDown(self):
# Clean up any resources created during tests
self.bus = None
def test_invalid_skill_id(self):
bus = FakeBus()
loader = PluginSkillLoader(bus, "invalid-skill-id")
with self.assertRaises(RuntimeError):
loader.load()
def test_invalid_path(self):
bus = FakeBus()
loader = SkillLoader(bus, "/invalid/path")
with self.assertRaises(ValueError):
loader.load() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Update GitHub Actions versions and consider adding Python 3.11
The following actions should be updated to their latest versions for better security and features:
actions/checkout@v2
→actions/checkout@v4
actions/setup-python@v2
→actions/setup-python@v4
Consider adding Python 3.11 to the matrix for future compatibility.
Apply this diff:
📝 Committable suggestion
🧰 Tools
🪛 actionlint
38-38: the runner of "actions/checkout@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
40-40: the runner of "actions/setup-python@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)