From 4e71361b2dc25c024b2578e93a67db51c2d890bf Mon Sep 17 00:00:00 2001 From: Michael Ludlow Date: Sat, 27 Dec 2025 15:03:26 -0500 Subject: [PATCH] fix(analyzer): add C#/Java/Swift/Kotlin project files to security hash (#351) * fix(analyzer): add C#/Java/Swift/Kotlin project files to security hash Fixes #222 The security profile hash calculation was missing key config files for several languages, causing the profile not to regenerate when: - C# projects (.csproj, .sln, .fsproj, .vbproj) changed - Java/Kotlin/Scala projects (pom.xml, build.gradle, etc.) changed - Swift packages (Package.swift) changed Changes: - Add Java, Kotlin, Scala, Swift config files to hash_files list - Add glob patterns for .NET project files (can be anywhere in tree) - Update fallback source extensions to include .cs, .swift, .kt, .java Signed-off-by: Black Circle Sentinel * fix(analyzer): replace empty except pass with continue --------- Signed-off-by: Black Circle Sentinel Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com> --- apps/backend/project/analyzer.py | 52 ++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/apps/backend/project/analyzer.py b/apps/backend/project/analyzer.py index 3ee8b38d..dbe7300d 100644 --- a/apps/backend/project/analyzer.py +++ b/apps/backend/project/analyzer.py @@ -90,28 +90,52 @@ class ProjectAnalyzer: This allows us to know when to re-analyze. """ hash_files = [ + # JavaScript/TypeScript "package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", + # Python "pyproject.toml", "requirements.txt", "Pipfile", "poetry.lock", + # Rust "Cargo.toml", "Cargo.lock", + # Go "go.mod", "go.sum", + # Ruby "Gemfile", "Gemfile.lock", + # PHP "composer.json", "composer.lock", + # Java/Kotlin/Scala + "pom.xml", + "build.gradle", + "build.gradle.kts", + "settings.gradle", + "settings.gradle.kts", + "build.sbt", + # Swift + "Package.swift", + # Infrastructure "Makefile", "Dockerfile", "docker-compose.yml", "docker-compose.yaml", ] + # Glob patterns for project files that can be anywhere in the tree + glob_patterns = [ + "*.csproj", # C# projects + "*.sln", # Visual Studio solutions + "*.fsproj", # F# projects + "*.vbproj", # VB.NET projects + ] + hasher = hashlib.md5(usedforsecurity=False) files_found = 0 @@ -123,13 +147,35 @@ class ProjectAnalyzer: hasher.update(f"{filename}:{stat.st_mtime}:{stat.st_size}".encode()) files_found += 1 except OSError: - pass + continue + + # Check glob patterns for project files that can be anywhere + for pattern in glob_patterns: + for filepath in self.project_dir.glob(f"**/{pattern}"): + try: + stat = filepath.stat() + rel_path = filepath.relative_to(self.project_dir) + hasher.update(f"{rel_path}:{stat.st_mtime}:{stat.st_size}".encode()) + files_found += 1 + except OSError: + continue # If no config files found, hash the project directory structure # to at least detect when files are added/removed if files_found == 0: - # Count Python, JS, and other source files as a proxy for project structure - for ext in ["*.py", "*.js", "*.ts", "*.go", "*.rs"]: + # Count source files as a proxy for project structure + source_exts = [ + "*.py", + "*.js", + "*.ts", + "*.go", + "*.rs", + "*.cs", + "*.swift", + "*.kt", + "*.java", + ] + for ext in source_exts: count = len(list(self.project_dir.glob(f"**/{ext}"))) hasher.update(f"{ext}:{count}".encode()) # Also include the project directory name for uniqueness