XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFESystem

Preserve USB workspace when upgrading the verified Desktop image

2e39557
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

5 个文件 +362 -10
Modified AGENTS.md +6 -0
@@ -1,5 +1,11 @@
1 1 # XFESystem 用户约定
2 2
3 2026-10-17 用户明确恢复写入授权,已将 **0.3.0-dev.4-bing-css-monaco.1 / Desktop USB 工作区单系统** 写入专用 USB `230222336207` / `5000000000002AEF`。源镜像保持 `e463fa94b7fa162662c330b0c0fa7d1f1e9ac21a05b57086a66a3d52900c18de`;完整 `268435456` 字节容量调整及工作区恢复后的预期/实际 SHA256 均为 `5248ef1bf450c1cff99a44830bd115100c924173f802c64110f0edf330fbc473`,真实盘尾 GPT `ActualLastLba=500118191` 通过。**已有 64 MiB 工作区已实际备份并逐字节恢复**,SHA256 `b2c02a637875fdea037978e837bdba80e1c9fe0fa151712faaa3bafa841fbeab`,位置随新版 FAT 分配迁移,不清空用户文件和设置。
4
5 初次更新因两版自带 `UsbHello.dll` 哈希不同而在首个磁盘字节写入前拒绝,已打开的句柄随后关闭,原失败留存。写盘器增加仅适用 `IndependentCSharpUsb256` 的 `-PreviousWriteResult` / `-PreviousWriteResultSha256`:显式固定同一专用设备的历史成功回执,核验并锁定旧镜像、清单、启动回执、源码快照;只有与已验证旧版示例完全相符的文件允许备份升级,任意用户替换和额外文件继续拒绝覆盖。本次旧示例确实匹配上一版原文件,5632 字节已单独备份。17 项新增检查、原工作区升级保护、原物理写盘保护及 5 项交付分派检查通过;软件镜像与其原有 17 组、1666 项宿主/原生验收证据未改变,本轮未重跑完整应用验收。
6
7 最终辅助 PID `91856` 实际退出码 0 且已不存在,句柄关闭,fresh 身份相符、非系统/启动盘并保持离线。完成记录 `build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981/Completion.json` SHA256 `9c7fe55940092b5b9c24cf86ed397637f7f374efebbc7b8c108709efca1babad`,同目录 `Postflight.json` SHA256 `2e96bec8f4052f164833639b8e78ccf941b31759d22bfd7279ca7f36607ea0db`。详情 `docs/BingCssMonacoUsb20261017.md` / `docs/validation-results/BingCssMonacoUsb20261017.json`。原 ZIP 和主目录 EFI CRLF 差异保持原样;`DeliveryComplete=true`、`UsbWritten=true` 仅指本次实体介质更新,不能等同实体启动/网络/输入或完整发行验收,`FullReleaseQualified=false`。
8
3 9 2026-10-16 继续完成 **0.3.0-dev.4-bing-css-monaco.1 / Desktop 单系统实验镜像**。修复嵌套 flex 内在宽度、字形分段计量、循环百分比导致的导航裁剪和百分比重复解析;二维 transform 同步绘制/裁剪/命中/范围/冻结快照,官网箭头不再是大 L。Monaco 空会话已复现为短 .NET 正则被 GC 墙钟暂停触发 100 ms 超时,并被 undefined editor 掩盖。私有 Jint 增加有界字面替换及仅纯匹配/替换的 GC 暂停恢复:扣除已耗时、最多两次、不重放 JS 回调、不提高网站预算;保留首个真实初始化错误。最终四线程 384 次实际编辑器打开与 GC 压力无空会话、无原文丢失;不是永久无停顿保证。
4 10
5 11 真实 Edge 官网对照及原生 Bing v9 验收通过:主页照片/热点/二维码/旋转箭头、两次实际查询、各七个导航、实际 PNG 图标像素和两个结果页各六帧连续滚动至底部。新增 DOMParser/TreeWalker/Text.splitText、正确共享 Node 原型、Promise 微任务隔离、经典脚本 MIME/nosniff 规则和诚实统一 UA。固定 AngleSharp.Xml 1.2.0,完整精确提交 MIT 版权随包;拒绝 DTD/外部声明,未引入宿主 XML 网络/文件接口。初次 System.Xml 链接失败、提前截取占位图、验收调用参数错误、旧暂存锁文件及未指定 QEMU 的启动计划失败均保留,不计为成功。
Added docs/BingCssMonacoUsb20261017.md +51 -0
@@ -0,0 +1,51 @@
1 # 2026-10-17 Desktop Bing/CSS/Monaco 实体 USB 更新
2
3 用户明确“现在可以写入U盘了”,恢复本次专用介质写入授权。已将原来通过验收的 **0.3.0-dev.4-bing-css-monaco.1** 写入 Desktop 单系统 U 盘,保留已有工作区。Console 没有写入,原 ZIP、软件内核和镜像源文件保持原字节。
4
5 ## 目标与写后验证
6
7 - USB:`lankxin T.Pssd USB 3.2`,序列号 `230222336207`,UniqueId `5000000000002AEF`;本次为磁盘 3,但选择和多次复核依靠完整设备身份。
8 - 实际容量 `256060514304` 字节,512 字节逻辑扇区,非系统/启动盘,写前后离线。
9 - 使用 `IndependentCSharpUsb256` 新计划及令牌;源码、当前验收回执和旧版升级证据在打开目标前锁定。
10 - 完整原镜像回读后恢复工作区,再调整 GPT;随后完整回读 `268435456` 字节,并核验真实末尾的 GPT 表和备份头。`ActualLastLba=500118191`。
11 - 辅助进程 PID `91856` 已实际退出,退出码 0;所有句柄关闭,独立 fresh 磁盘枚举确认身份相符、非系统/启动盘、保持离线。
12
13 | 内容 | SHA256 |
14 | --- | --- |
15 | 未修改的源镜像 | `e463fa94b7fa162662c330b0c0fa7d1f1e9ac21a05b57086a66a3d52900c18de` |
16 | 内核 | `5ecfc11d5d9d8b1d70e3be55d413089f0d8b8ec98fd27e6f3cf9d86b1d965680` |
17 | 恢复工作区及适配容量后的预期/实际完整镜像 | `5248ef1bf450c1cff99a44830bd115100c924173f802c64110f0edf330fbc473` |
18 | 原有 64 MiB 工作区备份及恢复内容 | `b2c02a637875fdea037978e837bdba80e1c9fe0fa151712faaa3bafa841fbeab` |
19 | 写入完成回执 | `9c7fe55940092b5b9c24cf86ed397637f7f374efebbc7b8c108709efca1babad` |
20 | 写后核对回执 | `2e96bec8f4052f164833639b8e78ccf941b31759d22bfd7279ca7f36607ea0db` |
21
22 已有工作区从字节偏移 `139294720` 迁移到新 FAT 分配的 `191322624`,完整 `67108864` 字节备份后逐字节恢复。完整镜像预期哈希同时包含该工作区覆盖区和 GPT 几何变化,因此不同于发行包源镜像哈希。
23
24 ## 首次拒绝与旧版示例升级
25
26 首次写盘器发现现有 `UserFiles/UsbHello.dll` 与新版默认示例哈希不同,保护检查在首个磁盘字节写入前拒绝更新,已经打开的目标句柄随后关闭。记录保留在:
27
28 `build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-1792196697603/`
29
30 旧版原示例 SHA256 为 `a53f9369ad37786fd109b0a418f38366a0e32779ee67c8890f7aed3a8cc9300c`,新版为 `e25d6eadaae9c392aab086cc1610d31a2390f65b5349a7a4ec436609c3ca6d19`。直接放宽任意同名 DLL 检查会覆盖用户替换文件,因此本次增加明确的历史发行绑定:
31
32 1. `-PreviousWriteResult` 必须同时给出调用者已固定的 `-PreviousWriteResultSha256`,且仅支持 USB 工作区升级。
33 2. 历史回执必须为同一序列号和 UniqueId 的成功写入,完整回读和盘尾 GPT 通过;旧镜像、清单、启动回执及源码快照的哈希必须与该回执一致。
34 3. 旧启动回执必须确认其镜像、源码快照及 USB 持久化验收。上述旧证据进入新计划的令牌绑定,写入前保持文件锁定。
35 4. 实体盘中同名文件只有与该已验证旧版原示例完全一致时才允许备份后升级;任意用户替换文件、额外根文件和额外导入文件仍拒绝覆盖。
36
37 本次固定的上一版完成回执 SHA256 为 `89fb40a03274085352d4f1366fb96a217982d30bcb3d19914cf93bd25461fe53`。实际盘内示例匹配该旧版原文件,完整 5632 字节已独立备份并哈希回读;原有工作区同步完整备份。之后新计划重试写入并完成上述全部验证。旧失败目录的 `resolved-by-write.json` 关联新成功记录,没有覆盖原始失败。
38
39 ## 验证与证据
40
41 Windows PowerShell 5.1 的 17 项新增检查覆盖固定历史证据、错误设备身份、缺失/错误哈希、失败或不完整历史验收、变化的旧镜像/启动回执、原示例备份、完整工作区恢复、任意用户替换拒绝以及令牌绑定。原有工作区升级保护和物理写盘保护检查通过;交付分派的 5 项离线检查通过。这些测试只操作普通文件,没有使用实体盘。
42
43 本次实际写入使用的镜像仍绑定原有 17 组、1666 项宿主检查及原生 Bing v9、Monaco 编辑、文档、终端、USB 双冷启动和其他数据卷验收;完整应用验收本轮没有重复执行。主目录原有 EFI CRLF 差异的原始 SHA256 仍为 `9536c5475483ff61441b673ba6f7efa3beb579e3a48d3bba9dc05fc0dfb084b8`,未暂存。
44
45 成功写盘原始目录:
46
47 `build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981/`
48
49 其中保留 `Selection.json`、`DryPlan.json`、`WritePlan.json`、`Completion.json`、`Postflight.json`、实际进程退出记录、日志和两个用户数据保护备份。摘要见 `docs/validation-results/BingCssMonacoUsb20261017.json`,原镜像验收见 `docs/validation-results/BingCssMonaco20261016.json`。
50
51 `DeliveryComplete=true`、`UsbWritten=true` 表示这次专用实体介质更新完成。实体启动、网络和输入没有因这次写盘取得新的验收,完整 Chromium 兼容、GPU/CUDA、SMP 和长期稳定性仍不属于本次结果,`FullReleaseQualified=false`。
Added docs/validation-results/BingCssMonacoUsb20261017.json +144 -0
@@ -0,0 +1,144 @@
1 {
2 "Kind": "XfeBingCssMonacoUsbDelivery20261017",
3 "Version": "0.3.0-dev.4-bing-css-monaco.1",
4 "Edition": "Desktop",
5 "DeploymentPolicy": "SingleEditionOnly",
6 "Date": "2026-10-17",
7 "UserAuthorizedPhysicalWrite": true,
8 "ImageDeliveryComplete": true,
9 "DeliveryComplete": true,
10 "UsbWritten": true,
11 "PhysicalDiskOpened": true,
12 "FullReleaseQualified": false,
13 "PhysicalBootAcceptancePassed": false,
14 "StorageEnabled": true,
15 "RamOnly": false,
16 "SourceRoot": "C:\\Users\\XFEstudio\\.codex\\worktrees\\browser-load-speed\\XFESystem",
17 "ImagePath": "C:\\Users\\XFEstudio\\.codex\\worktrees\\browser-load-speed\\XFESystem\\build\\IndependentKernel\\Proof-1792113213603993800\\System.img",
18 "ImageSha256": "e463fa94b7fa162662c330b0c0fa7d1f1e9ac21a05b57086a66a3d52900c18de",
19 "ImageBytes": 268435456,
20 "SourceImageUnchanged": true,
21 "KernelSha256": "5ecfc11d5d9d8b1d70e3be55d413089f0d8b8ec98fd27e6f3cf9d86b1d965680",
22 "OriginalZip": "dist/XFESystem-Desktop-Independent-USB-0.3.0-dev.4-bing-css-monaco.1-1792113907524-4bb5edd7.zip",
23 "OriginalZipSha256": "235e3bfb2428070097d3e6a2a2d48fedc21055ef3eea5f1c4a8d2557efd4149b",
24 "PreviousImageOnlyReport": "docs/validation-results/BingCssMonaco20261016.json",
25 "OriginalHostSuites": 17,
26 "OriginalHostChecks": 1666,
27 "FullHostSuitesRerunThisRound": false,
28 "FinalDeliveryGate": {
29 "Kind": "XfeIndependentFinalDeliveryGate",
30 "Passed": true,
31 "Method": "Open.ps1 -ValidateOnly",
32 "LauncherPath": "C:\\Users\\XFEstudio\\.codex\\worktrees\\browser-load-speed\\XFESystem\\Tools\\IndependentKernel\\Open.ps1",
33 "LauncherSha256": "6df41e37899a3b4485efac895eef4319313a9d090fbe0ed81190d11d2c00f525",
34 "ImageSha256": "e463fa94b7fa162662c330b0c0fa7d1f1e9ac21a05b57086a66a3d52900c18de",
35 "BootResultSha256": "a15a69581e8502577ce434b3db07fa9d343f2e58558ef70a129f7e24b86d9878",
36 "EvidenceHarnessSha256": {
37 "Tools/IndependentKernel/TestBoot.py": "4b1a682938966992b0eaa29a7d8cd4eafabad1d9cdb89a833f584d697bb86370",
38 "Tools/IndependentKernel/IndependentBingEvidence.py": "499cf62ca48181b28e4fd64dcbe99323c1751289aee061c65505729a634b0c8d",
39 "Tools/IndependentKernel/IndependentDocumentEvidence.py": "de08fd45747481a29808cfeabaec49ded4abfb7a5e0ae739e8c6ab01419e7909",
40 "Tools/IndependentKernel/TestUsbStorage.py": "f7d89268d0dae145d638ea3369d9536c8aee928ebce101c0402862d88040f14c",
41 "Tools/CSharpBoot/ReadImage.py": "85d29000e7e655e2db29805bcfeab8b49bf83cbfa8cfd4d346c15b12250db1df"
42 },
43 "Edition": "Desktop",
44 "ConsoleWorkflowPassed": false,
45 "BingNativeHttpsPassed": true,
46 "DocumentWorkflowPassed": true,
47 "TerminalWorkflowPassed": true,
48 "FullCssParityVerified": false,
49 "PhysicalInputHardwareAcceptancePassed": false,
50 "NoVmStarted": true,
51 "NoDiskWrites": true
52 },
53 "SingleEditionImageProof": {
54 "Kind": "XfeSingleEditionImageProof",
55 "Passed": true,
56 "Edition": "Desktop",
57 "KernelCount": 1,
58 "BootEntryCount": 1,
59 "SystemSelectionMenu": false,
60 "BootMenuTimeoutSeconds": 0,
61 "UsbWorkspace": true,
62 "FilePaths": [
63 "EFI/BOOT/BOOTX64.EFI",
64 "EFI/XFE/Limine.efi",
65 "Limine.conf",
66 "System/BootShim.json",
67 "System/Kernel.elf",
68 "UserFiles/UsbHello.dll",
69 "Workspace.bin"
70 ],
71 "ConfigurationSha256": "cd184a4d0539f869460a9bb5d74ffd222f197e274f85df75df757a9241f8e050"
72 },
73 "UsbStorageAcceptancePassed": true,
74 "FreshDisk": {
75 "Number": 3,
76 "FriendlyName": "lankxin T.Pssd USB 3.2",
77 "SerialNumber": "230222336207",
78 "UniqueId": "5000000000002AEF",
79 "Size": 256060514304,
80 "LogicalSectorSize": 512,
81 "BusType": "USB",
82 "IsOffline": true,
83 "IsSystem": false,
84 "IsBoot": false
85 },
86 "Verification": {
87 "ImageBytesVerified": 268435456,
88 "ExpectedAdjustedImageSha256": "5248ef1bf450c1cff99a44830bd115100c924173f802c64110f0edf330fbc473",
89 "ActualAdjustedImageSha256": "5248ef1bf450c1cff99a44830bd115100c924173f802c64110f0edf330fbc473",
90 "ActualLastLba": 500118191,
91 "ActualTailBackupGptVerified": true,
92 "FullImageVerified": true
93 },
94 "PreservedWorkspace": {
95 "SourceOffset": 139294720,
96 "DestinationOffset": 191322624,
97 "Bytes": 67108864,
98 "SnapshotPath": "C:\\Users\\XFEstudio\\Desktop\\work\\CSharp\\GitHub\\XFEstudio\\XFESystem\\build\\usb-media\\XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981\\PreservedWorkspace-3f66d1f6b5bd4e2289a3ec35a84e7ee4.bin",
99 "Sha256": "b2c02a637875fdea037978e837bdba80e1c9fe0fa151712faaa3bafa841fbeab",
100 "Restored": true
101 },
102 "PreservedStockImport": {
103 "SnapshotPath": "C:\\Users\\XFEstudio\\Desktop\\work\\CSharp\\GitHub\\XFEstudio\\XFESystem\\build\\usb-media\\XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981\\PreviousStockImport-188860af4aac4d6db292519b9622e619-UsbHello.dll",
104 "Sha256": "a53f9369ad37786fd109b0a418f38366a0e32779ee67c8890f7aed3a8cc9300c",
105 "Bytes": 5632,
106 "PreviousCompletionSha256": "89fb40a03274085352d4f1366fb96a217982d30bcb3d19914cf93bd25461fe53",
107 "CandidateSha256": "e25d6eadaae9c392aab086cc1610d31a2390f65b5349a7a4ec436609c3ca6d19",
108 "ReplacementVerified": true
109 },
110 "HelperExitCode": 0,
111 "HelperCompleted": true,
112 "HelperProcessStillExists": false,
113 "HandlesClosed": true,
114 "FreshIdentityMatches": true,
115 "CompletionPath": "build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981/Completion.json",
116 "CompletionSha256": "9c7fe55940092b5b9c24cf86ed397637f7f374efebbc7b8c108709efca1babad",
117 "PostflightPath": "build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-retry-1792196976981/Postflight.json",
118 "PostflightSha256": "2e96bec8f4052f164833639b8e78ccf941b31759d22bfd7279ca7f36607ea0db",
119 "InitialRefusal": {
120 "Path": "build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-1792196697603/Completion.json",
121 "Sha256": "6ef8241bd02e6f422ef6589c408b5f4d6dfefe6b1e25bcb54830ff2df4a90240",
122 "PhysicalDiskOpened": true,
123 "DiskBytesWritten": false,
124 "HandlesClosed": true,
125 "Reason": "Old stock UsbHello.dll hash differed from candidate default",
126 "ResolvedByPinnedPreviousRelease": true,
127 "ResolutionPath": "build/usb-media/XFEstudio-Desktop-BingCssMonaco-0.3.0-dev.4-1792196697603/resolved-by-write.json"
128 },
129 "WriterSha256": "75560a4efcaf68c5c9f16982b8f0bdbfa122fcd8a19c636574008bd881b63307",
130 "Guards": {
131 "Kind": "XfeUsbUpdateGuardResults",
132 "Passed": true,
133 "PreviousStockImportChecks": 17,
134 "DeliveryGateChecks": 5,
135 "OriginalWorkspaceUpdateGuardsPassed": true,
136 "OriginalPhysicalMediaGuardsPassed": true,
137 "Runtime": "Windows PowerShell 5.1",
138 "PhysicalDiskUsedForTests": false,
139 "FullHostSuitesRerun": false,
140 "FinishedUtc": "2026-10-17T00:29:37.8527131Z"
141 },
142 "UnrelatedMainEfiSha256": "9536c5475483ff61441b673ba6f7efa3beb579e3a48d3bba9dc05fc0dfb084b8",
143 "FinishedUtc": "2026-10-17T00:30:50.4589773Z"
144 }
Added scripts/physical-media-previous-import-tests.ps1 +98 -0
@@ -0,0 +1,98 @@
1 # Real previous-release evidence and regular-file migration tests. No raw disks.
2 [CmdletBinding()]
3 param([Parameter(Mandatory=$true)][string]$Image,
4 [Parameter(Mandatory=$true)][string]$PreviousWriteResult,
5 [Parameter(Mandatory=$true)][string]$PreviousWriteResultSha256)
6 $ErrorActionPreference='Stop'
7 $candidate=$Image
8 $previousPath=$PreviousWriteResult
9 $previousHash=$PreviousWriteResultSha256
10 . (Join-Path $PSScriptRoot 'physical-media.ps1') -LoadFunctionsOnly
11 $directory=Join-Path (Join-Path $PSScriptRoot '../build') ('PreviousStockImportTests-'+[Guid]::NewGuid().ToString('N'))
12 [void][IO.Directory]::CreateDirectory($directory)
13 $disk=[pscustomobject]@{Number=3;SerialNumber='230222336207';UniqueId='5000000000002AEF';Size=[uint64]256060514304;BusType='USB';LogicalSectorSize=512}
14 $script:checks=0
15 function Check([bool]$Condition,[string]$Message){if(!$Condition){throw $Message};$script:checks++}
16 function Refuse([scriptblock]$Action,[string]$Message){$failed=$false;try{& $Action | Out-Null}catch{$failed=$true};Check $failed $Message}
17 function Fixture($Receipt,[string]$Name){$path=Join-Path $directory $Name;$Receipt | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $path -Encoding UTF8;return $path}
18 $prior=Get-Content -LiteralPath $previousPath -Raw -Encoding UTF8 | ConvertFrom-Json
19 $originalImageHash=(Get-FileHash -LiteralPath $candidate -Algorithm SHA256).Hash
20 $originalOldHash=(Get-FileHash -LiteralPath $prior.Plan.image -Algorithm SHA256).Hash
21 $known=Get-XfePreviousStockImport $previousPath $previousHash $disk
22 Check ($known.DefaultImportSha256 -ceq $prior.ExperimentalEvidence.DefaultImportSha256 -and $known.EvidenceLocks.Count -eq 5) 'Previous stock release was not bound.'
23 Refuse {Get-XfePreviousStockImport $previousPath '' $disk} 'Missing pin was accepted.'
24 Refuse {Get-XfePreviousStockImport $previousPath ('0'*64) $disk} 'Wrong completion pin was accepted.'
25 $disk.SerialNumber='another-usb'
26 Refuse {Get-XfePreviousStockImport $previousPath $previousHash $disk} 'Wrong serial was accepted.'
27 $disk.SerialNumber='230222336207';$disk.UniqueId='another-unique-id'
28 Refuse {Get-XfePreviousStockImport $previousPath $previousHash $disk} 'Wrong unique ID was accepted.'
29 $disk.UniqueId='5000000000002AEF'
30 foreach($change in @('failed','not-persistent','incomplete-readback','changed-image','changed-boot')) {
31 $fixture=Get-Content -LiteralPath $previousPath -Raw -Encoding UTF8 | ConvertFrom-Json
32 switch($change) {
33 'failed' {$fixture.Status='failed'}
34 'not-persistent' {$fixture.ExperimentalEvidence.PersistentConfigurationVerified=$false}
35 'incomplete-readback' {$fixture.Verification.FullImageVerified=$false}
36 'changed-image' {$path=Join-Path $directory 'changed.img';[IO.File]::WriteAllBytes($path,[byte[]]@(1,2,3));$fixture.ExperimentalEvidence.ImagePath=$path}
37 'changed-boot' {
38 $boot=Get-Content -LiteralPath $fixture.ExperimentalEvidence.BootResultPath -Raw -Encoding UTF8 | ConvertFrom-Json
39 $boot.Passed=$false
40 $path=Fixture $boot 'failed-boot.json'
41 $fixture.ExperimentalEvidence.BootResultPath=$path
42 $fixture.ExperimentalEvidence.BootResultSha256=(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
43 }
44 }
45 $path=Fixture $fixture ($change+'.json')
46 $hash=(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
47 Refuse {Get-XfePreviousStockImport $path $hash $disk} ('Invalid previous release accepted: '+$change)
48 }
49 $manifest=Get-Content -LiteralPath ($candidate+'.json') -Raw -Encoding UTF8 | ConvertFrom-Json
50 $currentImport=(Get-Content -LiteralPath $previousPath -Raw -Encoding UTF8 | ConvertFrom-Json).ExperimentalEvidence.DefaultImportSha256
51 # A deliberately different candidate hash exercises the migration branch even
52 # when the supplied old/current fixtures happen to contain the same sample.
53 $differentImport='f'*64
54 if($differentImport -ceq $currentImport){$differentImport='e'*64}
55 $oldPath=Join-Path $directory 'Existing.img';Copy-Item -LiteralPath $prior.Plan.image -Destination $oldPath
56 $newPath=Join-Path $directory 'Updated.img';Copy-Item -LiteralPath $candidate -Destination $newPath
57 $old=$source=$target=$null
58 try {
59 $old=[IO.File]::Open($oldPath,[IO.FileMode]::Open,[IO.FileAccess]::ReadWrite,[IO.FileShare]::Read)
60 Refuse {Get-XfePreservedWorkspace $old $old.Length $directory $differentImport} 'Unidentified changed import was overwritten.'
61 $preserved=Get-XfePreservedWorkspace $old $old.Length $directory $differentImport $known
62 Check ($preserved.Bytes.Length -eq 64MB -and $preserved.StockImportBackup.Sha256 -ceq $currentImport -and
63 (Get-FileHash -LiteralPath $preserved.StockImportBackup.SnapshotPath -Algorithm SHA256).Hash.ToLowerInvariant() -ceq $currentImport) 'Previous stock sample was not backed up exactly.'
64 Check ((Get-FileHash -LiteralPath $preserved.SnapshotPath -Algorithm SHA256).Hash.ToLowerInvariant() -ceq $preserved.Sha256) 'Workspace backup was not exact.'
65 $source=[IO.File]::OpenRead($candidate)
66 $target=[IO.File]::Open($newPath,[IO.FileMode]::Open,[IO.FileAccess]::ReadWrite,[IO.FileShare]::Read)
67 $target.SetLength(300MB)
68 $patch=[pscustomobject]@{Offset=[uint64]$manifest.WorkspaceFirstLba*512;Bytes=$preserved.Bytes}
69 Write-XfeBytes $target $patch.Offset $patch.Bytes
70 Set-XfeAdjustedGpt $target (Get-XfeAdjustedGpt $source $target.Length)
71 $target.Flush($true)
72 $verification=Test-XfeAdjustedReadback $source $target $target.Length $patch
73 Check ($verification.FullImageVerified -and $verification.ActualTailBackupGptVerified) 'Cross-version full workspace restore failed.'
74 # A user replacement must still fail with valid old-release authorization.
75 $boot=Read-XfeBytes $old (2048*512) 512
76 $reserved=[BitConverter]::ToUInt16($boot,14);$fatSectors=[BitConverter]::ToUInt32($boot,36)
77 $clusterBytes=[int]$boot[13]*512
78 $fat=Read-XfeBytes $old ((2048+$reserved)*512) ($fatSectors*512)
79 $data=([uint64]2048+$reserved+2*[uint64]$fatSectors)*512
80 $root=@(Get-XfeFatDirectory $old $data $fat ([BitConverter]::ToUInt32($boot,44)) $clusterBytes)
81 $folder=@($root | Where-Object ShortName -CEQ 'USERFILE ')[0]
82 $file=@(Get-XfeFatDirectory $old $data $fat $folder.Cluster $clusterBytes)[0]
83 $offset=$data+([uint64]$file.Cluster-2)*$clusterBytes
84 $original=Read-XfeBytes $old $offset 512
85 $changed=[byte[]]$original.Clone();$changed[0]=$changed[0] -bxor 1
86 Write-XfeBytes $old $offset $changed
87 Refuse {Get-XfePreservedWorkspace $old $old.Length $directory $differentImport $known} 'A user replacement bypassed old-release validation.'
88 Write-XfeBytes $old $offset $original
89 $plain=Get-XfeMediaIdentity $disk @() 'image-hash' 'LegacyPhysical256' $null
90 $withPrevious=Get-XfeMediaIdentity $disk @() 'image-hash' 'LegacyPhysical256' $null $known
91 Check ((Get-XfeToken $plain) -cne (Get-XfeToken $withPrevious)) 'Previous-release authorization was omitted from the plan token.'
92 } finally {
93 foreach($stream in @($old,$source,$target)){if($stream){$stream.Dispose()}}
94 Check ((Get-FileHash -LiteralPath $candidate -Algorithm SHA256).Hash -ceq $originalImageHash -and
95 (Get-FileHash -LiteralPath $prior.Plan.image -Algorithm SHA256).Hash -ceq $originalOldHash -and
96 (Get-FileHash -LiteralPath $previousPath -Algorithm SHA256).Hash.ToLowerInvariant() -ceq $previousHash) 'Original accepted inputs changed.'
97 }
98 [ordered]@{Kind='XfePreviousStockImportTests';Passed=$true;Checks=$script:checks;PhysicalDiskOpened=$false;Directory=$directory} | ConvertTo-Json
Modified scripts/physical-media.ps1 +63 -10
@@ -11,6 +11,8 @@ param(
11 11 [string]$BootResult,
12 12 [string]$PythonPath = 'python',
13 13 [string]$ResultPath,
14 [string]$PreviousWriteResult,
15 [string]$PreviousWriteResultSha256,
14 16 [switch]$LoadFunctionsOnly
15 17 )
16 18 $ErrorActionPreference = 'Stop'
@@ -231,7 +233,40 @@ function Get-XfeFatDirectory($Target,[uint64]$Data,[byte[]]$Fat,[uint32]$Cluster
231 233 $Cluster=[BitConverter]::ToUInt32($Fat,[int]$Cluster*4) -band 268435455
232 234 }
233 235 }
234 function Get-XfePreservedWorkspace($Target,[uint64]$DiskBytes,[string]$BackupDirectory,[string]$DefaultImportSha256) {
236 function Get-XfePreviousStockImport([string]$Path,[string]$ExpectedHash,$Disk) {
237 if($ExpectedHash -cnotmatch '^[0-9a-f]{64}$'){throw 'A pinned previous completion SHA256 is required.'}
238 $receiptPath=(Resolve-Path -LiteralPath $Path).ProviderPath
239 if((Get-FileHash -LiteralPath $receiptPath -Algorithm SHA256).Hash.ToLowerInvariant() -cne $ExpectedHash){throw 'Previous USB completion hash changed.'}
240 $receipt=Get-Content -LiteralPath $receiptPath -Raw -Encoding UTF8 | ConvertFrom-Json
241 $old=$receipt.ExperimentalEvidence
242 if($receipt.Kind -cne 'XfePhysicalMediaOperation' -or $receipt.Profile -cne 'IndependentCSharpUsb256' -or
243 $receipt.Status -cne 'verified' -or $receipt.PhysicalDiskOpened -ne $true -or $receipt.HandlesClosed -ne $true -or
244 $receipt.FinalDiskState -cne 'offline' -or $receipt.Verification.FullImageVerified -ne $true -or
245 $receipt.Verification.ActualTailBackupGptVerified -ne $true -or $receipt.Verification.ImageBytesVerified -ne 256MB -or
246 $receipt.Plan.disk_serial -cne ([string]$Disk.SerialNumber).Trim() -or $receipt.Plan.disk_unique_id -cne ([string]$Disk.UniqueId).Trim() -or
247 $old.Profile -cne 'IndependentCSharpUsb256' -or $old.PersistentConfigurationVerified -ne $true -or
248 $old.UsbStorageAcceptancePassed -ne $true -or $old.DefaultImportSha256 -cnotmatch '^[0-9a-f]{64}$' -or
249 $old.ImageSha256 -cne $receipt.Plan.image_sha256 -or $old.ImageBytes -ne 256MB){
250 throw 'Previous completion is not a verified persistent release for this USB.'
251 }
252 $locks=@([pscustomobject]@{Path=$receiptPath;Sha256=$ExpectedHash})
253 foreach($pair in @(@($old.ImagePath,$old.ImageSha256),@($old.ImageManifestPath,$old.ImageManifestSha256),
254 @($old.BootResultPath,$old.BootResultSha256),@($old.SourceSnapshotPath,$old.SourceSnapshotSha256))) {
255 if([string]::IsNullOrWhiteSpace($pair[0]) -or $pair[1] -cnotmatch '^[0-9a-f]{64}$' -or
256 (Get-FileHash -LiteralPath $pair[0] -Algorithm SHA256).Hash.ToLowerInvariant() -cne $pair[1]){throw 'Previous release image or evidence changed.'}
257 $locks += [pscustomobject]@{Path=$pair[0];Sha256=$pair[1]}
258 }
259 $manifest=Get-Content -LiteralPath $old.ImageManifestPath -Raw -Encoding UTF8 | ConvertFrom-Json
260 $boot=Get-Content -LiteralPath $old.BootResultPath -Raw -Encoding UTF8 | ConvertFrom-Json
261 if($manifest.ImageSha256 -cne $old.ImageSha256 -or $manifest.UsbWorkspace -ne $true -or
262 $manifest.ImageBytes -ne 256MB -or $boot.Passed -ne $true -or $boot.SourcesUnchanged -ne $true -or
263 $boot.UsbStorageAcceptancePassed -ne $true -or $boot.ImageSha256 -cne $old.ImageSha256 -or
264 $boot.SourceSnapshotSha256 -cne $old.SourceSnapshotSha256){throw 'Previous release is not bound to its accepted image.'}
265 return [pscustomobject]@{ReceiptPath=$receiptPath;ReceiptSha256=$ExpectedHash;ImageSha256=$old.ImageSha256;
266 DefaultImportSha256=$old.DefaultImportSha256;EvidenceLocks=$locks}
267 }
268 function Get-XfePreservedWorkspace($Target,[uint64]$DiskBytes,[string]$BackupDirectory,[string]$DefaultImportSha256,$PreviousStockImport=$null) {
269 $stockBackup=$null
235 270 $header=Read-XfeBytes $Target 512 512
236 271 if([Text.Encoding]::ASCII.GetString($header,0,8) -cne 'EFI PART'){return $null}
237 272 $entry=Read-XfeBytes $Target 1024 128
@@ -265,10 +300,20 @@ function Get-XfePreservedWorkspace($Target,[uint64]$DiskBytes,[string]$BackupDir
265 300 }
266 301 $hasher=[Security.Cryptography.SHA256]::Create()
267 302 try {$importHash=([BitConverter]::ToString($hasher.ComputeHash($fileBytes))).Replace('-','').ToLowerInvariant()}finally{$hasher.Dispose()}
268 if($importHash -cne $DefaultImportSha256){throw 'UserFiles/UsbHello.dll contains changed user data; migrate it before updating. No disk data was overwritten.'}
303 if($importHash -cne $DefaultImportSha256){
304 # An explicitly pinned, successfully written previous release can
305 # identify an old stock example. Other user replacements still fail.
306 if(!$PreviousStockImport -or $importHash -cne $PreviousStockImport.DefaultImportSha256){throw 'UserFiles/UsbHello.dll contains changed user data; migrate it before updating. No disk data was overwritten.'}
307 $importSnapshot=Join-Path $BackupDirectory ('PreviousStockImport-'+[Guid]::NewGuid().ToString('N')+'-UsbHello.dll')
308 $backupStream=[IO.File]::Open($importSnapshot,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::Read)
309 try{$backupStream.Write($fileBytes,0,$fileBytes.Length);$backupStream.Flush($true)}finally{$backupStream.Dispose()}
310 if((Get-FileHash -LiteralPath $importSnapshot -Algorithm SHA256).Hash.ToLowerInvariant() -cne $importHash){throw 'Previous stock import backup verification failed; no disk data was overwritten.'}
311 $stockBackup=[pscustomobject]@{SnapshotPath=$importSnapshot;Sha256=$importHash;Bytes=$fileBytes.Length;
312 PreviousCompletionSha256=$PreviousStockImport.ReceiptSha256;CandidateSha256=$DefaultImportSha256;ReplacementVerified=$false}
313 }
269 314 }
270 315 }
271 if($workspace.Count -eq 0){return $null}
316 if($workspace.Count -eq 0){if($stockBackup){throw 'Previous persistent workspace is missing; update refused.'};return $null}
272 317 [uint32]$first=$workspace[0].Cluster;[uint32]$needed=67108864/$clusterBytes
273 318 for([uint32]$i=0;$i -lt $needed;$i++) {
274 319 [uint32]$cluster=$first+$i
@@ -284,15 +329,16 @@ function Get-XfePreservedWorkspace($Target,[uint64]$DiskBytes,[string]$BackupDir
284 329 [BitConverter]::ToUInt32($bytes,20) -ne (Get-XfeCrc32 ([byte[]]$bytes[0..19]))){throw 'Existing workspace descriptor is invalid; automatic overwrite refused.'}
285 330 $snapshot=Join-Path $BackupDirectory ('PreservedWorkspace-'+[Guid]::NewGuid().ToString('N')+'.bin')
286 331 [IO.File]::WriteAllBytes($snapshot,$bytes)
287 return [pscustomobject]@{Bytes=$bytes;OriginalOffset=$offset;SnapshotPath=$snapshot;Sha256=(Get-FileHash -LiteralPath $snapshot -Algorithm SHA256).Hash.ToLowerInvariant()}
332 return [pscustomobject]@{Bytes=$bytes;OriginalOffset=$offset;SnapshotPath=$snapshot;Sha256=(Get-FileHash -LiteralPath $snapshot -Algorithm SHA256).Hash.ToLowerInvariant();StockImportBackup=$stockBackup}
288 333 }
289 function Get-XfeMediaIdentity($Disk, $Partitions, [string]$ImageHash, [string]$Profile, $Evidence) {
334 function Get-XfeMediaIdentity($Disk, $Partitions, [string]$ImageHash, [string]$Profile, $Evidence, $PreviousStockImport=$null) {
290 335 $identity = '{0}|{1}|{2}|{3}|{4}|{5}|{6}' -f $Disk.Number, $Disk.UniqueId, ([string]$Disk.SerialNumber).Trim(), $Disk.Size, $Disk.BusType, $Disk.LogicalSectorSize, $ImageHash
291 336 if ($Profile -in @('CSharpExperimental128','IndependentCSharp128','IndependentCSharpUsb256','IndependentDualCSharp256')) {
292 337 $writerHash = (Get-FileHash -LiteralPath (Join-Path $PSScriptRoot 'physical-media.ps1') -Algorithm SHA256).Hash.ToLowerInvariant()
293 338 $verifierHash = (Get-FileHash -LiteralPath (Join-Path $PSScriptRoot 'physical-media-verify.py') -Algorithm SHA256).Hash.ToLowerInvariant()
294 339 $identity += '|{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}' -f $Profile,$Evidence.ImageManifestSha256,$Evidence.BootResultSha256,$Evidence.SourceSnapshotSha256,(Get-XfePartitionFingerprint $Partitions),$writerHash,$verifierHash,$Evidence.KernelProjectSha256
295 340 }
341 if($PreviousStockImport){$identity += '|previous-stock-import|'+$PreviousStockImport.ReceiptSha256}
296 342 return $identity
297 343 }
298 344 if ($LoadFunctionsOnly) { return }
@@ -309,6 +355,7 @@ try {
309 355 if ($ImageProfile -ceq 'IndependentDualCSharp256') {
310 356 throw 'Dual-system deployment was retired at the user request. Select one Console or Desktop image with IndependentCSharp128 (RAM) or IndependentCSharpUsb256 (USB workspace); no disk was opened.'
311 357 }
358 if(($PreviousWriteResult -or $PreviousWriteResultSha256) -and $ImageProfile -cne 'IndependentCSharpUsb256'){throw 'Previous stock import evidence is supported only for USB workspace updates.'}
312 359 if (-not $Image -or $DiskNumber -lt 0) { throw 'Specify -Image FILE.img and -DiskNumber N. Without -Write this only produces a review plan.' }
313 360 if ($env:OS -ne 'Windows_NT') { throw 'This script requires Windows Storage cmdlets.' }
314 361 $imagePath = (Resolve-Path -LiteralPath $Image).ProviderPath
@@ -335,7 +382,9 @@ $disk = Get-Disk -Number $DiskNumber -ErrorAction Stop
335 382 $parts = @(Get-Partition -DiskNumber $DiskNumber -ErrorAction Stop)
336 383 Assert-XfeDisk $disk $parts $imageInfo.Length
337 384 if ($ImageProfile -in @('CSharpExperimental128','IndependentCSharp128','IndependentCSharpUsb256','IndependentDualCSharp256')) { Assert-XfeExperimentalDisk $disk $parts $imageInfo.Length }
338 $identity = Get-XfeMediaIdentity $disk $parts $imageHash $ImageProfile $evidence
385 $previousStock=$null
386 if($PreviousWriteResult -or $PreviousWriteResultSha256){$previousStock=Get-XfePreviousStockImport $PreviousWriteResult $PreviousWriteResultSha256 $disk}
387 $identity = Get-XfeMediaIdentity $disk $parts $imageHash $ImageProfile $evidence $previousStock
339 388 $token = Get-XfeToken $identity
340 389 $plan = [ordered]@{
341 390 schema = 1
@@ -354,6 +403,7 @@ $plan = [ordered]@{
354 403 image_sha256 = $imageHash
355 404 image_profile = $ImageProfile
356 405 experimental_evidence = $evidence
406 previous_stock_import = $previousStock
357 407 full_release_qualified = $false
358 408 stability_passed = $false
359 409 cuda_execution_verified = $false
@@ -386,7 +436,7 @@ $freshDisk = Get-Disk -Number $DiskNumber -ErrorAction Stop
386 436 $freshParts = @(Get-Partition -DiskNumber $DiskNumber -ErrorAction Stop)
387 437 Assert-XfeDisk $freshDisk $freshParts $imageInfo.Length
388 438 if ($ImageProfile -in @('CSharpExperimental128','IndependentCSharp128','IndependentCSharpUsb256','IndependentDualCSharp256')) { Assert-XfeExperimentalDisk $freshDisk $freshParts $imageInfo.Length }
389 $freshIdentity = Get-XfeMediaIdentity $freshDisk $freshParts $imageHash $ImageProfile $evidence
439 $freshIdentity = Get-XfeMediaIdentity $freshDisk $freshParts $imageHash $ImageProfile $evidence $previousStock
390 440 if ($freshIdentity -cne $identity) { throw 'Target identity changed since the plan; refusing the write.' }
391 441 $rawPath = '\\.\PhysicalDrive' + $DiskNumber
392 442 $target = $null
@@ -416,13 +466,14 @@ try {
416 466 foreach($artifact in $evidence.AdditionalEvidenceLocks){$evidenceLocks += Open-XfeLockedImage $artifact.Path $artifact.Sha256}
417 467 }
418 468 }
469 if($previousStock){foreach($artifact in $previousStock.EvidenceLocks){$evidenceLocks += Open-XfeLockedImage $artifact.Path $artifact.Sha256}}
419 470 # Recheck the target after hashing while the source is locked. No disk state
420 471 # changes until both exact identities and the locked source hash are valid.
421 472 $lockedDisk=Get-Disk -Number $DiskNumber -ErrorAction Stop
422 473 $lockedParts=@(Get-Partition -DiskNumber $DiskNumber -ErrorAction Stop)
423 474 Assert-XfeDisk $lockedDisk $lockedParts $imageInfo.Length
424 475 if ($ImageProfile -in @('CSharpExperimental128','IndependentCSharp128','IndependentCSharpUsb256','IndependentDualCSharp256')) { Assert-XfeExperimentalDisk $lockedDisk $lockedParts $imageInfo.Length }
425 $lockedIdentity=Get-XfeMediaIdentity $lockedDisk $lockedParts $imageHash $ImageProfile $evidence
476 $lockedIdentity=Get-XfeMediaIdentity $lockedDisk $lockedParts $imageHash $ImageProfile $evidence $previousStock
426 477 if($lockedIdentity -cne $identity){throw 'Target identity changed while locking the source; refusing before any target mutation.'}
427 478 Set-Disk -Number $DiskNumber -IsOffline $true -ErrorAction Stop
428 479 $log.Stage='copying-physical-image'
@@ -438,13 +489,14 @@ try {
438 489 $openedParts=@(Get-Partition -DiskNumber $DiskNumber -ErrorAction Stop)
439 490 Assert-XfeDisk $openedDisk $openedParts $imageInfo.Length
440 491 if ($ImageProfile -in @('CSharpExperimental128','IndependentCSharp128','IndependentCSharpUsb256','IndependentDualCSharp256')) { Assert-XfeExperimentalDisk $openedDisk $openedParts $imageInfo.Length }
441 if ((Get-XfeMediaIdentity $openedDisk $openedParts $imageHash $ImageProfile $evidence) -cne $identity) { throw 'Target identity changed while opening its handle; refusing before any disk byte was written.' }
492 if ((Get-XfeMediaIdentity $openedDisk $openedParts $imageHash $ImageProfile $evidence $previousStock) -cne $identity) { throw 'Target identity changed while opening its handle; refusing before any disk byte was written.' }
442 493 $workspacePatch=$null
443 494 if($ImageProfile -ceq 'IndependentCSharpUsb256') {
444 $preserved=Get-XfePreservedWorkspace $target ([uint64]$openedDisk.Size) (Split-Path -Parent ([IO.Path]::GetFullPath($ResultPath))) $evidence.DefaultImportSha256
495 $preserved=Get-XfePreservedWorkspace $target ([uint64]$openedDisk.Size) (Split-Path -Parent ([IO.Path]::GetFullPath($ResultPath))) $evidence.DefaultImportSha256 $previousStock
445 496 if($preserved) {
446 497 $workspacePatch=[pscustomobject]@{Offset=[uint64]$evidence.WorkspaceFirstLba*512;Bytes=$preserved.Bytes}
447 498 $log.PreservedWorkspace=[ordered]@{SourceOffset=$preserved.OriginalOffset;DestinationOffset=$workspacePatch.Offset;Bytes=67108864;SnapshotPath=$preserved.SnapshotPath;Sha256=$preserved.Sha256;Restored=$false}
499 if($preserved.StockImportBackup){$log.PreservedStockImport=$preserved.StockImportBackup}
448 500 }
449 501 }
450 502 [void]$source.Seek(0,[IO.SeekOrigin]::Begin);[void]$target.Seek(0,[IO.SeekOrigin]::Begin)
@@ -471,6 +523,7 @@ try {
471 523 $target.Flush($true)
472 524 $log.Stage='verifying-complete-adjusted-image-and-tail'
473 525 $log.Verification = Test-XfeAdjustedReadback $source $target ([uint64]$lockedDisk.Size) $workspacePatch
526 if($log.PreservedStockImport){$log.PreservedStockImport.ReplacementVerified=$true}
474 527 $log.Status='verified'
475 528 $log.FinalDiskState='offline'
476 529 Write-Host "Written and read-back verified disk $DiskNumber. GPT backup relocated to the physical disk end. Disk remains OFFLINE; disconnect the USB safely or reboot to UEFI."