Skip to content

Add FastAPI web service with Next.js UI#33

Merged
jamesbconner merged 28 commits intomainfrom
v1.3.0
Feb 22, 2026
Merged

Add FastAPI web service with Next.js UI#33
jamesbconner merged 28 commits intomainfrom
v1.3.0

Conversation

@jamesbconner
Copy link
Copy Markdown
Owner

@jamesbconner jamesbconner commented Feb 21, 2026

  • Add FastAPI sidecar API with multipart form handling and file processing
  • Create modular router structure for all SVG operations (create, add, remove, rename, list, extract, inspect, validate, split-paths)
  • Implement async dependency injection for temporary directory lifecycle management
  • Add Pydantic response models for consistent API responses
  • Implement SVG upload sanitization to strip scripts and enforce size limits
  • Add Next.js web UI with dark mode support and responsive design
  • Create reusable React components for file upload, processing options, and results display
  • Add theme context and API client hooks for seamless frontend-backend integration
  • Update CLI with web command to launch the API server and UI
  • Update project configuration for optional web dependencies and static asset bundling
  • Update architecture documentation with API design patterns and request lifecycle
  • Update .gitignore to exclude built web artifacts and Next.js cache
  • Update CHANGELOG and version metadata for v1.3.0 release

Note

Medium Risk
Adds a new HTTP surface area (file uploads + static hosting) and changes packaging/release flow to bundle built web assets, which could affect security and distribution integrity if misconfigured.

