ref: Add ruff rules for bandit (S) (#4111)

* Add ruff rules for bandit (S)

* Changes following review
This commit is contained in:
Christophe Bornet 2024-10-23 00:33:37 +02:00 • committed by GitHub
commit 8224bce532
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 455 additions and 41 deletions

View file

@ -24,7 +24,7 @@ def get_patched_openai_client(shared_component_cache):
url = "https://raw.githubusercontent.com/BerriAI/litellm/refs/heads/main/model_prices_and_context_window.json"
response = requests.get(url)
response = requests.get(url, timeout=10)
data = json.loads(response.text)
# Extract the model names into a Python list

View file

@ -53,7 +53,7 @@ def normalize_newlines(multiline_text):
def parse_curl_command(curl_command):
tokens = shlex.split(normalize_newlines(curl_command))
tokens = [token for token in tokens if token and token != " "]
tokens = [token for token in tokens if token and token != " "] # noqa: S105
if tokens and "curl" not in tokens[0]:
msg = "Invalid curl command"
raise ValueError(msg)
@ -78,7 +78,7 @@ def parse_curl_command(curl_command):
i = 0
while i < len(tokens):
token = tokens[i]
if token == "-X":
if token == "-X": # noqa: S105
i += 1
args["method"] = tokens[i].lower()
method_on_curl = tokens[i].lower()
@ -91,7 +91,7 @@ def parse_curl_command(curl_command):
elif token in {"-H", "--header"}:
i += 1
args["headers"].append(tokens[i])
elif token == "--compressed":
elif token == "--compressed": # noqa: S105
args["compressed"] = True
elif token in {"-k", "--insecure"}:
args["insecure"] = True

View file

@ -1,5 +1,4 @@
import unicodedata
import xml.etree.ElementTree as ET
from collections.abc import Callable
from concurrent import futures
from pathlib import Path
@ -7,6 +6,7 @@ from pathlib import Path
import chardet
import orjson
import yaml
from defusedxml import ElementTree
from langflow.schema import Data
@ -155,8 +155,8 @@ def parse_text_file_to_data(file_path: str, *, silent_errors: bool) -> Data | No
elif file_path.endswith((".yaml", ".yml")):
text = yaml.safe_load(text)
elif file_path.endswith(".xml"):
xml_element = ET.fromstring(text)
text = ET.tostring(xml_element, encoding="unicode")
xml_element = ElementTree.fromstring(text)
text = ElementTree.tostring(xml_element, encoding="unicode")
except Exception as e:
if not silent_errors:
msg = f"Error loading file {file_path}: {e}"

View file

@ -74,7 +74,7 @@ class AddContentToPage(LCToolComponent):
"children": blocks,
}
response = requests.patch(url, headers=headers, json=data)
response = requests.patch(url, headers=headers, json=data, timeout=10)
response.raise_for_status()
return response.json()

View file

@ -81,7 +81,7 @@ class NotionPageCreator(LCToolComponent):
}
try:
response = requests.post("https://api.notion.com/v1/pages", headers=headers, json=data)
response = requests.post("https://api.notion.com/v1/pages", headers=headers, json=data, timeout=10)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:

View file

@ -55,7 +55,7 @@ class NotionDatabaseProperties(LCToolComponent):
"Notion-Version": "2022-06-28", # Use the latest supported version
}
try:
response = requests.get(url, headers=headers)
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()
return data.get("properties", {})

View file

@ -109,7 +109,7 @@ class NotionListPages(LCToolComponent):
return f"Invalid JSON format for query: {e}"
try:
response = requests.post(url, headers=headers, json=query_payload)
response = requests.post(url, headers=headers, json=query_payload, timeout=10)
response.raise_for_status()
results = response.json()
return results["results"]

View file

@ -58,7 +58,7 @@ class NotionUserList(LCToolComponent):
"Notion-Version": "2022-06-28",
}
response = requests.get(url, headers=headers)
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
data = response.json()

View file

@ -55,7 +55,7 @@ class NotionPageContent(LCToolComponent):
"Notion-Version": "2022-06-28",
}
try:
blocks_response = requests.get(blocks_url, headers=headers)
blocks_response = requests.get(blocks_url, headers=headers, timeout=10)
blocks_response.raise_for_status()
blocks_data = blocks_response.json()
return self.parse_blocks(blocks_data.get("results", []))

View file

@ -104,7 +104,7 @@ class NotionSearch(LCToolComponent):
"sort": {"direction": sort_direction, "timestamp": "last_edited_time"},
}
response = requests.post(url, headers=headers, json=data)
response = requests.post(url, headers=headers, json=data, timeout=10)
response.raise_for_status()
results = response.json()

View file

