#Requires -Version 5.1 # Standalone preflight contract checks; synthetic metadata, no Cargo/build/UI. $ErrorActionPreference = 'Stop' Set-StrictMode -Version Latest . (Join-Path $PSScriptRoot 'windows-notices.ps1') $fixture = Join-Path ([IO.Path]::GetTempPath()) ('arcadia-notices-' + [guid]::NewGuid().ToString('N')) [void][IO.Directory]::CreateDirectory($fixture) $utf8 = New-Object Text.UTF8Encoding($false) function Write-Fixture([string]$Relative, [string]$Text) { $path = Join-Path $fixture $Relative [void][IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($path)) [IO.File]::WriteAllText($path, $Text, $utf8) return $path } $null = Write-Fixture 'LICENSE' 'Synthetic workspace license for tests only' $null = Write-Fixture 'Cargo.toml' '[workspace]' $null = Write-Fixture 'docs/openapi.json' '{}' $null = Write-Fixture 'build/windows_manifest.rs' '// synthetic shared build input' $null = Write-Fixture 'rust/share/doc/rust/COPYRIGHT.html' 'Synthetic Rust distribution notice' $null = Write-Fixture 'rust/share/doc/rust/COPYRIGHT-library.html' 'Synthetic Rust library notice' $null = Write-Fixture 'rust/lib/fake.rlib' 'Synthetic target library' $packages = @(); $nodes = @(); $lock = @() foreach ($name in @('oa-desktop', 'oa-server', 'normal', 'build', 'dev-only', 'unreachable')) { $external = $name -notlike 'oa-*' $root = if ($external) { "registry/src/test/$name-1.0.0" } else { "workspace/$name" } $manifest = Write-Fixture "$root/Cargo.toml" "[package]`nname = `"$name`"`nversion = `"1.0.0`"" $null = Write-Fixture "$root/src/lib.rs" '// synthetic source' $null = Write-Fixture "$root/LICENSE" "Synthetic notice for $name" $source = if ($external) { 'registry+https://github.com/rust-lang/crates.io-index' } else { $null } $id = $name if ($external) { $archive = Write-Fixture "registry/cache/test/$name-1.0.0.crate" "Synthetic cached archive $name" $sha = (Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant() $lock += "[[package]]`nname = `"$name`"`nversion = `"1.0.0`"`nsource = `"$source`"`nchecksum = `"$sha`"`n" } $packages += [pscustomobject]@{ id = $id; name = $name; version = '1.0.0'; source = $source; license = 'MIT'; license_file = $null; manifest_path = $manifest; repository = 'https://example.invalid/test' } $deps = @() if ($name -eq 'oa-desktop') { foreach ($pair in @(@('normal', $null), @('build', 'build'), @('dev-only', 'dev'))) { $deps += [pscustomobject]@{ pkg = $pair[0]; dep_kinds = @([pscustomobject]@{ kind = $pair[1] }) } } } $nodes += [pscustomobject]@{ id = $id; deps = $deps; features = @() } } $null = Write-Fixture 'Cargo.lock' ($lock -join "`n") $script:FixtureMetadata = [pscustomobject]@{ packages = $packages; workspace_members = @('oa-desktop', 'oa-server'); resolve = [pscustomobject]@{ nodes = $nodes } } $script:FixtureTarget = 'x86_64-pc-windows-msvc' function cargo { if (($args -join ' ') -notmatch '--locked --offline' -or ($args -join ' ') -notmatch "--filter-platform $script:FixtureTarget") { throw 'Unexpected Cargo command' } $global:LASTEXITCODE = 0 $script:FixtureMetadata | ConvertTo-Json -Depth 12 } function rustc { $global:LASTEXITCODE = 0 if ($args[0] -eq '-Vv') { return 'rustc synthetic-test' } if ($args[1] -eq 'sysroot') { return (Join-Path $fixture 'rust') } if ($args[1] -eq 'target-libdir') { return (Join-Path $fixture 'rust/lib') } throw 'Unexpected Rust command' } $manifestPath = Write-Fixture 'supplements/manifest.json' '{"packages":[],"assets":[],"runtimes":[]}' function Collect { Get-WindowsNotices $fixture x86_64-pc-windows-msvc $manifestPath '' } function Assert([bool]$Condition, [string]$Message) { if (-not $Condition) { throw $Message } } function Refuses([string]$Pattern) { try { $null = Collect; throw 'Expected preflight refusal' } catch { if ($_.Exception.Message -notmatch $Pattern) { throw } } } $result = Collect $names = @($result.Inventory.packages | ForEach-Object { $_.name }) Assert ($names.Count -eq 4 -and $names -contains 'normal' -and $names -contains 'build' -and $names -notcontains 'dev-only' -and $names -notcontains 'unreachable') 'Normal/build graph selection failed' Assert ($result.Inventory.rust.notices.Count -eq 2) 'Rust reports missing' Assert ($result.Inventory.workspace_build_inputs_sha256.Count -eq 5) 'Shared compiler input inventory missing' $script:FixtureTarget = 'x86_64-unknown-linux-gnu' $linuxNotices = Get-ArcadiaNotices $fixture $script:FixtureTarget $manifestPath '' @('oa-server') Assert ($linuxNotices.Inventory.packages.Count -eq 1 -and $linuxNotices.Inventory.packages[0].name -eq 'oa-server') 'Server-only Linux notice graph includes desktop roots' Assert ($linuxNotices.Inventory.root_packages.Count -eq 1 -and $linuxNotices.Inventory.root_packages[0] -eq 'oa-server' -and $null -eq $linuxNotices.Inventory.runtime) 'Linux target/root/runtime identity not retained' try { $null = Get-ArcadiaNotices $fixture $script:FixtureTarget $manifestPath 'unexpected-runtime'; throw 'Expected runtime refusal' } catch { if ($_.Exception.Message -notmatch 'only to the gnullvm target') { throw } } $script:FixtureTarget = 'x86_64-pc-windows-msvc' $before = ($result.Inventory.packages | Where-Object name -eq normal).local_source_sha256['src/lib.rs'] $null = Write-Fixture 'registry/src/test/normal-1.0.0/src/lib.rs' '// locally changed source' $after = ((Collect).Inventory.packages | Where-Object name -eq normal).local_source_sha256['src/lib.rs'] Assert ($before -ne $after) 'Local source hash was replaced by a cached checksum' $null = Write-Fixture 'registry/cache/test/normal-1.0.0.crate' 'Tampered archive' Refuses 'Cached crate archive differs' $null = Write-Fixture 'registry/cache/test/normal-1.0.0.crate' 'Synthetic cached archive normal' $null = Write-Fixture 'registry/src/test/normal-1.0.0/src/lib.rs' "//! include_bytes!(`"../../dev/absent.ttf`")`n /// let font = include_bytes!(`"../../dev/absent.otf`");`n// include_bytes!(`"../../dev/absent.woff2`")`npub fn normal_code() {}" Assert (@((Collect).Inventory.packages | Where-Object name -eq normal).Count -eq 1) 'Rustdoc font examples incorrectly treated as compiled assets' $null = Write-Fixture 'registry/src/test/normal-1.0.0/src/lib.rs' 'static FONT: &[u8] = include_bytes!("../../dev/absent.ttf");' Refuses 'Embedded font path escapes crate source root' $null = Write-Fixture 'registry/src/test/normal-1.0.0/src/lib.rs' 'static FONT: &[u8] = include_bytes!("../font.ttf");' $null = Write-Fixture 'registry/src/test/normal-1.0.0/font.ttf' 'Synthetic font bytes' Refuses 'Embedded font requires exact notice mapping' $fontNotice = Write-Fixture 'supplements/font-OFL.txt' 'Synthetic exact font notice' $fontAsset = [ordered]@{ name = 'normal'; version = '1.0.0'; path = 'font.ttf'; sha256 = (Get-FileHash -LiteralPath (Join-Path $fixture 'registry/src/test/normal-1.0.0/font.ttf') -Algorithm SHA256).Hash.ToLowerInvariant(); license = 'OFL-1.1'; notices = @([ordered]@{ file = 'font-OFL.txt'; sha256 = (Get-FileHash -LiteralPath $fontNotice -Algorithm SHA256).Hash.ToLowerInvariant(); url = 'https://example.invalid/font-OFL.txt' }) } $null = Write-Fixture 'supplements/manifest.json' ([ordered]@{ packages = @(); assets = @($fontAsset); runtimes = @() } | ConvertTo-Json -Depth 8) Assert (@((Collect).Inventory.packages | Where-Object name -eq normal).Count -eq 1) 'Exact font mapping was rejected' $null = Write-Fixture 'registry/src/test/normal-1.0.0/font.ttf' 'Different font bytes' Refuses 'Embedded font requires exact notice mapping' $null = Write-Fixture 'registry/src/test/normal-1.0.0/src/lib.rs' '// no font' $pkg = $script:FixtureMetadata.packages | Where-Object name -eq normal $pkg.source = 'git+https://example.invalid/test#123' Refuses 'Unsupported source requiring deliberate review' $pkg.source = 'registry+https://github.com/rust-lang/crates.io-index' $normalHash = (Get-FileHash -LiteralPath (Join-Path $fixture 'registry/cache/test/normal-1.0.0.crate') -Algorithm SHA256).Hash.ToLowerInvariant() $bad = [ordered]@{ packages = @([ordered]@{ name = 'normal'; version = '1.0.0'; checksum = $normalHash; notices = @([ordered]@{ file = '../LICENSE'; sha256 = ('0' * 64); url = 'https://example.invalid/test' }) }); assets = @(); runtimes = @() } $null = Write-Fixture 'supplements/manifest.json' ($bad | ConvertTo-Json -Depth 8) Refuses 'Notice path escapes source root' $bad.packages[0].notices[0].file = 'NOTICE.txt' $null = Write-Fixture 'supplements/NOTICE.txt' 'Synthetic supplemental notice' $null = Write-Fixture 'supplements/manifest.json' ($bad | ConvertTo-Json -Depth 8) Refuses 'Supplement changed' # A patched package is reachable through metadata but deliberately excluded # from workspace_members. Its registry supplement must not license local bytes. $registryNoticeHash = (Get-FileHash -LiteralPath (Join-Path $fixture 'supplements/NOTICE.txt') -Algorithm SHA256).Hash.ToLowerInvariant() $registrySupplement = [ordered]@{ name = 'normal'; version = '1.0.0'; checksum = $normalHash; notices = @([ordered]@{ file = 'NOTICE.txt'; sha256 = $registryNoticeHash; url = 'https://example.invalid/test' }) } $staleVendorSupplement = [ordered]@{ name = 'iced_widget'; version = '0.14.2'; checksum = ('b' * 64); notices = @([ordered]@{ file = 'registry-only-must-not-be-read.txt'; sha256 = ('c' * 64); url = 'https://example.invalid/registry-original' }) } $null = Write-Fixture 'supplements/manifest.json' ([ordered]@{ packages = @($registrySupplement, $staleVendorSupplement); assets = @(); runtimes = @() } | ConvertTo-Json -Depth 8) $registryBefore = ((Collect).Inventory.packages | Where-Object name -eq normal).local_source_sha256['src/lib.rs'] $vendorManifest = Write-Fixture 'crates/vendor/iced_widget/Cargo.toml' "[package]`nname = `"iced_widget`"`nversion = `"0.14.2`"`nlicense = `"MIT`"" $vendorSource = Write-Fixture 'crates/vendor/iced_widget/src/lib.rs' '// synthetic patched widget' $vendorLicense = Write-Fixture 'crates/vendor/iced_widget/LICENSE' 'Synthetic upstream widget license; not the workspace license' $vendorPatch = Write-Fixture 'crates/vendor/iced_widget/ARCADIA-PATCH.md' 'Synthetic exact upstream and patch provenance' $vendor = [pscustomobject]@{ id = 'local-iced-widget'; name = 'iced_widget'; version = '0.14.2'; source = $null; license = 'MIT'; license_file = $null; manifest_path = $vendorManifest; repository = 'https://example.invalid/widget' } $script:FixtureMetadata.packages += $vendor $script:FixtureMetadata.resolve.nodes += [pscustomobject]@{ id = $vendor.id; deps = @(); features = @('advanced') } $desktopNode = $script:FixtureMetadata.resolve.nodes | Where-Object id -eq 'oa-desktop' $desktopNode.deps += [pscustomobject]@{ pkg = $vendor.id; dep_kinds = @([pscustomobject]@{ kind = $null }) } Assert ($script:FixtureMetadata.workspace_members -notcontains $vendor.id) 'Vendor fixture accidentally became a workspace member' $withVendor = Collect $vendorRecord = $withVendor.Inventory.packages | Where-Object name -eq iced_widget Assert ($null -ne $vendorRecord) 'Excluded local dependency was omitted from the resolved notice graph' Assert ($vendorRecord.local_path -eq 'crates/vendor/iced_widget' -and $null -eq $vendorRecord.source -and $null -eq $vendorRecord.registry_checksum) 'Local package was attributed to registry bytes or the wrong repository path' Assert ($vendorRecord.notices.Count -eq 2) 'Vendor own license and patch evidence were not both retained' Assert (@($vendorRecord.notices | Where-Object { $_.path -match 'workspace-LICENSE|/supplement/' }).Count -eq 0) 'Vendor inherited the workspace license or stale registry supplement' foreach ($pair in @(@('Cargo.toml', $vendorManifest), @('src/lib.rs', $vendorSource), @('LICENSE', $vendorLicense), @('ARCADIA-PATCH.md', $vendorPatch))) { $expected = (Get-FileHash -LiteralPath $pair[1] -Algorithm SHA256).Hash.ToLowerInvariant() Assert ($vendorRecord.local_source_sha256[$pair[0]] -eq $expected) "Vendor source hash does not describe actual file: $($pair[0])" } foreach ($pair in @(@('LICENSE', $vendorLicense), @('ARCADIA-PATCH.md', $vendorPatch))) { $destination = "licenses/dependencies/iced_widget-0.14.2/$($pair[0])" Assert ($withVendor.Inputs[$destination] -eq $pair[1]) "Vendor notice did not retain actual source path: $($pair[0])" Assert ($withVendor.Hashes[$destination] -eq $vendorRecord.local_source_sha256[$pair[0]]) "Vendor notice hash differs from captured local source: $($pair[0])" } $workspaceRecord = $withVendor.Inventory.packages | Where-Object name -eq 'oa-desktop' Assert (@($workspaceRecord.notices | Where-Object path -match 'workspace-LICENSE$').Count -eq 1) 'Real workspace package lost its workspace license' $registryRecord = $withVendor.Inventory.packages | Where-Object name -eq normal Assert ($registryRecord.registry_checksum -eq $normalHash -and $null -eq $registryRecord.local_path) 'Registry identity changed while adding a local package' Assert (@($registryRecord.notices | Where-Object path -match '/supplement/NOTICE.txt$').Count -eq 1) 'Valid registry supplement was lost' $null = Write-Fixture 'crates/vendor/iced_widget/src/lib.rs' '// changed synthetic patched widget' $changedVendor = Collect $changedRecord = $changedVendor.Inventory.packages | Where-Object name -eq iced_widget Assert ($changedRecord.local_source_sha256['src/lib.rs'] -ne $vendorRecord.local_source_sha256['src/lib.rs']) 'Vendor source mutation was hidden by cached registry identity' Assert (($changedVendor.Inventory.packages | Where-Object name -eq normal).local_source_sha256['src/lib.rs'] -eq $registryBefore) 'Vendor mutation changed unrelated registry source inventory' $cliAfterVendor = Get-ArcadiaNotices $fixture x86_64-pc-windows-msvc $manifestPath '' @('oa-cli') Assert (@($cliAfterVendor.Inventory.packages | Where-Object name -eq iced_widget).Count -eq 0) 'Unreachable vendor leaked into CLI notices' $savedLicense = Join-Path $fixture 'saved-vendor-license' Move-Item -LiteralPath $vendorLicense -Destination $savedLicense try { Refuses 'Local dependency requires its own license text: iced_widget-0.14.2' } finally { Move-Item -LiteralPath $savedLicense -Destination $vendorLicense } # A sibling with the same textual prefix is outside the repository; it need # not exist, since containment must be checked before opening that manifest. $vendor.manifest_path = Join-Path ($fixture + '-outside') 'Cargo.toml' try { Refuses 'Local dependency is outside repository' } finally { $vendor.manifest_path = $vendorManifest } $registrySupplement.checksum = 'd' * 64 $null = Write-Fixture 'supplements/manifest.json' ([ordered]@{ packages = @($registrySupplement, $staleVendorSupplement); assets = @(); runtimes = @() } | ConvertTo-Json -Depth 8) Refuses 'Supplement is for different registry source: normal-1.0.0' $registrySupplement.checksum = $normalHash $null = Write-Fixture 'supplements/manifest.json' ([ordered]@{ packages = @($registrySupplement, $staleVendorSupplement); assets = @(); runtimes = @() } | ConvertTo-Json -Depth 8) $null = Write-Fixture 'registry/cache/test/normal-1.0.0.crate' 'Tampered archive with local vendor present' Refuses 'Cached crate archive differs' $null = Write-Fixture 'registry/cache/test/normal-1.0.0.crate' 'Synthetic cached archive normal' $null = Collect Write-Output 'PASS: excluded local package identity, own license and patch evidence, changed source bytes, repository containment, missing vendor license refusal, registry isolation and unchanged archive/supplement checks.' Write-Output 'PASS: normal/build and server-only Linux selection, cross-target runtime refusal, Rust reports, actual source hashes, stale archive refusal, doc-comment font exclusion, production font path/mapping refusals, exact font mapping and changed-byte refusal, unsupported source refusal, traversal refusal, altered supplement refusal.' Write-Output "Synthetic fixture retained for inspection: $fixture"