Overview
Adds an optional browser-based Web UI (svg2drawio web) backed by a new FastAPI sidecar under src/SVG2DrawIOLib/api/, exposing the existing CLI operations via /api/* endpoints and serving a bundled static frontend from the wheel.

Introduces upload hardening and API ergonomics: per-request temp-dir lifecycle, SVG sanitization with a 10MB limit, consistent error→HTTP mapping, and file-returning endpoints switched to in-memory Response(content=...) to avoid Windows temp cleanup races. Packaging/CI/release are updated to include a [web] extra, bundle the built UI into distributions (Node only for publishing/build), add Makefile dev/build targets, and expand tests/docs/version to 1.3.0.

Written by Cursor Bugbot for commit ea16510. This will update automatically on new commits. Configure here.

- Add FastAPI sidecar API with multipart form handling and file processing
- Create modular router structure for all SVG operations (create, add, remove, rename, list, extract, inspect, validate, split-paths)
- Implement async dependency injection for temporary directory lifecycle management
- Add Pydantic response models for consistent API responses
- Implement SVG upload sanitization to strip scripts and enforce size limits
- Add Next.js web UI with dark mode support and responsive design
- Create reusable React components for file upload, processing options, and results display
- Add theme context and API client hooks for seamless frontend-backend integration
- Update CLI with `web` command to launch the API server and UI
- Update project configuration for optional web dependencies and static asset bundling
- Update architecture documentation with API design patterns and request lifecycle
- Update .gitignore to exclude built web artifacts and Next.js cache
- Update CHANGELOG and version metadata for v1.3.0 release
- Update pre-commit config to include pydantic and fastapi type stubs
- Replace typing.AsyncGenerator with collections.abc.AsyncGenerator for Python 3.13 compatibility
- Prefix unused request parameters with underscore in exception handlers
- Add mypy overrides for pydantic, fastapi, and api modules to handle untyped decorators
- Add ruff lint exception for FastAPI Depends() pattern in router defaults
- Improve import organization and line wrapping for readability
- Add type: ignore comments for FastAPI exception handler registrations
- Update return type annotations for consistency across routers
- Replace unsafe path concatenation with safe_path_join in all router endpoints
- Capture and use sanitized SVG content instead of discarding sanitization result
- Add safe_path_join import to extract, inspect, list, remove, rename, and split_paths routers
- Add sanitize_svg_upload import to split_paths router
- Ensure uploaded files are properly validated before writing to disk
- Prevent path traversal vulnerabilities in file upload handling
- Add web extra to pip install command in CI workflow
- Ensures web service dependencies are available during CI runs
- Allows web-related tests and checks to execute properly
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Feb 21, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 96.58314% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/SVG2DrawIOLib/api/main.py 88.88% 2 Missing and 2 partials ⚠️
src/SVG2DrawIOLib/api/routers/inspect.py 88.88% 2 Missing and 1 partial ⚠️
src/SVG2DrawIOLib/api/exceptions.py 81.81% 2 Missing ⚠️
src/SVG2DrawIOLib/api/routers/rename.py 92.30% 1 Missing and 1 partial ⚠️
src/SVG2DrawIOLib/api/routers/split_paths.py 90.47% 2 Missing ⚠️
src/SVG2DrawIOLib/api/services/processing.py 97.89% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

- Extract dangerous elements set to use only local tag names
- Replace event handler prefix tuple with string constant
- Add JavaScript URI attributes set constant for reusable validation
- Update attribute filtering logic to use defined constants instead of hardcoded values
- Improves code maintainability and reduces duplication in sanitization checks
- Add duplicate filename detection in add_icons and create_library endpoints
- Generate unique filenames with counter suffix when duplicates are detected
- Improve filename handling for uploads without explicit filenames
- Refactor conditional logic in _strip_dangerous_content for better readability
- Fix operator precedence in JavaScript URI attribute validation checks
- Prevents file overwrites when multiple SVGs with same filename are uploaded
- Remove duplicate SVG upload handling logic from add_icons and create_library endpoints
- Extract file deduplication and sanitization into new process_svg_uploads function
- Improve SVG root tag validation to handle XML namespaces correctly
- Add whitespace stripping to JavaScript URI detection for better security
- Remove unused SplitPathsStats model from responses
- Consolidate upload processing logic into reusable service function to reduce code duplication
- Add tests for SVG upload sanitization covering valid SVGs, size limits, and XML validation
- Add tests for dangerous element removal (script, foreignObject, event handlers)
- Add tests for JavaScript URI stripping in href, xlink:href, and src attributes
- Add tests for whitespace-prefixed javascript: URIs (Bug #8)
- Add tests for safe attribute and href preservation
- Add tests for SVG processing options builder with default and custom configurations
- Add tests for API routers covering file upload endpoints and error handling
- Add tests for CLI web service integration
- Add httpx dependency to dev dependencies for HTTP testing
- Ensure comprehensive coverage of security sanitization and API functionality
- Convert single quotes to double quotes in SVG test strings
- Remove trailing whitespace from blank lines
- Add blank line after imports in test_cli_web.py
- Remove unused imports (sys, threading) from test_cli_web.py
- Reformat long argument lists to multi-line for readability
- Consolidate method signatures that exceeded line length limits
- Improve code formatting consistency across test suite
- Add --no-warn-unused-ignores flag to mypy args in pre-commit config
- Add type ignore comments to httpx client.post calls in test_api_routers.py
- Suppress mypy warnings for httpx type variance issues in file upload tests
- Improves CI linting consistency and reduces false positive warnings
- Refactor process_svg_uploads to return list of SVG paths instead of requiring glob after call
- Update add.py router to use returned paths directly
- Update create.py router to use returned paths directly
- Simplifies caller logic and reduces redundant file system operations
- Add test cases for uppercase .SVG file extension handling (Bug #12)
- Update production environment to use relative API URL for same-origin requests
- Add ConflictError exception class for resource conflicts (HTTP 409)
- Add conflict_error_handler to convert ConflictError to HTTP 409 responses
- Register ConflictError handler in FastAPI exception handlers
- Update rename_icon endpoint to catch ValueError and raise ConflictError when icon already exists
- Fix web CLI to use localhost for display when binding to 0.0.0.0
- Reorganize test classes in test_api_processing.py for better structure
- Add test case for rename conflict returning 409 status code
- Improves error handling for duplicate icon names during rename operations
- Register SVG namespace in ElementTree to prevent ns0: prefixes during serialization
- Add test case to verify namespace is preserved without unwanted prefixes
- Ensures sanitized SVG output maintains proper namespace declaration without namespace prefix pollution
- Remove global ValueError exception handler from main.py to prevent masking internal errors
- Add explicit ValueError handling in add, extract, inspect, list, remove, and rename routers
- Return 422 Unprocessable Entity for library format/parsing errors ("Invalid library")
- Let other ValueErrors propagate as 500 Internal Server Error for true processing failures
- Import HTTPException in routers that need explicit error handling
- Add clarifying comments explaining ValueError handling strategy
- Update test suite to verify correct HTTP status codes for library validation errors
- Change default `add_css` option from false to true in CreateTab
- Change default `add_css` option from false to true in ManageTab
- Aligns with improved SVG sanitization and processing pipeline to provide styled output by default
- Remove redundant type ignore comment from test_api_routers.py
- Comment was suppressing httpx type variance warning that is no longer needed
- Improves code clarity by eliminating outdated type suppression
- Remove generic ValueError handler from global exception middleware
- ValueError handling now delegated to individual routers for context-specific responses
- Aligns with explicit error handling pattern established in recent commits
- Add try-except blocks in add_icons and create_library to catch ValueError
- Convert ValueError to HTTPException with 422 status code for invalid parameters
- Import HTTPException in create.py router module
- Add test cases for invalid css_mode validation in both endpoints
- Ensures API returns proper validation error responses instead of unhandled exceptions
- Remove global ImportError exception handler to avoid masking genuine import bugs
- Add explicit ImportError handling in split_paths endpoint for missing optional dependencies
- Implement _has_dangerous_uri() helper function to detect javascript: and data: URI schemes
- Extend SVG sanitization to strip data: URIs from href, xlink:href, and src attributes
- Add comprehensive test coverage for data: URI sanitization across different attributes
- Update sanitization logic to use centralized dangerous URI detection instead of inline checks
- Add clarifying comments about why ImportError is not handled globally
- Import sanitize_filename helper in process_svg_uploads function
- Apply filename sanitization before duplicate detection logic
- Use sanitized filename for stem/extension extraction in counter loop
- Add test case for create endpoint with sanitized duplicate filenames
- Add test case for add endpoint with sanitized duplicate filenames
- Ensures filenames like "icon<1>.svg" and "icon_1_.svg" are properly deduplicated after sanitization (Bug #22)
…ublish workflow

- Add type validation for icon_names parameter in extract, inspect, and remove endpoints to ensure it's a JSON array, not a string, number, or object
- Raise HTTPException with 422 status code when icon_names is valid JSON but not an array type
- Include actual type name in error message for better debugging (e.g., "got str", "got int", "got dict")
- Add comprehensive test coverage for non-list JSON inputs across all three endpoints
- Set up Node.js 20 in publish workflow with npm caching
- Install web UI dependencies and build web UI as part of release process
- Copy built web UI into package before publishing to PyPI
- Fixes Bug #23 where non-array JSON values were not properly rejected
- Extract JSON parsing logic for icon_names into reusable parse_icon_names function in processing service
- Add validation for sizing strategy warnings in add and create endpoints
- Raise HTTPException with 422 status when width/height are mismatched or incomplete
- Remove duplicate icon_names parsing code from extract, inspect, and remove routers
- Update routers to use centralized parse_icon_names function
- Add comprehensive tests for parse_icon_names validation and sizing warnings
- Reduces code duplication and improves maintainability of icon name validation
@jamesbconner jamesbconner linked an issue Feb 22, 2026 that may be closed by this pull request
@jamesbconner jamesbconner self-assigned this Feb 22, 2026
@jamesbconner jamesbconner added the enhancement New feature or request label Feb 22, 2026
- Add type validation for each element in parsed icon_names JSON array
- Reject non-string elements (dicts, numbers, etc.) with 422 status code
- Include element type and index in error detail for debugging
- Add comprehensive test cases for dict, number, and mixed-type elements
- Prevents downstream errors from malformed icon name data
- Replace blanket data: URI block with targeted dangerous type filtering
- Allow safe image data URIs (image/png, image/jpeg, image/svg+xml, image/gif)
- Block dangerous data URI types (text/html, text/javascript, application/javascript)
- Continue blocking all javascript: URIs
- Update sanitization logic to check MIME type prefix instead of scheme only
- Add comprehensive test coverage for safe image data URIs
- Add tests for application/javascript and application/x-javascript blocking
- Update existing test assertions to check for specific dangerous types
- Improve test case insensitivity handling with normalized string comparison
- Normalize element tag names to lowercase before checking against dangerous elements set
- Update _DANGEROUS_ELEMENTS to store "foreignobject" in lowercase for consistent matching
- Add case-insensitive matching logic in _strip_dangerous_content function
- Add comprehensive test coverage for case-variant script elements (uppercase, mixed case, with namespace)
- Add comprehensive test coverage for case-variant foreignObject elements (uppercase, mixed case)
- Fixes Bug #28: SVG sanitization now properly removes dangerous elements regardless of case variation
- Extract duplicate ValueError handling logic from 5 router modules into reusable handle_library_value_error function
- Remove HTTPException imports from extract, inspect, list, and remove routers as they're no longer needed
- Update add, extract, inspect, list, and remove routers to use centralized error handler
- Consolidate library format/parsing error detection (422) vs internal error (500) logic in single location
- Improve maintainability by eliminating repeated error handling patterns across routers
- Add library format error handling to rename_icon endpoint
- Check for "Invalid library" error messages and delegate to handle_library_value_error
- Update handle_library_value_error return type to NoReturn for clarity
- Add docstring note that function always raises an exception
- Add test case for invalid library format returning 422 status code
- Ensures consistent error handling across all endpoints that process library files
- Change navbar title from "SVG2DrawIO" to "SVG2DrawIOLib"
- Update logo link to point to GitHub repository instead of internal /create route
- Align branding with project repository name for consistency
@jamesbconner jamesbconner merged commit ebccbab into main Feb 22, 2026
4 checks passed
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

"data:text/javascript",
"data:application/javascript",
"data:application/x-javascript",
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SVG data URIs bypass script sanitization

Medium Severity

The _DANGEROUS_DATA_URI_TYPES set does not include data:image/svg+xml, and the comment on line 25 explicitly classifies it as a "safe image type." However, data:image/svg+xml URIs can contain <script> elements, event handlers, and other executable content — the very things sanitize_svg_upload is designed to strip. This creates a bypass: a <image href="data:image/svg+xml,<svg onload='alert(1)'/>"/> would pass sanitization with the embedded script intact.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harden SVG imports

2 participants