Conversation
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
…otarization-errors Fix macOS notarization failures for production and nightly builds
…nd improve error handling
…improve error handling
…ofile detection (#355) * Initial plan * Add browser profile support for interactive authentication - Add browserType and browserProfile fields to DataverseConnection interface - Implement browser-specific launch logic in AuthManager - Update add/edit connection modals with browser selection UI - Support Chrome, Edge, Firefox, and Brave browsers - Fallback to default browser if profile not found Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review feedback - use helper functions consistently Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Refactor: Extract browser logic into separate BrowserManager - Create new BrowserManager class for browser detection and profile enumeration - Remove browser-related code from AuthManager - AuthManager now depends on BrowserManager via constructor injection - Add IPC channels for browser detection and profile listing - Update preload script to expose new browser APIs Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Implement dynamic browser profile detection in UI - Replace text input with dropdown for browser profiles - Dynamically detect browser installation on selection - Automatically load and populate browser profiles - Show warning when selected browser is not installed - Support both add and edit connection modals - Add modal-warning CSS for user feedback Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix: Browser profile detection in modals - Expose browser detection APIs in modalPreload.ts - Fix browser type change event to properly trigger profile loading - Set correct initial state for profile dropdown (No profile needed) - Remove premature loadBrowserProfiles() call that ran before DOM ready Fixes: - Profile selector now loads data when browser is selected - Browser detection APIs now available in modal context - Initial dropdown state shows correct message - Warning displays when browser not installed Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Enhance profile detection to show friendly names, support Chrome/Edge only - Read actual profile names from Local State file (e.g., "Person 1", "Work") - Fallback to reading individual Preferences files if Local State unavailable - Remove Firefox and Brave browser support (Chrome and Edge only) - UI now displays profile.name but stores profile.path for --profile-directory - Update both add and edit connection modals Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Move browser settings to separate section available for all auth types - Move browser type and profile selectors out of interactive-only section - Create new "Browser Settings (Optional)" section below Environment selector - Apply browser settings to all authentication types (interactive, clientSecret, usernamePassword, connectionString) - Browser profile used when tools need to open URLs with authentication - Updated both add and edit connection modals - Updated connectionManagement to apply browser settings to all auth types Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fixed style issue and added logos * Add browser profile tag to connection cards in sidebar - Add browserProfileName field to DataverseConnection type - Display browser icon and profile name as tag on connection cards - Tag shows Chrome/Edge icon with friendly profile name (e.g., "My Cool Profile") - Tag positioned next to environment badge - Update form controllers to capture and store profile name - Add CSS styling for connection-browser-tag with browser icon - Browser icons loaded from renderer/icons/logos/ Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix modal hanging issue - improve browser profile name collection - Fix collectFormData to safely handle empty profile selections - Only capture browserProfileName when a profile is actually selected - Add null-safe checks for selectedOptions array access - Prevent attempting to read textContent from empty value options Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Revert "Fix modal hanging issue - improve browser profile name collection" This reverts commit 607fde9. * Revert "Add browser profile tag to connection cards in sidebar" This reverts commit e1cab02. * feat: add browser profile name support in connection forms and UI * Update src/renderer/modules/connectionManagement.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/main/managers/browserManager.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/main/managers/browserManager.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/common/types/connection.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…derivation (#354) * Initial plan * Add optional filters parameter to saveFile function Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix extension extraction to use path.extname for robust handling Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* fix: enable recursive file search for notarization in release workflows * feat: add YAML regeneration steps for Windows, Linux, and macOS with correct SHA256 hashes * feat: add repackaging step for portable ZIP with signed EXE in Windows workflows
* fix: Enhance Label structure compliance and add polymorphic lookup support This commit addresses documentation review findings and adds support for polymorphic lookup attributes (Customer/Regarding fields) to complete metadata CRUD operations implementation for issue #319. ## Type Definitions (src/common/types/dataverse.ts) - Added `IsManaged?: boolean` property to LocalizedLabel interface * Microsoft examples show IsManaged included in all attribute/relationship/optionset requests * Properly tracks whether label originates from managed solution - UserLocalizedLabel remains optional in Label interface * Entity creation docs note it as read-only * However, Microsoft's own examples for attributes, relationships, and optionsets include it in POST requests * Implementation follows Microsoft's published examples ## DataverseManager Updates (src/main/managers/dataverseManager.ts) - Updated buildLabel() helper method: * Now creates LocalizedLabel with IsManaged: false property * Includes UserLocalizedLabel property set to same LocalizedLabel instance * Matches Microsoft's published examples for attribute/relationship creation * Example output: { LocalizedLabels: [{ Label: "Text", LanguageCode: 1033, IsManaged: false }], UserLocalizedLabel: { Label: "Text", LanguageCode: 1033, IsManaged: false } } - Added createPolymorphicLookupAttribute() method: * Enables creation of lookup fields that reference multiple entity types (Customer, Regarding scenarios) * Validates presence of non-empty Targets array with entity logical names * Automatically sets AttributeType="Lookup" and AttributeTypeName={ Value: "LookupType" } * Delegates to createAttribute() with proper polymorphic configuration * Returns { AttributeId: string } matching API contract * Comprehensive JSDoc with Customer (account/contact) and custom Regarding examples - Enhanced createRelationship() JSDoc: * Added CascadeConfiguration example with all cascade behaviors (Assign, Delete, Merge, Reparent, Share, Unshare) * Shows proper RemoveLink delete behavior for lookup fields - Enhanced updateRelationship() JSDoc: * Added example demonstrating cascade configuration updates (RemoveLink → Cascade) * Illustrates retrieve-modify-PUT pattern for relationship updates - Added LocalizedLabel to imports from common types ## IPC Infrastructure (src/common/ipc/channels.ts, src/main/index.ts) - Added CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel constant * Value: "dataverse.createPolymorphicLookupAttribute" - Registered IPC handler in main process: * Supports both primary and secondary connection targets * Extracts connectionId from WebContents based on connectionTarget parameter * Wraps dataverseManager.createPolymorphicLookupAttribute() with error handling * Proper cleanup with removeHandler() on application quit ## Preload Bridge (src/main/toolPreloadBridge.ts) - Exposed createPolymorphicLookupAttribute in toolboxAPI.dataverse - Exposed createPolymorphicLookupAttribute in window.dataverseAPI - Both accept (entityLogicalName, attributeDefinition, options?, connectionTarget?) parameters - Properly wrapped with ipcInvoke using CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE channel ## Public API Types (packages/dataverseAPI.d.ts) - Added createPolymorphicLookupAttribute method signature to DataverseAPI interface - Comprehensive JSDoc documentation: * Customer lookup example (account/contact on new_order entity) * Multi-entity Regarding example (account/contact/custom entities on new_note) * Documents Targets array requirement * Notes metadata publish requirement * Shows buildLabel() usage in examples - Method signature: (entityLogicalName, attributeDefinition, options?, connectionTarget?) => Promise<{ AttributeId: string }> ## Validation - TypeScript compilation: ✅ No errors - ESLint: ✅ 0 errors (TypeScript version warning acceptable) - All 12 implementation tasks completed - Documentation compliance verified against 5 Microsoft Learn articles ## Microsoft Documentation References - Attribute creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-column-definitions-using-web-api - Relationship creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-relationships-using-web-api - Option sets: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-optionsets - Polymorphic lookups: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/multitable-lookup - Entity creation: https://learn.microsoft.com/en-us/power-apps/developer/data-platform/webapi/create-update-entity-definitions-using-web-api Closes #319 metadata CRUD operations (enhancement for polymorphic lookups) * fix: improve metadata CRUD error handling and add comprehensive documentation FIXES (Code Review Issues): 1. **Metadata creation methods now throw descriptive errors on missing headers** - createEntityDefinition, createAttribute, createRelationship, createGlobalOptionSet - Previously returned empty strings silently when OData-EntityId header missing - Now throw explicit errors: "Failed to retrieve MetadataId from response. The OData-EntityId header was missing." - Guides users to identify real issues (network failures, API changes, etc.) 2. **GET_ATTRIBUTE_ODATA_TYPE IPC handler now enforces type safety** - Added runtime enum validation against AttributeMetadataType values - Removed unsafe `as any` cast that bypassed TypeScript's type system - Throws descriptive error listing all valid types when invalid value provided - Example: "Invalid attribute type: 'InvalidType'. Valid types are: String, Integer, Boolean, ..." TECHNICAL DISCOVERY: **Dataverse metadata operations return HTTP 204 No Content with NO response body**: - Standard operations (entity, attribute, relationship, global option set): 204 No Content - Only OData-EntityId header contains the created MetadataId - Empty response body → makeHttpRequest returns `response.data = {}` - Exception: CreateCustomerRelationships action returns 200 OK with JSON body containing AttributeId and RelationshipIds This discovery led to abandoning a proposed "fallback to response body" approach, as responseData["MetadataId"] would always be undefined for metadata operations. DOCUMENTATION IMPROVEMENTS: 1. **execute() method**: Added comprehensive JSDoc with examples for: - CreateCustomerRelationships action (customer lookup creation with 200 OK response) - InsertStatusValue action (status choice column values with StateCode) - UpdateStateValue action (state value metadata updates) - Bound vs unbound actions/functions 2. **queryData() method**: Added examples demonstrating: - Retrieving global option sets by name: `GlobalOptionSetDefinitions(Name='name')` - Retrieving all global option sets with filters - Retrieving by MetadataId 3. **createPolymorphicLookupAttribute()**: Added note about CreateCustomerRelationships alternative 4. **insertOptionValue()**: Added note about InsertStatusValue for status choice columns 5. **createGlobalOptionSet()**: Added retrieval example using queryData() BENEFITS: - **Fail-Fast Approach**: Clear errors replace silent failures, improving debuggability - **Type Safety**: Runtime enum validation prevents invalid API calls - **Complete Coverage**: All metadata operations from Microsoft documentation are supported via existing methods (execute, queryData) - **Developer Guidance**: JSDoc examples show how to use actions like CreateCustomerRelationships, InsertStatusValue, UpdateStateValue - **No New Methods Needed**: Generic execute() and queryData() methods handle all special cases VALIDATION: - ✅ TypeScript compilation passed (pnpm run typecheck) - ✅ Linting passed (pnpm run lint - 0 errors) - ✅ Application builds successfully (pnpm build) - ✅ All 6 file edits applied successfully * feat(dataverse): add whitelist-based header validation for metadata operations Implemented comprehensive security validation for custom headers in metadata operations to prevent header injection attacks and API compliance issues. SECURITY ENHANCEMENTS: - Added validateMetadataHeaders() method with whitelist-based validation - Validates all custom headers against allowed list from Microsoft documentation - Blocks attempts to override protected headers (Authorization, Content-Type, etc.) - Case-insensitive header matching per HTTP specification (RFC 2616) - Detailed error messages showing invalid headers and allowed alternatives ALLOWED CUSTOM HEADERS (per Microsoft Dataverse Web API docs): - MSCRM.SolutionUniqueName: Associates metadata changes with solutions - MSCRM.MergeLabels: Controls label merging behavior (true/false) - Consistency: Forces reading latest version (value: "Strong") - If-Match: Standard HTTP header for optimistic concurrency control - If-None-Match: Standard HTTP header for caching control PROTECTED HEADERS (never allowed in customHeaders): - Authorization, Accept, Content-Type, OData-MaxVersion, OData-Version, Prefer, Content-Length (all controlled by makeHttpRequest) IMPLEMENTATION: - Created ALLOWED_METADATA_HEADERS constant with whitelist (5 headers) - Created PROTECTED_HEADERS constant with blacklist (7 headers) - Integrated validation into buildMetadataHeaders() for automatic coverage - All metadata operations now automatically validated: * createEntityDefinition / updateEntityDefinition * createAttribute / updateAttribute * createRelationship / updateRelationship * createGlobalOptionSet / updateGlobalOptionSet * createPolymorphicLookup BENEFITS: - Prevents header injection attacks and accidental header overrides - Ensures API compliance with Microsoft's documented patterns - Provides clear developer feedback when invalid headers are used - Defense-in-depth validation even for type-safe inputs DOCUMENTATION REFERENCES: Based on thorough review of 6 Microsoft Learn articles covering all metadata operation types (entity, attribute, relationship, option set operations). Changes maintain backward compatibility - all existing code uses valid headers through typed MetadataOperationOptions interface. * fix(types): replace 'any' with MetadataOperationOptions in IPC handlers Improved type safety in metadata operation IPC handlers by replacing all occurrences of 'options?: any' with proper 'options?: MetadataOperationOptions' type annotation. CHANGES: - Added MetadataOperationOptions to type imports from ../common/types - Updated 9 IPC handler signatures to use MetadataOperationOptions: * CREATE_ENTITY_DEFINITION * UPDATE_ENTITY_DEFINITION * CREATE_ATTRIBUTE * UPDATE_ATTRIBUTE * CREATE_POLYMORPHIC_LOOKUP_ATTRIBUTE * CREATE_RELATIONSHIP * UPDATE_RELATIONSHIP * CREATE_GLOBAL_OPTION_SET * UPDATE_GLOBAL_OPTION_SET BENEFITS: - Eliminates use of 'any' type, maintaining TypeScript strict mode compliance - Provides IntelliSense and autocomplete for options parameter - Type safety ensures only valid options (solutionUniqueName, mergeLabels, consistencyStrong) can be passed through IPC layer - Consistency with DataverseManager method signatures - Compile-time validation of option properties This change maintains backward compatibility while adding proper type checking for all metadata operation options passed from tools via IPC. * chore: update version to 1.0.19 in package.json * feat(preload): sync metadata CRUD operations with toolPreloadBridge Synchronized preload.ts with toolPreloadBridge.ts to ensure both the main ToolBox UI and tool windows have identical metadata operation APIs available. This maintains API parity and enables future metadata manipulation from the main UI if needed. ADDED METADATA OPERATIONS (22 new methods in dataverse namespace): Metadata Helper Utilities: - buildLabel: Build localized Label objects for metadata operations - getAttributeODataType: Get OData type string for attribute type enums Entity (Table) Metadata CRUD: - createEntityDefinition: Create new entity/table definitions - updateEntityDefinition: Update existing entity definitions (PUT) - deleteEntityDefinition: Delete entity definitions Attribute (Column) Metadata CRUD: - createAttribute: Create new attributes/columns on entities - updateAttribute: Update existing attribute definitions (PUT) - deleteAttribute: Delete attributes from entities - createPolymorphicLookupAttribute: Create multi-table lookup attributes Relationship Metadata CRUD: - createRelationship: Create 1:N, N:N, or polymorphic relationships - updateRelationship: Update existing relationship definitions (PUT) - deleteRelationship: Delete relationships Global Option Set (Choice) Metadata CRUD: - createGlobalOptionSet: Create new global option sets/choices - updateGlobalOptionSet: Update existing global option sets (PUT) - deleteGlobalOptionSet: Delete global option sets Option Value Modification Actions (OData Actions): - insertOptionValue: Insert new option values into option sets - updateOptionValue: Update existing option values (labels, etc.) - deleteOptionValue: Delete option values from option sets - orderOption: Reorder option values within option sets BENEFITS: - API parity between main UI (preload.ts) and tool windows (toolPreloadBridge.ts) - Main ToolBox UI can now perform metadata operations if needed in future - Consistent API surface across all preload contexts - Future-proofing for internal metadata management UI features - All operations support primary/secondary connection targeting IMPLEMENTATION NOTES: - All methods maintain same signatures as toolPreloadBridge.ts - Options parameter uses Record<string, unknown> for flexibility - Connection targeting via optional connectionTarget parameter - Validated header whitelisting enforced by DataverseManager layer This synchronization ensures both contexts stay in sync as the metadata API evolves and provides maximum flexibility for future UI enhancements. --------- Co-authored-by: Power-Maverick <danish.naglekar@hotmail.com>
* Initial plan * Fix loading screen to only block tool panel, not entire window Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review: Fix listener leak and simplify null coalescing Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix IPC listener cleanup: use ipcMain.on instead of once Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix loading overlay bounds calculation and add close button - Get bounds directly from active tool BrowserView instead of renderer - Add getActiveToolBounds() method to ToolWindowManager - Remove rounded corners from overlay container - Add close button to manually dismiss loading overlay - Make overlay window focusable and closable Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Improve close button accessibility and contrast - Add aria-label for screen reader support - Increase background opacity for better contrast (0.1 -> 0.15) - Add visible focus indicator with blue border and shadow - Improve border visibility (0.2 -> 0.3 opacity) Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Fix overlay positioning and explicitly remove all rounded corners - Use content bounds (screen coordinates) instead of incorrectly adding window bounds to BrowserView bounds - Explicitly set border-radius:0 on overlay-container and close-button - BrowserView bounds are content-relative, overlay BrowserWindow needs screen coordinates Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Address code review feedback: fix shutdown handling, HTML escaping, and error telemetry - Add isMainWindowClosing flag to allow overlay to close during app shutdown - Escape HTML in loading message to prevent injection attacks - Improve error handling with captureException and full context (activeToolId, tags) - Properly destroy overlay window in cleanup - Add close listener on main window to set shutdown flag Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Refine code review fixes: use specific listener reference and clarify HTML escaping - Store closeHandler reference to remove specific listener (not all listeners) - Add comment explaining critical order of HTML entity replacements - Prevent potential issues with removeAllListeners affecting other code Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * Polish destroy logic for better clarity and consistency - Move overlayWindow null assignment inside if block for logical consistency - Set closeHandler to null after cleanup for better flow - Clearer separation of window cleanup vs handler cleanup Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com>
) * feat: add getCSDLDocument API for retrieving OData endpoint (#384) Add new getCSDLDocument() method to DataverseAPI that retrieves the complete CSDL/EDMX metadata document from Dataverse's OData $metadata endpoint. Key Features: - Returns raw XML containing complete schema metadata (entities, attributes, relationships, actions, functions, complex types, enum types) - Supports gzip/deflate compression for optimal transfer (70-80% size reduction) - Automatic decompression handling using Node.js zlib module - Multi-connection support (primary/secondary) for advanced tools - Response size: 1-5MB typical, up to 10MB+ for complex environments Implementation: - Added GET_CSDL_DOCUMENT IPC channel to channels.ts - Implemented getCSDLDocument() in DataverseManager with: - Custom HTTPS request handler (avoids JSON parsing) - Accept-Encoding: gzip, deflate headers - Automatic decompression via zlib.gunzip/inflate - Buffer-based response handling for binary data - Registered IPC handler in index.ts with connection targeting support - Exposed method in toolPreloadBridge.ts and preload.ts - Added comprehensive TypeScript definitions in dataverseAPI.d.ts Use Cases: - Build Dataverse REST Builder (DRB) clone tools - Create intelligent query builders and code generators - Generate TypeScript interfaces from schema - Explore entity relationships and metadata - Validate action/function parameters Naming Rationale: Method named getCSDLDocument() (not getMetadata()) to avoid confusion with existing entity metadata operations like getEntityMetadata() and getAllEntitiesMetadata(). CSDL (Common Schema Definition Language) clearly indicates it returns the OData service document. Related: #384 * fix: expose getCSDLDocument on window.dataverseAPI for direct tool access Fixed issue where getCSDLDocument was only accessible via window.toolboxAPI.dataverse.getCSDLDocument but not directly on window.dataverseAPI.getCSDLDocument like other Dataverse operations. Changes: - Added getCSDLDocument to toolPreloadBridge.ts dataverseAPI namespace - Now consistent with other operations (getSolutions, queryData, etc.) - Tools can call dataverseAPI.getCSDLDocument() directly as expected This ensures getCSDLDocument follows the same exposure pattern as all other Dataverse API methods. * fix: decompress error responses in getCSDLDocument for readable error messages Previously, error responses (non-200 status codes) were converted directly from Buffer to UTF-8 string without checking for compression. Since the request includes 'Accept-Encoding: gzip, deflate' header, Dataverse may return compressed error responses, resulting in garbled error messages. Changes: - Added decompression logic to error response path - Check content-encoding header (gzip/deflate/none) - Decompress error body before converting to string - Added try-catch to handle decompression failures gracefully - Error messages now readable regardless of compression This mirrors the success path's decompression logic and ensures consistent handling of both success and error responses.
* fix: clean up toolboxAPI type definitions and improve connection handling * fix: implement filesystem access management for tools with user consent model * Fix filesystem access tracking to use instanceId instead of toolId (#390) * Initial plan * fix: track filesystem access per instance instead of per tool This change fixes the issue where closing one instance of a tool would revoke filesystem access for all other instances of the same tool. Changes: - Updated ToolFileSystemAccessManager to use instanceId as key instead of toolId - Added getInstanceIdByWebContents() method to ToolWindowManager - Updated all filesystem IPC handlers to use instanceId - Updated closeTool() to revoke access only for the specific instance This ensures that each tool instance maintains its own filesystem permissions independently, allowing multiple instances of the same tool to run simultaneously without interfering with each other. Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> * refactor: eliminate code duplication in toolWindowManager methods Refactor getToolIdByWebContents() to call getInstanceIdByWebContents() and extract the toolId from the result, eliminating duplicated loop logic. Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Power-Maverick <36135520+Power-Maverick@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Bundle Size Report 📦
Bundle Analysis ReportsThe detailed bundle analysis reports are available in the workflow artifacts:
Download the artifacts from the workflow run to view interactive visualizations. Bundle size tracking is now active! This helps prevent bundle bloat. |
There was a problem hiding this comment.
Pull request overview
Release v1.1.3 updates the desktop app and its tool developer APIs to improve security (tool filesystem sandboxing), authentication UX (browser + profile selection for sign-in), and Dataverse capabilities (metadata operations), alongside release pipeline hardening.
Changes:
- Added per-tool-instance filesystem access control with explicit user-consent grants (
selectPath/saveFile) and revocation on tool close. - Added browser detection/profile enumeration and wired interactive auth to open URLs in a selected browser/profile; updated connection UI to configure these settings.
- Expanded Dataverse API with metadata CRUD helpers (plus
$metadata/CSDL retrieval) and updated build/release workflows (signing, notarization, hash regeneration).
Reviewed changes
Copilot reviewed 30 out of 34 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Copies new icons/logos assets into the renderer build output. |
| src/renderer/styles.scss | Adds styles for connection browser/profile badge UI. |
| src/renderer/modules/connectionManagement.ts | Persists browser settings on connections and renders a browser/profile badge in the sidebar. |
| src/renderer/modals/sharedStyles.ts | Adds shared modal warning styling. |
| src/renderer/modals/editConnection/view.ts | Adds “Browser Settings” fields to the edit-connection modal. |
| src/renderer/modals/editConnection/controller.ts | Loads browser install status/profiles and saves browser settings from the edit modal. |
| src/renderer/modals/addConnection/view.ts | Adds “Browser Settings” fields to the add-connection modal. |
| src/renderer/modals/addConnection/controller.ts | Loads browser install status/profiles and saves browser settings from the add modal. |
| src/main/utilities/filesystem.ts | Extends saveFile to accept optional dialog filters and derive defaults from extension. |
| src/main/toolPreloadBridge.ts | Hardens tool connection exposure (safe shape) and expands Dataverse/tool filesystem APIs. |
| src/main/preload.ts | Exposes browser detection/profile APIs to the main renderer and extends saveFile signature. |
| src/main/modalPreload.ts | Exposes browser detection/profile APIs to modal windows. |
| src/main/managers/toolWindowManager.ts | Hooks tool instance lifecycle to revoke filesystem grants; adds WebContents→instance/tool lookup and bounds retrieval. |
| src/main/managers/toolFileSystemAccessManager.ts | New manager to track and validate per-instance allowed filesystem paths. |
| src/main/managers/loadingOverlayWindowManager.ts | Reworks loading overlay to cover tool panel bounds, adds close behavior, and escapes message HTML. |
| src/main/managers/dataverseManager.ts | Adds metadata header validation, $metadata retrieval, and extensive metadata CRUD helpers. |
| src/main/managers/browserManager.ts | New manager for browser install detection, profile enumeration, and browser launch with profile. |
| src/main/managers/authManager.ts | Routes interactive auth browser launch through BrowserManager (profile-aware). |
| src/main/index.ts | Wires new managers, IPC handlers (browser + metadata + filesystem sandbox), and tool-panel-scoped loading overlay bounds. |
| src/common/types/dataverse.ts | Adds metadata-related shared types (labels, attribute types, operation options). |
| src/common/types/connection.ts | Adds connection-level BrowserType + browser/profile fields. |
| src/common/types/api.ts | Updates fileSystem.saveFile type signature to accept optional filters. |
| src/common/ipc/channels.ts | Adds IPC channels for browser detection/profile enumeration and Dataverse metadata endpoints. |
| packages/toolboxAPI.d.ts | Updates public tool typings (saveFile filters, connection surface tightening). |
| packages/package.json | Publishes @pptb/types as stable 1.0.19. |
| packages/dataverseAPI.d.ts | Expands tool-facing Dataverse typings for metadata utilities/CRUD and getCSDLDocument. |
| package.json | Bumps app version to 1.1.3. |
| buildScripts/notarize.js | Supports multi-asset notarization submission and status polling. |
| RELEASE_NOTES.md | Updates release notes for 1.1.3 features/fixes. |
| README.md | Updates “Force Checkin” comment timestamp. |
| .github/workflows/prod-release.yml | Enhances signing/notarization flow; repackages signed ZIPs; regenerates update YAML hashes. |
| .github/workflows/nightly-release.yml | Mirrors prod workflow improvements for nightly artifacts/hashes/notarization. |
| public async openBrowserWithProfile(url: string, connection: DataverseConnection): Promise<void> { | ||
| const browserType = connection.browserType || "default"; | ||
| const profileName = connection.browserProfile; | ||
|
|
||
| // If default browser or no profile specified, use standard shell.openExternal | ||
| if (browserType === "default" || !profileName) { | ||
| return shell.openExternal(url); | ||
| } |
There was a problem hiding this comment.
openBrowserWithProfile() ignores a non-default browserType when no browserProfile is set (it falls back to shell.openExternal). This makes the “Browser” selector ineffective unless a profile is chosen, and contradicts the UI text saying the browser choice applies even without a profile. Consider launching the selected browser even when browserProfile is empty (only omit the --profile-directory arg), and keep fallback to system default only when the requested browser executable can’t be resolved/started.
| const browserType = sanitizeInput(formPayload.browserType); | ||
| const browserProfile = sanitizeInput(formPayload.browserProfile); | ||
| const browserProfileName = sanitizeInput(formPayload.browserProfileName); | ||
| connection.browserType = (browserType || "default") as DataverseConnection["browserType"]; | ||
| connection.browserProfile = browserProfile || undefined; | ||
| connection.browserProfileName = browserProfileName || undefined; |
There was a problem hiding this comment.
browserType is read as a free-form string and then cast to DataverseConnection["browserType"]. This bypasses the BrowserType union and can persist invalid values (e.g., from tampered modal payloads), which then won’t match BrowserManager’s expectations. Please validate/normalize to the allowed set (default | chrome | edge) before assigning, and fall back to default for unknown values.
| type ToolSafeConnection = { | ||
| id: string; | ||
| name: string; | ||
| url: string; | ||
| environment: "Dev" | "Test" | "UAT" | "Production"; | ||
| createdAt?: string; | ||
| lastUsedAt?: string; | ||
| isActive?: boolean; | ||
| }; |
There was a problem hiding this comment.
ToolSafeConnection makes createdAt optional, but the published tool API typings (packages/toolboxAPI.d.ts) define createdAt as required. This mismatch can break tool code at runtime if a connection ever lacks createdAt (or if it’s not a string). Either require/validate createdAt in toToolSafeConnection() (return null if missing), or update the public types to mark it optional consistently.
| const iconsLogosSourceDir = "src/renderer/icons/logos"; | ||
| const iconsLogosTargetDir = "dist/renderer/icons/logos"; | ||
| try { | ||
| if (existsSync(iconsLogosSourceDir)) { | ||
| const iconFiles = readdirSync(iconsLogosSourceDir); | ||
| iconFiles.forEach((file: string) => { | ||
| const sourcePath = path.join(iconsLogosSourceDir, file); | ||
| const targetPath = path.join(iconsLogosTargetDir, file); | ||
| copyFileSync(sourcePath, targetPath); | ||
| }); | ||
| } | ||
| } catch (e) { | ||
| console.error(`Failed to copy icons directory:`, e); | ||
| } |
There was a problem hiding this comment.
The error message in this catch block is still Failed to copy icons directory, which is ambiguous now that light/dark/logos are copied separately. Consider making the message specific to the logos copy (or include the source/target dir) to make build failures easier to diagnose.
| spawn(executable, browserArgs, { | ||
| detached: true, | ||
| stdio: "ignore", | ||
| }).unref(); | ||
| } catch (error) { | ||
| // If browser launch fails, fallback to default browser |
There was a problem hiding this comment.
spawn() failures like ENOENT (command not found) are emitted asynchronously on the returned ChildProcess and won’t be caught by this try/catch. If a browser is configured but later uninstalled (or not on PATH on Linux), this can silently fail without falling back to shell.openExternal. Consider validating the executable for non-absolute commands (e.g., which/command -v) and/or attaching an error handler on the spawned process to trigger the fallback.
| spawn(executable, browserArgs, { | |
| detached: true, | |
| stdio: "ignore", | |
| }).unref(); | |
| } catch (error) { | |
| // If browser launch fails, fallback to default browser | |
| const child = spawn(executable, browserArgs, { | |
| detached: true, | |
| stdio: "ignore", | |
| }); | |
| child.on("error", (spawnError: Error & { code?: string }) => { | |
| logWarn(`Failed to launch ${browserType} with profile (spawn error), falling back to default: ${spawnError.message}`); | |
| shell.openExternal(url).catch((fallbackError: Error) => { | |
| logWarn(`Fallback to default browser also failed: ${fallbackError.message}`); | |
| }); | |
| }); | |
| child.unref(); | |
| } catch (error) { | |
| // If browser launch fails synchronously, fallback to default browser |
Please fill in this template.