prepare full KVM native CI candidate with verified NoAVX boot injection

This commit is contained in:
dh
2026-10-05 13:29:12 +02:00
parent a356b88ae4
commit 5f686c5c80
3 changed files with 179 additions and 18 deletions
@@ -3,6 +3,9 @@ name: PR and Push Build/Test
on:
pull_request:
push:
# The isolated NoAVX candidate uses the existing manual native workflow.
branches-ignore:
- codex/macos-native-full-kvm-noavx
workflow_dispatch:
jobs:
+10 -2
View File
@@ -1,9 +1,15 @@
# macOS 13 KVM/Cryptex diagnostic and prepared Full flow
# macOS 13 KVM/Cryptex/NoAVX diagnostic and prepared Full flow
This separate manual candidate probes Recovery readiness on the existing Ubuntu Docker daemon with KVM, the real Intel host CPU and macOS 13. It does not install macOS, erase a disk, install .NET or Apple CLT, or run Meeting Assistant. Passing proves only a fresh macOS 13+ x86_64 Recovery guest with root identity, a working launchd system domain, DiskArbitration and exactly one writable 64-GiB guest disk.
Baseline: bootstrap commit `4606de069678e8f95dfe3c7dad1bf5ce5384d30c`; separate branch `codex/macos-ci-kvm-compatibility`. KVM, CPU passthrough, Recovery major version and guest Cryptex staging change together. This is a compatibility experiment, not a causal single-variable A/B test. The TCG/bootstrap experiment remains separate.
The isolated Full NoAVX candidate starts at `a356b88ae4a0a26d68098460df86038f9831c080` on `codex/macos-native-full-kvm-noavx`. Its Compatibility code, archive/staging/configuration rejection checks, host-memory admission and captured-proof heartbeat are transferred from the offline-verified Recovery candidate `fef676c810cf78b39aabb872546a76e8ac2b29d5`. The additional NoAVX boot kext is the only guest change. Application/tests/specs, Apple bootstrap/installer, payload/SDK pins, owned-disk guards, TRX requirements, CPU/KVM/macOS 13 and guest/container limits are unchanged. Existing phase budgets remain Recovery 40, installation 80, toolchain 30 and tests 25 minutes within the 172-minute host/180-minute job limits. No successful native run is implied by preparation.
The [upstream NoAVX AVXpel 12.6 ZIP](https://raw.githubusercontent.com/dortania/OpenCore-Legacy-Patcher/f40057a5292f4804b51bcfe78d5047c7302a6434/payloads/Kexts/Misc/NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip) is pinned to OCLP commit `f40057a5292f4804b51bcfe78d5047c7302a6434`, 98,356 bytes and locally verified SHA256 `b5d6319d0a1f335684a92ecf23369bc3deb776be19e92b0a40860021409d20df`. Its two expected bundle files, identity/version and `OSBundleRequired=Root` are verified. After existing Lilu/Cryptex, `Kernel.Add` enables `NoAVXFSCompressionTypeZlib-AVXpel.kext` with `Arch=x86_64`, executable `Contents/MacOS/NoAVXFSCompressionTypeZlib`, plist `Contents/Info.plist`, `MinKernel=22.0.0` and empty `MaxKernel`; both file copies enter the existing SHA256SUMS checks. This is a filesystem-decompression hypothesis, not proof of the current readiness hang's cause.
Memory admission requires the unchanged 4-GiB guest plus 512 MiB QEMU overhead. The copied four fixtures accept run 4204's captured 5,138,696 KiB and reject 4 GiB, missing or invalid availability. This reserves no memory against other host workloads. The existing one-minute heartbeat reads only retained `guest-proof.log`, printing at most its latest two start/completion/result/version markers, capped at 256 characters each; no new guest query or timer is added. Five existing offline fixtures exercise those bounds. Pushes on this candidate branch skip the PR/Push workflow; pull-request and manual triggers remain.
## Reasons and remaining gaps
The existing daemon's Intel Celeron 1037U lacks AVX/AVX2; a separate diagnostic proved KVM enabled/paused state and clean exit. `CPU_MODEL=host` preserves actual instruction availability rather than advertising AVX2 through emulated Skylake. This candidate refuses a TCG or CPU-model fallback.
@@ -23,11 +29,13 @@ Orchestration/validation remain the .NET 10 file-based app `tools/ci/MacOsNative
~~~sh
dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --help
dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --validate
dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --validate --source /path/to/clean/pinned/dockur-clone --cryptex-archive /path/to/CryptexFixup-1.0.5-RELEASE.zip --output /path/to/fresh/validation
dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --validate --source /path/to/clean/pinned/dockur-clone --cryptex-archive /path/to/CryptexFixup-1.0.5-RELEASE.zip --noavx-archive /path/to/NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip --output /path/to/fresh/validation
~~~
`--validate` checks result/container contracts without Docker. With `--source` it verifies the actual Cryptex ZIP/bundle, source seams, generated OpenCore configuration and staging/checksum contracts, checks Bash syntax, then exercises four raw/zlib Recovery fixtures and twelve rejection cases with independent C# CRC32 readback. It also checks preservation of a successful resource snapshot after a later failed capture, leaving the supplied source untouched. It does not download/extract the LongQT ISO, verify a complete Apple Recovery image or execute the active-Lilu runtime checks. The ISO checksum is enforced during the later Docker build; active Lilu and EFI-copy checks execute only during container boot. The optional local Cryptex ZIP must match the release size/hash; omitting it downloads only the public 69,703-byte release. Use a fresh output directory. Dependencies are .NET 10, Git, Bash and Python 3 with its standard library; manual execution also requires the existing Linux/x64 Docker daemon and its existing KVM device.
The optional `--noavx-archive` supplies the exact local NoAVX ZIP; omitting it downloads the pinned small archive. The unchanged NoAVX validation checks staged bytes and actual generated `Kernel.Add`, including four invalid archives, two staging failures and five configuration rejections. Use `--validate --full` with the same arguments to exercise the existing Full bootstrap, installer, disk and TRX contracts as well; `MacOsNativeGuest.cs --validate` checks the unchanged guest payload/tar/fresh-test-result contracts. These checks do not install an SDK or execute Apple frameworks.
The manual-only workflow keeps these owned run/cleanup entry points; validation invokes neither:
~~~sh
+166 -16
View File
@@ -16,6 +16,8 @@ static class NativeDiagnostic
const string DockurCommit = "16a5b470cdd601bae8b05b02d748d7edfb36c12e";
const string CryptexUrl = "https://github.com/acidanthera/CryptexFixup/releases/download/1.0.5/CryptexFixup-1.0.5-RELEASE.zip";
const string CryptexHash = "25041d94a0fe9a0261caf0ba89b36dfcb21682bf3c697a34bcaddc839576ab30";
const string NoAvxUrl = "https://raw.githubusercontent.com/dortania/OpenCore-Legacy-Patcher/f40057a5292f4804b51bcfe78d5047c7302a6434/payloads/Kexts/Misc/NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip";
const string NoAvxHash = "b5d6319d0a1f335684a92ecf23369bc3deb776be19e92b0a40860021409d20df";
const string OpenCoreTemplateHash = "287328995d4198f1b05166f087d85bf7ef66bedafe150d17ad112ac8de60051d";
const string UdifChecksumBindingHash = "6109d04619e800c483fdac363d593cd1cd69f34131d2521417334e11d41c8bfa";
const string OwnerLabel = "org.meeting-assistant.native-diagnostic";
@@ -60,21 +62,25 @@ static class NativeDiagnostic
{
if (args.Length == 0 || args.Contains("--help"))
{
Console.WriteLine("dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --run|--cleanup|--validate [--full] [--output artifacts/native-macos] [--source existing-dockur-clone] [--cryptex-archive verified-release.zip] [--compression-chunk readonly-qualified-chunk]");
Console.WriteLine("dotnet run --file tools/ci/MacOsNativeDiagnostic.cs -- --run|--cleanup|--validate [--full] [--output artifacts/native-macos] [--source existing-dockur-clone] [--cryptex-archive verified-release.zip] [--noavx-archive verified-upstream.zip] [--compression-chunk readonly-qualified-chunk]");
return 0;
}
var output = Path.GetFullPath(Option(args, "--output") ?? "artifacts/native-macos");
var full = args.Contains("--full");
if (args.Contains("--validate"))
{
ValidateRunnerMemoryGate();
ValidateGuestProgress(output);
ValidateContracts();
if (full) ValidateFullContracts();
if (Option(args, "--source") is { } source)
{
await PrepareSource(Path.GetFullPath(source), output, full ? new string('0', 32) : "validation", false, CancellationToken.None, full, Option(args, "--cryptex-archive"));
await PrepareSource(Path.GetFullPath(source), output, full ? new string('0', 32) : "validation", false, CancellationToken.None, full, Option(args, "--cryptex-archive"), Option(args, "--noavx-archive"));
ValidateNoAvxStaging(output);
ValidateNoAvxRejections(output);
await ValidateResourceRetention(output);
await ValidateRecoveryPatch(output);
Save(Path.Combine(output, "validation.json"), new { success = true, profile = "kvm-host-ventura-cryptex", mode = full ? "full" : "readiness", helperSha256 = Hash(File.ReadAllBytes(Path.Combine("tools", "ci", "MacOsNativeDiagnostic.cs"))), udifChecksumBindingSha256 = Hash(File.ReadAllBytes(Path.Combine("tools", "ci", "macos-native-udif-checksums.py"))), baselineReadinessNormalized = true, resultNegativeCases = 6, containerNegativeCases = 11, recoveryPositiveCases = 4, recoveryNegativeCases = 12, independentFixtureCrc32Readback = true, resourceSnapshotRetention = true, cryptexArchiveVerified = true, configurationAndStagingContractsVerified = true, templateIsoDownloaded = false, activeLiluRuntimeChecked = false, sourceModified = false, dockerExecuted = false, guestExecuted = false, completedUtc = DateTimeOffset.UtcNow });
Save(Path.Combine(output, "validation.json"), new { success = true, profile = "kvm-host-ventura-cryptex-noavx", mode = full ? "full" : "readiness", helperSha256 = Hash(File.ReadAllBytes(Path.Combine("tools", "ci", "MacOsNativeDiagnostic.cs"))), udifChecksumBindingSha256 = Hash(File.ReadAllBytes(Path.Combine("tools", "ci", "macos-native-udif-checksums.py"))), baselineReadinessNormalized = true, resultNegativeCases = 6, containerNegativeCases = 11, recoveryPositiveCases = 4, recoveryNegativeCases = 12, independentFixtureCrc32Readback = true, resourceSnapshotRetention = true, cryptexArchiveVerified = true, noAvxArchiveVerified = true, configurationAndStagingContractsVerified = true, templateIsoDownloaded = false, activeLiluRuntimeChecked = false, sourceModified = false, dockerExecuted = false, guestExecuted = false, completedUtc = DateTimeOffset.UtcNow });
}
if (full) await ValidateDiskSerialParser(output);
if (Option(args, "--compression-chunk") is { } chunk)
@@ -108,7 +114,7 @@ static class NativeDiagnostic
throw new InvalidOperationException("This diagnostic runs on the existing Linux/x64 runner only.");
ValidateContracts();
var sourceCommit = (await Command("git", ["rev-parse", "HEAD"], output, "candidate-commit", deadline.Token)).Output.Trim();
Save(Path.Combine(output, "run-metadata.json"), new { token, startedUtc = DateTimeOffset.UtcNow, sourceCommit, dockurCommit = DockurCommit, profile = "kvm-host-ventura-cryptex", causalSingleVariableTest = false, kvm = true, cpuModel = "host", recoveryMajor = 13, cryptexVersion = "1.0.5", liluVersion = "1.7.1", runId = Environment.GetEnvironmentVariable("GITHUB_RUN_ID"), server = Environment.GetEnvironmentVariable("GITHUB_SERVER_URL"), architecture = RuntimeInformation.ProcessArchitecture.ToString(), deadlineMinutes, mode = full ? "full" : "readiness" });
Save(Path.Combine(output, "run-metadata.json"), new { token, startedUtc = DateTimeOffset.UtcNow, sourceCommit, dockurCommit = DockurCommit, profile = "kvm-host-ventura-cryptex-noavx", causalSingleVariableTest = true, comparisonBaselineCommit = "a356b88ae4a0a26d68098460df86038f9831c080", kvm = true, cpuModel = "host", recoveryMajor = 13, cryptexVersion = "1.0.5", liluVersion = "1.7.1", noAvxBaseVersion = "12.6", noAvxSha256 = NoAvxHash, runId = Environment.GetEnvironmentVariable("GITHUB_RUN_ID"), server = Environment.GetEnvironmentVariable("GITHUB_SERVER_URL"), architecture = RuntimeInformation.ProcessArchitecture.ToString(), deadlineMinutes, mode = full ? "full" : "readiness" });
var info = await Command("docker", ["info", "--format", "{{json .}}"], output, "docker-info", deadline.Token);
using (var document = JsonDocument.Parse(info.Output))
{
@@ -119,16 +125,15 @@ static class NativeDiagnostic
throw new InvalidOperationException("Existing Docker resources cannot fit this bounded 2-CPU/6-GiB diagnostic; no infrastructure change was requested.");
}
await Command("sh", ["-c", "cat /proc/meminfo; printf '\n[cgroup]\n'; cat /sys/fs/cgroup/memory.max /sys/fs/cgroup/cpu.max 2>/dev/null || true; printf '\n[workspace disk]\n'; df -Pk ."], output, "runner-resources", deadline.Token);
var available = System.Text.RegularExpressions.Regex.Match(File.ReadAllText("/proc/meminfo"), @"(?m)^MemAvailable:\s+(\d+) kB$");
if (!available.Success || long.Parse(available.Groups[1].Value) < 5L * 1024 * 1024)
throw new InvalidOperationException("Existing runner memory has less than the 5-GiB available diagnostic budget; no infrastructure change was requested.");
if (!HasAvailableGuestMemory(File.ReadAllText("/proc/meminfo")))
throw new InvalidOperationException("Existing runner memory cannot fit the 4-GiB guest plus its 512-MiB QEMU overhead budget; no infrastructure change was requested.");
var source = Path.Combine(work, "dockur");
await Command("git", ["clone", "--no-checkout", "https://github.com/dockur/macos.git", source], output, "dockur-clone", deadline.Token);
await Command("git", ["-C", source, "checkout", "--detach", DockurCommit], output, "dockur-checkout", deadline.Token);
var actualCommit = (await Command("git", ["-C", source, "rev-parse", "HEAD"], output, "dockur-commit", deadline.Token)).Output.Trim();
if (actualCommit != DockurCommit) throw new InvalidOperationException("Dockur source pin mismatch.");
if (full) await PreparePayload(source, output, token, sourceCommit, deadline.Token);
await PrepareSource(source, output, token, true, deadline.Token, full, Option(args, "--cryptex-archive"));
await PrepareSource(source, output, token, true, deadline.Token, full, Option(args, "--cryptex-archive"), Option(args, "--noavx-archive"));
await Command("docker", ["build", "--platform", "linux/amd64", "--label", OwnerLabel + "=" + token, "--tag", state.ImageTag, source], output, "docker-build", deadline.Token, echo: true);
var imageInspect = await Command("docker", ["image", "inspect", state.ImageTag], output, "image-inspect", deadline.Token);
using (var image = JsonDocument.Parse(imageInspect.Output))
@@ -204,6 +209,7 @@ static class NativeDiagnostic
if (heartbeat.Elapsed >= TimeSpan.FromSeconds(60))
{
Console.WriteLine($"[native-diagnostic] phase={phase}; elapsed={phaseStarted.Elapsed.TotalMinutes:F1}/{phaseBudget.TotalMinutes:F0} minutes; container=running; readiness={(permitted ? "passed" : "pending")}");
foreach (var progress in LastGuestProgress(Path.Combine(output, "guest-proof.log"))) Console.WriteLine("[native-diagnostic] guest-progress=" + progress);
heartbeat.Restart();
}
await Task.Delay(TimeSpan.FromSeconds(20), deadline.Token);
@@ -267,7 +273,7 @@ static class NativeDiagnostic
}
}
static async Task PrepareSource(string source, string output, string token, bool writeSource, CancellationToken cancellation, bool full = false, string? cryptexArchive = null)
static async Task PrepareSource(string source, string output, string token, bool writeSource, CancellationToken cancellation, bool full = false, string? cryptexArchive = null, string? noAvxArchive = null)
{
Directory.CreateDirectory(output);
var patchPath = Path.Combine(source, "src/install/recovery/patch.py");
@@ -285,7 +291,7 @@ static class NativeDiagnostic
var dockerfile = ReplaceOnce(File.ReadAllText(dockerPath), "FROM scratch AS base\nCOPY --from=qemux/qemu:7.50 --exclude=usr/bin/qemu-system-x86_64 / /\n", "FROM qemux/qemu:7.50@sha256:e7f6fda52503a546fd649670ba46e4bc23dc6dcef275bc3fac48877fbbc430df AS base\n");
dockerfile = ReplaceAllExact(dockerfile, "--from=qemux/qemu-macos:latest ", "--from=qemux/qemu-macos:latest@sha256:af64297171228f27d5f616249e18f6ad5e2fbc79c1cc517252521e8bcd8eadaa ", 2);
dockerfile = ReplaceOnce(dockerfile, "ADD $REPO_KVM_OPENCORE/releases/download/v$VERSION_KVM_OPENCORE/LongQT-OpenCore-v$VERSION_KVM_OPENCORE.iso /opencore.iso", "ADD --checksum=sha256:" + OpenCoreTemplateHash + " $REPO_KVM_OPENCORE/releases/download/v$VERSION_KVM_OPENCORE/LongQT-OpenCore-v$VERSION_KVM_OPENCORE.iso /opencore.iso");
var compatibility = await PrepareCompatibility(source, output, cryptexArchive, cancellation);
var compatibility = await PrepareCompatibility(source, output, cryptexArchive, noAvxArchive, cancellation);
var entryPath = Path.Combine(source, "src/entry.sh");
var entry = ReplaceOnce(File.ReadAllText(entryPath), "set -Eeuo pipefail\n", "set -Eeuo pipefail\n\n# Diagnostic budget: inspect existing Docker storage before Recovery download/boot.\ndf -Pk /storage\nfree_kib=$(df -Pk /storage | awk 'NR==2 {print $4}')\n[[ \"$free_kib\" =~ ^[0-9]+$ ]] && (( free_kib >= 8 * 1024 * 1024 )) || { echo 'Existing Docker storage has less than the 8-GiB diagnostic budget.' >&2; exit 1; }\n");
entry = ReplaceOnce(entry, ". init.sh # Initialize system\n", ". init.sh # Initialize system\n# Fail before Apple downloads if the existing daemon cannot retain this profile.\nenabled \"$KVM\" && [[ \"$CPU_MODEL\" == host && \"$VERSION\" == 13 ]] && grep -Eq '^vendor_id[[:space:]]*:[[:space:]]*GenuineIntel$' /proc/cpuinfo || { error 'Compatibility probe requires existing Intel KVM and the exact host/13 profile.'; exit 1; }\n");
@@ -379,7 +385,7 @@ static class NativeDiagnostic
return string.Join("\n", lines.Select(line => new string(' ', spaces) + (line.Length > 0 ? line[common..] : "")));
}
static async Task<(string Boot, string Config, string Assets)> PrepareCompatibility(string source, string output, string? archivePath, CancellationToken cancellation)
static async Task<(string Boot, string Config, string Assets)> PrepareCompatibility(string source, string output, string? archivePath, string? noAvxArchivePath, CancellationToken cancellation)
{
var boot = File.ReadAllText(Path.Combine(source, "src", "boot.sh"));
var config = File.ReadAllText(Path.Combine(source, "assets", "config.plist"));
@@ -410,24 +416,109 @@ static class NativeDiagnostic
var info = XDocument.Load(Path.Combine(assets, required[0])).Root!.Element("dict")!;
if (PlistValue(info, "CFBundleIdentifier").Value != "com.khronokernel.CryptexFixup" || PlistValue(info, "CFBundleVersion").Value != "1.0.5" || PlistValue(info, "CFBundleExecutable").Value != "CryptexFixup" || PlistValue(PlistValue(info, "OSBundleLibraries"), "as.vit9696.Lilu").Value != "1.4.7") throw new InvalidOperationException("Cryptex bundle identity/version/Lilu dependency mismatch.");
var fileHashes = required.ToDictionary(name => name, name => Hash(File.ReadAllBytes(Path.Combine(assets, name))));
byte[] noAvxBytes;
if (noAvxArchivePath is not null) noAvxBytes = await File.ReadAllBytesAsync(noAvxArchivePath, cancellation);
else
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30), MaxResponseContentBufferSize = 2 * 1024 * 1024 };
noAvxBytes = await client.GetByteArrayAsync(NoAvxUrl, cancellation);
}
var noAvxFiles = ReadNoAvxArchive(noAvxBytes);
File.WriteAllBytes(Path.Combine(output, "NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip"), noAvxBytes);
foreach (var (name, content) in noAvxFiles)
{
var destination = Path.Combine(assets, name);
Directory.CreateDirectory(Path.GetDirectoryName(destination)!);
File.WriteAllBytes(destination, content);
fileHashes.Add(name, Hash(content));
}
File.WriteAllText(Path.Combine(assets, "SHA256SUMS"), string.Concat(fileHashes.Select(pair => pair.Value + " " + pair.Key + "\n")), new UTF8Encoding(false));
Save(Path.Combine(output, "compatibility-boot-assets.json"), new { cryptexUrl = CryptexUrl, cryptexSha256 = CryptexHash, cryptexBytes = bytes.Length, cryptexFiles = fileHashes, templateUrl = "https://github.com/LongQT-sea/OpenCore-ISO/releases/download/v0.7/LongQT-OpenCore-v0.7.iso", templateSha256 = OpenCoreTemplateHash, templateBytes = 15884288, liluVersion = "1.7.1", liluBinarySha256 = "0c016d93cfe40c7fa3965813175c1b991a76f3d295efd5be66ae712b4a3ffb52", liluBinaryBytes = 526984, liluInfoSha256 = "fc885f3319f326e3af60e7965a5216b671772d39d40993ec695758bb43d6ea3a", causalSingleVariableTest = false });
Save(Path.Combine(output, "compatibility-boot-assets.json"), new { cryptexUrl = CryptexUrl, cryptexSha256 = CryptexHash, cryptexBytes = bytes.Length, compatibilityFiles = fileHashes, noAvxUrl = NoAvxUrl, noAvxSha256 = NoAvxHash, noAvxBytes = noAvxBytes.Length, noAvxBaseVersion = "12.6", noAvxMinimumDarwin = "22.0.0", noAvxRequired = "Root", templateUrl = "https://github.com/LongQT-sea/OpenCore-ISO/releases/download/v0.7/LongQT-OpenCore-v0.7.iso", templateSha256 = OpenCoreTemplateHash, templateBytes = 15884288, liluVersion = "1.7.1", liluBinarySha256 = "0c016d93cfe40c7fa3965813175c1b991a76f3d295efd5be66ae712b4a3ffb52", liluBinaryBytes = 526984, liluInfoSha256 = "fc885f3319f326e3af60e7965a5216b671772d39d40993ec695758bb43d6ea3a", causalSingleVariableTest = true, comparisonBaselineCommit = "a356b88ae4a0a26d68098460df86038f9831c080", changedBootAsset = "NoAVXFSCompressionTypeZlib-AVXpel.kext" });
var document = XDocument.Parse(config, LoadOptions.PreserveWhitespace);
var add = PlistValue(PlistValue(document.Root!.Element("dict")!, "Kernel"), "Add");
var expected = new[] { "Lilu.kext", "VMHide.kext", "VirtualSMC.kext", "WhateverGreen.kext", "VoodooPS2Controller.kext", "VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Keyboard.kext", "AppleMCEReporterDisabler.kext" };
if (!add.Elements("dict").Select(dict => PlistValue(dict, "BundlePath").Value).SequenceEqual(expected) || add.Elements("dict").Any(dict => PlistValue(dict, "Enabled").Name != "true")) throw new InvalidOperationException("Pinned Kernel.Add order/enabled contract mismatch.");
var cryptex = XElement.Parse("<dict><key>Arch</key><string>x86_64</string><key>BundlePath</key><string>CryptexFixup.kext</string><key>Comment</key><string>Official CryptexFixup 1.0.5; owned compatibility guest only</string><key>Enabled</key><true/><key>ExecutablePath</key><string>Contents/MacOS/CryptexFixup</string><key>MaxKernel</key><string></string><key>MinKernel</key><string>22.0.0</string><key>PlistPath</key><string>Contents/Info.plist</string></dict>");
add.Elements("dict").First().AddAfterSelf(cryptex);
cryptex.AddAfterSelf(XElement.Parse("<dict><key>Arch</key><string>x86_64</string><key>BundlePath</key><string>NoAVXFSCompressionTypeZlib-AVXpel.kext</string><key>Comment</key><string>OCLP 2.5.1 AVXpel 12.6; Ventura filesystem compression hypothesis</string><key>Enabled</key><true/><key>ExecutablePath</key><string>Contents/MacOS/NoAVXFSCompressionTypeZlib</string><key>MaxKernel</key><string></string><key>MinKernel</key><string>22.0.0</string><key>PlistPath</key><string>Contents/Info.plist</string></dict>"));
var bootArguments = PlistValue(PlistValue(PlistValue(PlistValue(document.Root.Element("dict")!, "NVRAM"), "Add"), "7C436110-AB2A-4BBB-A880-FE41995C9F82"), "boot-args").Value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (bootArguments.Intersect(new[] { "-cryptoff", "-liluoff", "-crypt_allow_hash_validation", "-crypt_force_avx", "-cryptbeta", "-lilubetaall" }).Any()) throw new InvalidOperationException("Unexpected Cryptex/Lilu disabling or forcing boot argument.");
boot = ReplaceOnce(boot, " cp -a \"$template/OC/Resources\" \"$EFI_DIR/OC/\"\n", " cp -a \"$template/OC/Resources\" \"$EFI_DIR/OC/\"\n" + CompatibilityStaging + "\n");
boot = ReplaceOnce(boot, " PLIST=\"/assets/config.plist\"\n", " [ ! -e /custom.plist ] || { error 'Compatibility profile refuses an unverified custom OpenCore config!'; exit 12; }\n PLIST=\"/assets/config.plist\"\n");
boot = ReplaceOnce(boot, " checkOpenCoreConfig\n addVmHideKext\n", " checkOpenCoreConfig\n" + CompatibilityConfigCheck + "\n addVmHideKext\n");
boot = ReplaceOnce(boot, " if [ -s \"$target\" ] && [ \"$previous\" = \"$current\" ]; then\n IMG=\"$target\"\n return 0\n fi\n", " # This owned compatibility probe always rebuilds; never trust a cached boot.img.\n");
boot = ReplaceOnce(boot, " echo \"VMHIDE=$vmhide\"\n", " echo \"VMHIDE=$vmhide\"\n echo \"COMPATIBILITY=kvm-host-ventura-cryptex\"\n sha256sum /assets/native-compatibility/SHA256SUMS\n");
boot = ReplaceOnce(boot, " echo \"VMHIDE=$vmhide\"\n", " echo \"VMHIDE=$vmhide\"\n echo \"COMPATIBILITY=kvm-host-ventura-cryptex-noavx\"\n sha256sum /assets/native-compatibility/SHA256SUMS\n");
return (boot, document.ToString(), assets);
}
static bool HasAvailableGuestMemory(string meminfo)
{
var available = System.Text.RegularExpressions.Regex.Match(meminfo, @"(?m)^MemAvailable:\s+(\d+) kB$");
return available.Success && long.TryParse(available.Groups[1].Value, out var kib) && kib >= 4L * 1024 * 1024 + 512L * 1024;
}
static string[] LastGuestProgress(string path)
{
if (!File.Exists(path)) return [];
var markers = new[] { "[proof-start]", "[proof-done]", "[proof-native-wait]", "[proof-result]", "[native-version]" };
return File.ReadLines(path).Where(line => markers.Any(marker => line.StartsWith(marker, StringComparison.Ordinal)))
.TakeLast(2).Select(line => line[..Math.Min(line.Length, 256)]).ToArray();
}
static void ValidateGuestProgress(string output)
{
var fixture = Path.Combine(output, "validation-guest-progress");
Directory.CreateDirectory(fixture);
var path = Path.Combine(fixture, "guest-proof.log");
File.Delete(path);
if (LastGuestProgress(path).Length != 0) throw new InvalidOperationException("Missing guest progress was fabricated.");
File.WriteAllText(path, "[proof-start] platform child=12\nignored native output\n[proof-native-wait] platform exit=0\n[proof-start] uid child=13\n", new UTF8Encoding(false));
if (!LastGuestProgress(path).SequenceEqual(new[] { "[proof-native-wait] platform exit=0", "[proof-start] uid child=13" })) throw new InvalidOperationException("Heartbeat must show the last two captured native progress markers.");
File.WriteAllText(path, "[proof-done] uid\n[native-version] 13.6\n[proof-result] true: readiness\n", new UTF8Encoding(false));
if (!LastGuestProgress(path).SequenceEqual(new[] { "[native-version] 13.6", "[proof-result] true: readiness" })) throw new InvalidOperationException("Heartbeat lost native version/result progress.");
File.WriteAllText(path, "[proof-start] " + new string('x', 1024) + "\n", new UTF8Encoding(false));
if (LastGuestProgress(path).Single().Length != 256) throw new InvalidOperationException("Heartbeat progress line exceeded its output bound.");
File.WriteAllText(path, "unrelated output\n", new UTF8Encoding(false));
if (LastGuestProgress(path).Length != 0) throw new InvalidOperationException("Heartbeat selected unrelated guest output.");
Save(Path.Combine(fixture, "receipt.json"), new { success = true, fixtureCases = 5, maximumLines = 2, maximumLineCharacters = 256, existingProofOnly = true, dockerExecuted = false, guestExecuted = false });
}
static void ValidateRunnerMemoryGate()
{
// Run 4204: 4-GiB guest plus 512-MiB QEMU overhead fits its captured available memory.
var cases = new[]
{
("captured-run4204", "MemTotal: 16281732 kB\nMemAvailable: 5138696 kB\n", true),
("below-guest-plus-overhead", "MemAvailable: 4194304 kB\n", false),
("missing", "MemTotal: 16281732 kB\n", false),
("invalid", "MemAvailable: unavailable kB\n", false)
};
foreach (var (name, meminfo, expected) in cases)
if (HasAvailableGuestMemory(meminfo) != expected)
throw new InvalidOperationException("Existing runner memory admission failed: " + name);
}
static Dictionary<string, byte[]> ReadNoAvxArchive(byte[] bytes)
{
if (bytes.Length != 98356 || Hash(bytes) != NoAvxHash) throw new InvalidOperationException("Pinned OCLP NoAVX archive size/hash mismatch.");
using var archive = new ZipArchive(new MemoryStream(bytes), ZipArchiveMode.Read);
var required = new[] { "NoAVXFSCompressionTypeZlib-AVXpel.kext/Contents/Info.plist", "NoAVXFSCompressionTypeZlib-AVXpel.kext/Contents/MacOS/NoAVXFSCompressionTypeZlib" };
var entries = archive.Entries.Where(entry => entry.FullName.StartsWith("NoAVXFSCompressionTypeZlib-AVXpel.kext/", StringComparison.Ordinal) && !entry.FullName.EndsWith('/')).ToArray();
if (entries.Length != 2 || required.Any(name => entries.Count(entry => entry.FullName == name) != 1) || entries.Any(entry => entry.Length <= 0 || entry.Length > 1024 * 1024)) throw new InvalidOperationException("NoAVX archive layout/size mismatch.");
var files = new Dictionary<string, byte[]>();
foreach (var entry in entries)
{
using var input = entry.Open();
using var content = new MemoryStream();
input.CopyTo(content);
if (content.Length != entry.Length) throw new InvalidOperationException("NoAVX archive entry length mismatch.");
files.Add(entry.FullName, content.ToArray());
}
var info = XDocument.Parse(Encoding.UTF8.GetString(files[required[0]])).Root!.Element("dict")!;
if (PlistValue(info, "CFBundleIdentifier").Value != "com.apple.AppleFSCompression.NoAVXFSCompressionTypeZlib" || PlistValue(info, "CFBundleExecutable").Value != "NoAVXFSCompressionTypeZlib" || PlistValue(info, "CFBundleVersion").Value != "1.0.0" || PlistValue(info, "CFBundleShortVersionString").Value != "132.100.2" || PlistValue(info, "OSBundleRequired").Value != "Root") throw new InvalidOperationException("NoAVX bundle identity/version/root requirement mismatch.");
return files;
}
static XElement PlistValue(XElement dictionary, string key)
{
var keys = dictionary.Elements("key").Where(element => element.Value == key).ToArray();
@@ -435,6 +526,59 @@ static class NativeDiagnostic
return value;
}
static void ValidateNoAvxStaging(string output)
{
var root = Path.Combine(output, "compatibility-assets", "NoAVXFSCompressionTypeZlib-AVXpel.kext", "Contents");
if (!File.Exists(Path.Combine(root, "Info.plist")) || !File.Exists(Path.Combine(root, "MacOS", "NoAVXFSCompressionTypeZlib")))
throw new InvalidOperationException("Offline validation requires the staged NoAVX bundle, with its upstream executable path.");
var files = ReadNoAvxArchive(File.ReadAllBytes(Path.Combine(output, "NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip")));
foreach (var (name, content) in files)
if (!File.ReadAllBytes(Path.Combine(output, "compatibility-assets", name)).SequenceEqual(content)) throw new InvalidOperationException("Staged NoAVX bytes differ from the pinned archive.");
var document = XDocument.Load(Path.Combine(output, "opencore-config.plist"));
ValidateNoAvxConfig(document);
}
static void ValidateNoAvxConfig(XDocument document)
{
var add = PlistValue(PlistValue(document.Root!.Element("dict")!, "Kernel"), "Add");
var entries = add.Elements("dict").ToArray();
var expected = new[] { "Lilu.kext", "CryptexFixup.kext", "NoAVXFSCompressionTypeZlib-AVXpel.kext", "VMHide.kext", "VirtualSMC.kext", "WhateverGreen.kext", "VoodooPS2Controller.kext", "VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Keyboard.kext", "AppleMCEReporterDisabler.kext" };
if (!entries.Select(dict => PlistValue(dict, "BundlePath").Value).SequenceEqual(expected) || entries.Any(dict => PlistValue(dict, "Enabled").Name != "true"))
throw new InvalidOperationException("Actual OpenCore Kernel.Add order or enabled contract mismatch.");
var noAvx = entries[2];
if (PlistValue(noAvx, "Arch").Value != "x86_64" || PlistValue(noAvx, "ExecutablePath").Value != "Contents/MacOS/NoAVXFSCompressionTypeZlib" || PlistValue(noAvx, "PlistPath").Value != "Contents/Info.plist" || PlistValue(noAvx, "MinKernel").Value != "22.0.0" || PlistValue(noAvx, "MaxKernel").Value != "")
throw new InvalidOperationException("Actual NoAVX Kernel.Add paths, architecture or Darwin bounds mismatch.");
}
static void ValidateNoAvxRejections(string output)
{
static void Reject(Action validation, string name)
{
try { validation(); } catch (InvalidOperationException) { return; }
throw new InvalidOperationException("NoAVX validator accepted invalid " + name);
}
var bytes = File.ReadAllBytes(Path.Combine(output, "NoAVXFSCompressionTypeZlib-AVXpel-v12.6.zip"));
var corrupt = (byte[])bytes.Clone();
corrupt[corrupt.Length / 2] ^= 1;
foreach (var invalid in new[] { Array.Empty<byte>(), bytes[..^1], bytes.Concat(new byte[] { 0 }).ToArray(), corrupt }) Reject(() => ReadNoAvxArchive(invalid), "archive size/hash");
var staged = Path.Combine(output, "compatibility-assets", "NoAVXFSCompressionTypeZlib-AVXpel.kext", "Contents", "MacOS", "NoAVXFSCompressionTypeZlib");
var original = File.ReadAllBytes(staged);
try
{
File.Delete(staged);
Reject(() => ValidateNoAvxStaging(output), "missing staging executable");
var changed = (byte[])original.Clone();
changed[0] ^= 1;
File.WriteAllBytes(staged, changed);
Reject(() => ValidateNoAvxStaging(output), "changed staging executable");
}
finally { File.WriteAllBytes(staged, original); }
var config = File.ReadAllText(Path.Combine(output, "opencore-config.plist"));
foreach (var invalid in new[] { config.Replace("NoAVXFSCompressionTypeZlib-AVXpel.kext", "Wrong.kext", StringComparison.Ordinal), config.Replace("Contents/MacOS/NoAVXFSCompressionTypeZlib", "Contents/MacOS/NoAVXFSCompressionTypeZlib-AVXpel", StringComparison.Ordinal), config.Replace("22.0.0", "21.0.0", StringComparison.Ordinal), config.Replace("<true", "<false", StringComparison.Ordinal), config.Replace("<string>x86_64</string>", "<string>arm64</string>", StringComparison.Ordinal) }) Reject(() => ValidateNoAvxConfig(XDocument.Parse(invalid)), "Kernel.Add");
ValidateNoAvxStaging(output);
Save(Path.Combine(output, "noavx-validation.json"), new { success = true, archiveNegativeCases = 4, stagingNegativeCases = 2, kernelAddNegativeCases = 5, archiveSha256 = NoAvxHash, actualStagedBytesVerified = true, actualGeneratedKernelAddVerified = true, dockerExecuted = false, guestExecuted = false });
}
const string CompatibilityStaging = """
# Only the freshly extracted, owned guest EFI is changed; never the host.
local lilu="$EFI_DIR/OC/Kexts/Lilu.kext/Contents"
@@ -443,23 +587,29 @@ static class NativeDiagnostic
0c016d93cfe40c7fa3965813175c1b991a76f3d295efd5be66ae712b4a3ffb52 "$lilu/MacOS/Lilu" | sha256sum -c - || { error "Pinned active Lilu files mismatch!"; exit 12; }
[ "$(xmlstarlet sel -T -t -v '/plist/dict/key[.="CFBundleVersion"]/following-sibling::string[1]' "$lilu/Info.plist")" = 1.7.1 ] || { error "Active Lilu version mismatch!"; exit 12; }
[ ! -e "$EFI_DIR/OC/Kexts/CryptexFixup.kext" ] || { error "Unexpected pre-existing Cryptex kext!"; exit 12; }
[ ! -e "$EFI_DIR/OC/Kexts/NoAVXFSCompressionTypeZlib-AVXpel.kext" ] || { error "Unexpected pre-existing NoAVX kext!"; exit 12; }
(cd /assets/native-compatibility && sha256sum -c SHA256SUMS) || { error "Pinned Cryptex staging files mismatch!"; exit 12; }
cp -a /assets/native-compatibility/CryptexFixup.kext "$EFI_DIR/OC/Kexts/"
cp -a /assets/native-compatibility/NoAVXFSCompressionTypeZlib-AVXpel.kext "$EFI_DIR/OC/Kexts/"
(cd "$EFI_DIR/OC/Kexts" && sha256sum -c /assets/native-compatibility/SHA256SUMS) || { error "Active Cryptex copy mismatch!"; exit 12; }
info "[compatibility-boot] Lilu=1.7.1 CryptexFixup=1.0.5 files=verified; guest injection and Recovery readiness remain unproved"
info "[compatibility-boot] Lilu=1.7.1 CryptexFixup=1.0.5 NoAVX=AVXpel-12.6 files=verified; guest injection and Recovery readiness remain unproved"
""";
const string CompatibilityConfigCheck = """
local kernel='/plist/dict/key[.="Kernel"]/following-sibling::dict[1]/key[.="Add"]/following-sibling::array[1]'
local actual expected
actual=$(xmlstarlet sel -T -t -m "$kernel/dict" -v 'key[.="BundlePath"]/following-sibling::string[1]' -n "$CFG") || exit 12
expected=$(printf '%s\n' Lilu.kext CryptexFixup.kext VMHide.kext VirtualSMC.kext WhateverGreen.kext VoodooPS2Controller.kext VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Keyboard.kext AppleMCEReporterDisabler.kext)
expected=$(printf '%s\n' Lilu.kext CryptexFixup.kext NoAVXFSCompressionTypeZlib-AVXpel.kext VMHide.kext VirtualSMC.kext WhateverGreen.kext VoodooPS2Controller.kext VoodooPS2Controller.kext/Contents/PlugIns/VoodooPS2Keyboard.kext AppleMCEReporterDisabler.kext)
[ "$actual" = "$expected" ] || { error "Active Kernel.Add order mismatch!"; exit 12; }
[ "$(xmlstarlet sel -T -t -v "name($kernel/dict[1]/key[.='Enabled']/following-sibling::*[1])" -v "name($kernel/dict[2]/key[.='Enabled']/following-sibling::*[1])" "$CFG")" = truetrue ] || { error "Active Lilu/Cryptex must both be enabled!"; exit 12; }
actual=$(xmlstarlet sel -T -t -m "$kernel/dict[2]" -v 'key[.="Arch"]/following-sibling::string[1]' -n -v 'key[.="ExecutablePath"]/following-sibling::string[1]' -n -v 'key[.="PlistPath"]/following-sibling::string[1]' -n -v 'key[.="MinKernel"]/following-sibling::string[1]' -n -v 'key[.="MaxKernel"]/following-sibling::string[1]' "$CFG") || exit 12
expected=$(printf '%s\n' x86_64 Contents/MacOS/CryptexFixup Contents/Info.plist 22.0.0 '')
[ "$actual" = "$expected" ] || { error "Active Cryptex Kernel.Add paths/architecture/Darwin bounds mismatch!"; exit 12; }
info "[compatibility-config] Kernel.Add=Lilu,CryptexFixup before remaining baseline kexts; MinKernel=22.0.0 MaxKernel=empty"
[ "$(xmlstarlet sel -T -t -v "name($kernel/dict[3]/key[.='Enabled']/following-sibling::*[1])" "$CFG")" = true ] || { error "Active NoAVX must be enabled!"; exit 12; }
actual=$(xmlstarlet sel -T -t -m "$kernel/dict[3]" -v 'key[.="Arch"]/following-sibling::string[1]' -n -v 'key[.="ExecutablePath"]/following-sibling::string[1]' -n -v 'key[.="PlistPath"]/following-sibling::string[1]' -n -v 'key[.="MinKernel"]/following-sibling::string[1]' -n -v 'key[.="MaxKernel"]/following-sibling::string[1]' "$CFG") || exit 12
expected=$(printf '%s\n' x86_64 Contents/MacOS/NoAVXFSCompressionTypeZlib Contents/Info.plist 22.0.0 '')
[ "$actual" = "$expected" ] || { error "Active NoAVX Kernel.Add paths/architecture/Darwin bounds mismatch!"; exit 12; }
info "[compatibility-config] Kernel.Add=Lilu,CryptexFixup,NoAVX before remaining baseline kexts; MinKernel=22.0.0 MaxKernel=empty"
""";
static string ReplaceOnce(string text, string oldValue, string newValue) => ReplaceAllExact(text, oldValue, newValue, 1);