@ -87,7 +87,7 @@ class NotionPageUpdate(LCToolComponent):
try:
logger.info(f"Sending request to Notion API: URL: {url}, Data: {json.dumps(data)}")
response = requests.patch(url, headers=headers, json=data)
response = requests.patch(url, headers=headers, json=data, timeout=10)
response.raise_for_status()
updated_page = response.json()

View file

@ -25,7 +25,7 @@ class JsonAgentComponent(LCAgentComponent):
path = Path(self.path)
if path.suffix in ("yaml", "yml"):
with path.open(encoding="utf-8") as file:
yaml_dict = yaml.load(file, Loader=yaml.FullLoader)
yaml_dict = yaml.safe_load(file)
spec = JsonSpec(dict_=yaml_dict)
else:
spec = JsonSpec.from_file(path)

View file

@ -27,7 +27,7 @@ class OpenAPIAgentComponent(LCAgentComponent):
path = Path(self.path)
if path.suffix in ("yaml", "yml"):
with path.open(encoding="utf-8") as file:
yaml_dict = yaml.load(file, Loader=yaml.FullLoader)
yaml_dict = yaml.safe_load(file)
spec = JsonSpec(dict_=yaml_dict)
else:
spec = JsonSpec.from_file(path)

View file

@ -81,7 +81,9 @@ class GoogleDriveComponent(Component):
msg = f"Error loading documents: {e}"
raise ValueError(msg) from e
assert len(docs) == 1, "Expected a single document to be loaded."
if len(docs) != 1:
msg = "Expected a single document to be loaded."
raise ValueError(msg)
data = docs_to_data(docs)
# Return the loaded documents

View file

@ -34,7 +34,9 @@ class EmbeddingSimilarityComponent(Component):
embedding_vectors: list[Data] = self.embedding_vectors
# Assert that the list contains exactly two Data objects
assert len(embedding_vectors) == 2, "Exactly two embedding vectors are required." # noqa: PLR2004
if len(embedding_vectors) != 2: # noqa: PLR2004
msg = "Exactly two embedding vectors are required."
raise ValueError(msg)
embedding_1 = np.array(embedding_vectors[0].data["embeddings"])
embedding_2 = np.array(embedding_vectors[1].data["embeddings"])

View file

@ -29,7 +29,9 @@ class AIMLEmbeddingsImpl(BaseModel, Embeddings):
for index, future in futures:
try:
result_data = future.result()
assert len(result_data["data"]) == 1, "Expected one embedding"
if len(result_data["data"]) != 1:
msg = "Expected one embedding"
raise ValueError(msg)
embeddings[index] = result_data["data"][0]["embedding"]
except (
httpx.HTTPStatusError,

View file

@ -68,7 +68,7 @@ class GroqModel(LCModelComponent):
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
try:
response = requests.get(url, headers=headers)
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
model_list = response.json()
return [model["id"] for model in model_list.get("data", [])]

View file

@ -113,7 +113,7 @@ class AstraDBCQLToolComponent(LCToolComponent):
if self.projection_fields != "*":
url += f'&fields={urllib.parse.quote(self.projection_fields.replace(" ", ""))}'
res = requests.request("GET", url=url, headers=headers)
res = requests.request("GET", url=url, headers=headers, timeout=10)
if int(res.status_code) >= HTTPStatus.BAD_REQUEST:
return res.text

View file

@ -61,7 +61,7 @@ class SearXNGToolComponent(LCToolComponent):
try:
url = f"{field_value}/config"
response = requests.get(url=url, headers=self.search_headers.copy())
response = requests.get(url=url, headers=self.search_headers.copy(), timeout=10)
data = None
if response.headers.get("Content-Encoding") == "zstd":
data = json.loads(response.content)
@ -105,6 +105,7 @@ class SearXNGToolComponent(LCToolComponent):
"language": SearxSearch._language,
"format": "json",
},
timeout=10,
).json()
num_results = min(SearxSearch._max_results, len(response["results"]))

View file

