Phase 14 complete — v0.4 Robustness milestone closed:
- HardwareTestHelper.GetIpOrSkip: Assert.Ignore when HEIDENHAIN/SIEMENS/MITSUBISHI_IP not set (ISS-007)
- Hardware_ConnectAsync_RealMachine [Category("Hardware")] added to all 3 integration test files
- LicenseFileTests: 4 tests covering empty, whitespace, valid base64, nonexistent path
- Validate_EmptyFingerprint_ReturnsFalse: confirms validator safe against empty input (ISS-008 scaffold)
- NcProgramManager.Tests.csproj: <Compile> entries for 2 new files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.6 KiB
| phase | plan | type | status | completed | commit |
|---|---|---|---|---|---|
| 13-robustness-fixes | 01 | summary | complete | 2026-05-18 | 4cd7715 |
Summary: Plan 13-01 — Robustness Fixes
What Was Built
Three targeted defensive fixes. No new files. No interface changes.
Task 1 — MachineFingerprint null guard (ISS-001)
File: Licensing/MachineFingerprint.cs
Both WMI property reads now use null-safe operators:
mo.Properties["processorID"]?.Value?.ToString() ?? string.Emptyobj["SerialNumber"]?.ToString() ?? string.Empty
Customers on hardware where WMI returns null for processorID or SerialNumber no longer get an unhandled NullReferenceException at license check startup.
Task 2 — SHA256 provider disposed (ISS-005)
File: Licensing/LicenseValidator.cs
SHA256CryptoServiceProvider wrapped in using block inside Validate(). Disposed on every call — success or failure. RSACryptoServiceProvider pattern unchanged. Public key constant untouched.
Task 3 — LSV2 connect timeout aborts socket (ISS-006)
File: Cnc/Heidenhain/Lsv2Client.cs
Connect() now calls _tcp.Close() when ConnectAsync().Wait(timeout) returns false. Closes the underlying socket, causing the pending task to complete with SocketException rather than holding a thread-pool slot indefinitely. No async/await introduced (Connect() stays synchronous by design).
Acceptance Criteria Results
| AC | Description | Result |
|---|---|---|
| AC-1 | WMI null returns non-null string, no throw | PASS |
| AC-2 | SHA256 provider disposed after every Validate() | PASS |
| AC-3 | Timeout branch closes socket before returning false | PASS |
Decisions Made
?? string.Emptyused (not?? "unknown") — fingerprint string concatenated; empty is correct fallback_tcp.Close()in baretry { } catch { }— same pattern as existing Disconnect() in same file- No CancellationTokenSource pattern (ISS-006 fix note suggested it) — simpler Close() approach sufficient for .NET 4.7.2 synchronous design
Deferred
None — all three tasks completed as planned.
Files Modified
Licensing/MachineFingerprint.cs— null guards on WMI readsLicensing/LicenseValidator.cs— SHA256 using blockCnc/Heidenhain/Lsv2Client.cs— socket close on timeout
Issues Closed
- ISS-001 — MachineFingerprint null dereference on unusual hardware ✓
- ISS-005 — SHA256 crypto provider not disposed ✓
- ISS-006 — LSV2 connect timeout doesn't abort hung task ✓
Commit
4cd7715 — fix(robustness): null guard WMI reads, dispose SHA256, abort LSV2 timeout (ISS-001, ISS-005, ISS-006)