From 8861546ad8d4929f6ff7e12420c5722a666eab11 Mon Sep 17 00:00:00 2001 From: Simon Alibert <75076266+aliberts@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:19:26 +0100 Subject: [PATCH] [Security] Add Bandit (#795) --- .pre-commit-config.yaml | 17 ++++++-- lerobot/common/utils/utils.py | 41 +++++++++++-------- lerobot/scripts/eval.py | 4 +- lerobot/scripts/visualize_dataset_html.py | 6 ++- .../templates/visualize_dataset_template.html | 26 ++++++------ pyproject.toml | 11 ++++- 6 files changed, 67 insertions(+), 38 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b921f4e1..dba87705 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,7 @@ exclude: ^(tests/data) default_language_version: python: python3.10 repos: + ##### Style / Misc. ##### - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: @@ -14,7 +15,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/crate-ci/typos - rev: v1.29.10 + rev: v1.30.0 hooks: - id: typos args: [--force-exclude] @@ -23,16 +24,24 @@ repos: hooks: - id: pyupgrade - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.9.6 + rev: v0.9.9 hooks: - id: ruff args: [--fix] - id: ruff-format + + ##### Security ##### - repo: https://github.com/gitleaks/gitleaks - rev: v8.23.3 + rev: v8.24.0 hooks: - id: gitleaks - repo: https://github.com/woodruffw/zizmor-pre-commit - rev: v1.3.1 + rev: v1.4.1 hooks: - id: zizmor + - repo: https://github.com/PyCQA/bandit + rev: 1.8.3 + hooks: + - id: bandit + args: ["-c", "pyproject.toml"] + additional_dependencies: ["bandit[toml]"] diff --git a/lerobot/common/utils/utils.py b/lerobot/common/utils/utils.py index d0c12b30..cd26f04b 100644 --- a/lerobot/common/utils/utils.py +++ b/lerobot/common/utils/utils.py @@ -17,6 +17,7 @@ import logging import os import os.path as osp import platform +import subprocess from copy import copy from datetime import datetime, timezone from pathlib import Path @@ -165,23 +166,31 @@ def capture_timestamp_utc(): def say(text, blocking=False): - # Check if mac, linux, or windows. - if platform.system() == "Darwin": - cmd = f'say "{text}"' - if not blocking: - cmd += " &" - elif platform.system() == "Linux": - cmd = f'spd-say "{text}"' - if blocking: - cmd += " --wait" - elif platform.system() == "Windows": - # TODO(rcadene): Make blocking option work for Windows - cmd = ( - 'PowerShell -Command "Add-Type -AssemblyName System.Speech; ' - f"(New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('{text}')\"" - ) + system = platform.system() - os.system(cmd) + if system == "Darwin": + cmd = ["say", text] + + elif system == "Linux": + cmd = ["spd-say", text] + if blocking: + cmd.append("--wait") + + elif system == "Windows": + cmd = [ + "PowerShell", + "-Command", + "Add-Type -AssemblyName System.Speech; " + f"(New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('{text}')", + ] + + else: + raise RuntimeError("Unsupported operating system for text-to-speech.") + + if blocking: + subprocess.run(cmd, check=True) + else: + subprocess.Popen(cmd, creationflags=subprocess.CREATE_NO_WINDOW if system == "Windows" else 0) def log_say(text, play_sounds, blocking=False): diff --git a/lerobot/scripts/eval.py b/lerobot/scripts/eval.py index a4f79afc..47225993 100644 --- a/lerobot/scripts/eval.py +++ b/lerobot/scripts/eval.py @@ -454,7 +454,7 @@ def _compile_episode_data( @parser.wrap() -def eval(cfg: EvalPipelineConfig): +def eval_main(cfg: EvalPipelineConfig): logging.info(pformat(asdict(cfg))) # Check device is available @@ -499,4 +499,4 @@ def eval(cfg: EvalPipelineConfig): if __name__ == "__main__": init_logging() - eval() + eval_main() diff --git a/lerobot/scripts/visualize_dataset_html.py b/lerobot/scripts/visualize_dataset_html.py index a0da0869..a6899ce9 100644 --- a/lerobot/scripts/visualize_dataset_html.py +++ b/lerobot/scripts/visualize_dataset_html.py @@ -194,7 +194,7 @@ def run_server( ] response = requests.get( - f"https://huggingface.co/datasets/{repo_id}/resolve/main/meta/episodes.jsonl" + f"https://huggingface.co/datasets/{repo_id}/resolve/main/meta/episodes.jsonl", timeout=5 ) response.raise_for_status() # Split into lines and parse each line as JSON @@ -318,7 +318,9 @@ def get_episode_language_instruction(dataset: LeRobotDataset, ep_index: int) -> def get_dataset_info(repo_id: str) -> IterableNamespace: - response = requests.get(f"https://huggingface.co/datasets/{repo_id}/resolve/main/meta/info.json") + response = requests.get( + f"https://huggingface.co/datasets/{repo_id}/resolve/main/meta/info.json", timeout=5 + ) response.raise_for_status() # Raises an HTTPError for bad responses dataset_info = response.json() dataset_info["repo_id"] = repo_id diff --git a/lerobot/templates/visualize_dataset_template.html b/lerobot/templates/visualize_dataset_template.html index d81ce630..96ef28d3 100644 --- a/lerobot/templates/visualize_dataset_template.html +++ b/lerobot/templates/visualize_dataset_template.html @@ -42,22 +42,22 @@ - +
- -
- +
- @@ -83,7 +83,7 @@

- @@ -476,7 +476,7 @@ episodes: {{ episodes }}, pageSize: 100, page: 1, - + init() { // Find which page contains the current episode_id const currentEpisodeId = {{ episode_id }}; @@ -485,23 +485,23 @@ this.page = Math.floor(episodeIndex / this.pageSize) + 1; } }, - + get totalPages() { return Math.ceil(this.episodes.length / this.pageSize); }, - + get paginatedEpisodes() { const start = (this.page - 1) * this.pageSize; const end = start + this.pageSize; return this.episodes.slice(start, end); }, - + nextPage() { if (this.page < this.totalPages) { this.page++; } }, - + prevPage() { if (this.page > 1) { this.page--; @@ -515,7 +515,7 @@ window.addEventListener('keydown', (e) => { // Use the space bar to play and pause, instead of default action (e.g. scrolling) const { keyCode, key } = e; - + if (keyCode === 32 || key === ' ') { e.preventDefault(); const btnPause = document.querySelector('[x-ref="btnPause"]'); diff --git a/pyproject.toml b/pyproject.toml index 7684ce48..9a7c9730 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,10 +111,19 @@ exclude = [ "venv", ] - [tool.ruff.lint] select = ["E4", "E7", "E9", "F", "I", "N", "B", "C4", "SIM"] +[tool.bandit] +exclude_dirs = [ + "tests", + "benchmarks", + "lerobot/common/datasets/push_dataset_to_hub", + "lerobot/common/datasets/v2/convert_dataset_v1_to_v2", + "lerobot/common/policies/pi0/conversion_scripts", + "lerobot/scripts/push_dataset_to_hub.py", +] +skips = ["B101", "B311", "B404", "B603"] [tool.typos] default.extend-ignore-re = [