From 80d312edfb9118e4ac3875da13302819d1c23aed Mon Sep 17 00:00:00 2001 From: Joe Esquibel Date: Sun, 2 Aug 2026 17:39:30 -0400 Subject: [PATCH 1/4] Reapply "Extraction hardening: tcl (#990)" This reverts commit 6cf3478f2fe71450ee22102a5a79cb82effa9cf9. --- gitgalaxy/standards/language_standards.py | 6 +- tests/extraction/languages/test_tcl.py | 167 ++++++++++++++++++ .../extraction/test_args_extraction_strict.py | 11 -- .../test_function_extraction_strict.py | 5 - 4 files changed, 171 insertions(+), 18 deletions(-) create mode 100644 tests/extraction/languages/test_tcl.py diff --git a/gitgalaxy/standards/language_standards.py b/gitgalaxy/standards/language_standards.py index 3a8f828f..2cf034b1 100644 --- a/gitgalaxy/standards/language_standards.py +++ b/gitgalaxy/standards/language_standards.py @@ -11961,11 +11961,11 @@ class PrismConfigSchema(TypedDict): # 4. func_start (Executable Logic Anchors) # MUST HAVE EXACTLY ONE CAPTURE GROUP. # Captures standard procs and namespaced procs (e.g., `proc ::my::func`). - "func_start": re.compile(r"^[ \t]*proc[ \t]+([a-zA-Z0-9_:]+)(?=[ \t]*\{|[ \t\n]|$)", re.M), + "func_start": re.compile(r"^[ \t]*proc[ \t\n]+([a-zA-Z0-9_:]+)(?=[ \t]*\{|[ \t\n]|$)", re.M), # 5. class_start (Object / Entity Declarations) # Captures TclOO, Snit, and Itcl class definitions. "class_start": re.compile( - r"^[ \t]*(?:oo::class[ \t]+create|snit::type|itcl::class)[ \t]+([a-zA-Z0-9_:]+)(?=[ \t]*\{|[ \t\n]|$)", + r"^[ \t]*(?:oo::class[ \t\n]+create|snit::type|itcl::class)[ \t\n]+([a-zA-Z0-9_:]+)(?=[ \t]*\{|[ \t\n]|$)", re.M, ), # --- PHASE 2: RISK & STRUCTURAL INTEGRITY --- @@ -12036,6 +12036,8 @@ class PrismConfigSchema(TypedDict): # 24. import (Dependency Inclusions) # Package and module loading. "import": re.compile(r"^[ \t]*(?:package[ \t]+require|source|load)\b", re.M), + "dependency_injection": None, + "_dependency_capture": re.compile(r"^[ \t]*(?:package[ \t\n]+require|source|load)[ \t\n]+(?:-exact[ \t\n]+)?(?:\{?[\"']?)([^\"'\s#{}]+)", re.M), # 25. ownership (Authorship Metadata) "ownership": re.compile( r"^[ \t]*#[ \t]*(?:Author|Created by|Maintainer|Copyright):\s+(.*)", diff --git a/tests/extraction/languages/test_tcl.py b/tests/extraction/languages/test_tcl.py new file mode 100644 index 00000000..31a4acee --- /dev/null +++ b/tests/extraction/languages/test_tcl.py @@ -0,0 +1,167 @@ +""" +Tcl extraction hardening (epic #848). See +tests/extraction/how_to_harden_extraction.md for the methodology. + +Covers all four extraction gauntlets for tcl in one file: func_start, +args, class_start, _dependency_capture. +""" + +import sys +from pathlib import Path +import pytest +from typing import Any + +from gitgalaxy.standards.language_standards import LANGUAGE_DEFINITIONS + +_EXTRACTION_DIR = str(Path(__file__).resolve().parent.parent) +if _EXTRACTION_DIR not in sys.path: + sys.path.insert(0, _EXTRACTION_DIR) + +from _extraction_harness import ( # noqa: E402 + assert_invalid_no_match, + assert_pathological_dependency_match, + assert_pathological_match, + assert_redos_immune, + assert_valid_dependency_match, + assert_valid_match, +) + +TCL_RULES = LANGUAGE_DEFINITIONS["tcl"]["rules"] + +FUNCTION_CASES: dict[str, Any] = { + "valid": [ + ("proc TargetFunc {", "TargetFunc"), + ("proc TargetFunc {a b} {", "TargetFunc"), + ("proc ::namespace::TargetFunc {args} {", "TargetFunc"), + ], + "invalid": [ + "set TargetFunc", + "if {$TargetFunc}", + "TargetFunc a b", + "if {$a == $b} {", + "set proc TargetFunc", + "puts \"proc TargetFunc {\"" + ], + "pathological": [ + ("proc \t TargetFunc \t {", "TargetFunc"), + ("proc \\\n TargetFunc {", "TargetFunc"), + ("proc \n ::namespace::TargetFunc \n { \n a \n b \n } \n {", "TargetFunc"), + ], +} + +ARGS_CASES: dict[str, Any] = { + "valid": [ + ("proc TargetFunc {a b} {", "TargetFunc"), + ("proc ::namespace::TargetFunc {args} {", "TargetFunc"), + ("proc TargetFunc {{a 1} b} {", "TargetFunc"), + ], + "invalid": [ + "TargetFunc a b", + "if {$a == $b} {", + ], + "pathological": [ + ("proc \n ::namespace::TargetFunc \n { \n a \n b \n } \n {", "TargetFunc"), + ("proc TargetFunc \n { \n {a 1} \n {b 2} \n } \n {", "TargetFunc"), + ("proc \\\n TargetFunc \\\n { \\\n a \\\n b \\\n } \\\n {", "TargetFunc") + ], +} + +CLASS_CASES: dict[str, Any] = { + "valid": [ + ("oo::class create TargetClass {", "TargetClass"), + ("snit::type TargetClass {", "TargetClass"), + ("itcl::class TargetClass {", "TargetClass"), + ], + "invalid": [ + "set TargetClass", + "if {$TargetClass}", + "TargetClass create foo" + ], + "pathological": [ + ("oo::class \t create \t TargetClass \t {", "TargetClass"), + ("oo::class \n create \n TargetClass \n {", "TargetClass"), + ("snit::type \n TargetClass \n {", "TargetClass"), + ], +} + +DEPENDENCY_CASES: dict[str, Any] = { + "valid": [ + ("package require TargetPkg", "TargetPkg"), + ("source TargetPkg.tcl", "TargetPkg.tcl"), + ("load TargetPkg.so", "TargetPkg.so"), + ("package require -exact TargetPkg 1.0", "TargetPkg"), + ("source \"TargetPkg.tcl\"", "TargetPkg.tcl"), + ], + "invalid": [ + "puts TargetPkg", + "set package TargetPkg", + "puts \"package require TargetPkg\"", + ], + "pathological": [ + ("package \\\n require \\\n TargetPkg", "TargetPkg"), + ("source \\\n TargetPkg.tcl", "TargetPkg.tcl"), + ("package \t require \t TargetPkg", "TargetPkg"), + ], +} + + +class TestTclExtraction: + # ------------------------------------------------------------------------- + # func_start + # ------------------------------------------------------------------------- + @pytest.mark.parametrize("payload,expected", FUNCTION_CASES["valid"]) + def test_func_start_valid(self, payload, expected): + assert_valid_match(TCL_RULES["func_start"], payload, expected, "tcl") + + @pytest.mark.parametrize("payload", FUNCTION_CASES["invalid"]) + def test_func_start_invalid(self, payload): + assert_invalid_no_match(TCL_RULES["func_start"], payload, "tcl") + + @pytest.mark.parametrize("payload,expected", FUNCTION_CASES["pathological"]) + def test_func_start_pathological(self, payload, expected): + assert_pathological_match(TCL_RULES["func_start"], payload, expected, "tcl") + + # ------------------------------------------------------------------------- + # args + # ------------------------------------------------------------------------- + @pytest.mark.parametrize("payload,expected", ARGS_CASES["valid"]) + def test_args_valid(self, payload, expected): + assert_valid_match(TCL_RULES["args"], payload, expected, "tcl") + + @pytest.mark.parametrize("payload", ARGS_CASES["invalid"]) + def test_args_invalid(self, payload): + assert_invalid_no_match(TCL_RULES["args"], payload, "tcl") + + @pytest.mark.parametrize("payload,expected", ARGS_CASES["pathological"]) + def test_args_pathological(self, payload, expected): + assert_pathological_match(TCL_RULES["args"], payload, expected, "tcl") + + # ------------------------------------------------------------------------- + # class_start + # ------------------------------------------------------------------------- + @pytest.mark.parametrize("payload,expected", CLASS_CASES["valid"]) + def test_class_start_valid(self, payload, expected): + assert_valid_match(TCL_RULES["class_start"], payload, expected, "tcl") + + @pytest.mark.parametrize("payload", CLASS_CASES["invalid"]) + def test_class_start_invalid(self, payload): + assert_invalid_no_match(TCL_RULES["class_start"], payload, "tcl") + + @pytest.mark.parametrize("payload,expected", CLASS_CASES["pathological"]) + def test_class_start_pathological(self, payload, expected): + assert_pathological_match(TCL_RULES["class_start"], payload, expected, "tcl") + + # ------------------------------------------------------------------------- + # _dependency_capture + # ------------------------------------------------------------------------- + @pytest.mark.parametrize("payload,expected", DEPENDENCY_CASES["valid"]) + def test_dependency_valid(self, payload, expected): + assert_valid_dependency_match(TCL_RULES["_dependency_capture"], payload, expected, "tcl") + + @pytest.mark.parametrize("payload", DEPENDENCY_CASES["invalid"]) + def test_dependency_invalid(self, payload): + assert_invalid_no_match(TCL_RULES["_dependency_capture"], payload, "tcl") + + @pytest.mark.parametrize("payload,expected", DEPENDENCY_CASES["pathological"]) + def test_dependency_pathological(self, payload, expected): + assert_pathological_dependency_match(TCL_RULES["_dependency_capture"], payload, expected, "tcl") diff --git a/tests/extraction/test_args_extraction_strict.py b/tests/extraction/test_args_extraction_strict.py index a98d92cc..efe73296 100644 --- a/tests/extraction/test_args_extraction_strict.py +++ b/tests/extraction/test_args_extraction_strict.py @@ -70,17 +70,6 @@ ) ], }, - "tcl": { - "valid": [ - ("proc TargetFunc {a b} {", "TargetFunc"), - ("proc ::namespace::TargetFunc {args} {", "TargetFunc"), - ], - "invalid": ["TargetFunc a b", "if {$a == $b} {"], - "pathological": [ - # Vertical Tcl procs - ("proc \n ::namespace::TargetFunc \n { \n a \n b \n } \n {", "TargetFunc") - ], - }, "scheme": { "valid": [ ("(define (TargetFunc a b)", "TargetFunc"), diff --git a/tests/extraction/test_function_extraction_strict.py b/tests/extraction/test_function_extraction_strict.py index cbcb4ec7..a8cd6a02 100644 --- a/tests/extraction/test_function_extraction_strict.py +++ b/tests/extraction/test_function_extraction_strict.py @@ -179,11 +179,6 @@ "invalid": ["
", ""], "pathological": [("