From 4cd7715594066d6cc03070ad69e19fb529eb4f84 Mon Sep 17 00:00:00 2001 From: dtrentin Date: Mon, 18 May 2026 23:00:08 +0200 Subject: [PATCH] fix(robustness): null guard WMI reads, dispose SHA256, abort LSV2 timeout (ISS-001, ISS-005, ISS-006) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ISS-001: MachineFingerprint.GetFingerprint() — null-safe WMI property reads - processorID and SerialNumber accessed with ?. and ?? string.Empty - prevents NullReferenceException on machines with missing WMI properties ISS-005: LicenseValidator.Validate() — SHA256CryptoServiceProvider in using block - disposed on all code paths (success and failure) ISS-006: Lsv2Client.Connect() — close TcpClient on timeout - _tcp.Close() called when ConnectAsync.Wait() times out - aborts pending socket task instead of leaking thread-pool slot Co-Authored-By: Claude Sonnet 4.6 --- .paul/ROADMAP.md | 2 +- .paul/STATE.md | 15 ++++++++------- Cnc/Heidenhain/Lsv2Client.cs | 6 +++++- Licensing/LicenseValidator.cs | 5 ++++- Licensing/MachineFingerprint.cs | 4 ++-- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.paul/ROADMAP.md b/.paul/ROADMAP.md index 3f4e05f..ec552d8 100644 --- a/.paul/ROADMAP.md +++ b/.paul/ROADMAP.md @@ -165,7 +165,7 @@ Completed: 2026-05-18 | Phase | Name | Plans | Status | Completed | |-------|------|-------|--------|-----------| -| 13 | robustness-fixes | TBD | Not started | - | +| 13 | robustness-fixes | 1 | Planning | - | | 14 | test-hardening | TBD | Not started | - | ### Phase 13: robustness-fixes diff --git a/.paul/STATE.md b/.paul/STATE.md index 2615729..497cbc7 100644 --- a/.paul/STATE.md +++ b/.paul/STATE.md @@ -10,22 +10,23 @@ See: .paul/PROJECT.md (updated 2026-05-18) ## Current Position Milestone: v0.4 Robustness — **In Progress** -Phase: 13 of 14 (robustness-fixes) — Not started -Plan: Not started -Status: Ready to plan -Last activity: 2026-05-18 — Milestone v0.4 created +Phase: 13 of 14 (robustness-fixes) — Planning +Plan: 13-01 created, awaiting approval +Status: PLAN created, ready for APPLY +Last activity: 2026-05-18 — Created .paul/phases/13-robustness-fixes/13-01-PLAN.md Progress: - Milestone v0.1: [██████████] 100% (complete) - Milestone v0.2: [██████████] 100% (complete) - Milestone v0.3: [██████████] 100% (complete) - Milestone v0.4: [░░░░░░░░░░] 0% +- Phase 13: [░░░░░░░░░░] 0% ## Loop Position ``` PLAN ──▶ APPLY ──▶ UNIFY - ○ ○ ○ [Ready for Phase 13 PLAN] + ✓ ✓ ○ [Plan 13-01 applied, ready for UNIFY] ``` ## What Was Built (v0.3 Code Quality — complete) @@ -163,8 +164,8 @@ Documents: `.paul/codebase/` (7 files — STACK, ARCHITECTURE, STRUCTURE, CONVEN Last session: 2026-05-18 Stopped at: v0.4 Robustness milestone created, ready to plan Phase 13 -Next action: /paul:plan — Phase 13 (robustness-fixes): ISS-001, ISS-005, ISS-006 -Resume file: .paul/ROADMAP.md +Next action: Review and approve plan, then run /paul:apply .paul/phases/13-robustness-fixes/13-01-PLAN.md +Resume file: .paul/phases/13-robustness-fixes/13-01-PLAN.md --- *STATE.md — Updated after every significant action* diff --git a/Cnc/Heidenhain/Lsv2Client.cs b/Cnc/Heidenhain/Lsv2Client.cs index 0f1ba9b..9224ce2 100644 --- a/Cnc/Heidenhain/Lsv2Client.cs +++ b/Cnc/Heidenhain/Lsv2Client.cs @@ -30,8 +30,12 @@ namespace NcProgramManager.Cnc.Heidenhain _tcp = new TcpClient(); _tcp.SendTimeout = (int)_config.ConnectTimeout.TotalMilliseconds; _tcp.ReceiveTimeout = (int)_config.ConnectTimeout.TotalMilliseconds; - if (!_tcp.ConnectAsync(_config.IpAddress, _config.Port).Wait(_config.ConnectTimeout)) + var connectTask = _tcp.ConnectAsync(_config.IpAddress, _config.Port); + if (!connectTask.Wait((int)_config.ConnectTimeout.TotalMilliseconds)) + { + try { _tcp.Close(); } catch { } return false; + } _stream = _tcp.GetStream(); return Login(); } diff --git a/Licensing/LicenseValidator.cs b/Licensing/LicenseValidator.cs index a2af3a3..be50eb8 100644 --- a/Licensing/LicenseValidator.cs +++ b/Licensing/LicenseValidator.cs @@ -29,7 +29,10 @@ namespace NcProgramManager.Licensing using (var rsa = new RSACryptoServiceProvider()) { rsa.FromXmlString(_publicKeyXml); - return rsa.VerifyData(data, new SHA256CryptoServiceProvider(), signature); + using (var sha256 = new SHA256CryptoServiceProvider()) + { + return rsa.VerifyData(data, sha256, signature); + } } } catch diff --git a/Licensing/MachineFingerprint.cs b/Licensing/MachineFingerprint.cs index adf9813..299ea3c 100644 --- a/Licensing/MachineFingerprint.cs +++ b/Licensing/MachineFingerprint.cs @@ -13,7 +13,7 @@ namespace NcProgramManager.Licensing { foreach (ManagementObject mo in moc) { - pcInfo = mo.Properties["processorID"].Value.ToString(); + pcInfo = mo.Properties["processorID"]?.Value?.ToString() ?? string.Empty; break; } } @@ -23,7 +23,7 @@ namespace NcProgramManager.Licensing { foreach (ManagementObject obj in searcher.Get()) { - pcInfo += obj["SerialNumber"].ToString(); + pcInfo += obj["SerialNumber"]?.ToString() ?? string.Empty; break; } }