From 13eb08d3e48b8f710d6c9fe7e96f6ba5126bcccf Mon Sep 17 00:00:00 2001 From: OneDeadMachine Date: Fri, 14 Aug 2026 11:45:44 +0300 Subject: [PATCH] feat: add v3 remote repair center --- README.md | 22 +- docs/architecture.en.md | 25 ++ docs/architecture.md | 34 +- docs/known-issues-catalog.md | 35 ++ docs/remote-center.md | 36 ++ src/W-Fix.App/App.xaml | 3 +- src/W-Fix.App/App.xaml.cs | 61 +++ src/W-Fix.App/MainWindow.xaml | 9 +- src/W-Fix.App/MainWindow.xaml.cs | 10 +- src/W-Fix.App/RemoteCenterWindow.xaml | 268 ++++++++++++ src/W-Fix.App/RemoteCenterWindow.xaml.cs | 64 +++ src/W-Fix.App/Services/UserPromptService.cs | 18 + .../ViewModels/MainWindowViewModel.cs | 25 +- .../ViewModels/RemoteCenterViewModel.cs | 405 +++++++++++++++++ src/W-Fix.App/W-Fix.App.csproj | 3 +- .../Abstractions/RemoteRepairContracts.cs | 133 ++++++ .../Catalog/KnownIssueCatalogService.cs | 209 +++++++++ .../Catalog/known-issues-public.pem | 4 + src/W-Fix.Core/Catalog/known-issues.json | 20 + .../Diagnostics/CoreDiagnosticRules.cs | 215 +++++++++ .../Diagnostics/DiagnosticService.cs | 34 ++ .../Infrastructure/WindowsCredentialStore.cs | 145 +++++++ .../Models/KnownIssueCatalogModels.cs | 36 ++ src/W-Fix.Core/Models/RemoteRepairModels.cs | 222 ++++++++++ src/W-Fix.Core/Remote/PowerShellJson.cs | 26 ++ .../Remote/PowerShellRemoteSession.cs | 51 +++ .../Remote/RemoteMaintenanceService.cs | 19 + .../Remote/RemotePreflightService.cs | 136 ++++++ .../Remote/RemotePrinterInventoryService.cs | 180 ++++++++ .../Repair/LegacyFixerRepairAction.cs | 129 ++++++ src/W-Fix.Core/Repair/RepairActionRegistry.cs | 30 ++ src/W-Fix.Core/Repair/RepairExecutor.cs | 293 +++++++++++++ src/W-Fix.Core/Repair/RepairPlanner.cs | 66 +++ src/W-Fix.Core/Reporting/RunReportService.cs | 77 ++++ .../Reporting/SupportBundleService.cs | 91 ++++ src/W-Fix.Core/Services/PowerShellEngine.cs | 39 +- .../Services/RemoteCredentialContext.cs | 49 +++ src/W-Fix.Core/Services/TargetParser.cs | 59 +++ src/W-Fix.Core/W-Fix.Core.csproj | 6 +- tests/W-Fix.Core.Tests/RemoteRepairTests.cs | 407 ++++++++++++++++++ tools/W-Fix.CatalogSigner/Program.cs | 67 +++ .../W-Fix.CatalogSigner.csproj | 8 + 42 files changed, 3732 insertions(+), 37 deletions(-) create mode 100644 docs/architecture.en.md create mode 100644 docs/known-issues-catalog.md create mode 100644 docs/remote-center.md create mode 100644 src/W-Fix.App/RemoteCenterWindow.xaml create mode 100644 src/W-Fix.App/RemoteCenterWindow.xaml.cs create mode 100644 src/W-Fix.App/Services/UserPromptService.cs create mode 100644 src/W-Fix.App/ViewModels/RemoteCenterViewModel.cs create mode 100644 src/W-Fix.Core/Abstractions/RemoteRepairContracts.cs create mode 100644 src/W-Fix.Core/Catalog/KnownIssueCatalogService.cs create mode 100644 src/W-Fix.Core/Catalog/known-issues-public.pem create mode 100644 src/W-Fix.Core/Catalog/known-issues.json create mode 100644 src/W-Fix.Core/Diagnostics/CoreDiagnosticRules.cs create mode 100644 src/W-Fix.Core/Diagnostics/DiagnosticService.cs create mode 100644 src/W-Fix.Core/Infrastructure/WindowsCredentialStore.cs create mode 100644 src/W-Fix.Core/Models/KnownIssueCatalogModels.cs create mode 100644 src/W-Fix.Core/Models/RemoteRepairModels.cs create mode 100644 src/W-Fix.Core/Remote/PowerShellJson.cs create mode 100644 src/W-Fix.Core/Remote/PowerShellRemoteSession.cs create mode 100644 src/W-Fix.Core/Remote/RemoteMaintenanceService.cs create mode 100644 src/W-Fix.Core/Remote/RemotePreflightService.cs create mode 100644 src/W-Fix.Core/Remote/RemotePrinterInventoryService.cs create mode 100644 src/W-Fix.Core/Repair/LegacyFixerRepairAction.cs create mode 100644 src/W-Fix.Core/Repair/RepairActionRegistry.cs create mode 100644 src/W-Fix.Core/Repair/RepairExecutor.cs create mode 100644 src/W-Fix.Core/Repair/RepairPlanner.cs create mode 100644 src/W-Fix.Core/Reporting/RunReportService.cs create mode 100644 src/W-Fix.Core/Reporting/SupportBundleService.cs create mode 100644 src/W-Fix.Core/Services/RemoteCredentialContext.cs create mode 100644 src/W-Fix.Core/Services/TargetParser.cs create mode 100644 tests/W-Fix.Core.Tests/RemoteRepairTests.cs create mode 100644 tools/W-Fix.CatalogSigner/Program.cs create mode 100644 tools/W-Fix.CatalogSigner/W-Fix.CatalogSigner.csproj diff --git a/README.md b/README.md index 3720e20..20b6850 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Platform](https://img.shields.io/badge/platform-Windows%2010%2F11-blue?logo=windows)](https://www.microsoft.com/windows) [![.NET](https://img.shields.io/badge/.NET-8.0-purple?logo=dotnet)](https://dotnet.microsoft.com/) -[![Release](https://img.shields.io/badge/version-2.2.0-green)](https://github.com/OneDeadMachine/W-Fix/releases) +[![Release](https://img.shields.io/badge/version-3.0.0--beta.1-blue)](https://github.com/OneDeadMachine/W-Fix/releases) [![License](https://img.shields.io/badge/license-MIT-orange)](LICENSE) [![Author](https://img.shields.io/badge/author-OneDeadMachine-red)](https://github.com/OneDeadMachine) @@ -44,6 +44,10 @@ | 12 | **Принтер по умолчанию** | Default printer | Сброс реестра + `SetDefaultPrinter` | ### Плюс: +- 🌐 **Remote Repair Center v3** — несколько доменных ПК, preflight, инвентаризация, автоматический план, проверка и изолированный rollback +- 🧠 **Диагностические правила** — вывод по наблюдаемым фактам, уверенность и официальный источник известной проблемы +- 🔐 **Credential Manager** — альтернативная доменная учётная запись без пароля в конфигурации, CLI или логах +- 📊 **Отчёты** — JSON/HTML для каждого запуска и обезличенный ZIP support bundle - 🌐 **Удалённые машины** — системные шаги через WinRM, а пользовательские настройки принтера — в реальном интерактивном сеансе - 🔍 **Обнаружение принтеров** — CIM / WMI / Get-Printer (тройной fallback) - 📋 **Полный лог** — каждый шаг фиксера отображается в реальном времени @@ -59,6 +63,13 @@ 3. Выбери принтер в левой панели 4. Выбери фиксер в правой панели → нажми **«Применить»** +Для нескольких компьютеров открой **Remote Center**: + +1. Добавь имена вручную либо через поиск Active Directory. +2. Выполни **Preflight** — ping носит справочный характер, рабочее подключение определяется по WinRM. +3. Запусти **Диагностику**, проверь факты и сформированный план. +4. Подтверди пакетный ремонт. Сбой одной машины не останавливает остальные; обратимые шаги неуспешной цели откатываются. + > ⚠️ Права администратора обязательны — фиксеры изменяют реестр и службы Windows. --- @@ -96,6 +107,11 @@ dotnet publish src/W-Fix.App/W-Fix.App.csproj ` W-Fix/ ├── src/ │ ├── W-Fix.Core/ # Бизнес-логика +│ │ ├── Abstractions/ # Контракты сессии, диагностики, ремонта и отчётов +│ │ ├── Remote/ # WinRM preflight и инвентаризация +│ │ ├── Diagnostics/ # Evidence-based правила +│ │ ├── Repair/ # Планировщик, legacy-адаптер и batch executor +│ │ ├── Catalog/ # Подписанный каталог Windows known issues │ │ ├── Fixers/ # 12 фиксеров (FixerBase → IFixer) │ │ ├── Services/ │ │ │ ├── WmiService.cs # Обнаружение принтеров (CIM/WMI/PS) @@ -106,6 +122,7 @@ W-Fix/ │ │ └── Models/ # PrinterInfo, FixResult, LogEntry ... │ └── W-Fix.App/ # WPF UI (MVVM + CommunityToolkit) │ ├── ViewModels/ +│ ├── RemoteCenterWindow.xaml │ ├── Views/ │ └── Assets/icon.ico └── publish/W-Fix.exe # Готовый портативный файл @@ -116,6 +133,9 @@ W-Fix/ Подробности внутренних границ, выполнения PowerShell и правил для фиксеров: [docs/architecture.md](docs/architecture.md). +Работа с новым центром: [docs/remote-center.md](docs/remote-center.md). Формат и подпись базы проблем: +[docs/known-issues-catalog.md](docs/known-issues-catalog.md). + --- ## 📋 Системные требования diff --git a/docs/architecture.en.md b/docs/architecture.en.md new file mode 100644 index 0000000..0fab4ac --- /dev/null +++ b/docs/architecture.en.md @@ -0,0 +1,25 @@ +# W-Fix v3 architecture + +W-Fix v3 separates presentation, remote transport, inventory, diagnosis, planning, execution, verification, +rollback, and reporting. `App.xaml.cs` is the WPF composition root; view models receive dependencies instead of +constructing WMI, Active Directory, backup, or repair services. + +The Remote Center pipeline is: + +1. Normalize manual or Active Directory computers into `TargetDescriptor` values. +2. Run capability-based preflight over WinRM. Ping is informational and never decides reachability. +3. Capture OS/build/KB, queues, jobs, ports, drivers, policies, Protected Print Mode, and PrintService events. +4. Produce evidence-backed `DiagnosticFinding` values and a capability-filtered `RepairPlan`. +5. Create targeted checkpoints, execute with bounded concurrency, verify through a fresh inventory, and roll back + only the failed target. +6. Persist a JSON/HTML run report and optionally export an anonymized support bundle. + +The twelve v2 fixers remain available through `LegacyFixerRepairAction`. This compatibility boundary preserves +working repair scripts while orchestration moves to `IRepairAction`, `IRepairPlanner`, and `IRepairExecutor`. + +Alternate domain credentials are stored only in Windows Credential Manager. The password is materialized for a +short-lived `PSCredential`; it is never embedded in a PowerShell script, process arguments, configuration, or logs. + +The known-issues catalog is declarative. A valid ECDSA signature does not grant code execution: catalog entries can +only reference action IDs compiled into W-Fix. Microsoft source URLs are restricted to `learn.microsoft.com` and +`support.microsoft.com`. diff --git a/docs/architecture.md b/docs/architecture.md index e02f1cf..b381ab4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -6,6 +6,11 @@ - `W-Fix.Core.Models` — данные принтеров, журнал и типизированные результаты операций. - `W-Fix.Core.Services` — обнаружение принтеров, Active Directory и выполнение PowerShell. - `W-Fix.Core.Fixers` — прикладные сценарии диагностики и исправления. +- `W-Fix.Core.Abstractions` — стабильные контракты транспорта, инвентаризации, диагностики, ремонта и отчётов. +- `W-Fix.Core.Remote` — WinRM/WSMan-сессии, capability preflight и снимок печатной подсистемы. +- `W-Fix.Core.Diagnostics` — правила, формирующие находки только из наблюдаемых фактов. +- `W-Fix.Core.Repair` — планирование, адаптер двенадцати v2-фиксеров и ограниченное пакетное выполнение. +- `W-Fix.Core.Catalog` — встроенный и подписанный онлайн-каталог известных проблем Windows. UI не должен самостоятельно определять успешность системной команды. Источником истины является `PowerShellExecutionResult`, а итог многошагового фиксера вычисляется из результатов всех выполненных шагов. @@ -71,8 +76,29 @@ PowerShell Remoting выполняет команды в сервисном ко уже вошедшего пользователя. Если интерактивного сеанса нет, операция завершается явной ошибкой — W-Fix не сообщает ложный успех для HKCU администратора. -## Следующий архитектурный этап +## Конвейер Remote Center v3 -Вынести создание сервисов из `MainWindowViewModel` в composition root и ввести интерфейсы исполнителя, -обнаружения принтеров и диалогов. Это позволит тестировать фиксеры без реального изменения Windows и добавить -интеграционные проверки снимка/отката на изолированной тестовой машине. +`App.xaml.cs` является composition root. ViewModel больше не создают системные сервисы самостоятельно. +Пользовательский поток имеет фиксированные границы: + +1. `TargetDescriptor` создаётся из ручного списка либо объекта Active Directory. +2. `IRemotePreflightService` проверяет DNS, WinRM, административный токен, CIM, Spooler, Task Scheduler, + интерактивного пользователя, pending reboot и место на системном диске. Ping остаётся справочным сигналом. +3. `IPrinterInventoryService` собирает ОС/build/UBR, KB, очереди, задания, порты, драйверы, политики, + Protected Print Mode и свежие ошибки PrintService. +4. `IDiagnosticRule` создаёт `DiagnosticFinding` с доказательствами, уверенностью и локальными action ID. +5. `IRepairPlanner` исключает действия, для которых цель не имеет требуемых capabilities. +6. `IRepairExecutor` ограничивает параллелизм, создаёт снимок до мутации, выполняет шаг, повторно диагностирует + цель и при неуспехе откатывает её независимо от остальных машин. +7. `IRunReportService` сохраняет JSON/HTML в `%ProgramData%\W-Fix\Runs\`. + +Каталог известных проблем декларативен и не содержит скриптов. Даже корректно подписанная запись может выбрать +только действие, уже скомпилированное и зарегистрированное в W-Fix. + +## Риски и подтверждения + +- `Reversible` — обычное подтверждение плана и обязательный снимок. +- `Disruptive` — заметная маркировка (например, временная остановка Spooler). +- `Irreversible` — дополнительный диалог; сюда относятся удаление заданий или пакетов драйверов. +- Protected Print Mode не переключается автоматически: режим может удалить несовместимые очереди и драйверы. +- Удаление Windows Update не является обычным действием; допускается только отдельным экспертным сценарием. diff --git a/docs/known-issues-catalog.md b/docs/known-issues-catalog.md new file mode 100644 index 0000000..397dfc4 --- /dev/null +++ b/docs/known-issues-catalog.md @@ -0,0 +1,35 @@ +# Known issues catalog / Каталог известных проблем + +## Русский + +W-Fix содержит fallback-каталог `Catalog/known-issues.json` и пытается получить два release asset: + +- `known-issues.json`; +- `known-issues.json.sig` — Base64 ECDSA P-256/SHA-256 подпись точных байтов JSON. + +Онлайн-файл принимается только при корректной подписи, поддерживаемой схеме, непросроченном `expiresAt`, уникальных +ID и HTTPS-ссылках на `learn.microsoft.com` либо `support.microsoft.com`. При ошибке используется последний валидный +подписанный кэш, затем встроенный fallback. Каталог не содержит PowerShell: `recommendedActionIds` может ссылаться +только на встроенные `legacy:*` действия. + +Подпись выпуска: + +```powershell +dotnet run --project tools/W-Fix.CatalogSigner -- sign ` + src/W-Fix.Core/Catalog/known-issues.json ` + path/to/known-issues-private.pem ` + artifacts/known-issues.json.sig +``` + +Закрытый ключ нельзя добавлять в Git. Публичный ключ находится в `known-issues-public.pem` и закреплён в приложении. +При ротации ключа сначала выпускается версия W-Fix с новым публичным ключом. + +## English + +W-Fix accepts a remote known-issues catalog only when its detached ECDSA P-256/SHA-256 signature is valid, the schema +is supported, the document is not expired, IDs are unique, and every source is an approved Microsoft HTTPS host. +Failure falls back to the last valid signed cache and then to the embedded catalog. + +Catalog content is declarative and cannot deliver scripts or commands. It can only select `legacy:*` repair actions +already compiled into W-Fix. Never commit the private signing key; rotate the embedded public key through an application +release before signing the feed with a new key. diff --git a/docs/remote-center.md b/docs/remote-center.md new file mode 100644 index 0000000..2f42059 --- /dev/null +++ b/docs/remote-center.md @@ -0,0 +1,36 @@ +# Remote Repair Center / Центр удалённого ремонта + +## Русский + +### Требования + +- доменные Windows 10/11 x64; +- административная учётная запись; +- WinRM/PowerShell Remoting; +- Task Scheduler и вошедший пользователь — только для HKCU/принтера по умолчанию; +- запуск W-Fix от имени администратора. + +### Рабочий процесс + +1. Откройте **Remote Center** из главного окна. +2. Добавьте FQDN/NetBIOS вручную или найдите машины в Active Directory. +3. По умолчанию используется текущая Windows-учётка и Kerberos. Альтернативную доменную учётку можно явно + сохранить в Credential Manager; пароль сразу очищается из формы. +4. Нажмите **Preflight**. Недоступная capability отключает только зависящие от неё действия. +5. Нажмите **Диагностика** и изучите факты, уверенность и план. +6. Нажмите **Ремонт**. Обычный план требует одного подтверждения; необратимые шаги — дополнительного. +7. Откройте HTML/JSON-отчёт либо экспортируйте обезличенный ZIP. + +Параллелизм ограничен диапазоном 1–10, значение по умолчанию — 3. Ошибка одной машины не останавливает пакет. +Отмена прекращает запуск новых целей и инициирует rollback незавершённой обратимой цели. Перезагрузка никогда не +отправляется автоматически: в конце используется отдельная кнопка и подтверждение. + +## English + +Remote Center officially targets domain-joined Windows 10/11 x64 clients. Add computers manually or through Active +Directory, run preflight, capture inventory, review evidence and the proposed repair plan, then confirm the batch. + +The default authentication path is the current Windows identity with Kerberos. An alternate domain account is stored +only after an explicit action in Windows Credential Manager. Concurrency defaults to three and can be set from one to +ten. A failed target is verified and rolled back independently; it does not stop the remaining targets. Reboots always +require a separate end-of-run confirmation. diff --git a/src/W-Fix.App/App.xaml b/src/W-Fix.App/App.xaml index f1d2151..97884ec 100644 --- a/src/W-Fix.App/App.xaml +++ b/src/W-Fix.App/App.xaml @@ -1,8 +1,7 @@ + xmlns:ui="http://schemas.modernwpf.com/2019"> diff --git a/src/W-Fix.App/App.xaml.cs b/src/W-Fix.App/App.xaml.cs index 2625f2e..1879de3 100644 --- a/src/W-Fix.App/App.xaml.cs +++ b/src/W-Fix.App/App.xaml.cs @@ -1,11 +1,24 @@ using System.IO; using System.Windows; +using Microsoft.Extensions.DependencyInjection; using Serilog; +using WFix.App.Services; +using WFix.App.ViewModels; +using WFix.Core.Abstractions; +using WFix.Core.Catalog; +using WFix.Core.Diagnostics; +using WFix.Core.Infrastructure; +using WFix.Core.Remote; +using WFix.Core.Repair; +using WFix.Core.Reporting; +using WFix.Core.Services; namespace WFix.App; public partial class App : Application { + public IServiceProvider Services { get; private set; } = null!; + protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); @@ -39,12 +52,60 @@ protected override void OnStartup(StartupEventArgs e) MessageBoxButton.OK, MessageBoxImage.Error); ex.Handled = true; }; + + Services = ConfigureServices(); + Services.GetRequiredService().Show(); } + public RemoteCenterWindow CreateRemoteCenterWindow() => + Services.GetRequiredService(); + protected override void OnExit(ExitEventArgs e) { Log.Information("W-Fix завершён"); + (Services as IDisposable)?.Dispose(); Log.CloseAndFlush(); base.OnExit(e); } + + private static IServiceProvider ConfigureServices() + { + var services = new ServiceCollection(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddTransient(); + services.AddSingleton(); + services.AddTransient(); + + return services.BuildServiceProvider(new ServiceProviderOptions + { + ValidateOnBuild = true, + ValidateScopes = true + }); + } } diff --git a/src/W-Fix.App/MainWindow.xaml b/src/W-Fix.App/MainWindow.xaml index 11325f4..0ff8354 100644 --- a/src/W-Fix.App/MainWindow.xaml +++ b/src/W-Fix.App/MainWindow.xaml @@ -12,10 +12,6 @@ Background="#0D1117" FontFamily="Segoe UI" FontSize="13"> - - - - @@ -45,13 +41,16 @@ - + +