Skip to content

Comments

release/1.4.0-alpha#385

Merged
marc-romu merged 25 commits intomainfrom
dev
Feb 15, 2026
Merged

release/1.4.0-alpha#385
marc-romu merged 25 commits intomainfrom
dev

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Feb 15, 2026

SmartHopper 1.4.0: Enhanced Security and MacOS Compatibility

This release introduces critical security enhancements with SHA-256 provider hash verification and significantly improves macOS compatibility, making SmartHopper more secure and accessible across platforms.

🔒 Provider Hash Verification

Added comprehensive SHA-256 hash verification system for AI provider DLLs to enhance security across all platforms. The new verification system includes a "Verify Providers Hash" menu item for manual integrity checks, automatic hash generation during release workflows, and multi-tier verification with graceful degradation when hashes are unavailable.

🖥️ Enhanced About Dialog

Improved About dialog now automatically displays current SmartHopper version and platform information using the new VersionHelper class, providing users with clear system information at a glance.

🍎 macOS Compatibility Improvements

Significant enhancements for macOS users including provider loading support on non-Windows platforms with appropriate security warnings, fixed URL handling to prevent incorrect file:// URI generation, and resolved component state management deadlocks by reorganizing event firing patterns.

🔧 Settings and Encryption

Fixed first-time initialization to use EncryptionVersion 2 by default, which stores a local hash for secrets encryption, improving the security of stored API keys and sensitive configuration data.

🛡️ Security Enhancements

Enhanced provider security with SHA-256 hash verification system to protect against tampered provider DLLs, implementing platform-appropriate security measures with Authenticode + hash verification on Windows and hash verification on macOS.

🛠️ Technical Requirements

  • Rhino 8.24 or above is required
  • Windows 10/11 (macOS compatibility improved)
  • Valid API keys for MistralAI, OpenAI or DeepSeek

⚠️ Important Notes

  • This release includes significant security improvements for provider verification
  • macOS compatibility has been substantially improved
  • API keys are required, and usage costs apply based on your provider
  • Some features may still be subject to change in future releases

🤝 We Value Your Feedback!

Help shape SmartHopper's future by:

  • Sharing your experiences with the new security features
  • Reporting any macOS compatibility issues via our issues
  • Suggesting improvements via our discussion
  • Telling us what security features would help your workflow most

We hope you enjoy these enhanced security and compatibility improvements!

Happy designing! 🎨

nof2504 and others added 25 commits February 13, 2026 14:20
…e forks

