nc_program_manager/.paul/phases/07-license-core/07-01-SUMMARY.md
dtrentin 39a9566858 feat(07-license-core): RSA offline license core
Phase 07 complete:
- IMachineFingerprint + ILicenseValidator interfaces
- MachineFingerprint: WMI CPU ProcessorID + BaseBoard SerialNumber
- LicenseValidator: RSACryptoServiceProvider + SHA256, injectable public key
- LicenseFile.TryRead: out-param bool, no exceptions from file I/O
- 6 NUnit tests (valid/wrong-machine/tampered/empty/not-base64/missing-file)
- 118 tests total, 116 pass, 2 Fanuc FOCAS ignored (Windows DLL)
- Fix: missing 'using System' in CncMachineFactoryTests.cs
- Fix: Dockerfile.test updated for NcProgramManager rename

PublicKeyXml = PLACEHOLDER until Phase 09 generates real key pair.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:58:14 +02:00

6.4 KiB

phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration started completed
07-license-core 01 licensing
rsa
cryptography
wmi
fingerprint
unit-tests
net472
phase provides
06-rename-cleanup NcProgramManager namespace + renamed csproj files
IMachineFingerprint interface + MachineFingerprint WMI implementation
ILicenseValidator interface + LicenseValidator RSA-SHA256 verifier
LicenseFile.TryRead helper
6 unit tests covering valid/invalid/tampered/missing license scenarios
08-license-integration (wires these into Program.cs)
09-license-generator (produces real key pair; PublicKeyXml PLACEHOLDER replaced here)
added patterns
Constructor injection for testability (internal ctor accepts public key XML)
RSACryptoServiceProvider + SHA256CryptoServiceProvider for .NET 4.7.2 compat
created modified
Licensing/IMachineFingerprint.cs
Licensing/ILicenseValidator.cs
Licensing/LicenseFile.cs
Licensing/MachineFingerprint.cs
Licensing/LicenseValidator.cs
NcProgramManager.Tests/Unit/LicenseValidatorTests.cs
NcProgramManager.csproj
NcProgramManager.Tests/NcProgramManager.Tests.csproj
RSA asymmetric: private key vendor-only, public key embedded in binary
PublicKeyXml is PLACEHOLDER until Phase 09 generates real key pair
Constructor injection: internal LicenseValidator(string publicKeyXml) for test isolation
SHA256CryptoServiceProvider (not HashAlgorithmName) — .NET 4.7.2 RSACryptoServiceProvider overload
LicenseValidator(string publicKeyXml) internal ctor mirrors NcProgramValidator injection pattern
TryRead out-param bool pattern: no exceptions escape from file I/O
~2h (split across sessions) 2026-05-17T00:00:00Z 2026-05-17T21:00:00Z

Phase 07 Plan 01: license-core Summary

RSA offline license core shipped: IMachineFingerprint + ILicenseValidator interfaces, WMI fingerprint reader, RSA-SHA256 verifier with injectable key, LicenseFile TryRead helper — 118 tests pass (116 run, 2 Fanuc FOCAS ignored).

Performance

Metric Value
Duration ~2h
Started 2026-05-17
Completed 2026-05-17
Tasks 3 completed
Files modified 8

Acceptance Criteria Results

Criterion Status Notes
AC-1: Machine fingerprint readable via interface Pass MachineFingerprint : IMachineFingerprint — WMI logic extracted (not testable on Linux; verified via code review)
AC-2: Valid license passes validation Pass Validate_ValidLicense_ReturnsTrue — in-memory RSA sign+verify
AC-3: Invalid license rejected Pass Validate_WrongMachineFingerprint_ReturnsFalse, Validate_TamperedLicense_ReturnsFalse
AC-4: Corrupted/missing license file handled Pass LicenseFile_TryRead_NonExistentPath_ReturnsFalse

Accomplishments

  • 5 new files in Licensing/ — interfaces, implementations, file helper — clean DI-ready layer
  • 6 LicenseValidator tests all pass in Docker (Mono 6.12 / .NET 4.7.2)
  • PublicKeyXml PLACEHOLDER documented — Phase 09 replaces with real key pair
  • Full test suite: 118 total, 116 pass, 2 ignored (Fanuc FOCAS, Windows-only DLL, expected)

Files Created/Modified

File Change Purpose
Licensing/IMachineFingerprint.cs Created Interface for fingerprint provider
Licensing/ILicenseValidator.cs Created Interface for RSA validator
Licensing/LicenseFile.cs Created TryRead: reads .lic base64, returns false on missing/empty
Licensing/MachineFingerprint.cs Created WMI: CPU ProcessorID + BaseBoard SerialNumber
Licensing/LicenseValidator.cs Created RSACryptoServiceProvider VerifyData with SHA256
NcProgramManager.Tests/Unit/LicenseValidatorTests.cs Created 6 NUnit tests; generates ephemeral key pair in SetUp
NcProgramManager.csproj Modified +5 Compile entries for Licensing/*.cs
NcProgramManager.Tests/NcProgramManager.Tests.csproj Modified +1 Compile entry for LicenseValidatorTests.cs

Decisions Made

Decision Rationale Impact
RSA asymmetric (not AES) Private key vendor-only; embedded public key safe to decompile Phase 09 must generate real 2048-bit key pair
RSACryptoServiceProvider + SHA256CryptoServiceProvider .NET 4.7.2: VerifyData(byte[], object, byte[]) overload — HashAlgorithmName variant requires RSA base class Locked to this API; no upgrade path issue
PublicKeyXml = PLACEHOLDER Real key not yet generated; prevents Phase 07 from blocking on Phase 09 Phase 09 outputs real XML; copy-paste into LicenseValidator.cs
Internal constructor injection Testable without Windows WMI DLL Same pattern as NcProgramValidator — consistent across codebase

Deviations from Plan

Summary

Type Count Impact
Auto-fixed 1 Pre-existing bug, zero scope creep
Scope additions 0
Deferred 0

Auto-fixed Issues

1. Build — Missing using System; in CncMachineFactoryTests.cs

  • Found during: Docker build (msbuild step)
  • Issue: InvalidOperationException unresolved — using System; absent from CncMachineFactoryTests.cs
  • Fix: Added using System; at top of file
  • Files: NcProgramManager.Tests/Unit/CncMachineFactoryTests.cs
  • Verification: Docker build passed; all 118 tests ran

2. Dockerfile.test — Stale FanucProgramManager paths

  • Found during: First Docker build attempt
  • Issue: Dockerfile.test still referenced FanucProgramManager.* paths from before Phase 06 rename
  • Fix: Updated all paths to NcProgramManager.*
  • Files: Dockerfile.test
  • Verification: Docker build and test run succeeded

Next Phase Readiness

Ready:

  • IMachineFingerprint / ILicenseValidator injectable into any caller
  • LicenseValidator verified correct with real RSA operations
  • LicenseFile.TryRead ready for -licfile= arg wiring

Concerns:

  • PublicKeyXml is PLACEHOLDER — production build will silently reject all licenses until Phase 09 provides real key and it's copied in
  • MachineFingerprint uses WMI — only tested via code review on Linux; validate on Windows hardware

Blockers:

  • None — Phase 08 can proceed

Phase: 07-license-core, Plan: 01 Completed: 2026-05-17