test harness: extend matrix to all 9 PC types

Adds rows for Standard-Timeclock, CMM, Keyence, Lab, WaxAndTrace,
Genspect, Display, Shopfloor alongside the existing Standard-Machine.
Per-type apps verified against the corresponding v2 manifest's detection
methods (PC-DMIS 2016/2019R2/Protect Viewer/CLM/goCMM for CMM;
VR-6000/USB driver for Keyence; kiosk shortcut for Display).

Common app list deduped via "$ref": "common.<key>" pattern. Verifier
resolves refs into the per-type apps array at runtime so each row stays
short and PCTypes-filter-aware (Lab + Display + Shopfloor get fewer
common apps because the manifest's PCTypes filter excludes them from
FMS hosts pin / Oracle / OpenText respectively).

verify-state.ps1 changes:
- $ref resolution against the matrix.common namespace
- Registry method now permits no DetectionName (key-existence only,
  e.g. Protect Viewer)
- New PnpUtilGrep method for INF-driver checks (Keyence USB driver)

Smoke-verified end-to-end on the win11 VM as SYSTEM via qga - 60 checks
across 9 PC types. Type-specific failures (5 CMM, 2 Keyence, 1 Display)
correctly surface "no payload staged" rather than masking it as pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-02 17:58:26 -04:00
parent b4e5152471
commit 395d045cdf
2 changed files with 170 additions and 16 deletions

View File

@@ -31,12 +31,41 @@ if (-not $entry) {
exit 1
}
# Resolve `{ "$ref": "common.<key>" }` entries: matrix.json uses $ref to dedup
# common app lists (e.g. "common.all", "common.fmsResolver") so per-PC-type
# rows can compose without copy/paste. Walk the apps list, expand each ref
# inline, drop the ref placeholder.
$resolvedApps = @()
foreach ($a in $entry.apps) {
$refVal = $a.PSObject.Properties['$ref']
if ($refVal) {
$parts = $refVal.Value -split '\.'
if ($parts.Count -eq 2 -and $parts[0] -eq 'common') {
$key = $parts[1]
$list = $matrix.common.$key
if ($list) {
foreach ($x in $list) { $resolvedApps += $x }
continue
}
Write-Host "[WARN] unresolved `$ref: $($refVal.Value)"
continue
}
Write-Host "[WARN] unsupported `$ref form: $($refVal.Value)"
continue
}
$resolvedApps += $a
}
function Test-AppState {
param($app)
$v = $app.verify
switch ($v.method) {
'Registry' {
if (-not (Test-Path -LiteralPath $v.path)) { return @{ pass=$false; detail="reg path missing: $($v.path)" } }
# No DetectionName/value -> key existence is enough (e.g. Protect Viewer entry)
if (-not $v.name) {
return @{ pass=$true; detail="reg key exists: $($v.path)" }
}
$val = (Get-ItemProperty -LiteralPath $v.path -Name $v.name -ErrorAction SilentlyContinue).$($v.name)
if ($null -eq $val) { return @{ pass=$false; detail="reg name $($v.name) not present" } }
if ($v.value -and $val -ne $v.value) {
@@ -70,12 +99,19 @@ function Test-AppState {
if ($hit) { return @{ pass=$true; detail="pattern matched: $($v.pattern)" } }
return @{ pass=$false; detail="pattern not found: $($v.pattern)" }
}
'PnpUtilGrep' {
$drivers = & pnputil /enum-drivers 2>&1 | Out-String
if ($drivers -match $v.pattern) {
return @{ pass=$true; detail="pnputil match: $($v.pattern)" }
}
return @{ pass=$false; detail="pnputil no match for: $($v.pattern)" }
}
default { return @{ pass=$false; detail="unknown method: $($v.method)" } }
}
}
$total = 0; $passed = 0; $failed = @()
foreach ($app in $entry.apps) {
foreach ($app in $resolvedApps) {
$total++
$r = Test-AppState -app $app
if ($r.pass) {