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.
116 lines
6.7 KiB
PowerShell
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."
|