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.
56 lines
3.0 KiB
PowerShell
56 lines
3.0 KiB
PowerShell
param([string]$AgentRoot = (Join-Path $PSScriptRoot '..'))
|
|
$ErrorActionPreference = 'Stop'
|
|
$checks=0
|
|
foreach ($file in @('MinerOpsAgentService.ps1','EnrichOneMiner.ps1','MinerOpsApi3EnrichmentPoller.ps1','MinerOpsPoolPoller.ps1')) {
|
|
$tokens=$null; $errors=$null
|
|
$ast=[System.Management.Automation.Language.Parser]::ParseFile((Join-Path $AgentRoot $file),[ref]$tokens,[ref]$errors)
|
|
if ($errors.Count) { throw "Parse errors in ${file}: $errors" }
|
|
$checks++
|
|
if ($file -eq 'MinerOpsAgentService.ps1') {
|
|
$function=$ast.Find({param($n) $n -is [System.Management.Automation.Language.FunctionDefinitionAst] -and $n.Name -eq 'Invoke-AgentApi'},$true)
|
|
Invoke-Expression $function.Extent.Text
|
|
}
|
|
}
|
|
function Read-AgentConfig { return @{hub_url='https://hub.invalid';agent_id='simulated-agent';agent_secret='disposable-only'} }
|
|
$script:requests=@()
|
|
function Invoke-RestMethod {
|
|
param($Method,$Uri,$Headers,$ContentType,$Body,$TimeoutSec)
|
|
$parsed=$Body | ConvertFrom-Json
|
|
$script:requests+=@{body=$parsed;headers=$Headers}
|
|
return @{ok=$true}
|
|
}
|
|
foreach ($selection in @(@{path='/api/agent/discoveries';field='discoveries'},@{path='/api/agent/miner-snapshots';field='miners'})) {
|
|
$script:requests=@();$body=@{agent_id='simulated-agent'}
|
|
$body[$selection.field]=@(1..257 | ForEach-Object { @{sample=$_;miner_version='signed-version'} })
|
|
$result=Invoke-AgentApi -Method POST -Path $selection.path -Body $body
|
|
$sizes=@($script:requests | ForEach-Object { @($_.body.($selection.field)).Count })
|
|
if (($sizes -join ',') -ne '128,128,1') { throw "Unsafe batching: $sizes" }
|
|
foreach ($request in $script:requests) {
|
|
if ($request.headers['X-MinerOps-Agent-ID'] -ne 'simulated-agent') { throw 'Identity lost' }
|
|
}
|
|
if ($result.processed -ne 257) { throw 'Samples lost' }
|
|
$checks+=3
|
|
}
|
|
# Execute the actual target-validation prefix only; transport functions/loops are never loaded.
|
|
$source=Get-Content -LiteralPath (Join-Path $AgentRoot 'EnrichOneMiner.ps1') -Raw
|
|
$start=$source.IndexOf('$config = Read-AgentConfig')
|
|
$finish=$source.IndexOf('$commands = @(',$start)
|
|
$prefix=$source.Substring($start,$finish-$start)
|
|
$script:targetRequests=0
|
|
function Invoke-RestMethod {
|
|
param($Method,$Uri,$Headers,$ContentType,$Body)
|
|
$script:targetRequests++
|
|
if ($Uri -notlike '*/api/agent/discovery-target') { throw 'Unexpected request' }
|
|
return @{ok=$true;ip_address='198.51.100.10'}
|
|
}
|
|
$DiscoveryId='';$ObservationVersion='';$CommandId='';$IpAddress='203.0.113.99'
|
|
$denied=$false
|
|
try { Invoke-Expression $prefix } catch { $denied=$_.Exception.Message -eq 'discovery_observation_required' }
|
|
if (!$denied -or $script:targetRequests -ne 0) { throw 'Missing identity was not rejected before I/O' }
|
|
$checks++
|
|
$DiscoveryId='00000000-0000-4000-8000-000000000001';$ObservationVersion='version';$CommandId='command'
|
|
Invoke-Expression $prefix
|
|
if ($IpAddress -ne '198.51.100.10' -or $script:targetRequests -ne 1) { throw 'Unvalidated target retained' }
|
|
$checks++
|
|
Write-Output "Discovery PowerShell checks passed: $checks; mocked Hub only; zero miner sockets."
|