Skip to content

Commit

Permalink
Enable Bandit security linter (#633)
Browse files Browse the repository at this point in the history
* nidaqmx: Add a dependency on the Bandit security linter

* nidaqmx: Update poetry.lock

* nidaqmx: Address or acknowledge potential security issues

* github: Run Bandit in build.yml
  • Loading branch information
bkeryan authored Sep 10, 2024
1 parent c60e5a8 commit c09f2e2
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
run: poetry run mypy
- name: Run mypy (Windows)
run: poetry run mypy --platform win32
- name: Run Bandit security checks
run: poetry run bandit -c pyproject.toml -r generated/nidaqmx
- name: Generate ni-daqmx files
run: |
rm -fr generated/nidaqmx
Expand Down
29 changes: 22 additions & 7 deletions generated/nidaqmx/_install_daqmx.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
import pathlib
import re
import shutil
import subprocess
import subprocess # nosec: B404
import sys
import tempfile
import traceback
import requests
import zipfile
from typing import Generator, List, Optional, Tuple
from urllib.parse import urlparse

import click

Expand All @@ -30,6 +31,7 @@
_logger = logging.getLogger(__name__)

METADATA_FILE = "_installer_metadata.json"
_NETWORK_TIMEOUT_IN_SECONDS = 60


def _parse_version(version: str) -> Tuple[int, ...]:
Expand Down Expand Up @@ -96,7 +98,8 @@ def _get_daqmx_installed_version() -> Optional[str]:
_logger.debug("Checking for installed NI-DAQmx version")
commands_info = LINUX_COMMANDS[distribution]
query_command = commands_info.get_daqmx_version
query_output = subprocess.run(query_command, stdout=subprocess.PIPE, text=True).stdout
# Run the package query command defined by _linux_installation_commands.py.
query_output = subprocess.run(query_command, stdout=subprocess.PIPE, text=True).stdout # nosec: B603

if distribution == "ubuntu":
version_match = re.search(r"ii\s+ni-daqmx\s+(\d+\.\d+\.\d+)", query_output)
Expand Down Expand Up @@ -233,16 +236,17 @@ def _install_daqmx_driver_windows_core(download_url: str) -> None:
Download and launch NI-DAQmx Driver installation in an interactive mode
"""
temp_file = None
_validate_download_url(download_url)
try:
with _multi_access_temp_file() as temp_file:
_logger.info("Downloading Driver to %s", temp_file)
response = requests.get(download_url)
response = requests.get(download_url, timeout=_NETWORK_TIMEOUT_IN_SECONDS)
response.raise_for_status()
with open(temp_file, 'wb') as f:
f.write(response.content)
_logger.info("Installing NI-DAQmx")
subprocess.run([temp_file], shell=True, check=True)
# Run the installer that we just downloaded from https://download.ni.com.
subprocess.run([temp_file], shell=True, check=True) # nosec: B602
except subprocess.CalledProcessError as e:
_logger.info("Failed to install NI-DAQmx driver.", exc_info=True)
raise click.ClickException(
Expand All @@ -262,10 +266,11 @@ def _install_daqmx_driver_linux_core(download_url: str, release: str) -> None:
"""
if sys.platform.startswith("linux"):
_validate_download_url(download_url)
try:
with _multi_access_temp_file(suffix=".zip") as temp_file:
_logger.info("Downloading Driver to %s", temp_file)
response = requests.get(download_url)
response = requests.get(download_url, timeout=_NETWORK_TIMEOUT_IN_SECONDS)
response.raise_for_status()
with open(temp_file, 'wb') as f:
f.write(response.content)
Expand All @@ -283,7 +288,10 @@ def _install_daqmx_driver_linux_core(download_url: str, release: str) -> None:
directory_to_extract_to, distro.id(), distro.version(), release
):
print("\nRunning command:", " ".join(command))
subprocess.run(command, check=True)
# Run the commands defined in
# _linux_installation_commands.py to install the package
# that we just downloaded from https://download.ni.com.
subprocess.run(command, check=True) # nosec: B603

# Check if the installation was successful
if not _get_daqmx_installed_version():
Expand Down Expand Up @@ -312,6 +320,13 @@ def _install_daqmx_driver_linux_core(download_url: str, release: str) -> None:
raise NotImplementedError("This function is only supported on Linux.")


def _validate_download_url(download_url: str) -> None:
"""Velidate that the download URL uses https and points to a trusted site."""
parsed_url = urlparse(download_url)
if parsed_url.scheme != "https" or parsed_url.netloc != "download.ni.com":
raise click.ClickException(f"Unsupported download URL: {download_url}")


def _ask_user_confirmation(user_message: str) -> bool:
"""
Prompt for user confirmation
Expand Down
172 changes: 169 additions & 3 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ matplotlib = {version=">=3.9.0", python = ">=3.9"}
nptdms = ">=1.9.0"

[tool.poetry.group.lint.dependencies]
bandit = { version = ">=1.7", extras = ["toml"] }
ni-python-styleguide = ">=0.4.1"
mypy = ">=1.0"
types-protobuf = "^4.21"
Expand Down Expand Up @@ -149,3 +150,8 @@ module = [
"nidaqmx.*",
]
ignore_missing_imports = true

[tool.bandit]
skips = [
"B101", # assert_used
]
Loading

0 comments on commit c09f2e2

Please sign in to comment.