# SecureStoreManager Integration into ConfigManager **Date:** 2026-01-20 **Status:** Ready for Implementation **Estimated Phases:** 9 ## Overview Merge the complete functionality of SecureStoreManager into ConfigManager, creating a unified configuration and secrets management application. This integration adds encrypted secret store management to the existing configuration editing capabilities. ## Design Decisions | Decision | Choice | Rationale | |----------|--------|-----------| | Integration model | Tree node with explicit auth | Security: secrets require conscious authentication | | Store discovery | Hybrid (auto-discover + manual add) | Convenience for co-located stores, flexibility for external | | Credential caching | Prompt every time (session cache opt-in) | Default to most secure behavior | | Save behavior | Separate saves (config vs stores) | Different security domains shouldn't couple | | Service architecture | Use cases layer | Matches existing pattern, separation of concerns | ## Architecture ### Tree Structure ``` 📁 Configuration ├── DataSync ├── DataAccess ├── Auth ├── LDAP ├── Search └── Excel Export 📁 Pipelines └── (pipeline nodes) 🛡️ Secure Stores ├── 🔒 production.secrets (locked) └── 🔓 development.secrets (unlocked) ├── 🔑 ConnectionStrings:JDE └── 🔑 LdapPassword ``` ### Service Layer ``` MainWindowViewModel ├── IConfigFileService (existing - config operations) ├── IStoreUseCases (new - secure store operations) └── ISecretUseCases (new - secret operations) └── ISecureStoreManager (new - low-level encryption) ``` --- ## Phase 1: Project Setup & Dependencies ### 1.1 Add SecureStore NuGet Package **File:** `NEW/src/Utils/JdeScoping.ConfigManager/JdeScoping.ConfigManager.csproj` Add: ```xml ``` ### 1.2 Add Avalonia.Headless.XUnit to Test Project **File:** `NEW/tests/JdeScoping.ConfigManager.Tests/JdeScoping.ConfigManager.Tests.csproj` Add: ```xml ``` --- ## Phase 2: Copy Service Layer ### 2.1 Copy Core Service Files Copy from `SecureStoreManager/Services/` to `ConfigManager/Services/SecureStore/`: | Source | Destination | |--------|-------------| | `ISecureStoreManager.cs` | `Services/SecureStore/ISecureStoreManager.cs` | | `SecureStoreManager.cs` | `Services/SecureStore/SecureStoreManager.cs` | Update namespace: `JdeScoping.SecureStoreManager.Services` → `JdeScoping.ConfigManager.Services.SecureStore` ### 2.2 Copy Use Cases Copy from `SecureStoreManager/Application/` to `ConfigManager/Application/`: | Source | Destination | |--------|-------------| | `StoreUseCases.cs` | `Application/StoreUseCases.cs` | | `SecretUseCases.cs` | `Application/SecretUseCases.cs` | Update namespaces accordingly. ### 2.3 Copy Constants Copy from `SecureStoreManager/Constants/` to `ConfigManager/Constants/`: | Source | Destination | |--------|-------------| | `DialogStrings.cs` | `Constants/SecureStoreStrings.cs` (rename to avoid conflicts) | | `FileExtensions.cs` | `Constants/SecureStoreFileExtensions.cs` | ### 2.4 Copy Clipboard Service Copy from `SecureStoreManager/Services/` to `ConfigManager/Services/`: | Source | Destination | |--------|-------------| | `IClipboardService.cs` | `Services/IClipboardService.cs` | | `AvaloniaClipboardService.cs` | `Services/AvaloniaClipboardService.cs` | --- ## Phase 3: Extend Tree Node Model ### 3.1 Update TreeNodeType Enum **File:** `ViewModels/TreeNodeViewModel.cs` ```csharp public enum TreeNodeType { Folder, SettingsSection, Pipeline, SecureStoresFolder, // New SecureStore, // New Secret // New } ``` ### 3.2 Add SecureStore-Specific Properties **File:** `ViewModels/TreeNodeViewModel.cs` Add to `TreeNodeViewModel`: ```csharp /// /// Gets or sets whether this secure store is currently unlocked. /// Only applicable for SecureStore node types. /// public bool IsUnlocked { get => _isUnlocked; set { if (SetProperty(ref _isUnlocked, value)) { OnPropertyChanged(nameof(LockIcon)); OnPropertyChanged(nameof(IsLocked)); } } } /// /// Gets whether this secure store is locked. /// public bool IsLocked => !IsUnlocked; /// /// Gets the lock icon for secure store nodes. /// public string LockIcon => IsUnlocked ? "🔓" : "🔒"; /// /// Gets or sets the full path to the secure store file. /// Only applicable for SecureStore node types. /// public string? StorePath { get; init; } ``` ### 3.3 Update Icon Property Logic Update the `Icon` property or add computed property for dynamic icons based on node type and lock state. --- ## Phase 4: Create New ViewModels ### 4.1 SecureStoreFormViewModel (Locked State) **File:** `ViewModels/Forms/SecureStoreLockedFormViewModel.cs` Displays when a locked store is selected: - Store name and path - "This store is locked" message - "Unlock Store..." button - Last modified date (from file system) ### 4.2 SecureStoreFormViewModel (Unlocked State) **File:** `ViewModels/Forms/SecureStoreUnlockedFormViewModel.cs` Displays when an unlocked store is selected: - Store name and path - Secret count - "Lock Store" button - "Add Secret" button - List of secrets (or indicate to select a secret from tree) ### 4.3 SecretFormViewModel **File:** `ViewModels/Forms/SecretFormViewModel.cs` Displays when a secret is selected: - Key (read-only) - Value (password-masked by default) - Show/Hide toggle button - Copy to Clipboard button - Delete button Properties: ```csharp public string Key { get; } public string Value { get; set; } public bool IsValueVisible { get; set; } public string DisplayValue => IsValueVisible ? Value : new string('*', 8); public ICommand ToggleVisibilityCommand { get; } public ICommand CopyToClipboardCommand { get; } ``` ### 4.4 Dialog ViewModels Copy and adapt from SecureStoreManager: | Source | Destination | |--------|-------------| | `NewStoreDialogViewModel.cs` | `ViewModels/Dialogs/NewStoreDialogViewModel.cs` | | `OpenStoreDialogViewModel.cs` | `ViewModels/Dialogs/UnlockStoreDialogViewModel.cs` (rename) | | `SecretEditDialogViewModel.cs` | `ViewModels/Dialogs/SecretEditDialogViewModel.cs` | --- ## Phase 5: Create New Views ### 5.1 Form Views **Directory:** `Views/Forms/` | File | Purpose | |------|---------| | `SecureStoreLockedFormView.axaml` | Shows unlock button for locked stores | | `SecureStoreUnlockedFormView.axaml` | Shows store info when unlocked | | `SecretFormView.axaml` | Secret key/value editor with masking | ### 5.2 Dialog Views **Directory:** `Views/Dialogs/` | File | Purpose | |------|---------| | `NewStoreDialog.axaml` | Create new secure store | | `UnlockStoreDialog.axaml` | Enter credentials to unlock | | `SecretEditDialog.axaml` | Add/edit secret key-value | ### 5.3 Update DataTemplates **File:** `App.axaml` Add DataTemplates for automatic form selection: ```xml ``` --- ## Phase 6: Update MainWindowViewModel ### 6.1 Add Dependencies ```csharp private readonly IStoreUseCases _storeUseCases; private readonly ISecretUseCases _secretUseCases; private readonly IClipboardService _clipboardService; ``` ### 6.2 Add Secure Store Commands ```csharp // Store commands public ICommand NewStoreCommand { get; } public ICommand AddExistingStoreCommand { get; } public ICommand UnlockStoreCommand { get; } public ICommand LockStoreCommand { get; } public ICommand SaveStoreCommand { get; } public ICommand LockAllStoresCommand { get; } public ICommand GenerateKeyFileCommand { get; } // Secret commands public ICommand AddSecretCommand { get; } public ICommand EditSecretCommand { get; } public ICommand DeleteSecretCommand { get; } public ICommand CopySecretCommand { get; } ``` ### 6.3 Add Store State Tracking ```csharp // Track open stores (store path -> credentials for session caching if enabled) private readonly Dictionary _openStores = new(); private class SecureStoreState { public bool IsUnlocked { get; set; } public TreeNodeViewModel TreeNode { get; set; } } ``` ### 6.4 Update BuildTreeNodes Method Add logic to: 1. Create "Secure Stores" folder node 2. Discover `*.secrets.json` files in config folder 3. Create SecureStore nodes for each discovered file 4. Add manual store tracking ### 6.5 Update Form Selection Logic Extend `OnSelectedNodeChanged` to handle: - `SecureStoresFolder` → Show instructions/empty state - `SecureStore` (locked) → Show `SecureStoreLockedFormViewModel` - `SecureStore` (unlocked) → Show `SecureStoreUnlockedFormViewModel` - `Secret` → Show `SecretFormViewModel` --- ## Phase 7: Update Menu Bar and Toolbar ### 7.1 Add Secure Stores Menu **File:** `Views/MainWindow.axaml` Add new menu between "Tools" and "Help": ```xml ``` ### 7.2 Add Toolbar Buttons Add after existing buttons with separator: ```xml ``` ### 7.3 Add Context Menus Add context menu to TreeView for right-click actions on nodes. --- ## Phase 8: Register Services ### 8.1 Update App.axaml.cs **File:** `App.axaml.cs` Add to `ConfigureServices`: ```csharp // SecureStore Services services.AddSingleton(); services.AddSingleton(sp => new AvaloniaClipboardService(GetMainWindow)); // SecureStore Use Cases services.AddSingleton(); services.AddSingleton(); ``` --- ## Phase 9: Migrate Tests ### 9.1 Copy Service Tests Copy from `SecureStoreManager.Tests/Services/` to `ConfigManager.Tests/Services/SecureStore/`: | Source | Destination | |--------|-------------| | `SecureStoreManagerTests.cs` | `Services/SecureStore/SecureStoreManagerTests.cs` | Update namespaces. ### 9.2 Create New ViewModel Tests **Directory:** `ConfigManager.Tests/ViewModels/Forms/` | File | Tests | |------|-------| | `SecureStoreLockedFormViewModelTests.cs` | Locked state display, unlock command | | `SecureStoreUnlockedFormViewModelTests.cs` | Unlocked state, secret list, lock command | | `SecretFormViewModelTests.cs` | Value masking, visibility toggle, copy | ### 9.3 Create Dialog ViewModel Tests **Directory:** `ConfigManager.Tests/ViewModels/Dialogs/` | File | Tests | |------|-------| | `NewStoreDialogViewModelTests.cs` | Validation, path selection | | `UnlockStoreDialogViewModelTests.cs` | Credential validation | | `SecretEditDialogViewModelTests.cs` | Key/value validation | ### 9.4 Extend MainWindowViewModelTests Add tests for: - Secure store tree node creation - Store unlock/lock workflow - Secret CRUD operations - Form selection for store/secret nodes ### 9.5 Extend TreeNodeViewModelTests Add tests for: - New node types (SecureStoresFolder, SecureStore, Secret) - Lock state properties - Icon computation for store nodes ### 9.6 Create UI Tests (Optional) If UI testing is desired, copy patterns from `SecureStoreManager.Tests/Views/`: - Test dialog visual structure - Test form view elements --- ## File Inventory ### New Files to Create **Services (5 files):** - `Services/SecureStore/ISecureStoreManager.cs` - `Services/SecureStore/SecureStoreManager.cs` - `Services/IClipboardService.cs` - `Services/AvaloniaClipboardService.cs` **Application (2 files):** - `Application/StoreUseCases.cs` - `Application/SecretUseCases.cs` **Constants (2 files):** - `Constants/SecureStoreStrings.cs` - `Constants/SecureStoreFileExtensions.cs` **ViewModels (6 files):** - `ViewModels/Forms/SecureStoreLockedFormViewModel.cs` - `ViewModels/Forms/SecureStoreUnlockedFormViewModel.cs` - `ViewModels/Forms/SecretFormViewModel.cs` - `ViewModels/Dialogs/NewStoreDialogViewModel.cs` - `ViewModels/Dialogs/UnlockStoreDialogViewModel.cs` - `ViewModels/Dialogs/SecretEditDialogViewModel.cs` **Views (6 files):** - `Views/Forms/SecureStoreLockedFormView.axaml` + `.cs` - `Views/Forms/SecureStoreUnlockedFormView.axaml` + `.cs` - `Views/Forms/SecretFormView.axaml` + `.cs` - `Views/Dialogs/NewStoreDialog.axaml` + `.cs` - `Views/Dialogs/UnlockStoreDialog.axaml` + `.cs` - `Views/Dialogs/SecretEditDialog.axaml` + `.cs` **Tests (8+ files):** - `Services/SecureStore/SecureStoreManagerTests.cs` - `ViewModels/Forms/SecureStoreLockedFormViewModelTests.cs` - `ViewModels/Forms/SecureStoreUnlockedFormViewModelTests.cs` - `ViewModels/Forms/SecretFormViewModelTests.cs` - `ViewModels/Dialogs/NewStoreDialogViewModelTests.cs` - `ViewModels/Dialogs/UnlockStoreDialogViewModelTests.cs` - `ViewModels/Dialogs/SecretEditDialogViewModelTests.cs` ### Files to Modify - `JdeScoping.ConfigManager.csproj` (add SecureStore package) - `App.axaml.cs` (register services) - `App.axaml` (add DataTemplates) - `ViewModels/TreeNodeViewModel.cs` (add enum values, properties) - `ViewModels/MainWindowViewModel.cs` (add commands, store handling) - `Views/MainWindow.axaml` (add menu, toolbar, context menu) - `JdeScoping.ConfigManager.Tests.csproj` (add Avalonia.Headless.XUnit) --- ## Implementation Order 1. **Phase 1** - Project setup (dependencies) 2. **Phase 2** - Copy service layer (foundation) 3. **Phase 3** - Extend tree model (data structure) 4. **Phase 4** - Create ViewModels (business logic) 5. **Phase 5** - Create Views (UI) 6. **Phase 6** - Update MainWindowViewModel (orchestration) 7. **Phase 7** - Update menus/toolbar (discoverability) 8. **Phase 8** - Register services (wiring) 9. **Phase 9** - Migrate tests (verification) --- ## Verification Checklist After implementation, verify: - [ ] Can create new secure store with key file - [ ] Can create new secure store with password - [ ] Can add existing store to tree - [ ] Stores appear locked by default - [ ] Double-click unlocks store (shows dialog) - [ ] Unlock button in form works - [ ] Unlocked store shows secrets in tree - [ ] Can add new secret - [ ] Can edit existing secret - [ ] Can delete secret - [ ] Secret value is masked by default - [ ] Show/Hide toggle works - [ ] Copy to clipboard works - [ ] Can lock store manually - [ ] Lock All Stores works - [ ] Save Store saves only that store - [ ] Save (Ctrl+S) only saves config - [ ] Unsaved changes indicator works for stores - [ ] Generate Key File works - [ ] All tests pass