@vercel/python
Advanced tools
+5
-4
| { | ||
| "name": "@vercel/python", | ||
| "version": "6.14.1", | ||
| "version": "6.15.0", | ||
| "main": "./dist/index.js", | ||
@@ -19,3 +19,3 @@ "license": "Apache-2.0", | ||
| "dependencies": { | ||
| "@vercel/python-analysis": "0.5.0" | ||
| "@vercel/python-analysis": "0.6.0" | ||
| }, | ||
@@ -38,4 +38,5 @@ "devDependencies": { | ||
| "which": "3.0.0", | ||
| "@vercel/build-utils": "13.4.2", | ||
| "@vercel/error-utils": "2.0.3" | ||
| "@vercel/error-utils": "2.0.3", | ||
| "@vercel/build-utils": "13.4.3", | ||
| "@vercel/python-runtime": "0.5.0" | ||
| }, | ||
@@ -42,0 +43,0 @@ "scripts": { |
+82
-4
@@ -48,2 +48,78 @@ # Auto-generated template used by vercel dev (Python, ASGI) | ||
| def _normalize_service_route_prefix(raw_prefix): | ||
| if not raw_prefix: | ||
| return '' | ||
| prefix = raw_prefix.strip() | ||
| if not prefix: | ||
| return '' | ||
| if not prefix.startswith('/'): | ||
| prefix = f'/{prefix}' | ||
| return '' if prefix == '/' else prefix.rstrip('/') | ||
| def _is_service_route_prefix_strip_enabled(): | ||
| raw = os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX_STRIP') | ||
| if not raw: | ||
| return False | ||
| return raw.lower() in ('1', 'true') | ||
| _SERVICE_ROUTE_PREFIX = ( | ||
| _normalize_service_route_prefix(os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX')) | ||
| if _is_service_route_prefix_strip_enabled() | ||
| else '' | ||
| ) | ||
| def _strip_service_route_prefix(path_value): | ||
| if not path_value: | ||
| path_value = '/' | ||
| elif not path_value.startswith('/'): | ||
| path_value = f'/{path_value}' | ||
| prefix = _SERVICE_ROUTE_PREFIX | ||
| if not prefix: | ||
| return path_value, '' | ||
| if path_value == prefix: | ||
| return '/', prefix | ||
| if path_value.startswith(f'{prefix}/'): | ||
| stripped = path_value[len(prefix):] | ||
| return stripped if stripped else '/', prefix | ||
| return path_value, '' | ||
| def _apply_service_route_prefix_to_scope(scope): | ||
| path_value, matched_prefix = _strip_service_route_prefix(scope.get('path', '/')) | ||
| if not matched_prefix: | ||
| return scope | ||
| updated_scope = dict(scope) | ||
| updated_scope['path'] = path_value | ||
| raw_path = scope.get('raw_path') | ||
| if isinstance(raw_path, (bytes, bytearray)): | ||
| try: | ||
| decoded = bytes(raw_path).decode('utf-8', 'surrogateescape') | ||
| stripped_raw, _ = _strip_service_route_prefix(decoded) | ||
| updated_scope['raw_path'] = stripped_raw.encode( | ||
| 'utf-8', 'surrogateescape' | ||
| ) | ||
| except Exception: | ||
| pass | ||
| existing_root = scope.get('root_path', '') or '' | ||
| if existing_root and existing_root != '/': | ||
| existing_root = existing_root.rstrip('/') | ||
| else: | ||
| existing_root = '' | ||
| updated_scope['root_path'] = f'{existing_root}{matched_prefix}' | ||
| return updated_scope | ||
| # Prepare static files app (if starlette/fastapi installed) | ||
@@ -63,4 +139,6 @@ static_app = None | ||
| async def app(scope, receive, send): | ||
| if static_app is not None and scope.get('type') == 'http': | ||
| req_path = scope.get('path', '/') or '/' | ||
| effective_scope = _apply_service_route_prefix_to_scope(scope) | ||
| if static_app is not None and effective_scope.get('type') == 'http': | ||
| req_path = effective_scope.get('path', '/') or '/' | ||
| safe = _p.normpath(req_path).lstrip('/') | ||
@@ -72,7 +150,7 @@ full = _p.join(PUBLIC_DIR, safe) | ||
| if (target == base or target.startswith(base + _p.sep)) and _p.isfile(target): | ||
| await static_app(scope, receive, send) | ||
| await static_app(effective_scope, receive, send) | ||
| return | ||
| except Exception: | ||
| pass | ||
| await USER_ASGI_APP(scope, receive, send) | ||
| await USER_ASGI_APP(effective_scope, receive, send) | ||
@@ -79,0 +157,0 @@ |
+60
-0
@@ -27,2 +27,50 @@ """ | ||
| def _normalize_service_route_prefix(raw_prefix): | ||
| if not raw_prefix: | ||
| return '' | ||
| prefix = raw_prefix.strip() | ||
| if not prefix: | ||
| return '' | ||
| if not prefix.startswith('/'): | ||
| prefix = f'/{prefix}' | ||
| return '' if prefix == '/' else prefix.rstrip('/') | ||
| def _is_service_route_prefix_strip_enabled(): | ||
| raw = os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX_STRIP') | ||
| if not raw: | ||
| return False | ||
| return raw.lower() in ('1', 'true') | ||
| _SERVICE_ROUTE_PREFIX = ( | ||
| _normalize_service_route_prefix(os.environ.get('VERCEL_SERVICE_ROUTE_PREFIX')) | ||
| if _is_service_route_prefix_strip_enabled() | ||
| else '' | ||
| ) | ||
| def _strip_service_route_prefix(path_info): | ||
| if not path_info: | ||
| path_info = '/' | ||
| elif not path_info.startswith('/'): | ||
| path_info = f'/{path_info}' | ||
| prefix = _SERVICE_ROUTE_PREFIX | ||
| if not prefix: | ||
| return path_info, '' | ||
| if path_info == prefix: | ||
| return '/', prefix | ||
| if path_info.startswith(f'{prefix}/'): | ||
| stripped = path_info[len(prefix):] | ||
| return stripped if stripped else '/', prefix | ||
| return path_info, '' | ||
| _mod = import_module(USER_MODULE) | ||
@@ -78,2 +126,14 @@ _app = getattr(_mod, "app", None) | ||
| def _combined_app(environ, start_response): | ||
| path_info, matched_prefix = _strip_service_route_prefix( | ||
| environ.get("PATH_INFO", "/") or "/" | ||
| ) | ||
| environ["PATH_INFO"] = path_info | ||
| if matched_prefix: | ||
| script_name = environ.get("SCRIPT_NAME", "") or "" | ||
| if script_name and script_name != "/": | ||
| script_name = script_name.rstrip("/") | ||
| else: | ||
| script_name = "" | ||
| environ["SCRIPT_NAME"] = f"{script_name}{matched_prefix}" | ||
| # Try static first; if 404 then delegate to user app | ||
@@ -80,0 +140,0 @@ captured_status = "" |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 11 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
372137
3.49%10597
3.16%8
-11.11%18
5.88%151
8.63%+ Added
- Removed