118 lines
3.0 KiB
PowerShell
118 lines
3.0 KiB
PowerShell
$ErrorActionPreference = "Stop"
|
|
|
|
$root = Split-Path $PSScriptRoot -Parent
|
|
$bootstrap = Join-Path $root "Enroll-MinerOpsAgent.ps1"
|
|
|
|
$tokens = $null
|
|
$parseErrors = $null
|
|
|
|
[System.Management.Automation.Language.Parser]::ParseFile(
|
|
$bootstrap,
|
|
[ref] $tokens,
|
|
[ref] $parseErrors
|
|
) | Out-Null
|
|
|
|
if ($parseErrors.Count -gt 0) {
|
|
throw "Enroll-MinerOpsAgent.ps1 parser errors: $($parseErrors.Message -join '; ')"
|
|
}
|
|
|
|
$source = Get-Content -LiteralPath $bootstrap -Raw
|
|
|
|
function Assert-SourceContains {
|
|
param(
|
|
[Parameter(Mandatory)][string] $Pattern,
|
|
[Parameter(Mandatory)][string] $Message
|
|
)
|
|
|
|
if ($source -notmatch $Pattern) {
|
|
throw $Message
|
|
}
|
|
}
|
|
|
|
Assert-SourceContains 'enrollment\.json' `
|
|
"Bootstrap enrollment file is not explicit."
|
|
|
|
Assert-SourceContains '/api/agent/enroll' `
|
|
"Bootstrap does not use the secure enrollment endpoint."
|
|
|
|
Assert-SourceContains 'Read-Host[\s\S]*-AsSecureString' `
|
|
"API3 password is not prompted as a SecureString."
|
|
|
|
Assert-SourceContains 'agent-config\.json\.pending' `
|
|
"Atomic pending config path is missing."
|
|
|
|
Assert-SourceContains 'agent-config\.recovery\.json' `
|
|
"Post-redemption credential recovery path is missing."
|
|
|
|
Assert-SourceContains 'Protect-MinerOpsCredentialFile' `
|
|
"Credential file ACL protection is missing."
|
|
|
|
Assert-SourceContains 'S-1-5-18' `
|
|
"SYSTEM ACL entry is missing."
|
|
|
|
Assert-SourceContains 'S-1-5-32-544' `
|
|
"Administrators ACL entry is missing."
|
|
|
|
Assert-SourceContains 'WindowsIdentity\]::GetCurrent\(\)\.User' `
|
|
"Installing user ACL entry is missing."
|
|
|
|
Assert-SourceContains 'Move-Item[\s\S]*\$ConfigPath' `
|
|
"Atomic final config move is missing."
|
|
|
|
Assert-SourceContains '& \$Installer' `
|
|
"Bootstrap does not hand off to the safe installer."
|
|
|
|
Assert-SourceContains 'Start-ScheduledTask -TaskName "MinerOpsAgent"' `
|
|
"Fresh Agent startup is missing."
|
|
|
|
Assert-SourceContains 'Remove-Item -LiteralPath \$EnrollmentPath' `
|
|
"Consumed extracted enrollment token is not removed."
|
|
|
|
$existingConfigGuard = $source.IndexOf(
|
|
'Test-Path -LiteralPath $ConfigPath'
|
|
)
|
|
|
|
$redeemCall = $source.IndexOf(
|
|
'"$HubUrl/api/agent/enroll"'
|
|
)
|
|
|
|
if (
|
|
$existingConfigGuard -lt 0 -or
|
|
$redeemCall -lt 0 -or
|
|
$existingConfigGuard -gt $redeemCall
|
|
) {
|
|
throw "Existing Agent identity must be rejected before token redemption."
|
|
}
|
|
|
|
$configMove = $source.IndexOf(
|
|
'-Destination $ConfigPath'
|
|
)
|
|
|
|
$installerCall = $source.IndexOf(
|
|
'& $Installer'
|
|
)
|
|
|
|
if (
|
|
$configMove -lt 0 -or
|
|
$installerCall -lt 0 -or
|
|
$configMove -gt $installerCall
|
|
) {
|
|
throw "Permanent Agent credentials must be persisted before installation."
|
|
}
|
|
|
|
foreach ($sensitiveVariable in @(
|
|
'EnrollmentToken',
|
|
'Api3PasswordPlain'
|
|
)) {
|
|
if (
|
|
$source -match (
|
|
'(?im)Write-(Host|Output|Verbose|Information).*?\$' +
|
|
$sensitiveVariable
|
|
)
|
|
) {
|
|
throw "$sensitiveVariable must not be written to output."
|
|
}
|
|
}
|
|
|
|
Write-Host "MinerOps enrollment bootstrap source safety tests passed."
|