@ -161,7 +161,7 @@ class CodeParser:
# Handle cases where the type is not found in the constructed environment
with contextlib.suppress(NameError):
return_type = eval(return_type_str, eval_env)
return_type = eval(return_type_str, eval_env) # noqa: S307
func = CallableCodeDetails(
name=node.name,

View file

@ -18,6 +18,8 @@ from grandalf.graphs import Vertex as GrandalfVertex
from grandalf.layouts import SugiyamaLayout
from grandalf.routing import EdgeViewer, route_with_lines
MINIMUM_EDGE_VIEW_POINTS = 2
class VertexViewer:
"""Class to define vertex box boundaries that will be accounted for during graph building by grandalf."""
@ -41,8 +43,12 @@ class AsciiCanvas:
"""Class for drawing in ASCII."""
def __init__(self, cols, lines) -> None:
assert cols > 1
assert lines > 1
if cols <= 1:
msg = "cols must be greater than 1"
raise ValueError(msg)
if lines <= 1:
msg = "lines must be greater than 1"
raise ValueError(msg)
self.cols = cols
self.lines = lines
self.canvas = [[" "] * cols for _ in range(lines)]
@ -60,9 +66,15 @@ class AsciiCanvas:
def point(self, x, y, char) -> None:
"""Create a point on ASCII canvas."""
assert len(char) == 1
assert 0 <= x < self.cols
assert 0 <= y < self.lines
if len(char) != 1:
msg = "char must be a single character"
raise ValueError(msg)
if x < 0 or x >= self.cols:
msg = "x is out of bounds"
raise ValueError(msg)
if y < 0 or y >= self.lines:
msg = "y is out of bounds"
raise ValueError(msg)
self.canvas[y][x] = char
def line(self, x0, y0, x1, y1, char) -> None:
@ -92,8 +104,12 @@ class AsciiCanvas:
def box(self, x0, y0, width, height) -> None:
"""Create a box on ASCII canvas."""
assert width > 1
assert height > 1
if width <= 1:
msg = "width must be greater than 1"
raise ValueError(msg)
if height <= 1:
msg = "height must be greater than 1"
raise ValueError(msg)
width -= 1
height -= 1
@ -161,7 +177,9 @@ def draw_graph(vertexes, edges, *, return_ascii=True):
canvas = AsciiCanvas(canvas_cols, canvas_lines)
for edge in sug.g.sE:
assert len(edge.view._pts) > 1
if len(edge.view._pts) < MINIMUM_EDGE_VIEW_POINTS:
msg = "edge.view._pts must have at least 2 points"
raise ValueError(msg)
for index in range(1, len(edge.view._pts)):
start = edge.view._pts[index - 1]
end = edge.view._pts[index]

View file

@ -194,7 +194,7 @@ async def flow_function({func_args}):
compiled_func = compile(func_body, "<string>", "exec")
local_scope: dict = {}
exec(compiled_func, globals(), local_scope)
exec(compiled_func, globals(), local_scope) # noqa: S102
return local_scope["flow_function"]

View file

@ -18,7 +18,7 @@ from langflow.schema.table import Column, TableSchema
class FieldTypes(str, Enum):
TEXT = "str"
INTEGER = "int"
PASSWORD = "str" # noqa: PIE796
PASSWORD = "str" # noqa: PIE796, S105
FLOAT = "float"
BOOLEAN = "bool"
DICT = "dict"

View file

@ -38,7 +38,7 @@ def create_input_schema(inputs: list["InputTypes"]) -> type[BaseModel]:
literal_string = f"Literal{input_model.options}"
# validate that the literal_string is a valid literal
field_type = eval(literal_string, {"Literal": Literal})
field_type = eval(literal_string, {"Literal": Literal}) # noqa: S307
if hasattr(input_model, "is_list") and input_model.is_list:
field_type = list[field_type] # type: ignore[valid-type]
if input_model.name:

View file

@ -1,5 +1,5 @@
DEFAULT_SUPERUSER = "langflow"
DEFAULT_SUPERUSER_PASSWORD = "langflow"
DEFAULT_SUPERUSER_PASSWORD = "langflow" # noqa: S105
VARIABLES_TO_GET_FROM_ENVIRONMENT = [
"OPENAI_API_KEY",
"ANTHROPIC_API_KEY",

View file

@ -22,7 +22,12 @@ class KubernetesSecretManager:
# initialize the Kubernetes API client
self.core_api = client.CoreV1Api()
def create_secret(self, name: str, data: dict, secret_type: str = "Opaque"):
def create_secret(
self,
name: str,
data: dict,
secret_type: str = "Opaque", # noqa: S107
):
"""Create a new secret in the specified namespace.
Args:

View file

@ -59,7 +59,6 @@ ignore = [
# Rules that are TODOs
"ANN", # Missing type annotations
"D1", # Missing docstrings
"S",
"SLF",
]
@ -67,6 +66,12 @@ ignore = [
"langflow/api/v1/*" = [
"TCH", # FastAPI needs to evaluate types at runtime
]
"langflow/{components/tools/python_code_structured_tool.py,custom/code_parser/code_parser.py,utils/validate.py}" = [
"S102", # Use of exec
]
"langflow/services/cache/*" = [
"S301", # Use of pickle
]
[tool.uv]
dev-dependencies = [
@ -154,6 +159,7 @@ dependencies = [
"clickhouse-connect==0.7.19",
"assemblyai>=0.33.0",
"fastapi-pagination>=0.12.29",
"defusedxml>=0.7.1",
]
[project.urls]