아바타 저장소 승격 계약을 완성

This commit is contained in:
Yun Chan 2026-08-29 23:58:33 +09:00
parent ac9b702688
commit ccdcfcd2f5
36 changed files with 14734 additions and 222 deletions

View file

@ -0,0 +1,392 @@
function Get-PublicRuntimeTaskXmlSha256 {
param([Parameter(Mandatory = $true)][string]$Xml)
$bytes = [System.Text.UTF8Encoding]::new($false).GetBytes($Xml)
$hasher = [System.Security.Cryptography.SHA256]::Create()
try {
return ([BitConverter]::ToString($hasher.ComputeHash($bytes))).Replace("-", "").ToLowerInvariant()
} finally {
$hasher.Dispose()
}
}
function Get-PublicRuntimeTaskXmlContractSha256 {
param([Parameter(Mandatory = $true)][string]$Xml)
try {
[xml]$document = $Xml
$enabledNodes = @(
$document.SelectNodes("//*[local-name()='Settings']/*[local-name()='Enabled']")
)
if ($enabledNodes.Count -ne 1) {
throw "Task XML must contain exactly one settings Enabled node"
}
$enabledNodes[0].InnerText = "TASK_OPERATIONAL_STATE"
return Get-PublicRuntimeTaskXmlSha256 -Xml $document.OuterXml
} catch {
throw "Public runtime task XML contract normalization failed"
}
}
function Get-PublicRuntimeTaskDefinitionSetSha256 {
param([Parameter(Mandatory = $true)][object[]]$Entries)
$lines = @()
foreach ($entry in @($Entries | Sort-Object role)) {
if (
[string]$entry.role -notmatch "^(boot|watchdog)$" -or
[string]$entry.xml_sha256 -notmatch "^[0-9a-f]{64}$"
) {
throw "Public runtime task definition digest input is invalid"
}
$enabled = "false"
if ([bool]$entry.enabled) {
$enabled = "true"
}
$lines += ([string]$entry.role + ":" + [string]$entry.xml_sha256 + ":" + $enabled)
}
if ($lines.Count -ne 2) {
throw "Public runtime task definition set must contain exactly two roles"
}
return Get-PublicRuntimeTaskXmlSha256 -Xml (@($lines) -join "`n")
}
function Get-ExactRootScheduledTaskForDefinition {
param([Parameter(Mandatory = $true)][string]$TaskName)
if (
[string]::IsNullOrWhiteSpace($TaskName) -or
$TaskName -match "[\\/\x00-\x1f\x7f]"
) {
throw "Public runtime scheduled task name is invalid"
}
$matches = @(
Get-ScheduledTask `
-TaskName $TaskName `
-TaskPath "\" `
-ErrorAction SilentlyContinue
)
if ($matches.Count -ne 1) {
throw "Public runtime root scheduled task is missing or ambiguous"
}
return $matches[0]
}
function Assert-PublicRuntimeCoordinatedTaskNamesExact {
param([Parameter(Mandatory = $true)][string[]]$TaskNames)
$actual = @($TaskNames | Sort-Object -Unique)
$expected = @("VignettePublicRuntime", "VignettePublicRuntimeWatchdog")
if (
$actual.Count -ne 2 -or
-not ($actual -ccontains $expected[0]) -or
-not ($actual -ccontains $expected[1])
) {
throw "Public runtime task-definition cutover requires the exact two root tasks"
}
}
function Get-PublicRuntimeTaskDefinitionSnapshot {
param(
[string]$BootTaskName = "VignettePublicRuntime",
[string]$WatchdogTaskName = "VignettePublicRuntimeWatchdog",
[switch]$RequireEnabled
)
if ([string]::Equals(
$BootTaskName,
$WatchdogTaskName,
[System.StringComparison]::OrdinalIgnoreCase
)) {
throw "Public runtime boot and watchdog task names must differ"
}
$entries = @()
foreach ($spec in @(
[pscustomobject][ordered]@{ role = "boot"; task_name = $BootTaskName },
[pscustomobject][ordered]@{ role = "watchdog"; task_name = $WatchdogTaskName }
)) {
$task = Get-ExactRootScheduledTaskForDefinition -TaskName $spec.task_name
if ($RequireEnabled -and -not [bool]$task.Settings.Enabled) {
throw "Expected public runtime task is not enabled before bootstrap"
}
$actions = @($task.Actions)
if ($actions.Count -ne 1) {
throw "Public runtime task must have exactly one action"
}
$xml = [string](Export-ScheduledTask -InputObject $task -ErrorAction Stop)
if ([string]::IsNullOrWhiteSpace($xml)) {
throw "Public runtime scheduled task XML snapshot is empty"
}
$entries += [pscustomobject][ordered]@{
role = [string]$spec.role
task_name = [string]$spec.task_name
xml_sha256 = Get-PublicRuntimeTaskXmlSha256 -Xml $xml
contract_sha256 = Get-PublicRuntimeTaskXmlContractSha256 -Xml $xml
enabled = [bool]$task.Settings.Enabled
action_execute = [string]$actions[0].Execute
action_arguments = [string]$actions[0].Arguments
action_working_directory = [string]$actions[0].WorkingDirectory
}
}
return [pscustomobject][ordered]@{
entries = @($entries)
set_sha256 = Get-PublicRuntimeTaskDefinitionSetSha256 -Entries $entries
}
}
function Assert-PublicRuntimeTaskDefinitionSnapshotCurrent {
param([Parameter(Mandatory = $true)][object]$ExpectedSnapshot)
$boot = @($ExpectedSnapshot.entries | Where-Object role -eq "boot")
$watchdog = @($ExpectedSnapshot.entries | Where-Object role -eq "watchdog")
if ($boot.Count -ne 1 -or $watchdog.Count -ne 1) {
throw "Expected public runtime task definition snapshot is invalid"
}
$actual = Get-PublicRuntimeTaskDefinitionSnapshot `
-BootTaskName ([string]$boot[0].task_name) `
-WatchdogTaskName ([string]$watchdog[0].task_name)
if ([string]$actual.set_sha256 -cne [string]$ExpectedSnapshot.set_sha256) {
throw "Public runtime task definition set drifted"
}
return $actual
}
function Get-PublicRuntimeExpectedTaskActionContracts {
param(
[Parameter(Mandatory = $true)][string]$StableSourceRoot,
[Parameter(Mandatory = $true)][string]$ExpectedSourceCommit,
[Parameter(Mandatory = $true)][string]$ExpectedSourceTree,
[Parameter(Mandatory = $true)][string]$PythonPath,
[Parameter(Mandatory = $true)][string]$UserUploadDir,
[Parameter(Mandatory = $true)][string]$UserUploadManifestPath,
[Parameter(Mandatory = $true)][string]$ExpectedUserUploadManifestSha256,
[Parameter(Mandatory = $true)][string]$UserUploadWriteFreezePath,
[Parameter(Mandatory = $true)][string]$CloudflaredPath,
[Parameter(Mandatory = $true)][string]$CloudflaredConfigPath,
[Parameter(Mandatory = $true)][string]$PublicHealthUrl
)
$root = (Resolve-Path -LiteralPath $StableSourceRoot).Path
$bootScript = (Resolve-Path -LiteralPath (Join-Path $root "scripts\boot-public-runtime.ps1")).Path
$watchScript = (Resolve-Path -LiteralPath (Join-Path $root "scripts\watch-public-runtime.ps1")).Path
$startScript = (Resolve-Path -LiteralPath (Join-Path $root "scripts\start-public-runtime.ps1")).Path
$watchLauncher = (Resolve-Path -LiteralPath (Join-Path $root "scripts\watch-public-runtime-task.vbs")).Path
$bootSha256 = (Get-FileHash -LiteralPath $bootScript -Algorithm SHA256).Hash.ToLowerInvariant()
$watchSha256 = (Get-FileHash -LiteralPath $watchScript -Algorithm SHA256).Hash.ToLowerInvariant()
$startSha256 = (Get-FileHash -LiteralPath $startScript -Algorithm SHA256).Hash.ToLowerInvariant()
$resolvedPython = (Resolve-Path -LiteralPath $PythonPath).Path
$resolvedCloudflared = (Resolve-Path -LiteralPath $CloudflaredPath).Path
$resolvedCloudflaredConfig = (Resolve-Path -LiteralPath $CloudflaredConfigPath).Path
$pythonSha256 = (Get-FileHash -LiteralPath $resolvedPython -Algorithm SHA256).Hash.ToLowerInvariant()
$cloudflaredSha256 = (Get-FileHash -LiteralPath $resolvedCloudflared -Algorithm SHA256).Hash.ToLowerInvariant()
$cloudflaredConfigSha256 = (Get-FileHash -LiteralPath $resolvedCloudflaredConfig -Algorithm SHA256).Hash.ToLowerInvariant()
$windowsPowerShell = Join-Path $env:SystemRoot "System32\WindowsPowerShell\v1.0\powershell.exe"
$wscript = Join-Path $env:SystemRoot "System32\wscript.exe"
$bootArguments = @(
"-NoProfile",
"-ExecutionPolicy Bypass",
"-WindowStyle Hidden",
"-File `"$bootScript`"",
"-StableSourceRoot `"$root`"",
"-ExpectedSourceCommit $ExpectedSourceCommit",
"-ExpectedSourceTree $ExpectedSourceTree",
"-ExpectedBootScriptSha256 $bootSha256",
"-ExpectedStartScriptSha256 $startSha256",
"-ExpectedPythonSha256 $pythonSha256",
"-ExpectedCloudflaredSha256 $cloudflaredSha256",
"-ExpectedCloudflaredConfigSha256 $cloudflaredConfigSha256",
"-Python `"$resolvedPython`"",
"-Cloudflared `"$resolvedCloudflared`"",
"-CloudflaredConfig `"$resolvedCloudflaredConfig`"",
"-UserUploadDir `"$UserUploadDir`"",
"-UserUploadManifestPath `"$UserUploadManifestPath`"",
"-ExpectedUserUploadManifestSha256 $ExpectedUserUploadManifestSha256",
"-UserUploadWriteFreezePath `"$UserUploadWriteFreezePath`""
) -join " "
$watchArguments = @(
"-File `"$watchScript`"",
"-StableSourceRoot `"$root`"",
"-ExpectedSourceCommit $ExpectedSourceCommit",
"-ExpectedSourceTree $ExpectedSourceTree",
"-ExpectedWatchdogSha256 $watchSha256",
"-ExpectedStartScriptSha256 $startSha256",
"-ExpectedPythonSha256 $pythonSha256",
"-ExpectedCloudflaredSha256 $cloudflaredSha256",
"-ExpectedCloudflaredConfigSha256 $cloudflaredConfigSha256",
"-Python `"$resolvedPython`"",
"-Cloudflared `"$resolvedCloudflared`"",
"-CloudflaredConfig `"$resolvedCloudflaredConfig`"",
"-UserUploadDir `"$UserUploadDir`"",
"-UserUploadManifestPath `"$UserUploadManifestPath`"",
"-ExpectedUserUploadManifestSha256 $ExpectedUserUploadManifestSha256",
"-UserUploadWriteFreezePath `"$UserUploadWriteFreezePath`"",
"-PublicHealthUrl `"$PublicHealthUrl`""
) -join " "
return @(
[pscustomobject][ordered]@{
role = "boot"
execute = $windowsPowerShell
arguments = $bootArguments
working_directory = $root
},
[pscustomobject][ordered]@{
role = "watchdog"
execute = $wscript
arguments = "`"$watchLauncher`" $watchArguments"
working_directory = $root
}
)
}
function Assert-NewPublicRuntimeTaskDefinitionsPinned {
param(
[Parameter(Mandatory = $true)][object]$Snapshot,
[Parameter(Mandatory = $true)][string]$StableSourceRoot,
[Parameter(Mandatory = $true)][string]$ExpectedSourceCommit,
[Parameter(Mandatory = $true)][string]$ExpectedSourceTree,
[Parameter(Mandatory = $true)][string]$PythonPath,
[Parameter(Mandatory = $true)][string]$UserUploadDir,
[Parameter(Mandatory = $true)][string]$UserUploadManifestPath,
[Parameter(Mandatory = $true)][string]$ExpectedUserUploadManifestSha256,
[Parameter(Mandatory = $true)][string]$UserUploadWriteFreezePath,
[Parameter(Mandatory = $true)][string]$CloudflaredPath,
[Parameter(Mandatory = $true)][string]$CloudflaredConfigPath,
[Parameter(Mandatory = $true)][string]$PublicHealthUrl,
[switch]$AllowEnabled
)
if (@($Snapshot.entries).Count -ne 2) {
throw "New public runtime task definition set is incomplete"
}
$contracts = @(
Get-PublicRuntimeExpectedTaskActionContracts `
-StableSourceRoot $StableSourceRoot `
-ExpectedSourceCommit $ExpectedSourceCommit `
-ExpectedSourceTree $ExpectedSourceTree `
-PythonPath $PythonPath `
-UserUploadDir $UserUploadDir `
-UserUploadManifestPath $UserUploadManifestPath `
-ExpectedUserUploadManifestSha256 $ExpectedUserUploadManifestSha256 `
-UserUploadWriteFreezePath $UserUploadWriteFreezePath `
-CloudflaredPath $CloudflaredPath `
-CloudflaredConfigPath $CloudflaredConfigPath `
-PublicHealthUrl $PublicHealthUrl
)
foreach ($entry in @($Snapshot.entries)) {
if (-not $AllowEnabled -and [bool]$entry.enabled) {
throw "New public runtime task definition must remain disabled until operational receipt"
}
$contract = @($contracts | Where-Object role -eq ([string]$entry.role))
if (
$contract.Count -ne 1 -or
-not [string]::Equals(
[string]$entry.action_execute,
[string]$contract[0].execute,
[System.StringComparison]::OrdinalIgnoreCase
) -or
[string]$entry.action_arguments -cne [string]$contract[0].arguments -or
-not [string]::Equals(
[string]$entry.action_working_directory,
[string]$contract[0].working_directory,
[System.StringComparison]::OrdinalIgnoreCase
)
) {
throw "New public runtime task action contract drift"
}
}
return $Snapshot
}
function Invoke-PublicRuntimeTaskDefinitionInstallerPairDisabled {
param(
[Parameter(Mandatory = $true)][scriptblock]$BootInstaller,
[Parameter(Mandatory = $true)][scriptblock]$WatchdogInstaller,
[Parameter(Mandatory = $true)][object[]]$MaintenanceSnapshot,
[int]$TimeoutSec = 30
)
try {
$null = & $BootInstaller
$null = & $WatchdogInstaller
Assert-PublicRuntimeTasksDisabledAndIdle `
-Snapshot $MaintenanceSnapshot `
-TimeoutSec $TimeoutSec
} catch {
Suspend-PublicRuntimeTasks `
-Snapshot $MaintenanceSnapshot `
-TimeoutSec $TimeoutSec
Assert-PublicRuntimeTasksDisabledAndIdle `
-Snapshot $MaintenanceSnapshot `
-TimeoutSec $TimeoutSec
throw
}
}
function Enable-NewPublicRuntimeTaskDefinitions {
param([Parameter(Mandatory = $true)][object]$DisabledSnapshot)
$null = Assert-PublicRuntimeTaskDefinitionSnapshotCurrent `
-ExpectedSnapshot $DisabledSnapshot
$boot = @($DisabledSnapshot.entries | Where-Object role -eq "boot")
$watchdog = @($DisabledSnapshot.entries | Where-Object role -eq "watchdog")
if ($boot.Count -ne 1 -or $watchdog.Count -ne 1) {
throw "Disabled public runtime task definition snapshot is invalid"
}
try {
foreach ($entry in @($DisabledSnapshot.entries)) {
Enable-ScheduledTask `
-TaskName ([string]$entry.task_name) `
-TaskPath "\" `
-ErrorAction Stop `
| Out-Null
}
} catch {
foreach ($entry in @($DisabledSnapshot.entries)) {
Disable-ScheduledTask `
-TaskName ([string]$entry.task_name) `
-TaskPath "\" `
-ErrorAction SilentlyContinue `
| Out-Null
}
$failedTruth = Get-PublicRuntimeTaskDefinitionSnapshot `
-BootTaskName ([string]$boot[0].task_name) `
-WatchdogTaskName ([string]$watchdog[0].task_name)
if (@($failedTruth.entries | Where-Object enabled).Count -ne 0) {
throw "Public runtime task enable failed and compensation could not disable both tasks"
}
throw
}
$operational = Get-PublicRuntimeTaskDefinitionSnapshot `
-BootTaskName ([string]$boot[0].task_name) `
-WatchdogTaskName ([string]$watchdog[0].task_name) `
-RequireEnabled
foreach ($prior in @($DisabledSnapshot.entries)) {
$current = @($operational.entries | Where-Object role -eq ([string]$prior.role))
if (
$current.Count -ne 1 -or
[string]$current[0].contract_sha256 -cne [string]$prior.contract_sha256 -or
[string]$current[0].action_arguments -cne [string]$prior.action_arguments -or
-not [string]::Equals(
[string]$current[0].action_execute,
[string]$prior.action_execute,
[System.StringComparison]::OrdinalIgnoreCase
) -or
-not [string]::Equals(
[string]$current[0].action_working_directory,
[string]$prior.action_working_directory,
[System.StringComparison]::OrdinalIgnoreCase
)
) {
foreach ($entry in @($DisabledSnapshot.entries)) {
Disable-ScheduledTask `
-TaskName ([string]$entry.task_name) `
-TaskPath "\" `
-ErrorAction SilentlyContinue `
| Out-Null
}
throw "Public runtime task definition drifted while becoming operational"
}
}
return $operational
}