Files
minerops/agents/windows/tests/Test-MinerOpsControl.ps1
lussierj e898f283ab security: contain physical miner commands in Stage A
Disable physical control through legacy HTTP/M30 producers, typed admission,
queue dispatch and upgraded Windows executors. Restrict diagnostic transports
to exact read-only operations, with ordinal PowerShell validation before sockets.

Retire unsupported pending/claimed work with atomic, idempotent security audits.
Preserve prior delivery evidence and report unknown outcomes after a prior claim,
including explicitly repaired pending rows. Include containment, cancellation,
concurrency and malformed-payload regressions and the old-Agent cutover runbook.

Validation: independent final application-security revalidation PASS. Two unchanged
baseline source-assertion failures are documented as exceptions. Production release
still requires native Windows validation and verified fencing/stop/drain/upgrade;
server cancellation alone cannot revoke a cached command held by an old Agent.
2026-10-15 20:39:45 +00:00

116 lines
6.7 KiB
PowerShell

$ErrorActionPreference = "Stop"
$script:assertions = 0
$script:physicalCalls = 0
$script:readCalls = 0
$script:apiCalls = @()
$script:commands = @()
function Assert-Equal($Actual, $Expected, [string]$Message) {
$script:assertions++
if ($Actual -ne $Expected) { throw "$Message. Expected '$Expected', got '$Actual'." }
}
function Assert-Throws($Block, [string]$Message) {
$caught = $false
try { & $Block | Out-Null } catch {
$caught = $true
Assert-Equal $_.Exception.Message "physical_control_disabled_stage_a" $Message
}
Assert-Equal $caught $true "$Message must reject"
}
# Define functions from the real service AST, without executing its service loop,
# config loading, startup, or any scheduled tasks.
$root = Split-Path $PSScriptRoot -Parent
$tokens = $null; $parseErrors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
(Join-Path $root "MinerOpsAgentService.ps1"), [ref]$tokens, [ref]$parseErrors)
Assert-Equal $parseErrors.Count 0 "Service parser"
foreach ($function in $ast.FindAll({
param($node)
$node -is [System.Management.Automation.Language.FunctionDefinitionAst] -and
$node.Parent -is [System.Management.Automation.Language.NamedBlockAst]
}, $true)) {
Invoke-Expression $function.Extent.Text
}
$script:productionApi3Payload = (Get-Command Invoke-MinerOpsApi3Payload).ScriptBlock
$script:productionPlainCommand = (Get-Command Invoke-MinerPlainCommand).ScriptBlock
function Invoke-MinerOpsApi3Payload { $script:physicalCalls++; throw "Unexpected API3 transport" }
function Get-MinerOpsApi3Salt { $script:physicalCalls++; throw "Unexpected salt probe" }
function Invoke-MinerPlainCommand { $script:physicalCalls++; throw "Unexpected legacy transport" }
function Read-AgentConfig { return [pscustomobject]@{
agent_id = "simulated-agent"; site_id = ""; site_name = "Simulation"
api3_account = "operator"; api3_password = "mock-only"; api3_port = 4433
} }
function Write-AgentLog { param([string]$Message) }
function Invoke-AgentApi {
param([string]$Method, [string]$Path, [object]$Body)
$script:apiCalls += @{ method = $Method; path = $Path; body = $Body }
return @{ ok = $true }
}
function Get-PendingAgentCommands { return $script:commands }
function Run-KnownMinerPoll { $script:readCalls++; return @{ simulated = $true } }
function Run-NewMinerDiscovery { $script:readCalls++; return @{ simulated = $true } }
# The pre-module legacy implementation must also be inert, including helpers
# which used to support direct generic API3 or M30/4028 writes.
Assert-Throws { Run-MinerControlCommand -Payload @{ action = "reboot"; dry_run = $false } } "Legacy executor"
Assert-Throws { Invoke-MinerOpsApi3Service -IpAddress "192.0.2.1" -ServiceAction "stop" } "Legacy service helper"
Assert-Throws { & $script:productionApi3Payload -IpAddress "192.0.2.1" -Payload @{ cmd = "set.miner.service"; param = "stop" } } "Generic API3 payload helper"
Assert-Throws { & $script:productionPlainCommand -IpAddress "192.0.2.1" -Command "reboot" } "Generic legacy command helper"
Assert-Throws { Invoke-MinerOpsApi3AuthenticatedCommand -IpAddress "192.0.2.1" -Command "set.miner.service" -Param "stop" } "Legacy API3"
Assert-Throws { Invoke-MinerOpsLegacy4028Command -IpAddress "192.0.2.1" -CommandJson '{"command":"reboot"}' } "Legacy 4028"
Assert-Throws { Invoke-MinerOpsM30Legacy4028Test -Payload @{ legacy_4028_command = "reboot" } } "M30 helper"
. (Join-Path $root "MinerOpsControl.ps1")
Assert-Throws { Invoke-MinerOpsControlApi3Command -IpAddress "192.0.2.1" -Command "set.miner.service" -Param "stop" } "Typed transport"
Assert-Throws { Invoke-MinerOpsControlApi3Command -IpAddress "192.0.2.1" -Command "get.read_then_write" } "Disguised diagnostic"
$payloads = @(
@{ action = "legacy_4028"; legacy_4028_command = "reboot"; dry_run = $false },
@{ action = "reboot"; ip_address = "192.0.2.1" },
@{ schema_version = 1; action = "suspend"; ip_address = "192.0.2.1"; miner_id = "spoofed" },
@{ schema_version = 1; action = "resume"; ip_address = "192.0.2.1" },
@{ schema_version = 1; action = "performance_mode"; requested_value = "high"; ip_address = "192.0.2.1" },
@{ schema_version = 999; action = "suspend" },
@{ schema_version = "1"; action = "performance_mode"; performance_mode = "high" },
@{ command = "summary"; params = @{ cmd = "set.miner.service"; param = "stop" } },
@{ action = "read_reboot"; dry_run = $true },
@{},
'{"schema_version":0,"action":"reboot"}',
"{invalid-json"
)
foreach ($payload in $payloads) {
$result = Run-MinerControlCommand -Payload $payload
Assert-Equal $result.command_accepted $false "Rejected payload acceptance"
Assert-Equal $result.failure_code "physical_control_disabled_stage_a" "Rejected payload reason"
Assert-Equal $result._queue_status "failed" "Rejected payload terminal result"
Assert-Equal $result.verification_attempted $false "No physical verification/probe"
Assert-Equal $result.observed_service_state $null "No invented device state"
Assert-Equal $script:physicalCalls 0 "No physical calls"
$script:commands = @(@{ command_id = "legacy-delivery"; command_type = "miner_control"; request_payload = $payload })
$script:apiCalls = @()
Assert-Equal (Process-PendingCommands) 1 "Delivered legacy command handled"
Assert-Equal $script:apiCalls.Count 1 "One failed result submitted"
Assert-Equal $script:apiCalls[0].body.status "failed" "Legacy delivery failed"
Assert-Equal $script:apiCalls[0].body.result_payload.command_accepted $false "Legacy delivery not accepted"
Assert-Equal $script:physicalCalls 0 "No writes after delivery"
}
foreach ($kind in @("raw_api3", "miner_control_v2", "read_reboot", "")) {
$script:commands = @(@{ command_id = "unsupported"; command_type = $kind; request_payload = @{ action = "reboot" } })
$script:apiCalls = @()
Assert-Equal (Process-PendingCommands) 1 "Unknown command handled"
Assert-Equal $script:apiCalls[0].body.status "failed" "Unknown command fails closed"
}
Assert-Equal $script:readCalls 0 "No physical request reinterpreted as telemetry"
$script:commands = @(@{ command_id = "read-only"; command_type = "poll_known_miners_now"; request_payload = @{} })
$script:apiCalls = @()
Assert-Equal (Process-PendingCommands) 1 "Fixed read-only command available"
Assert-Equal $script:readCalls 1 "Only simulated read performed"
Assert-Equal $script:physicalCalls 0 "No physical calls in entire suite"
$script:apiCalls = @()
Send-AgentCheckin | Out-Null
Assert-Equal $script:apiCalls[0].body.control_available $false "Cannot advertise physical capability"
Assert-Equal $script:apiCalls[0].body.control_unavailable_reason "physical_control_disabled_stage_a" "Containment advertised"
Write-Host "Stage A Windows containment passed: $($script:assertions) assertions; zero physical transport calls."