- Added branch filter to only trigger on main, dev, and release/* branches
- Added repository check to skip workflow execution for PRs from forks
…ing (#382)

# fix(core): add macOS compatibility for provider loading and URL
handling

## Description

SmartHopper currently does not work on macOS due to three
platform-specific issues that cause crashes or incorrect behavior. This
PR addresses all three issues to enable cross-platform compatibility.

### Issue 1: `VerifySignature` crashes on macOS

`ProviderManager.VerifySignature()` calls
`X509Certificate.CreateFromSignedFile()`, which is a Windows-only API.
On macOS, this throws `PlatformNotSupportedException`, preventing any AI
provider from loading.

**Fix:** Wrap the Authenticode verification block in a
`RuntimeInformation.IsOSPlatform(OSPlatform.Windows)` guard. Strong-name
verification (which is cross-platform) remains active on all platforms.

### Issue 2: `BuildFullUrl` produces `file://` URLs on macOS

`AIProvider<T>.BuildFullUrl()` uses `Uri.TryCreate(endpoint,
UriKind.Absolute, out var abs)` to detect whether `endpoint` is already
an absolute URL. On Windows, relative paths like `/chat/completions`
return `false` from `TryCreate` with `UriKind.Absolute`. However, on
macOS, the same call returns `true` and produces a
`file:///chat/completions` URI, causing the base URL concatenation logic
to be skipped entirely. This results in HTTP requests being sent to
`file://` URLs, which fail silently.

**Fix:** Add an additional scheme check: `abs.Scheme ==
Uri.UriSchemeHttp || abs.Scheme == Uri.UriSchemeHttps`. This ensures
only actual HTTP/HTTPS URLs are treated as absolute, and relative paths
like `/chat/completions` are correctly appended to the provider's base
URL.

### Issue 3: `ComponentStateManager` deadlock on macOS

`ProcessTransitionQueue()` fires state transition events (`StateExited`,
`StateEntered`, `TransitionCompleted`) while holding `stateLock`. On
macOS, Grasshopper's threading model can cause event handlers to
re-enter methods that also acquire `stateLock`, leading to a deadlock.
This manifests as the UI freezing when components attempt state
transitions.

**Fix:** Refactor the transition logic to collect events inside the lock
but fire them outside:
- Extract event-firing logic from `ExecuteTransition` into a new
`ExecuteTransitionCore` that returns transition info without firing
events.
- Collect all transition results in a list while holding the lock.
- Release the lock via `Monitor.Exit`, fire all collected events, then
re-acquire via `Monitor.Enter`.
- Add a new `FireTransitionEvents` helper method for clarity.

### Issue 4 (NOT FIXED): `WebChatDialog` crashes when opening Chat UI on
macOS

`WebChatDialog.LoadInitialHtmlIntoWebView()` calls
`this._webView.LoadHtml(html, new Uri("https://smarthopper.local/"))`.
On macOS, the Eto.Forms `WKWebViewHandler.LoadHtml()` implementation
calls `WKWebView.LoadFileUrl(baseNSUrl, baseNSUrl)` for any non-null
`baseUri`, but `WKWebView.LoadFileUrl()` only accepts `file://` URLs.
Passing `https://smarthopper.local/` triggers an
`NSInvalidArgumentException: https://smarthopper.local/ is not a file
URL`, crashing Rhino.

This affects the CanvasButton chat window (the icon in the top-right
corner of the Grasshopper canvas). The crash occurs when the WebView is
first initialized.

**Root cause:** Eto.Forms macOS `WKWebViewHandler.LoadHtml()` (line
323-330 in the Eto source):
```csharp
public void LoadHtml(string html, Uri baseUri)
{
    var baseNSUrl = baseUri.ToNS();
    if (baseNSUrl != null)
        Control.LoadFileUrl(baseNSUrl, baseNSUrl);  // BUG: only works with file:// URLs
    Control.LoadHtmlString(html, baseNSUrl);
}
```

**Possible fix:** In `WebChatDialog.cs` line 970, pass `null` as
`baseUri` on non-Windows platforms (or pass a `file://` temp directory
URI). This would cause `LoadHtmlString` to use `about:blank` as the
origin, which should be sufficient since JS-to-C# communication uses
`WKUserContentController.AddScriptMessageHandler()` (not
origin-dependent). However, this fix has not been tested yet and is NOT
included in this PR.


## Testing Done

- Built the entire solution on macOS (Apple Silicon, .NET 9.0.304 SDK,
targeting net7.0) with 0 errors.
- Deployed all compiled assemblies to Grasshopper Libraries on macOS
Rhino 8.27.
- Verified AI provider loading succeeds (DeepSeek provider loaded and
functional).
- Tested AI chat interaction via Grasshopper Button →
AiStatefulAsyncComponent pipeline, confirmed successful API responses
and GhJSON output.
- Verified that the `BuildFullUrl` fix correctly constructs URLs like
`https://api.deepseek.com/chat/completions` instead of
`file:///chat/completions`.
- **Known issue:** The CanvasButton chat UI (WebChatDialog) still
crashes on macOS due to an Eto.Forms `WKWebView.LoadFileUrl()` bug when
passed an `https://` base URI. This is documented as Issue 4 above but
is NOT fixed in this PR.

## Checklist

- [x] This PR is focused on a single feature or bug fix
- [ ] Version in Solution.props was updated, if necessary, and follows
semantic versioning
- [x] CHANGELOG.md has been updated
- [x] PR title follows [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) format
- [x] PR description follows [Pull Request Description
Template](https://github.com/architects-toolkit/SmartHopper/blob/main/CONTRIBUTING.md#pull-request-description-template)
…ceholders

- Updated SolutionVersion from 1.3.0-alpha to 1.4.0-dev.260215
- Updated bug report template placeholders to reflect current versions (RH8.28, SmartHopper 1.4.0-alpha)
- Added explicit import of Solution.props in Directory.Build.props
- Added conditional check for SolutionVersion property to prevent empty version values
…eadlocks

- Moved all event invocations outside stateLock to prevent re-entrant lock acquisition
- Refactored ProcessTransitionQueue to collect transition results inside lock and fire events after release
- Updated ExecuteTransitionCore to return rejection info instead of firing TransitionRejected directly
- Modified ForceState to fire events outside lock
- Updated debounce methods (StartDebounce, CancelDebounce) to fire events outside lock
… and secure key storage

- Modified SmartHopperSettings constructor to accept encryptionVersion parameter (defaults to 1 for backward compatibility)
- Updated Load() method to detect first-run installations and initialize with encryption version 2
- Added automatic encryption key creation and secure storage for new installations
- Enhanced debug logging for settings save operations including TrustedProviders content
- Updated CHANGELOG.md to document the fix
- Reduced textWidth from 360 to 100 for testing
- Simplified contentHeight calculation to use only messageHeight
- Updated MinimumSize height to be dynamic based on contentHeight (clamped to 400px max)
- Commented out previous contentHeight formula for reference
…or LoadHtml

- Added platform detection using RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
- Modified LoadInitialHtmlIntoWebView to pass null baseUri on non-Windows platforms
- Added explanatory comment about WKWebView.LoadFileUrl() limitation on macOS
- Updated CHANGELOG.md to document URL handling fix for macOS compatibility
…omatic version detection

- Added VersionHelper class to Infrastructure.Utils for centralized version management
  - GetFullVersion() returns complete version with commit hash
  - GetDisplayVersion() returns user-friendly version without commit hash
  - IsDevelopment(), IsPrerelease(), IsStable() methods for version type detection
  - GetPrereleaseTag() extracts prerelease identifier (alpha/beta/rc)
- Added comprehensive unit tests for VersionHelper (
…DLLs

- Added automated hash generation in release workflow (release-4-build.yml)
  - Calculate SHA-256 hashes for all provider DLLs across platforms (net7.0-windows, net7.0)
  - Generate versioned JSON manifest with hash values, metadata, and build info
  - Upload hash manifest as release asset
  - Publish hash manifest to main branch under .github/pages/hashes/
  - Create index.html for hash repository with version listing
…o GitHub Actions and hash calculation tool

- Added version format validation (semantic versioning regex) across all actions and tools
- Added platform name validation to prevent path traversal attacks (no slashes, dots, or invalid characters)
- Added artifacts/pages directory sanitization to strip path traversal sequences (..\, ../)
- Added repository format validation (owner/repo pattern)
…riptions

- Renamed test-build-and-hash.yml to user-build-and-hash.yml
- Renamed test-publish-pages.yml to user-publish-pages.yml
- Updated workflow names from "🧪 Test" to "👤 User" prefix
- Simplified workflow descriptions to remove "test" terminology
… codebase

- Fixed inconsistent blank line spacing in multiple files
- Standardized whitespace around code blocks and statements
- Corrected variable references in PR version validation workflow (prVersion → version, targetVersion → version)
- Removed trailing whitespace and normalized line endings
- Applied consistent formatting to switch statements, conditional blocks, and method chains
…detect path traversal patterns

- Enhanced regex to explicitly check for leading/trailing dots and embedded dot sequences
- Changed from '[\\/\.\.:]|^\.|\..' to '[\\/]|^\.\.|^\.|.*\.\..*|.*:$' for more precise validation
- Prevents path traversal attacks while maintaining clear pattern matching logic
…t regex pattern

- Changed from blocklist approach (checking for invalid characters) to allowlist approach
- New regex '^[a-zA-Z0-9\.-]+$' only permits alphanumeric characters, dots, and hyphens
- Provides clearer validation logic while maintaining protection against path traversal attacks
…ovider-hashes action to use allowlist regex pattern

- Changed from blocklist approach (checking for invalid characters) to allowlist approach
- New regex '^[a-zA-Z0-9\.-]+$' only permits alphanumeric characters, dots, and hyphens
- Provides clearer validation logic while maintaining protection against path traversal attacks
…-provider-hashes action

- Changed output names from kebab-case to SCREAMING_SNAKE_CASE (hash-file → HASH_FILE, hash-count → HASH_COUNT)
- Maintains consistency with internal step output variable naming convention
- Removed automatic PR commenting from pr-build-hash-validation.yml workflow
- Removed automatic PR commenting from pr-version-validation.yml workflow
- Validation results still visible in workflow logs and job summaries
…tion workflow

- Added git ls-tree check to verify hashes directory exists on target branch before checkout
- Enhanced error handling for git checkout failures with proper exit code management
- Added explicit conflict detection flag to track validation state
- Improved logging to distinguish between missing directory and actual conflicts
- Prevents false positives when hashes directory doesn't exist on target branch
…lity improvements (#383)

# Description

This PR implements comprehensive security enhancements and macOS
compatibility improvements for SmartHopper:

**Security Enhancements:**
- Added SHA-256 hash verification system for AI provider DLLs to protect
against tampered code
- New "Verify Providers Hash" menu item for manual provider integrity
verification
- Comprehensive verification dialog with detailed status and hash
comparison
- Automatic hash generation during release workflow with public hash
repository
- Platform-appropriate security: Authenticode + hash verification on
Windows, hash-only on macOS

**macOS Compatibility:**
- Fixed provider loading on non-Windows platforms by skipping
unsupported Authenticode verification
- Resolved URL handling issues that caused incorrect file:// URI
generation
- Fixed ComponentStateManager deadlocks by refactoring event firing
outside state locks
- Enhanced WebChatDialog to prevent crashes on macOS by using null
baseUri for LoadHtml

**UI Improvements:**
- Enhanced About dialog with automatic version detection using new
VersionHelper class
- Added platform information display for better user support

**Infrastructure:**
- Added comprehensive input validation and sanitization to GitHub
Actions
- Created reusable GitHub Actions for build, hash calculation, and
publishing
- Refactored test workflows to user workflows with updated descriptions

## Breaking Changes

No breaking changes. All changes are backward compatible and enhance
existing functionality.

## Testing Done

- Verified SHA-256 hash verification does not cause issues when hash
file cannot be retrieved from the internet on Windows
- Tested provider loading functionality on Windows platforms
- Confirmed ComponentStateManager works well on Windows
- Validated WebChatDialog works on Windows
- Tested enhanced About dialog version detection

Testing on MacOS is pending because I do not have any to try it on.

## Checklist

- [x] This PR is focused on a single feature or bug fix
- [x] Version in Solution.props was updated, if necessary, and follows
semantic versioning
- [x] CHANGELOG.md has been updated
- [x] PR title follows [Conventional
Commits](https://www.conventionalcommits.org/en/v1.1.0/) format
- [x] PR description follows [Pull Request Description
Template](https://github.com/architects-toolkit/SmartHopper/blob/main/CONTRIBUTING.md#pull-request-description-template)
… fixes (#384)

This PR prepares the release for version 1.4.0-alpha with version update
and code style fixes:

- Updated version in Solution.props
- Updated changelog with closed-solved issues
- Updated README badges
@github-actions github-actions bot requested a review from marc-romu as a code owner February 15, 2026 19:27
@marc-romu marc-romu added this to the 1.4.0-alpha milestone Feb 15, 2026
@marc-romu marc-romu merged commit a5a8f03 into main Feb 15, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants