Skip to content

Commit 3e12d02

Browse files
author
ChidcGithub
committed
release: v0.7.2 - security improvements and UI refactoring
- Update Python version requirement to 3.9+ - Add ZIP compression bomb detection - Simplify error messages to avoid exposing internals - Add logging for exceptions in node_builder.py - Lock dependency versions in requirements.txt - Add Node.js/npm version requirements in package.json - Refactor SocialCardGenerator to black/white minimalist design - Update build number to 2596
1 parent ba45c73 commit 3e12d02

12 files changed

Lines changed: 495 additions & 392 deletions

File tree

README.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
# PyVizAST
1515

16-
[![Version](https://img.shields.io/badge/Version-0.7.1-blue.svg)](https://github.com/ChidcGithub/PyVizAST)
17-
[![Python](https://img.shields.io/badge/Python-3.8%2B-brightgreen.svg)](https://www.python.org/)
16+
[![Version](https://img.shields.io/badge/Version-0.7.2-blue.svg)](https://github.com/ChidcGithub/PyVizAST)
17+
[![Python](https://img.shields.io/badge/Python-3.9%2B-brightgreen.svg)](https://www.python.org/)
1818
[![License](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](LICENSE)
1919
[![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](https://github.com/ChidcGithub/PyVizAST)
2020
[![Status](https://img.shields.io/badge/Status-stable-brightgreen.svg)](https://github.com/ChidcGithub/PyVizAST)
@@ -82,7 +82,7 @@ PyVizAST/
8282
## Installation
8383

8484
### Prerequisites
85-
- Python 3.8+
85+
- Python 3.9+
8686
- Node.js 18+ (optional, for frontend)
8787

8888
### Quick Start
@@ -213,6 +213,50 @@ Contributions are welcome. Please submit pull requests to the main repository.
213213

214214
<summary>Version History</summary>
215215

216+
<details>
217+
<summary>v0.7.2 (2026-03-15)</summary>
218+
219+
**Bug Fixes & Security Improvements**
220+
221+
**Python Version Requirement:**
222+
- Updated minimum Python version from 3.8 to 3.9 (required for `ast.unparse()`)
223+
224+
**Security Improvements:**
225+
- Added ZIP compression bomb detection:
226+
- Maximum uncompressed size limit (500MB)
227+
- Maximum compression ratio check (100x)
228+
- Individual file size limit (5MB)
229+
- Simplified error messages to avoid exposing internal implementation details
230+
231+
**Code Quality:**
232+
- Added logging for exceptions in `node_builder.py`
233+
- Added user feedback for keyboard interrupt in `run.py`
234+
- Locked dependency versions in `requirements.txt` (fastapi, pydantic, uvicorn, etc.)
235+
- Added Node.js/npm version requirements in `package.json` (Node.js >= 18, npm >= 9)
236+
237+
**UI Improvements:**
238+
- Refactored Social Card Generator to black/white minimalist design
239+
- Simplified card visual effects with clean geometric AST visualization
240+
- Improved consistency with project's overall monochrome theme
241+
242+
**Verification:**
243+
- Confirmed all Map.get() calls in `ASTVisualizer3D.js` have proper null checks
244+
- Confirmed `ModuleInfo` dataclass has correct default values
245+
246+
**Files Modified:**
247+
- `run.py` - Python version check, keyboard interrupt handling
248+
- `backend/ast_parser/node_builder.py` - Exception logging
249+
- `backend/project_analyzer/scanner.py` - ZIP bomb detection
250+
- `backend/main.py` - Simplified error messages
251+
- `requirements.txt` - Version constraints
252+
- `frontend/package.json` - Node.js version requirements, version bump
253+
- `backend/config.py` - Version bump
254+
- `frontend/src/components/SocialCardGenerator.js` - Refactored to black/white minimalist design
255+
- `frontend/src/App.css` - Updated social card styles to match project theme
256+
- `README.md` - Version badge, Python requirement, changelog
257+
258+
</details>
259+
216260
<details>
217261
<summary>v0.7.1 (2026-03-14)</summary>
218262

backend/ast_parser/node_builder.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
@link: github.com/chidcGithub
66
"""
77
import ast
8+
import logging
89
from typing import Dict, List, Optional, Any
910

1011
from ..models.schemas import ASTNode, NodeType
1112
from .node_styles import NODE_STYLES
1213

14+
logger = logging.getLogger(__name__)
15+
1316

1417
class NodeBuilder:
1518
"""Builder class for creating AST nodes"""
@@ -570,7 +573,8 @@ def _get_default_value_string(self, default: ast.AST) -> str:
570573
"""Get default value as string representation"""
571574
try:
572575
return ast.unparse(default) if hasattr(ast, 'unparse') else repr(default)
573-
except Exception:
576+
except Exception as e:
577+
logger.debug(f"Failed to unparse default value: {e}")
574578
return "..."
575579

576580
def _contains_yield(self, node: ast.AST) -> bool:

backend/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
All version numbers are managed in this single file for easy updates.
44
"""
55

6-
VERSION = "0.7.1"
7-
BUILD = "2522"
6+
VERSION = "0.7.2"
7+
BUILD = "2596"
88
FULL_VERSION = f"v{VERSION}"

backend/main.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,29 +159,25 @@ async def general_exception_handler(request: Request, exc: Exception):
159159
"""Handle all uncaught exceptions"""
160160
log_exception(logger, exc, f"Request path: {request.url.path}")
161161

162-
# Extract error type and message for better user feedback
163-
error_type = type(exc).__name__
164-
error_message = str(exc) if str(exc) else "Unknown error occurred"
165-
166-
# Provide user-friendly messages based on error type
162+
# Provide user-friendly messages without exposing internal details
167163
if isinstance(exc, TypeError):
168-
detail = f"Type error during analysis: {error_message}. This may indicate a bug in the code being analyzed."
164+
detail = "An internal type error occurred. The code structure may be unexpected."
169165
elif isinstance(exc, AttributeError):
170-
detail = f"Attribute error during analysis: {error_message}. The code structure may be unexpected."
166+
detail = "An internal attribute error occurred. The code structure may be unexpected."
171167
elif isinstance(exc, ValueError):
172-
detail = f"Value error during analysis: {error_message}"
168+
detail = "An invalid value was encountered during analysis."
173169
elif isinstance(exc, KeyError):
174-
detail = f"Key error during analysis: {error_message}. Some expected data is missing."
170+
detail = "Some expected data is missing in the analysis."
175171
elif isinstance(exc, RecursionError):
176172
detail = "Code structure is too deeply nested to analyze. Consider simplifying the code."
177173
elif isinstance(exc, MemoryError):
178174
detail = "Not enough memory to analyze this code. Try with a smaller file."
179175
else:
180-
detail = f"Analysis error ({error_type}): {error_message}"
176+
detail = "An unexpected error occurred during analysis. Please try again."
181177

182178
return JSONResponse(
183179
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
184-
content={"detail": detail, "error_type": error_type}
180+
content={"detail": detail}
185181
)
186182

187183

backend/project_analyzer/scanner.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ class ProjectScanner:
5252
def __init__(self, ignore_dirs: Optional[Set[str]] = None,
5353
ignore_patterns: Optional[Set[str]] = None,
5454
max_file_size: int = 5 * 1024 * 1024, # 5MB
55-
max_files: int = 1000):
55+
max_files: int = 1000,
56+
max_zip_size: int = 500 * 1024 * 1024, # 500MB max uncompressed size
57+
max_zip_ratio: float = 100.0): # Max compression ratio
5658
"""
5759
Initialize the scanner
5860
@@ -61,11 +63,15 @@ def __init__(self, ignore_dirs: Optional[Set[str]] = None,
6163
ignore_patterns: File patterns to ignore
6264
max_file_size: Maximum file size in bytes
6365
max_files: Maximum number of files
66+
max_zip_size: Maximum total uncompressed size of ZIP
67+
max_zip_ratio: Maximum compression ratio (uncompressed/compressed)
6468
"""
6569
self.ignore_dirs = ignore_dirs or DEFAULT_IGNORE_DIRS
6670
self.ignore_patterns = ignore_patterns or DEFAULT_IGNORE_PATTERNS
6771
self.max_file_size = max_file_size
6872
self.max_files = max_files
73+
self.max_zip_size = max_zip_size
74+
self.max_zip_ratio = max_zip_ratio
6975

7076
def scan_zip(self, zip_path: str, project_name: Optional[str] = None) -> Tuple[ProjectScanResult, str]:
7177
"""
@@ -86,6 +92,37 @@ def scan_zip(self, zip_path: str, project_name: Optional[str] = None) -> Tuple[P
8692
try:
8793
# Extract ZIP file with path traversal protection
8894
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
95+
# Check for zip bomb (compression bomb) before extracting
96+
total_uncompressed_size = 0
97+
compressed_size = 0
98+
99+
for info in zip_ref.infolist():
100+
total_uncompressed_size += info.file_size
101+
compressed_size += info.compress_size
102+
103+
# Check individual file size
104+
if info.file_size > self.max_file_size:
105+
raise RuntimeError(
106+
f"ZIP contains file exceeding size limit: {info.filename} "
107+
f"({info.file_size} bytes > {self.max_file_size} bytes)"
108+
)
109+
110+
# Check total uncompressed size
111+
if total_uncompressed_size > self.max_zip_size:
112+
raise RuntimeError(
113+
f"ZIP total uncompressed size ({total_uncompressed_size} bytes) "
114+
f"exceeds limit ({self.max_zip_size} bytes)"
115+
)
116+
117+
# Check compression ratio (potential zip bomb indicator)
118+
if compressed_size > 0:
119+
ratio = total_uncompressed_size / compressed_size
120+
if ratio > self.max_zip_ratio:
121+
raise RuntimeError(
122+
f"ZIP compression ratio ({ratio:.1f}) exceeds limit ({self.max_zip_ratio}). "
123+
"This may be a compression bomb."
124+
)
125+
89126
# Check for path traversal attacks before extracting
90127
for member in zip_ref.namelist():
91128
# Skip entries that are absolute paths (Unix or Windows style)

frontend/package-lock.json

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
{
22
"name": "pyvizast-frontend",
3-
"version": "0.7.1",
3+
"version": "0.7.2",
44
"author": "Chidc (github.com/chidcGithub)",
55
"private": true,
6+
"engines": {
7+
"node": ">=18.0.0",
8+
"npm": ">=9.0.0"
9+
},
610
"dependencies": {
711
"@mediapipe/tasks-vision": "^0.10.32",
812
"@monaco-editor/react": "^4.6.0",

0 commit comments

Comments
 (0)