[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$taskRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$sourcePath = Join-Path $taskRoot 'Tools/PackageCSharp.ps1'
$collectedManifest = Join-Path $taskRoot 'Tools/CSharpBoot/Licenses/Collected/Manifest.json'
$collectedBefore = (Get-FileHash -LiteralPath $collectedManifest -Algorithm SHA256).Hash.ToLowerInvariant()
$tokens = $null; $parseErrors = $null
$ast = [Management.Automation.Language.Parser]::ParseFile($sourcePath,[ref]$tokens,[ref]$parseErrors)
if ($parseErrors.Count) { throw 'Package script did not parse.' }
$output = Join-Path $taskRoot ('build/CSharp/PackageWebsiteAssets-' + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())
$package = Join-Path $output 'FixturePackage'
[void][IO.Directory]::CreateDirectory($package)
foreach ($function in $ast.FindAll({param($node) $node -is [Management.Automation.Language.FunctionDefinitionAst]},$false)) { . ([scriptblock]::Create($function.Extent.Text)) }
$statements = @($ast.EndBlock.Statements)
$validating = $false
foreach ($statement in $statements) {
if ($statement.Extent.Text.StartsWith('$websiteCode =')) { $validating = $true }
if ($statement.Extent.Text.StartsWith('$image =')) { break }
if ($validating) { . ([scriptblock]::Create($statement.Extent.Text)) }
}
foreach ($statement in $statements) {
if ($statement -is [Management.Automation.Language.IfStatementAst] -and
($statement.Extent.Text.Contains("'DocumentAssets/Website/Exact'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/Lato'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/WebCjk'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/BootstrapIcons'"))) {
. ([scriptblock]::Create($statement.Extent.Text))
}
}
# Exercise the real receipt-copy block with explicitly non-release fixtures.
# No disk image, successful boot receipt or release package is fabricated.
$receiptMap = [ordered]@{}
foreach ($name in @('ReferenceFixture','NativeFixture')) {
$directory = Join-Path $output $name
[void][IO.Directory]::CreateDirectory($directory)
[IO.File]::WriteAllText((Join-Path $directory 'Dark.png'),$name)
[IO.File]::WriteAllText((Join-Path $directory 'Serial.log'),$name + ' fixture only')
$receiptPath = Join-Path $directory 'Result.json'
[IO.File]::WriteAllText($receiptPath,'{"FixtureOnly":true}')
$receiptMap[$name] = [ordered]@{Path=$receiptPath;Sha256=(Get-FileHash -LiteralPath $receiptPath -Algorithm SHA256).Hash.ToLowerInvariant()}
}
$reportFile = Join-Path $output 'FixtureReport.json'
[IO.File]::WriteAllText($reportFile,'{"FixtureOnly":true}')
[IO.File]::WriteAllText([IO.Path]::ChangeExtension($reportFile,'.md'),'Packaging fixture only; no boot acceptance.')
$report = [pscustomobject]@{Receipts=[pscustomobject]$receiptMap;NativeBuildWarnings=[pscustomobject]@{BuildLogBound=$false}}
foreach ($directory in @('Validation','Validation/Receipts','Validation/DisplayGuest')) { [void][IO.Directory]::CreateDirectory((Join-Path $package $directory)) }
$receiptBlock = @($statements | Where-Object { $_ -is [Management.Automation.Language.IfStatementAst] -and $_.Extent.Text.Contains('$evidenceFiles = @()') })
if ($receiptBlock.Count -ne 1) { throw 'Receipt-copy block was not uniquely located.' }
. ([scriptblock]::Create($receiptBlock[0].Extent.Text))
foreach ($name in $receiptMap.Keys) {
if ([IO.File]::ReadAllText((Join-Path $package ('Validation/Evidence/' + $name + '/Dark.png'))) -ne $name) { throw 'Same-named evidence was overwritten.' }
}
foreach ($relative in @('BrowserAssets/WebsiteCode/Manifest.json','BrowserAssets/WebsiteCode/WebsiteLicense.txt','BrowserAssets/WebsiteCode/Highlight.License.txt','DocumentAssets/Website/Exact/SourceManifest.json','DocumentAssets/Website/ThirdPartyNotices.md','DocumentAssets/Website/Licenses/LicenseManifest.json','Licenses/Preview6Fonts/Lato/OFL.txt','Licenses/Preview6Fonts/Lato/Manifest.json','Licenses/Preview6Fonts/WebCjk/OFL.txt','Licenses/Preview6Fonts/WebCjk/Manifest.json','Licenses/Preview6Fonts/WebCjk/BuildWebCjkFont.py','Licenses/Preview6Fonts/BootstrapIcons/License.md','Licenses/Preview6Fonts/BootstrapIcons/Manifest.json','Licenses/Preview6Fonts/BootstrapIcons/BuildWebIconFont.py')) {
if (!(Test-Path -LiteralPath (Join-Path $package $relative) -PathType Leaf)) { throw ('Required asset missing: ' + $relative) }
}
$rejected = $false
try { Confirm-AssetFile $websiteCode '../Monaco/0.52.2/LICENSE' ('0' * 64) } catch { $rejected = $true }
if (!$rejected) { throw 'Asset traversal was accepted.' }
$bytes = [IO.File]::ReadAllBytes($sourcePath)
if ($bytes[0] -ne 239 -or $bytes[1] -ne 187 -or $bytes[2] -ne 191) { throw 'PowerShell 5 UTF-8 BOM was lost.' }
$collectedAfter = (Get-FileHash -LiteralPath $collectedManifest -Algorithm SHA256).Hash.ToLowerInvariant()
if ($collectedBefore -ne $collectedAfter) { throw 'Original collected license manifest changed.' }
$result = [ordered]@{Schema='XfePackageWebsiteAssetsTest1';Passed=$true;FixtureOnly=$true;PowerShellVersion=$PSVersionTable.PSVersion.ToString();AssetSourceHashesVerified=$true;ExactSourceBytesPreserved=$true;WebsiteAndFontLicensesIncluded=$true;SameNamedReferenceAndNativeEvidencePreserved=$true;AssetTraversalRejected=$rejected;NoReleasePackageCreated=$true;OriginalCollectedManifestChanged=$false;OriginalCollectedManifestSha256=$collectedAfter;Output=$output}
$result | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $output 'Result.json') -Encoding UTF8
$result | ConvertTo-Json -Depth 5
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$taskRoot = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$sourcePath = Join-Path $taskRoot 'Tools/PackageCSharp.ps1'
$collectedManifest = Join-Path $taskRoot 'Tools/CSharpBoot/Licenses/Collected/Manifest.json'
$collectedBefore = (Get-FileHash -LiteralPath $collectedManifest -Algorithm SHA256).Hash.ToLowerInvariant()
$tokens = $null; $parseErrors = $null
$ast = [Management.Automation.Language.Parser]::ParseFile($sourcePath,[ref]$tokens,[ref]$parseErrors)
if ($parseErrors.Count) { throw 'Package script did not parse.' }
$output = Join-Path $taskRoot ('build/CSharp/PackageWebsiteAssets-' + [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds())
$package = Join-Path $output 'FixturePackage'
[void][IO.Directory]::CreateDirectory($package)
foreach ($function in $ast.FindAll({param($node) $node -is [Management.Automation.Language.FunctionDefinitionAst]},$false)) { . ([scriptblock]::Create($function.Extent.Text)) }
$statements = @($ast.EndBlock.Statements)
$validating = $false
foreach ($statement in $statements) {
if ($statement.Extent.Text.StartsWith('$websiteCode =')) { $validating = $true }
if ($statement.Extent.Text.StartsWith('$image =')) { break }
if ($validating) { . ([scriptblock]::Create($statement.Extent.Text)) }
}
foreach ($statement in $statements) {
if ($statement -is [Management.Automation.Language.IfStatementAst] -and
($statement.Extent.Text.Contains("'DocumentAssets/Website/Exact'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/Lato'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/WebCjk'") -or $statement.Extent.Text.Contains("'Licenses/Preview6Fonts/BootstrapIcons'"))) {
. ([scriptblock]::Create($statement.Extent.Text))
}
}
# Exercise the real receipt-copy block with explicitly non-release fixtures.
# No disk image, successful boot receipt or release package is fabricated.
$receiptMap = [ordered]@{}
foreach ($name in @('ReferenceFixture','NativeFixture')) {
$directory = Join-Path $output $name
[void][IO.Directory]::CreateDirectory($directory)
[IO.File]::WriteAllText((Join-Path $directory 'Dark.png'),$name)
[IO.File]::WriteAllText((Join-Path $directory 'Serial.log'),$name + ' fixture only')
$receiptPath = Join-Path $directory 'Result.json'
[IO.File]::WriteAllText($receiptPath,'{"FixtureOnly":true}')
$receiptMap[$name] = [ordered]@{Path=$receiptPath;Sha256=(Get-FileHash -LiteralPath $receiptPath -Algorithm SHA256).Hash.ToLowerInvariant()}
}
$reportFile = Join-Path $output 'FixtureReport.json'
[IO.File]::WriteAllText($reportFile,'{"FixtureOnly":true}')
[IO.File]::WriteAllText([IO.Path]::ChangeExtension($reportFile,'.md'),'Packaging fixture only; no boot acceptance.')
$report = [pscustomobject]@{Receipts=[pscustomobject]$receiptMap;NativeBuildWarnings=[pscustomobject]@{BuildLogBound=$false}}
foreach ($directory in @('Validation','Validation/Receipts','Validation/DisplayGuest')) { [void][IO.Directory]::CreateDirectory((Join-Path $package $directory)) }
$receiptBlock = @($statements | Where-Object { $_ -is [Management.Automation.Language.IfStatementAst] -and $_.Extent.Text.Contains('$evidenceFiles = @()') })
if ($receiptBlock.Count -ne 1) { throw 'Receipt-copy block was not uniquely located.' }
. ([scriptblock]::Create($receiptBlock[0].Extent.Text))
foreach ($name in $receiptMap.Keys) {
if ([IO.File]::ReadAllText((Join-Path $package ('Validation/Evidence/' + $name + '/Dark.png'))) -ne $name) { throw 'Same-named evidence was overwritten.' }
}
foreach ($relative in @('BrowserAssets/WebsiteCode/Manifest.json','BrowserAssets/WebsiteCode/WebsiteLicense.txt','BrowserAssets/WebsiteCode/Highlight.License.txt','DocumentAssets/Website/Exact/SourceManifest.json','DocumentAssets/Website/ThirdPartyNotices.md','DocumentAssets/Website/Licenses/LicenseManifest.json','Licenses/Preview6Fonts/Lato/OFL.txt','Licenses/Preview6Fonts/Lato/Manifest.json','Licenses/Preview6Fonts/WebCjk/OFL.txt','Licenses/Preview6Fonts/WebCjk/Manifest.json','Licenses/Preview6Fonts/WebCjk/BuildWebCjkFont.py','Licenses/Preview6Fonts/BootstrapIcons/License.md','Licenses/Preview6Fonts/BootstrapIcons/Manifest.json','Licenses/Preview6Fonts/BootstrapIcons/BuildWebIconFont.py')) {
if (!(Test-Path -LiteralPath (Join-Path $package $relative) -PathType Leaf)) { throw ('Required asset missing: ' + $relative) }
}
$rejected = $false
try { Confirm-AssetFile $websiteCode '../Monaco/0.52.2/LICENSE' ('0' * 64) } catch { $rejected = $true }
if (!$rejected) { throw 'Asset traversal was accepted.' }
$bytes = [IO.File]::ReadAllBytes($sourcePath)
if ($bytes[0] -ne 239 -or $bytes[1] -ne 187 -or $bytes[2] -ne 191) { throw 'PowerShell 5 UTF-8 BOM was lost.' }
$collectedAfter = (Get-FileHash -LiteralPath $collectedManifest -Algorithm SHA256).Hash.ToLowerInvariant()
if ($collectedBefore -ne $collectedAfter) { throw 'Original collected license manifest changed.' }
$result = [ordered]@{Schema='XfePackageWebsiteAssetsTest1';Passed=$true;FixtureOnly=$true;PowerShellVersion=$PSVersionTable.PSVersion.ToString();AssetSourceHashesVerified=$true;ExactSourceBytesPreserved=$true;WebsiteAndFontLicensesIncluded=$true;SameNamedReferenceAndNativeEvidencePreserved=$true;AssetTraversalRejected=$rejected;NoReleasePackageCreated=$true;OriginalCollectedManifestChanged=$false;OriginalCollectedManifestSha256=$collectedAfter;Output=$output}
$result | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath (Join-Path $output 'Result.json') -Encoding UTF8
$result | ConvertTo-Json -Depth 5