mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
## What changed - Build native voice SDK and runtime artifacts with Bazel for Linux GNU, macOS, and Windows on x64 and ARM64, then configure Cargo jobs to consume them. Keep musl builds in a separate job without these inputs. - Validate artifact receipts against the target, source commit, and source manifest; verify SDK file hashes and relocate pkg-config metadata. Package the runtime and plugins with nextest archives and restore `CODEX_TEST_VOICE_RUNTIME` when running shards. - Prepare native Windows voice tools for argument-comment linting and install ARM64 DotSlash on Windows ARM64. Reduce archive disk usage, bound Linux ARM64 build concurrency, and correct the JUnit artifact path. - Recognize TLS errors wrapped directly in `io::Error`. Make TLS fallback fixtures select the native backend explicitly, allow the MCP test server's non-loopback address, and isolate skill-root tests from ancestor Git markers. Install `git` in remote test containers and filter MCP discovery assertions to POST requests. ## Testing Add tests for relocated voice inputs, Windows ARM64 import libraries with host-native pkgconf, and rejection of mismatched receipts or corrupt SDK files. Extend untrusted-certificate coverage to an explicitly selected rustls backend. GitOrigin-RevId: da3ff690b94906edc1f8f60a3c7feda1bf66134a
154 lines
5.9 KiB
Python
154 lines
5.9 KiB
Python
"""Stage receipt-checked voice build inputs for Cargo and configure a shard."""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import shutil
|
|
import stat
|
|
import subprocess
|
|
import sys
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
|
|
from release_runtime import stage as stage_runtime
|
|
from runtime import digest
|
|
from sdk import MODULES
|
|
|
|
|
|
def read_receipt(path: Path, target: str, commit: str) -> dict:
|
|
receipt = json.loads(path.read_text())
|
|
if (
|
|
receipt["target"] != target
|
|
or receipt["sourceCommit"] != commit
|
|
or receipt["sourceManifestSha256"]
|
|
!= digest(Path(__file__).with_name("sources.json"))
|
|
):
|
|
raise ValueError("native inputs do not match target, commit and sources")
|
|
return receipt
|
|
|
|
|
|
def stage(sdk: Path, runtime: Path, output: Path, target: str, commit: str) -> None:
|
|
sdk, runtime, output = (
|
|
sdk.resolve(strict=True),
|
|
runtime.resolve(strict=True),
|
|
output.resolve(),
|
|
)
|
|
if any(output.is_relative_to(source) for source in (sdk, runtime)):
|
|
raise ValueError("output must be outside the native inputs")
|
|
files = read_receipt(sdk / "sdk.json", target, commit)["files"]
|
|
native = read_receipt(runtime / "runtime.json", target, commit)
|
|
library_dir = output / "runtime" / ("bin" if target.endswith("msvc") else "lib")
|
|
prepared = {
|
|
entry.get("sourceSha256"): runtime / entry["path"]
|
|
for entry in native["libraries"]
|
|
if Path(entry["path"]).parent.name == library_dir.name
|
|
}
|
|
|
|
output.mkdir(parents=True)
|
|
try:
|
|
stage_runtime(runtime, output / "runtime", target)
|
|
for entry in files:
|
|
source = (sdk / entry["path"]).resolve(strict=True)
|
|
relative = source.relative_to(sdk)
|
|
if digest(source) != entry["sha256"]:
|
|
raise ValueError(f"SDK file does not match its receipt: {relative}")
|
|
dest = output / "sdk" / relative
|
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
if source.suffix == ".pc":
|
|
# Some transitive libraries retain the producer's absolute prefix.
|
|
dest.write_text(
|
|
re.sub(
|
|
r"^prefix=.*$",
|
|
"prefix=${pcfiledir}/../..",
|
|
source.read_text(),
|
|
flags=re.MULTILINE,
|
|
)
|
|
)
|
|
else:
|
|
shutil.copy2(source, dest)
|
|
|
|
# Link with the prepared runtime bytes and put MSVC import libraries
|
|
# beside their DLLs so nextest collects a self-contained search path.
|
|
if relative.parent == Path("lib"):
|
|
alias = library_dir / relative.name
|
|
payload = (
|
|
source if source.suffix == ".lib" else prepared.get(entry["sha256"])
|
|
)
|
|
if payload and not alias.exists():
|
|
shutil.copy2(payload, alias)
|
|
except BaseException:
|
|
# Windows cannot delete read-only files copied from Bazel.
|
|
if os.name == "nt":
|
|
for copied in output.rglob("*"):
|
|
copied.chmod(copied.stat().st_mode | stat.S_IWRITE)
|
|
shutil.rmtree(output)
|
|
raise
|
|
|
|
|
|
def environment(root: Path, target: str, pkg_config: Path) -> dict[str, str]:
|
|
root, pkg_config = root.resolve(strict=True), pkg_config.resolve(strict=True)
|
|
read_receipt(root / "runtime/runtime.json", target, os.environ["GITHUB_SHA"])
|
|
suffix = target.replace("-", "_")
|
|
values = {
|
|
f"PKG_CONFIG_{suffix}": str(pkg_config),
|
|
f"PKG_CONFIG_PATH_{suffix}": str(root / "sdk/lib/pkgconfig"),
|
|
"CODEX_TEST_VOICE_RUNTIME": str(root / "runtime"),
|
|
}
|
|
for module in MODULES:
|
|
key = re.sub(r"[^A-Z0-9]", "_", module.upper())
|
|
values[f"SYSTEM_DEPS_{key}_SEARCH_NATIVE"] = str(
|
|
root / "runtime" / ("bin" if target.endswith("msvc") else "lib")
|
|
)
|
|
if module.startswith("gstreamer"):
|
|
values[f"SYSTEM_DEPS_{key}_LDFLAGS"] = ""
|
|
if not target.endswith("windows-msvc"):
|
|
origin = "@loader_path" if target.endswith("darwin") else "$ORIGIN"
|
|
values[f"CARGO_TARGET_{suffix.upper()}_RUSTFLAGS"] = (
|
|
f"-C link-arg=-Wl,-rpath,{origin}/../lib"
|
|
)
|
|
return values
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
producer = sub.add_parser("stage")
|
|
producer.add_argument("--sdk", type=Path, required=True)
|
|
producer.add_argument("--runtime", type=Path, required=True)
|
|
producer.add_argument("--output", type=Path, required=True)
|
|
consumer = sub.add_parser("configure")
|
|
consumer.add_argument("--root", type=Path, required=True)
|
|
for command in (producer, consumer):
|
|
command.add_argument("--target", required=True)
|
|
args = parser.parse_args()
|
|
if args.command == "stage":
|
|
stage(
|
|
args.sdk, args.runtime, args.output, args.target, os.environ["GITHUB_SHA"]
|
|
)
|
|
return
|
|
pkg_config = os.environ.get("VOICE_PKG_CONFIG") or shutil.which("pkg-config")
|
|
if not pkg_config:
|
|
parser.error("pkg-config is required on the build host")
|
|
values = environment(args.root, args.target, Path(pkg_config))
|
|
# Probe only the staged SDK so a missing native module cannot resolve from
|
|
# the host. Cargo keeps its usual system search for unrelated dependencies.
|
|
probe_env = {
|
|
**os.environ,
|
|
"PKG_CONFIG_PATH": "",
|
|
"PKG_CONFIG_LIBDIR": str(args.root.resolve() / "sdk/lib/pkgconfig"),
|
|
}
|
|
subprocess.run(
|
|
[pkg_config, "--exists", *MODULES, "gstreamer-1.0 >= 1.28"],
|
|
env=probe_env,
|
|
check=True,
|
|
)
|
|
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as output:
|
|
for key, value in values.items():
|
|
output.write(f"{key}={value}\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|