From fcc5885dcf315c9d049f6a4b2eb353c89c3902e1 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Tue, 21 Jul 2026 03:16:57 +0200 Subject: [PATCH] Validate manifest module imports --- tools/checks/check-manifest-shapes.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/checks/check-manifest-shapes.py b/tools/checks/check-manifest-shapes.py index c8cff57..0426924 100644 --- a/tools/checks/check-manifest-shapes.py +++ b/tools/checks/check-manifest-shapes.py @@ -6,12 +6,16 @@ from __future__ import annotations import argparse import importlib import json +import re import sys import tomllib from pathlib import Path META_ROOT = Path(__file__).resolve().parents[2] +MODULE_NAME_PATTERN = re.compile( + r"[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*" +) def main() -> int: @@ -56,8 +60,15 @@ def main() -> int: errors: list[str] = [] for repository_name, source_root, manifest_path in manifest_sources: module_name = ".".join(manifest_path.relative_to(source_root).with_suffix("").parts) + if MODULE_NAME_PATTERN.fullmatch(module_name) is None: + errors.append( + f"{repository_name}: manifest path does not map to a safe Python module name: {module_name!r}" + ) + continue try: - loaded_module = importlib.import_module(module_name) + # Module names are derived from repository-owned manifest paths and + # constrained to canonical Python identifiers immediately above. + loaded_module = importlib.import_module(module_name) # nosemgrep: python.lang.security.audit.non-literal-import.non-literal-import get_manifest = getattr(loaded_module, "get_manifest") manifest = get_manifest() except Exception as exc: # pragma: no cover - rendered as a check failure