[Security] Add Bandit (#795)

This commit is contained in:
Simon Alibert 2025-03-01 19:19:26 +01:00 committed by GitHub
parent 9c1a893ee3
commit 8861546ad8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 67 additions and 38 deletions

View File

@ -2,6 +2,7 @@ exclude: ^(tests/data)
default_language_version: default_language_version:
python: python3.10 python: python3.10
repos: repos:
##### Style / Misc. #####
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0 rev: v5.0.0
hooks: hooks:
@ -14,7 +15,7 @@ repos:
- id: end-of-file-fixer - id: end-of-file-fixer
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/crate-ci/typos - repo: https://github.com/crate-ci/typos
rev: v1.29.10 rev: v1.30.0
hooks: hooks:
- id: typos - id: typos
args: [--force-exclude] args: [--force-exclude]
@ -23,16 +24,24 @@ repos:
hooks: hooks:
- id: pyupgrade - id: pyupgrade
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.6 rev: v0.9.9
hooks: hooks:
- id: ruff - id: ruff
args: [--fix] args: [--fix]
- id: ruff-format - id: ruff-format
##### Security #####
- repo: https://github.com/gitleaks/gitleaks - repo: https://github.com/gitleaks/gitleaks
rev: v8.23.3 rev: v8.24.0
hooks: hooks:
- id: gitleaks - id: gitleaks
- repo: https://github.com/woodruffw/zizmor-pre-commit - repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.3.1 rev: v1.4.1
hooks: hooks:
- id: zizmor - id: zizmor
- repo: https://github.com/PyCQA/bandit
rev: 1.8.3
hooks:
- id: bandit
args: ["-c", "pyproject.toml"]
additional_dependencies: ["bandit[toml]"]

View File

@ -17,6 +17,7 @@ import logging
import os import os
import os.path as osp import os.path as osp
import platform import platform
import subprocess
from copy import copy from copy import copy
from datetime import datetime, timezone from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
@ -165,23 +166,31 @@ def capture_timestamp_utc():
def say(text, blocking=False): def say(text, blocking=False):
# Check if mac, linux, or windows. system = platform.system()
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}')\""
)
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): def log_say(text, play_sounds, blocking=False):

View File

