Skip to content

Servy 9.8

Latest

Choose a tag to compare

@aelassas aelassas released this 24 Aug 10:47
· 18 commits to main since this release

This release includes bug fixes, security patches, code quality improvements, and documentation updates. The full changelog is listed below.

Full Changelog

Click to expand release notes!
  • fix(security): Set-ServyExePermissions.ps1 - the -TargetAccount regex forbids spaces, so 11 of the 23 aliases in ServiceAccounts.cs are rejected, including the 'NT AUTHORITY\LocalService' and 'NT AUTHORITY\NetworkService' const values the product itself stores (#5479)
  • fix(core): ConfigParser.cs / ServiceInstallValidator.cs - Enum.TryParse ORs comma-separated names on non-Flags enums, so "RestartService, RestartProcess" silently installs as RestartComputer (#5507)
  • fix(core): ServiceManager.cs / LogonAsServiceGrant.cs - the EnsureLogOnAsServiceRight guard matches 1 of the 23 built-in account aliases ValidateCredentials accepts, so installing under .\NetworkService aborts with a Cannot resolve SID error (#5531)
  • fix(core): LogonAsServiceGrant.cs - HasLogonAsService only sees directly-assigned rights, so an account granted SeServiceLogonRight through a group is treated as lacking it and Ensure attempts a privileged LSA write (#5532)
  • fix(core): SecureData.cs - DecryptV2 discards the TryHashData result and verifies whatever is in the stackalloc buffer; Encrypt discards TryToBase64Chars and would persist a marker followed by NUL characters (#5542)
  • fix(core): SecureDataIntegrityException.cs / ServiceRepository.cs - two of the seven throw sites are policy refusals, not integrity failures, so an intact legacy record is shown to the user as corrupt and has its credential fields scrubbed (#5545)
  • fix(core): ServiceDependenciesValidator.cs - the name regex has no '+', so a load-order group dependency (+TDI) is rejected even though the SCM accepts one in lpDependencies (#5547)
  • fix(core): ServiceManager.cs - SetServiceDescription documents 'a null value removes the description', but a NULL lpDescription is Win32 for 'leave unchanged'; the empty string is what deletes it (#5554)
  • fix(core): Strings.resx / Helper.cs (Core) - Msg_InvalidServiceName is shown for four rejection branches but describes only the character one, so a service named CON is told to avoid nine characters it does not contain (sibling of #5169) (#5583)
  • fix(core): EnvironmentVariableParser.cs / StartOptionsParser.cs - 3 of 4 FormatException arms echo the whole KEY=VALUE record, and SafeParseEnvVars writes it unmasked to the service log (residual of #5029) (#5621)
  • fix(core): Strings.resx / ServiceDependenciesValidator.cs - the '+' load-order prefix added by #5547 reached the regex but none of the four documented character lists, so the rejection message still tells the user '+' is not allowed (#5650)
  • fix(infra): ServiceRepository.cs / SecureDataLegacyBlockedException.cs - the #5545 fix added the policy-refusal exception but no consumer branches on it, so an intact legacy record is still labelled corrupt and still scrubbed (#5568)
  • fix(infra): ServiceRepository.cs - UpsertBatchAsync preserves credentials from a SafeDecrypt-scrubbed row, so a Manager refresh writes NULL over the stored Password of any service whose secrets will not decrypt (#5572)
  • fix(infra): ServiceRepository.cs - SearchAsync is the only name lookup left on SQLite's ASCII-only LIKE, so the Manager search box cannot find a non-ASCII service name typed in the wrong case (#5573)
  • fix(infra): DatabaseInitializer.cs / SQLiteDbInitializer.cs - UNICODE_NOCASE is registered after connection.Open(), so a pooled connection fails every write to Services with 'no such collation sequence' (#5631)
  • fix(service): Servy fails to restart process (#5584)
  • fix(service): ProcessWrapper.cs / ProcessExtensions.cs - StopTree and StopDescendants leak the unvisited Process handles when the Toolhelp32 snapshot throws, and Service.cs swallows the fault without a log line (residual of #3770) (#5625)
  • fix(service): IServiceHelper.cs - LogStartupArguments' Security Note assigns masking to the logger, but all 8 masking calls are in the caller and every mask member is private/internal to ServiceHelper (#5627)
  • fix(service): ProcessLauncher.cs / EnvironmentVariableHelper.cs - PYTHONIOENCODING is on the ProtectedVariables denylist AND set by ApplyLanguageFixes, so the user's value is refused with a security warning and replaced (undoes #1141 for 1 of its 4 keys) (#5629)
  • fix(service): Service.cs - EvaluateExitOutcome's isHealthCheck term can never widen either condition, and the comment above it describes telemetry the code never collects (#5633)
  • fix(restarter): ServiceHelper.cs / Program.cs (Restarter) - the host kills Servy.Restarter.exe at 240s while RestartTimeoutSeconds accepts up to 86400, so a configured budget over 4 minutes aborts mid-restart and leaves the service stopped (#5618)
  • fix(ui): SplashWindow.xaml / AppBootstrapper.cs - the Topmost splash sits over the owner-less extraction-failure MessageBox, so startup blocks on a dialog hidden behind the splash (#5646)
  • fix(desktop): Strings.resx (Servy) / ServiceDto.cs - Info_PreLaunchTimeout says fire-and-forget disables logging, which it does not, and omits that the configured Pre-Launch Stdout/Stderr paths are silently ignored (#5651)
  • fix(desktop): Strings.resx (Servy) - Info_UserAccount omits the built-in and virtual service identities the Log On tab accepts, and the rule that their password fields must be left empty (#5653)
  • fix(desktop): ServiceCommands.cs (Servy) - OpenSecurityHardeningGuideAsync is the 1 of 31 message-box calls not awaited, so the error dialog no longer blocks the caller and a dispatcher fault is lost (#5658)
  • fix(manager): DependenciesViewModel.cs - LoadDependencyTreeAsync cancels its CTS but never passes the token to GetDependencies, so a superseded SCM walk runs to completion (#5560)
  • fix(manager): DependenciesViewModel.cs / ConsoleViewModel.cs - switching from a running service to a stopped one leaves the previous PID on screen; the #3313 latch cannot clear it and only PerformanceViewModel resets on selection (#5591)
  • fix(manager): MainViewModel.cs / LogsViewModel.cs - Dispose(bool) is virtual instead of override, so SearchableViewModelBase.Dispose never runs and its atomic guard stays 0 (#5593)
  • fix(cli): Msg_ServiceOperationFailed duplicates the service name - {1} is the action string, which already embeds it, so start/stop/restart/uninstall failures log "service 'X' for 'X'" (#5490)
  • fix(cli): the install --help paste reproduces the pre-#5547 --deps character set and the incomplete --user account list; the wiki documents load-order group dependencies nowhere (#5656)
  • fix(psm1): Servy.psm1 - the 32,000-character guard tells the user to shorten the environment variables and parameters, which are the only inputs that never reach the command line (#5492)
  • fix(psm1): Servy.psm1 - Invoke-ServyCli never re-checks HasExited after the poll loop, so a CLI that exits during the final sleep is reported as a timeout and a kill (#5493)
  • fix(notifications): ServyFailureEmail.ps1 - Server/From/To are read untrimmed while Port/UseSsl/TimeoutMs are trimmed, so an indented smtp-config.xml value is rejected or silently drops the alert (residual of #1626) (#5484)
  • fix(style): Format-SourceHygiene.ps1 - trims trailing whitespace from .md, which .editorconfig's [*.md] section sets to false; two trailing spaces are a Markdown hard break (residual of #5032) (#5475)
  • fix(style): Servy.CLI.IntegrationTests.csproj - the last of #4944's six BOM'd project files still carries a UTF-8 BOM, and Format-SourceHygiene.ps1 only strips it as a side effect of a whitespace fix the file does not need (#5476)
  • fix(setup): servy.iss / publish-sc.ps1 - the installer's [Files] paths hardcode Release and net10.0-windows, so build-config.ps1's BuildConfiguration key is honoured by the portable package but not by the installer (#5465)
  • fix(setup): servy.iss - the install path is substituted into the Task Scheduler XMLs unescaped, so an install directory containing '&' produces malformed task definitions (residual of #1345) (#5466)
  • fix(setup): servy.iss - AddToPath's presence check does not Trim/NormalizeFolder the existing PATH entries the way RemoveFromPath does, so an entry with a trailing backslash gets a duplicate appended (residual of #4989) (#5467)