diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b17a18b0dbdce..07000ff3d09c2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -979,6 +979,23 @@ repos: files: ^airflow/providers/.*/provider\.yaml|^docs/.* additional_dependencies: ['rich>=12.4.4', 'pyyaml', 'jinja2'] require_serial: true + - id: bandit + name: bandit + description: "Bandit is a tool for finding common security issues in Python code" + entry: bandit + language: python + language_version: python3 + types: [ python ] + additional_dependencies: ['bandit>=1.7.5'] + require_serial: true + files: ^airflow/.* + exclude: + airflow/example_dags/.* + args: + - "--skip" + - "B301,B324,B403,B404,B603" + - "--severity-level" + - "high" # TODO: remove this line when we fix all the issues ## ADD MOST PRE-COMMITS ABOVE THAT LINE # The below pre-commits are those requiring CI image to be built - id: mypy-dev diff --git a/STATIC_CODE_CHECKS.rst b/STATIC_CODE_CHECKS.rst index af235cd2d54b6..7f81ff1267fde 100644 --- a/STATIC_CODE_CHECKS.rst +++ b/STATIC_CODE_CHECKS.rst @@ -140,6 +140,8 @@ require Breeze Docker image to be built locally. +-----------------------------------------------------------+--------------------------------------------------------------+---------+ | ID | Description | Image | +===========================================================+==============================================================+=========+ +| bandit | bandit | | ++-----------------------------------------------------------+--------------------------------------------------------------+---------+ | blacken-docs | Run black on Python code blocks in documentation files | | +-----------------------------------------------------------+--------------------------------------------------------------+---------+ | check-aiobotocore-optional | Check if aiobotocore is an optional dependency only | | diff --git a/airflow/cli/cli_config.py b/airflow/cli/cli_config.py index 43b2590324186..e5a57f4552b3d 100644 --- a/airflow/cli/cli_config.py +++ b/airflow/cli/cli_config.py @@ -771,7 +771,7 @@ def string_lower_type(val): ) ARG_INTERNAL_API_HOSTNAME = Arg( ("-H", "--hostname"), - default="0.0.0.0", + default="0.0.0.0", # nosec help="Set the hostname on which to run the web server", ) ARG_INTERNAL_API_ACCESS_LOGFILE = Arg( diff --git a/airflow/cli/commands/internal_api_command.py b/airflow/cli/commands/internal_api_command.py index f558c89cab797..dd938015378a7 100644 --- a/airflow/cli/commands/internal_api_command.py +++ b/airflow/cli/commands/internal_api_command.py @@ -73,7 +73,7 @@ def internal_api(args): log.info(f"Starting the Internal API server on port {args.port} and host {args.hostname}.") app = create_app(testing=conf.getboolean("core", "unit_test_mode")) app.run( - debug=True, + debug=True, # nosec use_reloader=not app.config["TESTING"], port=args.port, host=args.hostname, diff --git a/airflow/providers/cncf/kubernetes/python_kubernetes_script.py b/airflow/providers/cncf/kubernetes/python_kubernetes_script.py index 75937287d582e..177c11764b5bf 100644 --- a/airflow/providers/cncf/kubernetes/python_kubernetes_script.py +++ b/airflow/providers/cncf/kubernetes/python_kubernetes_script.py @@ -22,6 +22,7 @@ from collections import deque import jinja2 +from jinja2 import select_autoescape def _balance_parens(after_decorator): @@ -83,6 +84,10 @@ def write_python_script( loader=template_loader, undefined=jinja2.StrictUndefined ) else: - template_env = jinja2.Environment(loader=template_loader, undefined=jinja2.StrictUndefined) + template_env = jinja2.Environment( + loader=template_loader, + undefined=jinja2.StrictUndefined, + autoescape=select_autoescape(["html", "xml"]), + ) template = template_env.get_template("python_kubernetes_script.jinja2") template.stream(**jinja_context).dump(filename) diff --git a/airflow/providers/ftp/hooks/ftp.py b/airflow/providers/ftp/hooks/ftp.py index 1935a698638a5..54892da965a97 100644 --- a/airflow/providers/ftp/hooks/ftp.py +++ b/airflow/providers/ftp/hooks/ftp.py @@ -18,7 +18,7 @@ from __future__ import annotations import datetime -import ftplib +import ftplib # nosec: B402 from typing import Any, Callable from airflow.hooks.base import BaseHook @@ -58,7 +58,7 @@ def get_conn(self) -> ftplib.FTP: if self.conn is None: params = self.get_connection(self.ftp_conn_id) pasv = params.extra_dejson.get("passive", True) - self.conn = ftplib.FTP(params.host, params.login, params.password) + self.conn = ftplib.FTP(params.host, params.login, params.password) # nosec: B321 self.conn.set_pasv(pasv) return self.conn @@ -277,7 +277,7 @@ def get_conn(self) -> ftplib.FTP: if params.port: ftplib.FTP_TLS.port = params.port - self.conn = ftplib.FTP_TLS(params.host, params.login, params.password) + self.conn = ftplib.FTP_TLS(params.host, params.login, params.password) # nosec: B321 self.conn.set_pasv(pasv) return self.conn diff --git a/airflow/providers/ftp/operators/ftp.py b/airflow/providers/ftp/operators/ftp.py index 89ea9f8f73ad8..98ff11bc2151a 100644 --- a/airflow/providers/ftp/operators/ftp.py +++ b/airflow/providers/ftp/operators/ftp.py @@ -20,7 +20,7 @@ import os import socket -from ftplib import FTP_PORT +from ftplib import FTP_PORT # nosec: B402 from functools import cached_property from pathlib import Path from typing import Any, Sequence diff --git a/airflow/providers/ftp/sensors/ftp.py b/airflow/providers/ftp/sensors/ftp.py index 19b69fb994cb3..847cf763537dd 100644 --- a/airflow/providers/ftp/sensors/ftp.py +++ b/airflow/providers/ftp/sensors/ftp.py @@ -17,7 +17,7 @@ # under the License. from __future__ import annotations -import ftplib +import ftplib # nosec: B402 import re from typing import TYPE_CHECKING, Sequence diff --git a/airflow/utils/python_virtualenv.py b/airflow/utils/python_virtualenv.py index d613782f32994..d49ac2b9b44ea 100644 --- a/airflow/utils/python_virtualenv.py +++ b/airflow/utils/python_virtualenv.py @@ -24,6 +24,7 @@ from pathlib import Path import jinja2 +from jinja2 import select_autoescape from airflow.utils.decorators import remove_task_decorator as _remove_task_decorator from airflow.utils.process_utils import execute_in_subprocess @@ -140,6 +141,10 @@ def write_python_script( loader=template_loader, undefined=jinja2.StrictUndefined ) else: - template_env = jinja2.Environment(loader=template_loader, undefined=jinja2.StrictUndefined) + template_env = jinja2.Environment( + loader=template_loader, + undefined=jinja2.StrictUndefined, + autoescape=select_autoescape(["html", "xml"]), + ) template = template_env.get_template("python_virtualenv_script.jinja2") template.stream(**jinja_context).dump(filename) diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py b/dev/breeze/src/airflow_breeze/pre_commit_ids.py index 8ef922f9817a4..35dd8883e3698 100644 --- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py +++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py @@ -24,6 +24,7 @@ PRE_COMMIT_LIST = [ "all", + "bandit", "blacken-docs", "check-aiobotocore-optional", "check-airflow-k8s-not-used", diff --git a/images/breeze/output_static-checks.svg b/images/breeze/output_static-checks.svg index 3c623b9948c72..650f6755a7aba 100644 --- a/images/breeze/output_static-checks.svg +++ b/images/breeze/output_static-checks.svg @@ -1,4 +1,4 @@ - +