MB-X Bilibili Pipeline
7 days ago 2ad0d6c34a5034fb13f2c5ef6ca9f06b47e44a75
dev/project-dev/bili_authenticated_extension/install_native_host.ps1
@@ -22,7 +22,11 @@
    [Parameter(DontShow = $true)]
    [string]$TestRegistryRoot,
    [Parameter(DontShow = $true)]
    [ValidateSet('none', 'after-root', 'after-payload', 'after-config', 'after-manifest', 'after-registry-key', 'after-registry-value')]
    [string]$TestPreviousInstallRoot,
    [Parameter(DontShow = $true)]
    [string]$TestPreviousArtifactReceipt,
    [Parameter(DontShow = $true)]
    [ValidateSet('none', 'after-root', 'after-payload', 'after-config', 'after-manifest', 'after-registry-key', 'after-registry-value', 'after-registry-value-mixed')]
    [string]$InjectFailure = 'none'
)
@@ -31,9 +35,17 @@
$expectedOrigin = 'chrome-extension://oidmclckpdmpabbfedplkbdplmfcenbb/'
$expectedHostName = 'com.project_info.bili_auth_ingress'
$expectedPublicDerHash = 'E83C2B2AF3CF011543FBA13FBC524D1122EEA68548F9F27B9F7A82B5D594666C'
$expectedExtensionBuild = 'project-info-bili-auth-ingress/1.0.0+20260805.v002'
$expectedHostBuild = 'project-info-bili-auth-native-host/1.0.0+20260805.v002'
$expectedExtensionBuild = 'project-info-bili-auth-ingress/1.2.25+20260829.generic.v027'
$expectedHostBuild = 'project-info-bili-auth-native-host/1.2.25+20260829.generic.v027'
$expectedHostExecutable = 'project-info-bili-auth-native-host.exe'
$expectedPreviousExtensionBuild = 'project-info-bili-auth-ingress/1.2.24+20260829.generic.v026'
$expectedPreviousVersion = '1.2.24+20260829.generic.v026'
$expectedPreviousManifestBytes = 381
$expectedPreviousManifestSha256 = '9FFAC5073A5839F030ED321840C5715ECBE2CC7276DD057A7236B3CF78AA5C38'
$expectedPreviousHostBytes = 21452778
$expectedPreviousHostSha256 = '24E0C15B9E8269F55F25E55A0614DD96BEF58CB0F7EE069C41F86AF95CD19762'
$expectedPreviousConfigBytes = 1870
$expectedPreviousConfigSha256 = 'ACA285C700CD970A846A824BD32E6826195B0204640F8445C288C7476EC475E3'
$publicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt2dT1HGYaI0DXM7zZwOTNBWXTKlMBJMpyDVjRUc+v6bUotmLyoraC+ay2scy9UQluSZVYq0tS8qvQNNvuZOlc5w2bOExm4TH2IIKvaVO8nVthHBnNz2kXdiM8ItN0vPZEmS+8gpTCI1+6wPTuUglMoXpqYBYhii8fJ5RkENRF3PRJBBigGt8soqdBFRY1QZUmpQv9dYw4dRq4L2C4QtBgClUg4bQpuCppiVZ9LHbePi9IAjc9r9R93KLzpaBuXdJpfVRE5w/6YHnxP8ovXxBdl7XktmrdH3xj7mWT7Q7ZBxkDNwn2RkruD45XgDD3yuNxOYSkLFMkseN+Ua69gSS4wIDAQAB'
function Stop-Injected([string]$Point) {
@@ -86,6 +98,26 @@
    }
}
function Assert-ExactSourceSnapshot([string]$Root, [string]$ManifestPath, [string[]]$ExpectedFiles, [object]$Manifest) {
    Assert-ExactSourceTree $Root $ManifestPath $ExpectedFiles
    foreach ($entry in $Manifest.files) {
        if ($entry.path -notmatch '^[A-Za-z0-9._/-]+$' -or $entry.path.Contains('..') -or
            $entry.sha256 -notmatch '^[A-F0-9]{64}$' -or $entry.bytes -lt 1) {
            throw 'Source artifact manifest contains an invalid entry.'
        }
        $candidate = [System.IO.Path]::GetFullPath((Join-Path $Root $entry.path))
        if (-not $candidate.StartsWith($Root + [System.IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) {
            throw 'Source artifact path escaped its root.'
        }
        $item = Get-Item -LiteralPath $candidate
        if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
            $item.Length -ne $entry.bytes -or
            (Get-FileHash -Algorithm SHA256 -LiteralPath $candidate).Hash -cne $entry.sha256) {
            throw 'Source artifact hash mismatch.'
        }
    }
}
function Copy-CreateNew([string]$Source, [string]$Destination) {
    $input = [System.IO.File]::Open($Source, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::Read)
    try {
@@ -110,6 +142,339 @@
    } finally {
        $stream.Dispose()
    }
}
function Get-FileIdentity([string]$Path) {
    $item = Get-Item -LiteralPath $Path -Force
    if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'Expected a regular non-reparse file.'
    }
    return [pscustomobject]@{
        Bytes = $item.Length
        Sha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash
    }
}
function ConvertTo-StrictPositiveInt64 {
    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$Value,
        [Parameter(Mandatory = $true)]
        [ValidateSet(
            'previous native host manifest bytes',
            'previous Host executable bytes',
            'previous config bytes'
        )]
        [string]$IdentityName
    )
    $isIntegralScalar =
        $Value -is [byte] -or $Value -is [sbyte] -or
        $Value -is [int16] -or $Value -is [uint16] -or
        $Value -is [int32] -or $Value -is [uint32] -or
        $Value -is [int64]
    if (-not $isIntegralScalar -or [long]$Value -lt 1) {
        throw "Pinned $IdentityName must be a positive integer scalar."
    }
    return [long]$Value
}
function ConvertTo-StrictSha256 {
    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$Value,
        [Parameter(Mandatory = $true)]
        [ValidateSet(
            'previous native host manifest SHA-256',
            'previous Host executable SHA-256',
            'previous config SHA-256'
        )]
        [string]$IdentityName
    )
    if ($Value -isnot [string] -or $Value -cnotmatch '^[A-F0-9]{64}$') {
        throw "Pinned $IdentityName must be an uppercase 64-character hexadecimal string."
    }
    return [string]$Value
}
function Assert-ExactPreviousInstall {
    [CmdletBinding(PositionalBinding = $false)]
    param(
        [Parameter(Mandatory = $true)]
        [string]$PreviousRoot,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$ManifestBytes,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$ManifestSha256,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$HostBytes,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$HostSha256,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$ConfigBytes,
        [Parameter(Mandatory = $true)]
        [AllowNull()]
        [object]$ConfigSha256
    )
    $pinnedManifestBytes = ConvertTo-StrictPositiveInt64 -Value $ManifestBytes -IdentityName 'previous native host manifest bytes'
    $pinnedManifestSha256 = ConvertTo-StrictSha256 -Value $ManifestSha256 -IdentityName 'previous native host manifest SHA-256'
    $pinnedHostBytes = ConvertTo-StrictPositiveInt64 -Value $HostBytes -IdentityName 'previous Host executable bytes'
    $pinnedHostSha256 = ConvertTo-StrictSha256 -Value $HostSha256 -IdentityName 'previous Host executable SHA-256'
    $pinnedConfigBytes = ConvertTo-StrictPositiveInt64 -Value $ConfigBytes -IdentityName 'previous config bytes'
    $pinnedConfigSha256 = ConvertTo-StrictSha256 -Value $ConfigSha256 -IdentityName 'previous config SHA-256'
    $rootItem = Get-Item -LiteralPath $PreviousRoot -Force
    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'Previous install root must be an ordinary non-reparse directory.'
    }
    $children = @(Get-ChildItem -LiteralPath $PreviousRoot -Force)
    if ($children.Count -ne 3 -or @($children | Where-Object { $_.PSIsContainer }).Count -ne 0 -or
        (Compare-Object -CaseSensitive @('config.json', 'native-host-manifest.json', $expectedHostExecutable) @($children.Name | Sort-Object))) {
        throw 'Previous install root does not contain the exact three-file preimage.'
    }
    foreach ($child in $children) {
        if ($child.Attributes -band [IO.FileAttributes]::ReparsePoint) {
            throw 'Previous install contains a reparse path.'
        }
    }
    $manifestPath = Join-Path $PreviousRoot 'native-host-manifest.json'
    $hostPath = Join-Path $PreviousRoot $expectedHostExecutable
    $configPath = Join-Path $PreviousRoot 'config.json'
    $manifestIdentity = Get-FileIdentity $manifestPath
    $hostIdentity = Get-FileIdentity $hostPath
    $configIdentity = Get-FileIdentity $configPath
    if ($manifestIdentity.Bytes -ne $pinnedManifestBytes) {
        throw 'Previous native host manifest bytes mismatch.'
    }
    if ($manifestIdentity.Sha256 -cne $pinnedManifestSha256) {
        throw 'Previous native host manifest SHA-256 mismatch.'
    }
    if ($hostIdentity.Bytes -ne $pinnedHostBytes) {
        throw 'Previous Host executable bytes mismatch.'
    }
    if ($hostIdentity.Sha256 -cne $pinnedHostSha256) {
        throw 'Previous Host executable SHA-256 mismatch.'
    }
    if ($configIdentity.Bytes -ne $pinnedConfigBytes) {
        throw 'Previous config bytes mismatch.'
    }
    if ($configIdentity.Sha256 -cne $pinnedConfigSha256) {
        throw 'Previous config SHA-256 mismatch.'
    }
    $previousManifest = Get-StrictJson $manifestPath
    if ((Compare-Object @('allowed_origins', 'description', 'name', 'path', 'type') @($previousManifest.PSObject.Properties.Name | Sort-Object)) -or
        $previousManifest.name -cne $expectedHostName -or
        $previousManifest.path -cne $hostPath -or
        $previousManifest.type -cne 'stdio' -or
        @($previousManifest.allowed_origins).Count -ne 1 -or
        $previousManifest.allowed_origins[0] -cne $expectedOrigin) {
        throw 'Previous native host manifest identity mismatch.'
    }
    $previousConfig = Get-StrictJson $configPath
    if ($previousConfig.schema -ne 2 -or
        $previousConfig.required_extension_build -cne $expectedPreviousExtensionBuild -or
        @($previousConfig.creator_allowlist).Count -ne 1 -or
        $previousConfig.creator_allowlist[0] -cne '1420210197') {
        throw 'Previous host config identity mismatch.'
    }
    return [pscustomobject]@{
        Root = $PreviousRoot
        ManifestPath = $manifestPath
        HostPath = $hostPath
        ConfigPath = $configPath
    }
}
function Get-RegistrySnapshot([string]$Path, [bool]$UseFileProvider) {
    if (-not (Test-Path -LiteralPath $Path)) {
        return [pscustomobject]@{
            Exists = $false
            ValueNames = @()
            SubKeyNames = @()
            DefaultKind = $null
            DefaultValue = $null
        }
    }
    if ($UseFileProvider) {
        $item = Get-Item -LiteralPath $Path -Force
        if (-not $item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
            throw 'Test registry key must be an ordinary non-reparse directory.'
        }
        $children = @(Get-ChildItem -LiteralPath $Path -Force)
        if (@($children | Where-Object { $_.Attributes -band [IO.FileAttributes]::ReparsePoint }).Count -ne 0) {
            throw 'Test registry contains a reparse path.'
        }
        $files = @($children | Where-Object { -not $_.PSIsContainer })
        $subkeys = @($children | Where-Object { $_.PSIsContainer } | ForEach-Object { $_.Name })
        $valueNames = @($files | ForEach-Object { if ($_.Name -ceq 'default.value') { '' } else { $_.Name } })
        $defaultPath = Join-Path $Path 'default.value'
        $defaultValue = $null
        $defaultKind = $null
        if (Test-Path -LiteralPath $defaultPath) {
            $defaultValue = [System.IO.File]::ReadAllText($defaultPath, [System.Text.UTF8Encoding]::new($false, $true))
            $defaultKind = 'String'
        }
        return [pscustomobject]@{
            Exists = $true
            ValueNames = $valueNames
            SubKeyNames = $subkeys
            DefaultKind = $defaultKind
            DefaultValue = $defaultValue
        }
    }
    $key = Get-Item -LiteralPath $Path -Force
    $valueNames = @($key.GetValueNames())
    $subKeyNames = @($key.GetSubKeyNames())
    $defaultValue = $null
    $defaultKind = $null
    if ($valueNames -contains '') {
        $defaultValue = $key.GetValue('', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
        $defaultKind = $key.GetValueKind('').ToString()
    }
    return [pscustomobject]@{
        Exists = $true
        ValueNames = $valueNames
        SubKeyNames = $subKeyNames
        DefaultKind = $defaultKind
        DefaultValue = $defaultValue
    }
}
function Test-RegistrySnapshotExact([object]$Snapshot, [string]$ExpectedDefault) {
    return $Snapshot.Exists -and
        @($Snapshot.ValueNames).Count -eq 1 -and $Snapshot.ValueNames[0] -ceq '' -and
        @($Snapshot.SubKeyNames).Count -eq 0 -and
        $Snapshot.DefaultKind -ceq 'String' -and
        $Snapshot.DefaultValue -ceq $ExpectedDefault
}
function Test-RegistrySnapshotEmpty([object]$Snapshot) {
    return $Snapshot.Exists -and @($Snapshot.ValueNames).Count -eq 0 -and @($Snapshot.SubKeyNames).Count -eq 0
}
function Set-RegistryDefaultAtomic([string]$Path, [string]$Value, [bool]$UseFileProvider) {
    if ($UseFileProvider) {
        $defaultPath = Join-Path $Path 'default.value'
        if (-not (Test-Path -LiteralPath $defaultPath)) {
            Write-Utf8CreateNew $defaultPath $Value
            return
        }
        $pending = Join-Path $Path ('.default.pending.' + [Guid]::NewGuid().ToString('N'))
        $backup = Join-Path $Path ('.default.backup.' + [Guid]::NewGuid().ToString('N'))
        try {
            Write-Utf8CreateNew $pending $Value
            [System.IO.File]::Replace($pending, $defaultPath, $backup, $true)
        } finally {
            if (Test-Path -LiteralPath $pending) {
                Remove-Item -LiteralPath $pending -Force
            }
            if (Test-Path -LiteralPath $backup) {
                Remove-Item -LiteralPath $backup -Force
            }
        }
        return
    }
    Set-Item -LiteralPath $Path -Value $Value -ErrorAction Stop
}
function Assert-NewInstallRoot(
    [string]$InstallRootPath,
    [string]$InstalledHostPath,
    [string]$InstalledConfigPath,
    [string]$InstalledManifestPath,
    [object]$ExpectedBuildEntry,
    [object]$ExpectedConfigIdentity
) {
    $rootItem = Get-Item -LiteralPath $InstallRootPath -Force
    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'Installed root must be an ordinary non-reparse directory.'
    }
    $children = @(Get-ChildItem -LiteralPath $InstallRootPath -Force)
    if ($children.Count -ne 3 -or @($children | Where-Object { $_.PSIsContainer }).Count -ne 0 -or
        (Compare-Object -CaseSensitive @('config.json', 'native-host-manifest.json', $expectedHostExecutable) @($children.Name | Sort-Object))) {
        throw 'Installed root does not contain the exact three-file set.'
    }
    foreach ($child in $children) {
        if ($child.Attributes -band [IO.FileAttributes]::ReparsePoint) {
            throw 'Installed root contains a reparse path.'
        }
    }
    $hostIdentity = Get-FileIdentity $InstalledHostPath
    $configIdentity = Get-FileIdentity $InstalledConfigPath
    if ($hostIdentity.Bytes -ne $ExpectedBuildEntry.bytes -or $hostIdentity.Sha256 -cne $ExpectedBuildEntry.sha256 -or
        $configIdentity.Bytes -ne $ExpectedConfigIdentity.Bytes -or $configIdentity.Sha256 -cne $ExpectedConfigIdentity.Sha256) {
        throw 'Installed payload identity mismatch.'
    }
    $persistedManifest = Get-StrictJson $InstalledManifestPath
    if ((Compare-Object @('allowed_origins', 'description', 'name', 'path', 'type') @($persistedManifest.PSObject.Properties.Name | Sort-Object)) -or
        $persistedManifest.name -cne $expectedHostName -or
        $persistedManifest.path -cne $InstalledHostPath -or
        $persistedManifest.type -cne 'stdio' -or
        @($persistedManifest.allowed_origins).Count -ne 1 -or
        $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
        throw 'Installed native host manifest identity mismatch.'
    }
}
function Remove-ProvenOwnedInstallRoot(
    [string]$InstallRootPath,
    [string]$InstalledHostPath,
    [string]$InstalledConfigPath,
    [string]$InstalledManifestPath,
    [object]$ExpectedBuildEntry,
    [object]$ExpectedConfigIdentity
) {
    if (-not (Test-Path -LiteralPath $InstallRootPath)) {
        return
    }
    $rootItem = Get-Item -LiteralPath $InstallRootPath -Force
    if (-not $rootItem.PSIsContainer -or ($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'RECOVERY_REQUIRED: target root is not a proven owned ordinary directory.'
    }
    $children = @(Get-ChildItem -LiteralPath $InstallRootPath -Force)
    if (@($children | Where-Object { $_.PSIsContainer -or ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) }).Count -ne 0 -or
        @($children | Where-Object { $_.Name -cnotin @('config.json', 'native-host-manifest.json', $expectedHostExecutable) }).Count -ne 0) {
        throw 'RECOVERY_REQUIRED: target root contains an unknown or reparse object.'
    }
    if (Test-Path -LiteralPath $InstalledHostPath) {
        $identity = Get-FileIdentity $InstalledHostPath
        if ($identity.Bytes -ne $ExpectedBuildEntry.bytes -or $identity.Sha256 -cne $ExpectedBuildEntry.sha256) {
            throw 'RECOVERY_REQUIRED: target host identity is ambiguous.'
        }
    }
    if (Test-Path -LiteralPath $InstalledConfigPath) {
        $identity = Get-FileIdentity $InstalledConfigPath
        if ($identity.Bytes -ne $ExpectedConfigIdentity.Bytes -or $identity.Sha256 -cne $ExpectedConfigIdentity.Sha256) {
            throw 'RECOVERY_REQUIRED: target config identity is ambiguous.'
        }
    }
    if (Test-Path -LiteralPath $InstalledManifestPath) {
        $persistedManifest = Get-StrictJson $InstalledManifestPath
        if ($persistedManifest.name -cne $expectedHostName -or
            $persistedManifest.path -cne $InstalledHostPath -or
            $persistedManifest.type -cne 'stdio' -or
            @($persistedManifest.allowed_origins).Count -ne 1 -or
            $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
            throw 'RECOVERY_REQUIRED: target manifest identity is ambiguous.'
        }
    }
    Remove-Item -LiteralPath $InstallRootPath -Recurse -Force
}
if ($ObservedExtensionId -cne $expectedId) {
@@ -195,14 +560,15 @@
    '__init__.py', 'background.js', 'build_host.ps1', 'config.example.json',
    'constants.py', 'dependencies/dependency-artifact-manifest.json',
    'dependencies/yt_dlp-2026.7.4-py3-none-any.whl',
    'install_native_host.ps1', 'job.py', 'manifest.json',
    'formal_legacy_identity_manifest.py', 'install_native_host.ps1', 'job.py', 'manifest.json',
    'native-host-manifest.template.json', 'native_host.py', 'protocol.py',
    'queue-producer.example.json', 'queue_producer.py', 'queue_state.py',
    'sidepanel.css', 'sidepanel.html', 'sidepanel.js', 'worker.py'
)
Assert-ExactSourceTree $sourceRoot $sourceManifestPath $expectedSourceFiles
Assert-ExactSourceSnapshot $sourceRoot $sourceManifestPath $expectedSourceFiles $sourceManifest
$dependencyManifestPath = Join-Path $sourceRoot 'dependencies/dependency-artifact-manifest.json'
$dependencyManifestItem = Get-Item -LiteralPath $dependencyManifestPath
if ($sourceManifest.schema -ne 1 -or $sourceManifest.target -cne 'BV1HA3o6oEJJ' -or
if ($sourceManifest.schema -ne 1 -or $sourceManifest.scope -cne 'generic-bilibili-queue' -or
    $sourceManifest.extension_id -cne $expectedId -or
    $sourceManifest.extension_build -cne $expectedExtensionBuild -or
    $sourceManifest.host_build -cne $expectedHostBuild -or
@@ -253,7 +619,7 @@
$buildManifest = Get-StrictJson $buildManifestPath
$buildScript = Join-Path $sourceRoot 'build_host.ps1'
if ($buildManifest.schema -ne 2 -or $buildManifest.target -cne 'BV1HA3o6oEJJ' -or
if ($buildManifest.schema -ne 2 -or $buildManifest.scope -cne 'generic-bilibili-queue' -or
    $buildManifest.extension_id -cne $expectedId -or
    $buildManifest.extension_build -cne $expectedExtensionBuild -or
    $buildManifest.host_build -cne $expectedHostBuild -or
@@ -315,21 +681,26 @@
if (($configItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -or $configItem.PSIsContainer) {
    throw 'Config file must be a regular non-reparse file.'
}
$configIdentity = Get-FileIdentity $config
$configObject = Get-StrictJson $config
$expectedConfigKeys = @(
    'schema', 'target', 'canonical_url', 'ffmpeg', 'ffmpeg_sha256', 'ffprobe',
    'ffprobe_sha256', 'bridge_python', 'bridge_python_sha256', 'bridge_script',
    'bridge_script_sha256', 'batch_json', 'batch_json_sha256', 'yt_dlp_executable',
    'yt_dlp_executable_sha256', 'destination'
    'schema', 'creator_allowlist', 'queue_path', 'queue_state_path', 'queue_lock_path',
    'reload_state_path', 'reload_generation', 'required_extension_build',
    'ffmpeg', 'ffmpeg_sha256', 'ffprobe', 'ffprobe_sha256', 'bridge_python',
    'bridge_python_sha256', 'bridge_script', 'bridge_script_sha256',
    'yt_dlp_executable', 'yt_dlp_executable_sha256', 'destination',
    'creator_name', 'formal_manifest_path', 'processing_handoff_path'
)
$actualConfigKeys = @($configObject.PSObject.Properties.Name | Sort-Object)
if ((Compare-Object ($expectedConfigKeys | Sort-Object) $actualConfigKeys) -or
    $configObject.schema -ne 1 -or $configObject.target -cne 'BV1HA3o6oEJJ' -or
    $configObject.canonical_url -cne 'https://www.bilibili.com/video/BV1HA3o6oEJJ' -or
    $configObject.bridge_script_sha256 -cne '749FC486B0F42315BD463F11771FE2A7C71CAB53DD9AC2E411CE82E1175DFF13') {
    $configObject.schema -ne 2 -or
    $configObject.required_extension_build -cne $expectedExtensionBuild -or
    $null -eq $configObject.creator_allowlist -or @($configObject.creator_allowlist).Count -lt 1 -or
    $configObject.reload_generation -cne 'bili-auth-generic-v027' -or
    $configObject.bridge_script_sha256 -cne '00F11DAF8387160DB863C89F0B33AB8480422233FF42199189222C989C7ED07E') {
    throw 'Host config identity mismatch.'
}
foreach ($name in @('ffmpeg', 'ffprobe', 'bridge_python', 'bridge_script', 'batch_json', 'yt_dlp_executable')) {
foreach ($name in @('ffmpeg', 'ffprobe', 'bridge_python', 'bridge_script', 'yt_dlp_executable')) {
    $value = $configObject.$name
    $expectedHash = $configObject."${name}_sha256"
    if (-not [System.IO.Path]::IsPathRooted($value) -or $value.StartsWith('\\') -or
@@ -351,30 +722,100 @@
if (-not $destinationItem.PSIsContainer -or ($destinationItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
    throw 'Host config destination must be an existing non-reparse directory.'
}
if (Get-ChildItem -LiteralPath $resolvedDestination -File | Where-Object { $_.Name.StartsWith('BV1HA3o6oEJJ.', [StringComparison]::OrdinalIgnoreCase) }) {
    throw 'Formal output already exists; overwrite is forbidden.'
if ([string]::IsNullOrWhiteSpace([string]$configObject.creator_name) -or
    [Text.Encoding]::UTF8.GetByteCount([string]$configObject.creator_name) -gt 240) {
    throw 'Host config creator_name is invalid.'
}
foreach ($name in @('formal_manifest_path', 'processing_handoff_path')) {
    $value = [string]$configObject.$name
    if (-not [System.IO.Path]::IsPathRooted($value) -or $value.StartsWith('\\')) {
        throw 'Host governed output path must be absolute and local.'
    }
    $parent = [System.IO.Path]::GetDirectoryName($value)
    $parentItem = Get-Item -LiteralPath $parent
    if (-not $parentItem.PSIsContainer -or ($parentItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'Host governed output parent must be an ordinary directory.'
    }
    if (Test-Path -LiteralPath $value) {
        $item = Get-Item -LiteralPath $value
        if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
            throw 'Host governed output must be an ordinary file.'
        }
    } elseif ($name -ceq 'formal_manifest_path') {
        throw 'Host formal manifest must already exist.'
    }
}
if ($configObject.formal_manifest_path -ceq $configObject.processing_handoff_path) {
    throw 'Host governed output paths must be distinct.'
}
if (Test-Path -LiteralPath $root) {
    throw 'InstallRoot already exists; overwrite is forbidden.'
}
$registryPath = "HKCU:\Software\Google\Chrome\NativeMessagingHosts\$expectedHostName"
$previousRoot = [System.IO.Path]::GetFullPath((Join-Path $env:LOCALAPPDATA "project-info\bili-auth-native-host\$expectedPreviousVersion"))
if ($TestFileRegistryProvider) {
    if (-not $TestRegistryRoot) {
        throw 'TestRegistryRoot is required for the test file registry provider.'
    if (-not $TestRegistryRoot -or -not $TestPreviousInstallRoot -or -not $TestPreviousArtifactReceipt) {
        throw 'The test file registry provider requires its registry root and previous-install fixture inputs.'
    }
    $testRegistryBase = [System.IO.Path]::GetFullPath($TestRegistryRoot)
    $tempBase = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath())
    if (-not $testRegistryBase.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase)) {
        throw 'The test registry provider must be under the current temporary directory.'
    $previousRoot = [System.IO.Path]::GetFullPath($TestPreviousInstallRoot)
    $previousReceiptPath = (Resolve-Path -LiteralPath $TestPreviousArtifactReceipt).Path
    if (-not $testRegistryBase.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
        -not $previousRoot.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
        -not $previousReceiptPath.StartsWith($tempBase, [StringComparison]::OrdinalIgnoreCase) -or
        ($root -notlike ($tempBase.TrimEnd('\') + '\*'))) {
        throw 'Test-only installer paths must be under the current temporary directory.'
    }
    $previousReceiptItem = Get-Item -LiteralPath $previousReceiptPath -Force
    if ($previousReceiptItem.PSIsContainer -or ($previousReceiptItem.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
        throw 'Test previous-artifact receipt must be a regular non-reparse file.'
    }
    $previousReceipt = Get-StrictJson $previousReceiptPath
    $expectedPreviousReceiptKeys = @(
        'schema', 'manifest_bytes', 'manifest_sha256', 'host_executable_bytes',
        'host_executable_sha256', 'config_bytes', 'config_sha256'
    )
    if ((Compare-Object ($expectedPreviousReceiptKeys | Sort-Object) @($previousReceipt.PSObject.Properties.Name | Sort-Object)) -or
        $previousReceipt.schema -ne 1) {
        throw 'Test previous-artifact receipt identity mismatch.'
    }
    $expectedPreviousManifestBytes = $previousReceipt.manifest_bytes
    $expectedPreviousManifestSha256 = $previousReceipt.manifest_sha256
    $expectedPreviousHostBytes = $previousReceipt.host_executable_bytes
    $expectedPreviousHostSha256 = $previousReceipt.host_executable_sha256
    $expectedPreviousConfigBytes = $previousReceipt.config_bytes
    $expectedPreviousConfigSha256 = $previousReceipt.config_sha256
    $registryPath = Join-Path $testRegistryBase $expectedHostName
} elseif ($TestRegistryRoot -or $InjectFailure -cne 'none') {
} elseif ($TestRegistryRoot -or $TestPreviousInstallRoot -or $TestPreviousArtifactReceipt -or $InjectFailure -cne 'none') {
    throw 'Test-only controls require TestFileRegistryProvider.'
} else {
    $expectedInstallRoot = [System.IO.Path]::GetFullPath((Join-Path $env:LOCALAPPDATA 'project-info\bili-auth-native-host\1.2.25+20260829.generic.v027'))
    if ($root -cne $expectedInstallRoot) {
        throw 'Production InstallRoot does not match the pinned v027 location.'
    }
}
if (Test-Path -LiteralPath $registryPath) {
    throw 'Native Messaging registration already exists; overwrite is forbidden.'
$previousIdentityParameters = @{
    PreviousRoot = $previousRoot
    ManifestBytes = $expectedPreviousManifestBytes
    ManifestSha256 = $expectedPreviousManifestSha256
    HostBytes = $expectedPreviousHostBytes
    HostSha256 = $expectedPreviousHostSha256
    ConfigBytes = $expectedPreviousConfigBytes
    ConfigSha256 = $expectedPreviousConfigSha256
}
$registryPreimage = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
if (-not $registryPreimage.Exists) {
    throw 'Exact v026 Native Messaging registration preimage is required.'
}
$previousInstall = Assert-ExactPreviousInstall @previousIdentityParameters
if (-not (Test-RegistrySnapshotExact $registryPreimage $previousInstall.ManifestPath)) {
    throw 'Existing Native Messaging registration does not match the pinned v026 preimage.'
}
$installMode = 'EXACT_V026_TO_V027_SWITCH'
if (-not $Install) {
    [pscustomobject]@{
@@ -383,16 +824,18 @@
        origin = $expectedOrigin
        host_name = $expectedHostName
        packaging = 'pyinstaller-onefile'
        install_mode = $installMode
    } | ConvertTo-Json -Compress
    return
}
if ($PSCmdlet.ShouldProcess($root, 'Install exact-BVID Native Messaging host for current user')) {
    $installedHost = Join-Path $root $expectedHostExecutable
    $installedConfig = Join-Path $root 'config.json'
    $manifestPath = Join-Path $root 'native-host-manifest.json'
    try {
        [System.IO.Directory]::CreateDirectory($root) | Out-Null
        Stop-Injected 'after-root'
        $installedHost = Join-Path $root $expectedHostExecutable
        $installedConfig = Join-Path $root 'config.json'
        Copy-CreateNew $resolvedHost $installedHost
        if ((Get-Item -LiteralPath $installedHost).Length -ne $buildEntry.bytes -or
            (Get-FileHash -Algorithm SHA256 -LiteralPath $installedHost).Hash -cne $buildEntry.sha256) {
@@ -405,7 +848,6 @@
            throw 'Installed config reread verification failed.'
        }
        Stop-Injected 'after-config'
        $manifestPath = Join-Path $root 'native-host-manifest.json'
        $manifest = [ordered]@{
            name = $expectedHostName
            description = 'project-info exact-BVID authenticated ingress'
@@ -414,38 +856,44 @@
            allowed_origins = @($expectedOrigin)
        }
        Write-Utf8CreateNew $manifestPath ($manifest | ConvertTo-Json -Depth 3)
        $persistedManifest = Get-StrictJson $manifestPath
        if ($persistedManifest.name -cne $expectedHostName -or
            $persistedManifest.path -cne $installedHost -or
            $persistedManifest.type -cne 'stdio' -or
            $persistedManifest.allowed_origins.Count -ne 1 -or
            $persistedManifest.allowed_origins[0] -cne $expectedOrigin) {
            throw 'Native host manifest reread verification failed.'
        }
        Assert-NewInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
        Stop-Injected 'after-manifest'
        if ($TestFileRegistryProvider) {
            [System.IO.Directory]::CreateDirectory($registryPath) | Out-Null
        } else {
            New-Item -Path $registryPath -ErrorAction Stop | Out-Null
        $lastRegistryPreimage = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
        $null = Assert-ExactPreviousInstall @previousIdentityParameters
        if (-not (Test-RegistrySnapshotExact $lastRegistryPreimage $previousInstall.ManifestPath)) {
            throw 'Native Messaging v026 preimage changed before the registry switch.'
        }
        Stop-Injected 'after-registry-key'
        if ($TestFileRegistryProvider) {
            Write-Utf8CreateNew (Join-Path $registryPath 'default.value') $manifestPath
        } else {
            Set-Item -LiteralPath $registryPath -Value $manifestPath -ErrorAction Stop
        Set-RegistryDefaultAtomic $registryPath $manifestPath $TestFileRegistryProvider.IsPresent
        if ($InjectFailure -ceq 'after-registry-value-mixed') {
            Write-Utf8CreateNew (Join-Path $registryPath 'unexpected.value') 'ambiguous'
                throw 'Injected ambiguous registry state after v026 switch.'
        }
        Stop-Injected 'after-registry-value'
        $committedRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
        if (-not (Test-RegistrySnapshotExact $committedRegistry $manifestPath)) {
            throw 'Native Messaging v026 registry commit reread verification failed.'
        }
        Assert-NewInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
    } catch {
        # Both targets were proven absent before the transaction, so any
        # surviving object belongs to this attempt even if a provider threw
        # after partially creating it.
        if (Test-Path -LiteralPath $registryPath) {
            Remove-Item -LiteralPath $registryPath -Recurse -Force
        $originalFailure = $_.Exception
        try {
            $rollbackRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
            if (Test-RegistrySnapshotExact $rollbackRegistry $manifestPath) {
                Set-RegistryDefaultAtomic $registryPath $previousInstall.ManifestPath $TestFileRegistryProvider.IsPresent
            } elseif (-not (Test-RegistrySnapshotExact $rollbackRegistry $previousInstall.ManifestPath)) {
                throw 'RECOVERY_REQUIRED: Native Messaging registration is neither the pinned v026 preimage nor this v027 attempt.'
            }
            $restoredRegistry = Get-RegistrySnapshot $registryPath $TestFileRegistryProvider.IsPresent
            if (-not (Test-RegistrySnapshotExact $restoredRegistry $previousInstall.ManifestPath)) {
                throw 'RECOVERY_REQUIRED: Native Messaging v026 registry preimage was not restored.'
            }
            $null = Assert-ExactPreviousInstall @previousIdentityParameters
            Remove-ProvenOwnedInstallRoot $root $installedHost $installedConfig $manifestPath $buildEntry $configIdentity
        } catch {
            throw "RECOVERY_REQUIRED: $($_.Exception.Message) Original failure: $($originalFailure.Message)"
        }
        if (Test-Path -LiteralPath $root) {
            Remove-Item -LiteralPath $root -Recurse -Force
        }
        throw
        throw $originalFailure
    }
}