Bind Agent observations, review, enrichment and telemetry to current Zone
and inventory authority. Preserve immutable MAC ownership and historical
snapshots with stale-result rejection and transactional security audits.
Retire unbound direct/range/scheduled discovery and one/bulk legacy summary
writes in both modes. Require reconciled exact inventory identity or
explicit Zone-scoped IP selection for CSV metadata imports.
Independent Blocker #1 application-security re-audit: PASS on tree
cf863aadc9. Evidence: 141 focused PostgreSQL/HTTP
tests passed; Chromium and PowerShell checks passed. Two documented baseline
source assertions remain unchanged. Production deployment is not approved.
145 lines
3.6 KiB
PowerShell
145 lines
3.6 KiB
PowerShell
$ErrorActionPreference = "Stop"
|
|
|
|
$ConfigPath = "C:\MinerOpsAgent\agent-config.json"
|
|
$Config = Get-Content -Raw $ConfigPath | ConvertFrom-Json
|
|
|
|
$HubUrl = ($Config.hub_url + "").TrimEnd("/")
|
|
$AgentId = $Config.agent_id
|
|
$AgentSecret = $Config.agent_secret
|
|
|
|
$Headers = @{
|
|
"X-MinerOps-Agent-ID" = $AgentId
|
|
"X-MinerOps-Agent-Secret" = $AgentSecret
|
|
}
|
|
|
|
function Normalize-MinerOpsIp {
|
|
param([string] $Ip)
|
|
|
|
if (-not $Ip) {
|
|
return ""
|
|
}
|
|
|
|
return ($Ip -replace "/32$", "").Trim()
|
|
}
|
|
|
|
function Invoke-MinerOps4028PoolsSimple {
|
|
param(
|
|
[Parameter(Mandatory=$true)] [string] $Ip,
|
|
[int] $Port = 4028,
|
|
[int] $TimeoutMs = 5000
|
|
)
|
|
|
|
$client = $null
|
|
$stream = $null
|
|
|
|
try {
|
|
$json = '{"command":"pools"}'
|
|
|
|
$client = New-Object System.Net.Sockets.TcpClient
|
|
$client.ReceiveTimeout = $TimeoutMs
|
|
$client.SendTimeout = $TimeoutMs
|
|
$client.Connect($Ip, $Port)
|
|
|
|
$stream = $client.GetStream()
|
|
$stream.ReadTimeout = $TimeoutMs
|
|
$stream.WriteTimeout = $TimeoutMs
|
|
|
|
$bytes = [System.Text.Encoding]::ASCII.GetBytes($json)
|
|
$stream.Write($bytes, 0, $bytes.Length)
|
|
$stream.Flush()
|
|
|
|
Start-Sleep -Milliseconds 500
|
|
|
|
$buffer = New-Object byte[] 131072
|
|
$read = $stream.Read($buffer, 0, $buffer.Length)
|
|
|
|
if ($read -le 0) {
|
|
return $null
|
|
}
|
|
|
|
$raw = [System.Text.Encoding]::ASCII.GetString($buffer, 0, $read).Trim([char]0).Trim()
|
|
|
|
if (-not $raw) {
|
|
return $null
|
|
}
|
|
|
|
$parsed = $raw | ConvertFrom-Json
|
|
|
|
if (-not $parsed.POOLS) {
|
|
return $null
|
|
}
|
|
|
|
return @($parsed.POOLS)
|
|
}
|
|
catch {
|
|
return $null
|
|
}
|
|
finally {
|
|
if ($stream) {
|
|
try { $stream.Close() } catch {}
|
|
}
|
|
|
|
if ($client) {
|
|
try { $client.Close() } catch {}
|
|
}
|
|
}
|
|
}
|
|
|
|
$response = Invoke-RestMethod -Method Get -Uri "$HubUrl/api/agent/known-miners" -Headers $Headers -TimeoutSec 60
|
|
|
|
$knownMiners = @()
|
|
|
|
if ($response.miners) {
|
|
$knownMiners = @($response.miners)
|
|
} elseif ($response.data -and $response.data.miners) {
|
|
$knownMiners = @($response.data.miners)
|
|
} elseif ($response.data -and $response.data.known_miners) {
|
|
$knownMiners = @($response.data.known_miners)
|
|
}
|
|
|
|
Write-Host "Known miners: $($knownMiners.Count)"
|
|
|
|
$poolSnapshots = New-Object System.Collections.Generic.List[object]
|
|
$count = 0
|
|
|
|
foreach ($miner in $knownMiners) {
|
|
$count++
|
|
|
|
$ip = Normalize-MinerOpsIp -Ip $miner.ip_address
|
|
|
|
if (-not $ip) {
|
|
continue
|
|
}
|
|
|
|
if (($count % 25) -eq 0) {
|
|
Write-Host "Checked $count / $($knownMiners.Count). Collected $($poolSnapshots.Count)."
|
|
}
|
|
|
|
$pools = @(Invoke-MinerOps4028PoolsSimple -Ip $ip)
|
|
|
|
if ($pools.Count -gt 0) {
|
|
$poolSnapshots.Add([pscustomobject]@{
|
|
miner_id = $miner.miner_id
|
|
miner_version = $miner.miner_version
|
|
ip_address = $ip
|
|
mac_address = $miner.mac_address
|
|
model = $miner.model
|
|
pools = @($pools)
|
|
})
|
|
}
|
|
}
|
|
|
|
Write-Host "Pool snapshots collected: $($poolSnapshots.Count)"
|
|
|
|
$allItems = @($poolSnapshots.ToArray())
|
|
$result = @()
|
|
for ($offset = 0; $offset -lt $allItems.Count; $offset += 128) {
|
|
$last = [Math]::Min($offset + 127, $allItems.Count - 1)
|
|
$body = @{agent_id=$AgentId; pool_snapshots=@($allItems[$offset..$last])} | ConvertTo-Json -Depth 80
|
|
$result += Invoke-RestMethod -Method Post -Uri "$HubUrl/api/agent/pool-snapshots" `
|
|
-Headers $Headers -Body $body -ContentType "application/json" -TimeoutSec 180
|
|
}
|
|
|
|
$result | ConvertTo-Json -Depth 10
|
|
|