@ -454,7 +454,7 @@ def _compile_episode_data(
@parser.wrap() @parser.wrap()
def eval(cfg: EvalPipelineConfig): def eval_main(cfg: EvalPipelineConfig):
logging.info(pformat(asdict(cfg))) logging.info(pformat(asdict(cfg)))
# Check device is available # Check device is available
@ -499,4 +499,4 @@ def eval(cfg: EvalPipelineConfig):
if __name__ == "__main__": if __name__ == "__main__":
init_logging() init_logging()
eval() eval_main()

View File

@ -194,7 +194,7 @@ def run_server(
] ]
response = requests.get( 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() response.raise_for_status()
# Split into lines and parse each line as JSON # 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: 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 response.raise_for_status() # Raises an HTTPError for bad responses
dataset_info = response.json() dataset_info = response.json()
dataset_info["repo_id"] = repo_id dataset_info["repo_id"] = repo_id

View File

@ -42,22 +42,22 @@
<ul> <ul>
<template x-for="episode in paginatedEpisodes" :key="episode"> <template x-for="episode in paginatedEpisodes" :key="episode">
<li class="font-mono text-sm mt-0.5"> <li class="font-mono text-sm mt-0.5">
<a :href="'episode_' + episode" <a :href="'episode_' + episode"
:class="{'underline': true, 'font-bold -ml-1': episode == {{ episode_id }}}" :class="{'underline': true, 'font-bold -ml-1': episode == {{ episode_id }}}"
x-text="'Episode ' + episode"></a> x-text="'Episode ' + episode"></a>
</li> </li>
</template> </template>
</ul> </ul>
<div class="flex items-center mt-3 text-xs" x-show="totalPages > 1"> <div class="flex items-center mt-3 text-xs" x-show="totalPages > 1">
<button @click="prevPage()" <button @click="prevPage()"
class="px-2 py-1 bg-slate-800 rounded mr-2" class="px-2 py-1 bg-slate-800 rounded mr-2"
:class="{'opacity-50 cursor-not-allowed': page === 1}" :class="{'opacity-50 cursor-not-allowed': page === 1}"
:disabled="page === 1"> :disabled="page === 1">
&laquo; Prev &laquo; Prev
</button> </button>
<span class="font-mono mr-2" x-text="` ${page} / ${totalPages}`"></span> <span class="font-mono mr-2" x-text="` ${page} / ${totalPages}`"></span>
<button @click="nextPage()" <button @click="nextPage()"
class="px-2 py-1 bg-slate-800 rounded" class="px-2 py-1 bg-slate-800 rounded"
:class="{'opacity-50 cursor-not-allowed': page === totalPages}" :class="{'opacity-50 cursor-not-allowed': page === totalPages}"
:disabled="page === totalPages"> :disabled="page === totalPages">
@ -65,10 +65,10 @@
</button> </button>
</div> </div>
</div> </div>
<!-- episodes menu for small screens --> <!-- episodes menu for small screens -->
<div class="flex overflow-x-auto md:hidden" x-data="episodePagination"> <div class="flex overflow-x-auto md:hidden" x-data="episodePagination">
<button @click="prevPage()" <button @click="prevPage()"
class="px-2 bg-slate-800 rounded mr-2" class="px-2 bg-slate-800 rounded mr-2"
:class="{'opacity-50 cursor-not-allowed': page === 1}" :class="{'opacity-50 cursor-not-allowed': page === 1}"
:disabled="page === 1">&laquo;</button> :disabled="page === 1">&laquo;</button>
@ -83,7 +83,7 @@
</p> </p>
</template> </template>
</div> </div>
<button @click="nextPage()" <button @click="nextPage()"
class="px-2 bg-slate-800 rounded ml-2" class="px-2 bg-slate-800 rounded ml-2"
:class="{'opacity-50 cursor-not-allowed': page === totalPages}" :class="{'opacity-50 cursor-not-allowed': page === totalPages}"
:disabled="page === totalPages">&raquo; </button> :disabled="page === totalPages">&raquo; </button>
@ -476,7 +476,7 @@
episodes: {{ episodes }}, episodes: {{ episodes }},
pageSize: 100, pageSize: 100,
page: 1, page: 1,
init() { init() {
// Find which page contains the current episode_id // Find which page contains the current episode_id
const currentEpisodeId = {{ episode_id }}; const currentEpisodeId = {{ episode_id }};
@ -485,23 +485,23 @@
this.page = Math.floor(episodeIndex / this.pageSize) + 1; this.page = Math.floor(episodeIndex / this.pageSize) + 1;
} }
}, },
get totalPages() { get totalPages() {
return Math.ceil(this.episodes.length / this.pageSize); return Math.ceil(this.episodes.length / this.pageSize);
}, },
get paginatedEpisodes() { get paginatedEpisodes() {
const start = (this.page - 1) * this.pageSize; const start = (this.page - 1) * this.pageSize;
const end = start + this.pageSize; const end = start + this.pageSize;
return this.episodes.slice(start, end); return this.episodes.slice(start, end);
}, },
nextPage() { nextPage() {
if (this.page < this.totalPages) { if (this.page < this.totalPages) {
this.page++; this.page++;
} }
}, },
prevPage() { prevPage() {
if (this.page > 1) { if (this.page > 1) {
this.page--; this.page--;
@ -515,7 +515,7 @@
window.addEventListener('keydown', (e) => { window.addEventListener('keydown', (e) => {
// Use the space bar to play and pause, instead of default action (e.g. scrolling) // Use the space bar to play and pause, instead of default action (e.g. scrolling)
const { keyCode, key } = e; const { keyCode, key } = e;
if (keyCode === 32 || key === ' ') { if (keyCode === 32 || key === ' ') {
e.preventDefault(); e.preventDefault();
const btnPause = document.querySelector('[x-ref="btnPause"]'); const btnPause = document.querySelector('[x-ref="btnPause"]');

View File

@ -111,10 +111,19 @@ exclude = [
"venv", "venv",
] ]
[tool.ruff.lint] [tool.ruff.lint]
select = ["E4", "E7", "E9", "F", "I", "N", "B", "C4", "SIM"] 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] [tool.typos]
default.extend-ignore-re = [ default.extend-ignore-re = [