fix(robustness): null guard WMI reads, dispose SHA256, abort LSV2 timeout (ISS-001, ISS-005, ISS-006)

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 <noreply@anthropic.com>
This commit is contained in:
dtrentin 2026-05-18 23:00:08 +02:00
parent d95ead59af
commit 4cd7715594
5 changed files with 20 additions and 12 deletions

View file

@ -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

View file

@ -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*

View file

@ -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();
}

View file

@ -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

View file

@ -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;
}
}