nc_program_manager/.paul/phases/13-robustness-fixes/13-01-SUMMARY.md
dtrentin 32f68c5ed5 feat(14-test-hardening): env-var hardware test scaffolding + LicenseFile edge cases
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>
2026-05-18 23:24:58 +02:00

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.Empty
  • obj["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.Empty used (not ?? "unknown") — fingerprint string concatenated; empty is correct fallback
  • _tcp.Close() in bare try { } 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 reads
  • Licensing/LicenseValidator.cs — SHA256 using block
  • Cnc/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)