Bundle native voice runtimes in Windows releases (#44922)

## Why

Windows release packages need the voice helper and native audio libraries. Realtime TLS connections on fresh Windows installations also need platform certificate validation so Windows can retrieve missing trusted roots on demand.

## What changed

- Build and sign the voice helper and audio DLLs for Windows x64 and ARM64, bundle a pinned Microsoft CRT DLL, and verify signatures and runtime receipts before packaging.
- Add verified, pinned Cygwin and native build tools plus MSVC linker, compiler, and path handling fixes for the Windows Bazel builds.
- Include voice resources in primary release archives and WinGet packages. Preserve WinGet executable names, update manifest hashes, and recognize the package root through matching entrypoint metadata. Keep Python runtime wheels voice-free to preserve their existing Windows support floor.
- Use Windows platform TLS validation for realtime WebSockets when no custom CA bundle is configured, preserving custom CA behavior.

## Testing

Add coverage for build-input integrity and unsafe paths, signed Windows runtime assembly, WinGet file and hash preservation, package discovery, and TLS trust selection, untrusted certificate rejection, and hostname validation.

GitOrigin-RevId: 423da35872fa5549d69fd4ca97d922bb49599386
This commit is contained in:
Benjamin Carlsson
2026-09-11 21:59:24 +00:00
committed by copyberry
parent 3f59eb965a
commit ce7fbb373b
38 changed files with 1629 additions and 46 deletions
+37
View File
@@ -0,0 +1,37 @@
"""Adapt an extracted signed Windows package to WinGet's existing root filenames."""
import argparse
import json
import shutil
from pathlib import Path
def prepare_winget_package(package: Path) -> None:
metadata_path = package / "codex-package.json"
metadata = json.loads(metadata_path.read_text(encoding="utf-8"))
target = metadata["target"]
if target not in ("x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"):
raise ValueError("WinGet requires a Windows package")
if metadata["entrypoint"] != "bin/codex.exe":
raise ValueError("WinGet requires the canonical Codex entrypoint")
entrypoint = f"codex-{target}.exe"
manifest_path = package / "codex-resources/voice/manifest.json"
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
manifest["sha256"][entrypoint] = manifest["sha256"].pop("bin/codex.exe")
(package / "bin/codex.exe").rename(package / entrypoint)
(package / "bin/codex-code-mode-host.exe").rename(
package / "codex-code-mode-host.exe"
)
# Keep resources in place for package-aware discovery and provide the root
# filenames declared by the existing WinGet portable installer manifest.
for helper in ("codex-command-runner.exe", "codex-windows-sandbox-setup.exe"):
shutil.copy2(package / "codex-resources" / helper, package / helper)
metadata["entrypoint"] = entrypoint
for path, value in ((metadata_path, metadata), (manifest_path, manifest)):
path.write_text(json.dumps(value, indent=2) + "\n", encoding="utf-8")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("package", type=Path)
prepare_winget_package(parser.parse_args().package)
+66
View File
@@ -1,12 +1,15 @@
#!/usr/bin/env python3
from pathlib import Path
import hashlib
import json
import sys
import tempfile
import unittest
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from build_winget_package import prepare_winget_package
from codex_package.layout import build_package_dir
from codex_package.layout import validate_package_dir
from codex_package.targets import PACKAGE_VARIANTS
@@ -15,6 +18,69 @@ from codex_package.targets import TARGET_SPECS
class PackageLayoutTest(unittest.TestCase):
def test_winget_preserves_signed_files_and_voice_hashes(self) -> None:
for target in ("x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"):
with self.subTest(target=target), tempfile.TemporaryDirectory() as temp:
package = Path(temp)
files = {
"bin/codex.exe": b"signed CLI",
"bin/codex-code-mode-host.exe": b"signed code mode host",
"codex-resources/codex-command-runner.exe": b"signed runner",
"codex-resources/codex-windows-sandbox-setup.exe": b"signed setup",
"codex-resources/voice/bin/codex-voice-host.exe": b"signed voice host",
"codex-resources/voice/bin/gstreamer-1.0-0.dll": b"signed audio DLL",
"codex-resources/voice/NOTICE.md": b"license notices",
"codex-path/rg.exe": b"ripgrep",
}
for name, contents in files.items():
path = package / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(contents)
metadata = {
"layoutVersion": 1,
"target": target,
"entrypoint": "bin/codex.exe",
}
(package / "codex-package.json").write_text(json.dumps(metadata))
manifest = {
"schemaVersion": 1,
"sha256": {
name: hashlib.sha256(contents).hexdigest()
for name, contents in files.items()
if name == "bin/codex.exe"
or name.startswith("codex-resources/voice/")
},
}
manifest_path = package / "codex-resources/voice/manifest.json"
manifest_path.write_text(json.dumps(manifest))
prepare_winget_package(package)
entrypoint = f"codex-{target}.exe"
files[entrypoint] = files.pop("bin/codex.exe")
files["codex-code-mode-host.exe"] = files.pop(
"bin/codex-code-mode-host.exe"
)
for helper in (
"codex-command-runner.exe",
"codex-windows-sandbox-setup.exe",
):
files[helper] = files[f"codex-resources/{helper}"]
actual = {
str(path.relative_to(package)).replace("\\", "/"): path.read_bytes()
for path in package.rglob("*")
if path.is_file()
}
actual_metadata = json.loads(actual.pop("codex-package.json"))
actual_manifest = json.loads(
actual.pop("codex-resources/voice/manifest.json")
)
self.assertEqual(actual, files)
metadata["entrypoint"] = entrypoint
self.assertEqual(actual_metadata, metadata)
manifest["sha256"][entrypoint] = manifest["sha256"].pop("bin/codex.exe")
self.assertEqual(actual_manifest, manifest)
for name, digest in actual_manifest["sha256"].items():
self.assertEqual(hashlib.sha256(actual[name]).hexdigest(), digest)
def test_macos_package_preserves_prebuilt_resource_binaries(self) -> None:
for variant_name in ("codex", "codex-app-server"):
for target in ("aarch64-apple-darwin", "x86_64-apple-darwin"):