From ea1d44b1a9f16906bc5d83ba052e2f8c8c37332d Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:22:05 -0700 Subject: [PATCH 01/12] fix(ci): accept the container's POSIX workspace in a Bosn receipt on Windows The receipt Bosn writes reports the workspace inside its Linux container, e.g. /work/repo. On Windows Path.is_absolute() needs a drive, so it is false for that path and proof_error rejected every genuine receipt as 'Bosn executed another workspace'. Both LocalGateProofTests cases failed on the windows-x86 and windows-arm preflight lanes, in every nightly since at least 2026-10-15. Require a root instead: it still rejects relative/repo and a drive-relative C:repo, and the resolve() comparison that follows still pins the exact path. --- ci/local_gate.py | 17 +++++++++++++++-- tests/test_ci_local_gate.py | 13 ++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ci/local_gate.py b/ci/local_gate.py index 4ed3fea3..8d41321d 100644 --- a/ci/local_gate.py +++ b/ci/local_gate.py @@ -17,7 +17,7 @@ import sys import tempfile from dataclasses import dataclass -from pathlib import Path +from pathlib import Path, PurePath from typing import TypeAlias JsonValue: TypeAlias = str | int | float | bool | list["JsonValue"] | dict[str, "JsonValue"] | None @@ -185,10 +185,23 @@ def _jobs_error(jobs: tuple[Job, ...]) -> str | None: return None +def _is_rooted(path: PurePath) -> bool: + """Whether a receipt's workspace names a location rather than a relative path. + + Bosn executes the gate inside a Linux container, so its receipt reports a + POSIX workspace such as ``/work/repo``. ``Path.is_absolute()`` is false for + that on Windows, where an absolute path also needs a drive, so the check + rejected every genuine receipt there. A root is what separates a located + path from ``relative/repo`` (or a drive-relative ``C:repo``) on every host; + the ``resolve()`` comparison that follows still pins the exact workspace. + """ + return bool(path.root) + + def proof_error(output: str, *, workspace: Path, head_sha: str) -> str | None: try: proof = _parse_proof(output) - if not proof.workspace.is_absolute() or proof.workspace.resolve() != workspace.resolve(): + if not _is_rooted(proof.workspace) or proof.workspace.resolve() != workspace.resolve(): return "Bosn executed another workspace" if proof.sha != head_sha: return "Bosn executed another commit" diff --git a/tests/test_ci_local_gate.py b/tests/test_ci_local_gate.py index 09b493b3..6b1e6994 100644 --- a/tests/test_ci_local_gate.py +++ b/tests/test_ci_local_gate.py @@ -5,7 +5,7 @@ import json import unittest from dataclasses import dataclass -from pathlib import Path +from pathlib import Path, PurePosixPath, PureWindowsPath from unittest.mock import patch from ci import local_gate @@ -48,6 +48,17 @@ def test_local_execution_uses_quick_dispatch_before_attesting(self) -> None: self.document["event"] = "workflow_dispatch" self.assertIsNone(self.error()) + def test_posix_receipt_workspace_counts_as_located_on_every_host(self) -> None: + # The receipt comes from a Linux container; Windows pathlib reports + # `/work/repo` as not absolute (no drive), which failed every real + # receipt on the Windows preflight lanes. + for flavour in (PurePosixPath, PureWindowsPath): + with self.subTest(flavour=flavour.__name__): + self.assertTrue(local_gate._is_rooted(flavour("/work/repo"))) + self.assertFalse(local_gate._is_rooted(flavour("relative/repo"))) + self.assertFalse(local_gate._is_rooted(PureWindowsPath("C:relative"))) + self.assertTrue(local_gate._is_rooted(PureWindowsPath("C:\\work\\repo"))) + def test_integration_label_preserves_additional_remote_coverage(self) -> None: trust = (local_gate.ROOT / "local-gate.toml").read_text().split("[gate.trust]", 1)[1] labels = next(line for line in trust.splitlines() if line.startswith("full-labels =")) From 3995edf8d36731f04c50f3c83ae361be7eb3ba2d Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:22:05 -0700 Subject: [PATCH 02/12] fix(lints): build dylint fixture libraries for the host under soldr on Windows dylint_testing builds the lint library with a nested cargo build and then loads it from /debug/. On Windows soldr cargo exports CARGO_BUILD_TARGET (its MSVC-default policy, soldr#2350 only exempts cargo dylint), the nested build inherits it and puts the library under //debug/, so both UI fixtures failed with 'could not read ...@nightly-...-x86_64-pc-windows-msvc.dll'. Reproduced on Linux by setting CARGO_BUILD_TARGET for the same fixture test. The library is a host cdylib loaded in-process by the driver, so clearing the variable for the nested build is always correct. --- lints/running-process-env-literal/src/lib.rs | 7 +++++++ lints/running-process-platform-boundary/src/lib.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/lints/running-process-env-literal/src/lib.rs b/lints/running-process-env-literal/src/lib.rs index 3bdd5d46..84816bcb 100644 --- a/lints/running-process-env-literal/src/lib.rs +++ b/lints/running-process-env-literal/src/lib.rs @@ -202,5 +202,12 @@ fn inside_env_module(cx: &LateContext<'_>, module: DefId) -> bool { #[test] fn ui() { + // dylint_testing builds this library with a nested `cargo build` and then + // loads it from `/debug/`. On Windows `soldr cargo` exports + // CARGO_BUILD_TARGET (its MSVC-default policy), which the nested build + // inherits and which moves the library to `//debug/`, + // so the fixture failed with "could not read ...dll". The lint library is + // a host cdylib, so building it for the host is always correct. + std::env::remove_var("CARGO_BUILD_TARGET"); dylint_testing::ui_test(env!("CARGO_PKG_NAME"), "ui"); } diff --git a/lints/running-process-platform-boundary/src/lib.rs b/lints/running-process-platform-boundary/src/lib.rs index 293e22ab..7d35fa6e 100644 --- a/lints/running-process-platform-boundary/src/lib.rs +++ b/lints/running-process-platform-boundary/src/lib.rs @@ -639,5 +639,12 @@ impl EarlyLintPass for EnforcePlatformBoundary { #[test] fn ui() { + // dylint_testing builds this library with a nested `cargo build` and then + // loads it from `/debug/`. On Windows `soldr cargo` exports + // CARGO_BUILD_TARGET (its MSVC-default policy), which the nested build + // inherits and which moves the library to `//debug/`, + // so the fixture failed with "could not read ...dll". The lint library is + // a host cdylib, so building it for the host is always correct. + std::env::remove_var("CARGO_BUILD_TARGET"); dylint_testing::ui_test(env!("CARGO_PKG_NAME"), "ui"); } From f6860de829c7cd5d04a49af0a5490690f9cf20e3 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:22:05 -0700 Subject: [PATCH 03/12] ci: reinstall a cross target's rust-std when the toolchain cache lost its files; C11 for ARM64 MSVC arm-musl warm-build: setup-soldr's solo-toolchain cache key carries no target list (tnone), and the restored toolchain listed rust-std-aarch64-unknown-linux-musl without its library files. rustup target add then says 'up to date' and soldr refuses the build. ci/install_rust_target.sh checks for libstd after the add and reinstalls when it is missing. rustup's own component remove rolls back when listed files are gone, so the script drops the component's entry and file list first and retries; verified locally by emptying the target's lib dir. windows-arm preflight: mimalloc-pprof 0.9.3 (testbins) defines MI_USE_C11_ATOMICS on aarch64-pc-windows-msvc, and MSVC's stdatomic.h refuses it without /std:c11. CFLAGS_aarch64_pc_windows_msvc is target scoped, so no other lane sees it. --- .github/workflows/ci-preflight-rust.yml | 10 +++--- .github/workflows/ci-preflight.yml | 5 +++ ci/install_rust_target.sh | 42 +++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100755 ci/install_rust_target.sh diff --git a/.github/workflows/ci-preflight-rust.yml b/.github/workflows/ci-preflight-rust.yml index a7cac2ba..6a45a2d2 100644 --- a/.github/workflows/ci-preflight-rust.yml +++ b/.github/workflows/ci-preflight-rust.yml @@ -16,7 +16,7 @@ name: CI Preflight Rust-only (Reusable) # C-build-script crates (rusqlite/bundled, blake3 asm, etc.). # - `zackees/setup-soldr@v0` provisions the toolchain from # rust-toolchain.toml and soldr's zccache-backed build cache -# (CACHE-025, zackees/ci.yml#209); `soldr rustup target add` adds +# (CACHE-025, zackees/ci.yml#209); `ci/install_rust_target.sh` adds # the rust-std for the musl target. # - `soldr cargo build/clippy/nextest --target ` builds # against the musl target. The platform-default linker is kept: @@ -95,7 +95,7 @@ jobs: linker: platform-default - name: Install ${{ inputs.target }} standard library - run: soldr rustup target add ${{ inputs.target }} --toolchain 1.95.0 + run: bash ci/install_rust_target.sh ${{ inputs.target }} 1.95.0 - name: cargo build --target ${{ inputs.target }} run: soldr cargo build --workspace --exclude running-process-py --all-targets --features ${{ inputs.features }} --target ${{ inputs.target }} @@ -121,7 +121,7 @@ jobs: prebuild-deps: none linker: platform-default - name: Install ${{ inputs.target }} standard library - run: soldr rustup target add ${{ inputs.target }} --toolchain 1.95.0 + run: bash ci/install_rust_target.sh ${{ inputs.target }} 1.95.0 - name: cargo clippy --target ${{ inputs.target }} run: soldr cargo clippy --workspace --exclude running-process-py --all-targets --features ${{ inputs.features }} --target ${{ inputs.target }} -- -D warnings @@ -147,7 +147,7 @@ jobs: prebuild-deps: none linker: platform-default - name: Install ${{ inputs.target }} standard library - run: soldr rustup target add ${{ inputs.target }} --toolchain 1.95.0 + run: bash ci/install_rust_target.sh ${{ inputs.target }} 1.95.0 - name: Install cargo-nextest uses: taiki-e/install-action@v2 with: @@ -201,7 +201,7 @@ jobs: prebuild-deps: none linker: platform-default - name: Install ${{ inputs.target }} standard library - run: soldr rustup target add ${{ inputs.target }} --toolchain 1.95.0 + run: bash ci/install_rust_target.sh ${{ inputs.target }} 1.95.0 - name: Install cargo-nextest uses: taiki-e/install-action@v2 with: diff --git a/.github/workflows/ci-preflight.yml b/.github/workflows/ci-preflight.yml index 6df8ea31..6a4af26a 100644 --- a/.github/workflows/ci-preflight.yml +++ b/.github/workflows/ci-preflight.yml @@ -65,6 +65,11 @@ env: # Windows and macOS lanes that share this workflow are unaffected. CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS: "-C link-arg=-Wl,--build-id=sha1" CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS: "-C link-arg=-Wl,--build-id=sha1" + # mimalloc-pprof 0.9.3 (testbins) defines MI_USE_C11_ATOMICS for + # aarch64-pc-windows-msvc, and MSVC's refuses that without + # /std:c11: "C atomics require C11 or later" broke the windows-arm build. + # cc-rs reads this per-target variable, so no other lane sees it. + CFLAGS_aarch64_pc_windows_msvc: "/std:c11" jobs: preflight: diff --git a/ci/install_rust_target.sh b/ci/install_rust_target.sh new file mode 100755 index 00000000..ca849cc1 --- /dev/null +++ b/ci/install_rust_target.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Install a Rust target's standard library, and reinstall it when the +# toolchain claims it but its files are missing. +# +# Usage: ci/install_rust_target.sh [toolchain] +# +# setup-soldr restores the toolchain from a solo-toolchain cache whose key does +# not include the added targets. A payload saved from a job that had added a +# target can come back with rustup's component manifest listing +# `rust-std-` but without the library files. `rustup target add` then +# reports "up to date" and changes nothing, and soldr refuses the build +# ("lists rust-std ... but the library files are missing"). Removing the +# component first makes the add a real install. `rustup component remove` +# itself rolls back when a file listed in the component's manifest is gone, +# so if it fails the component is dropped from the toolchain's installed list +# (`components`) and its file list (`manifest-*`), and the removal retried: +# rustup then only unregisters it from the channel config. +set -euo pipefail + +target="${1:?usage: install_rust_target.sh [toolchain]}" +toolchain="${2:-1.95.0}" + +soldr rustup target add "$target" --toolchain "$toolchain" + +rustc="$(soldr rustup which rustc --toolchain "$toolchain")" +rustlib="$(dirname "$(dirname "$rustc")")/lib/rustlib" +libdir="$rustlib/$target/lib" +if compgen -G "$libdir/libstd-*.rlib" > /dev/null; then + exit 0 +fi + +echo "rust-std for $target is registered but $libdir has no libstd; reinstalling" >&2 +if ! soldr rustup component remove "rust-std-$target" --toolchain "$toolchain"; then + sed -i "/^rust-std-$target\$/d" "$rustlib/components" + rm -f "$rustlib/manifest-rust-std-$target" + soldr rustup component remove "rust-std-$target" --toolchain "$toolchain" +fi +soldr rustup target add "$target" --toolchain "$toolchain" +if ! compgen -G "$libdir/libstd-*.rlib" > /dev/null; then + echo "rust-std for $target is still missing from $libdir after reinstall" >&2 + exit 1 +fi From 6486ad04bfa8e672074ecee772661a8492ebded3 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:22:05 -0700 Subject: [PATCH 04/12] deps: clear cargo audit (rustls, webpki, ruzstd, zstd, tokio) cargo audit --deny warnings failed with 11 vulnerabilities and 11 unsound warnings: - rustls 0.23.46, rustls-webpki 0.103.16, webpki-roots 1.0.11 and tokio 1.54.1 are semver-compatible lockfile bumps (RUSTSEC-2026-0346..0349, -0382, -0381, -0386). - zstd 0.13 -> 0.14 (zstd-safe 8.2) for the ConPTY asset decoder in running-process-platform-internal (RUSTSEC-2026-0391, -0395..-0406). Decoder::new is unchanged. - ruzstd 0.7 came through addr2line 0.24's loader enabling object's compression. Only the unpublished probe worker uses it; addr2line 0.27 / object 0.40 pull ruzstd 0.9.1 (RUSTSEC-2026-0344). running-process-probe keeps object 0.36: it enables no compression, so it never had ruzstd. No advisory is ignored. Local-Gate: v1 tree=5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43 secs=753 lanes=linux-quick:run Ci-Attestation: {"at":1793036167,"gate":"rust/all/fmt","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"7ae689ba8c89d43c7d930f7d3cca60af","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"python/all/static","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"1df0887341459828f2f84c417f8cd521","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"rust/x86_64-unknown-linux-gnu/check","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"be592b2ce8e24b29091dc54c2e8b957f","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"rust/x86_64-unknown-linux-gnu/dylint","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"d3733ace4131b392a53ff28b5f1d0889","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"rust/x86_64-unknown-linux-gnu/test","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"4e2b02e33c5e992d10749d7316cf3686","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"python/linux-x64/test","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"92d9686bec1a08c74613ebaedca0eb93","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} Ci-Attestation: {"at":1793036167,"gate":"general/linux-x64/perf","host":"linux-x86_64","key":"b117848b25916980eaa933601cf3c7c99e1481751480e3af5b98d34d9714f696","lane":"linux-quick","parents":["f6860de829c7cd5d04a49af0a5490690f9cf20e3"],"secs":753,"stamp":"ff9c7de713ca7fbc5f155b4bd74ebcd8","tree":"5b2297adc6a3d955a4a9b11d4a40c0afe5d9ac43","v":1,"via":"run"} --- Cargo.lock | 84 ++++++++++--------- .../Cargo.toml | 2 +- .../running-process-probe-worker/Cargo.toml | 6 +- 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f2308b5..5bfc9097 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,13 +4,13 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "e567177890eb1617b1f774005b66b26b2377afd138a2ca37aae7d8f0c81429d4" dependencies = [ - "gimli", + "gimli 0.34.0", "memmap2", - "object", + "object 0.40.0", "typed-arena", ] @@ -663,7 +663,7 @@ dependencies = [ "arrayvec", "cfg-if", "fallible-iterator 0.3.0", - "gimli", + "gimli 0.31.1", "macho-unwind-info", "pe-unwind-info", ] @@ -786,6 +786,15 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "gimli" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "glob" version = "0.3.3" @@ -1442,6 +1451,15 @@ name = "object" version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c" dependencies = [ "flate2", "memchr", @@ -2137,7 +2155,7 @@ dependencies = [ "getrandom 0.4.2", "libc", "mach2", - "object", + "object 0.36.7", "proptest", "prost", "prost-build", @@ -2213,7 +2231,7 @@ version = "4.10.17" dependencies = [ "addr2line", "lzma-rs", - "object", + "object 0.40.0", "pdb", "pdb-addr2line", "running-process-platform-internal", @@ -2297,9 +2315,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.45" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "log", "once_cell", @@ -2321,9 +2339,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.15" +version = "0.103.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281" dependencies = [ "ring", "rustls-pki-types", @@ -2350,9 +2368,9 @@ dependencies = [ [[package]] name = "ruzstd" -version = "0.7.3" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad02996bfc73da3e301efe90b1837be9ed8f4a462b6ed410aa35d00381de89f" +checksum = "69e4ce4a039f42bf25920b95667e4d789e98749ab11bbb8d2c2936f788421bb5" dependencies = [ "twox-hash", ] @@ -2574,12 +2592,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -2678,7 +2690,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2771,9 +2783,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.52.3" +version = "1.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" dependencies = [ "bytes", "libc", @@ -3072,13 +3084,9 @@ dependencies = [ [[package]] name = "twox-hash" -version = "1.6.3" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] +checksum = "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2" [[package]] name = "typed-arena" @@ -3316,14 +3324,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.7", + "webpki-roots 1.0.11", ] [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "f5f280bbb2b287bc8e7de7e3852945a0ff50d1bbcb5ed42b6c7a568c546df171" dependencies = [ "rustls-pki-types", ] @@ -3356,7 +3364,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3733,27 +3741,27 @@ checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zstd" -version = "0.13.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +checksum = "db3ae9bf90af6e40197bef767eeefc46ad6397420fe873830bd85e5fbbfb3c70" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.4" +version = "8.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +checksum = "ded520f16b29e1a9b771c722221b2b0a0398c2316d9bb3c42b458a5414d7434b" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.16+zstd.1.5.7" +version = "2.1.2+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +checksum = "481ada9c543b2323cbb7bbdbb5249177fbf0188ed959ed2c15e4b22421c84ed3" dependencies = [ "cc", "pkg-config", diff --git a/crates/running-process-platform-internal/Cargo.toml b/crates/running-process-platform-internal/Cargo.toml index a73e34ea..f0bb745c 100644 --- a/crates/running-process-platform-internal/Cargo.toml +++ b/crates/running-process-platform-internal/Cargo.toml @@ -80,7 +80,7 @@ png = { version = "0.17", optional = true } [target.'cfg(windows)'.dependencies] sha2 = { version = "0.10", optional = true } ureq = { version = "2", default-features = false, features = ["tls"], optional = true } -zstd = { version = "0.13", default-features = false, optional = true } +zstd = { version = "0.14", default-features = false, optional = true } tar = { version = "0.4", default-features = false, optional = true } windows-sys = { version = "0.61", features = [ "Wdk_System_Threading", diff --git a/crates/running-process-probe-worker/Cargo.toml b/crates/running-process-probe-worker/Cargo.toml index a41c9e51..45d17460 100644 --- a/crates/running-process-probe-worker/Cargo.toml +++ b/crates/running-process-probe-worker/Cargo.toml @@ -45,11 +45,11 @@ pdb = "0.8" # own. Same isolation argument as every other parser here: it lives in the # disposable worker, never in the daemon. pdb-addr2line = "0.12" -object = { version = "0.36", default-features = false, features = ["read", "std"] } +object = { version = "0.40", default-features = false, features = ["read", "std"] } [target.'cfg(not(target_os = "windows"))'.dependencies] lzma-rs = "0.3" -object = { version = "0.36", default-features = false, features = ["read", "std"] } +object = { version = "0.40", default-features = false, features = ["read", "std"] } # DWARF line programs, for resolving a frame to file:line (#803). # # The `loader` feature is what provides `addr2line::Loader`, which owns its @@ -60,7 +60,7 @@ object = { version = "0.36", default-features = false, features = ["read", "std" # Unix-only, alongside the rest of the ELF/Mach-O parsing. The Windows half is # blocked separately: `pdb` 0.8 panics iterating line programs on PDBs rustc # produces, so that side needs a different crate (see #803). -addr2line = { version = "0.24", default-features = false, features = [ +addr2line = { version = "0.27", default-features = false, features = [ "std", "loader", ] } From 00fff690b6a9d5b7e443a55358540556f265ff7c Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:53:03 -0700 Subject: [PATCH 05/12] deps: mimalloc-pprof 0.9.5 for the ARM64 MSVC atomics fix, instead of /std:c11 The target-scoped CFLAGS_aarch64_pc_windows_msvc=/std:c11 reached ring's build too, which compiles aarch64-pc-windows-msvc with clang, and broke it. mimalloc-pprof 0.9.4 is the upstream fix for the original failure: it drops 0.9.3's build-script MI_USE_C11_ATOMICS allowlist and detects C11 atomics in the header, so real MSVC (no __STDC_VERSION__ without /std:c11) keeps its intrinsic wrapper. 0.9.5 is the latest 0.9.x; its new default pprof feature keeps today's behaviour. --- .github/workflows/ci-preflight.yml | 5 ----- Cargo.lock | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-preflight.yml b/.github/workflows/ci-preflight.yml index 6a4af26a..6df8ea31 100644 --- a/.github/workflows/ci-preflight.yml +++ b/.github/workflows/ci-preflight.yml @@ -65,11 +65,6 @@ env: # Windows and macOS lanes that share this workflow are unaffected. CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUSTFLAGS: "-C link-arg=-Wl,--build-id=sha1" CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS: "-C link-arg=-Wl,--build-id=sha1" - # mimalloc-pprof 0.9.3 (testbins) defines MI_USE_C11_ATOMICS for - # aarch64-pc-windows-msvc, and MSVC's refuses that without - # /std:c11: "C atomics require C11 or later" broke the windows-arm build. - # cc-rs reads this per-target variable, so no other lane sees it. - CFLAGS_aarch64_pc_windows_msvc: "/std:c11" jobs: preflight: diff --git a/Cargo.lock b/Cargo.lock index 5bfc9097..295733c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1357,9 +1357,9 @@ dependencies = [ [[package]] name = "mimalloc-pprof" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d30b36d87ca14bd04fec54438531e7ef88ee0f28b34d75a37ddc98ac3fa93d" +checksum = "9143eb24178e618a9671d22074e2e64badd61454a1ae5c042325daf8238f5407" dependencies = [ "cc", ] From 891628742cd0ea4d164322e23f0c11e129d4b879 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:53:03 -0700 Subject: [PATCH 06/12] fix(probe-worker): object 0.40 types PE section characteristics Windows-only test code compared the characteristics with a bare integer; object 0.40 wraps them in pe::SectionFlags. Use IMAGE_SCN_MEM_EXECUTE's value. Checked with cargo check --target x86_64-pc-windows-msvc. --- crates/running-process-probe-worker/src/pdb_symbols.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/running-process-probe-worker/src/pdb_symbols.rs b/crates/running-process-probe-worker/src/pdb_symbols.rs index 9ea1b5e6..34a062ce 100644 --- a/crates/running-process-probe-worker/src/pdb_symbols.rs +++ b/crates/running-process-probe-worker/src/pdb_symbols.rs @@ -767,9 +767,9 @@ mod tests { let ranges: Vec<(u64, u64)> = file .sections() .filter(|s| match s.flags() { - // IMAGE_SCN_MEM_EXECUTE + // object 0.40 types the characteristics as `pe::SectionFlags`. object::SectionFlags::Coff { characteristics } => { - characteristics & 0x2000_0000 != 0 + characteristics.0 & object::pe::IMAGE_SCN_MEM_EXECUTE.0 != 0 } _ => false, }) From 83b6be3d9134f5a9fa35c15d63a4545e82b42c57 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 10:56:45 -0700 Subject: [PATCH 07/12] fix(platform): register session-relay fds without tokio's deprecated AsyncFd::new tokio 1.54 (taken for RUSTSEC-2026-0386) deprecates the safe AsyncFd::new as unsound, which fails clippy -D warnings with the session-relay feature (seen on the x86-musl lint lane). AsyncFd::register is the replacement; it is unsafe because the reactor trusts the descriptor to stay open and stable, which an owned, never-reassigned OwnedFd guarantees. Local-Gate: v1 tree=b5913c2528a3cc53b8cd4ab46594ee0475629407 secs=738 lanes=linux-quick:run Ci-Attestation: {"at":1793038149,"gate":"rust/all/fmt","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"003af76e7c20c44625d689701b7a9272","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"python/all/static","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"317dfc809b1ccb69c47f76eb41a77bc3","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"rust/x86_64-unknown-linux-gnu/check","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"66ff714a2c723c090ccac8c3cde3b46c","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"rust/x86_64-unknown-linux-gnu/dylint","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"89f18e0f20f17cb6af10dcaf3bd94a35","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"rust/x86_64-unknown-linux-gnu/test","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"c2532ecb1fe0b427afa7b39b2e582231","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"python/linux-x64/test","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"cdff651cec13f1ea8ec7623f0ecdd23d","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} Ci-Attestation: {"at":1793038149,"gate":"general/linux-x64/perf","host":"linux-x86_64","key":"072f5621a5448164a873cbedc4ff7877002efce0211e222df937b3fade13fe73","lane":"linux-quick","parents":["891628742cd0ea4d164322e23f0c11e129d4b879"],"secs":738,"stamp":"2e85710c2173947a08306aa28b7f5348","tree":"b5913c2528a3cc53b8cd4ab46594ee0475629407","v":1,"via":"run"} --- .../src/platform_linux_session_relay.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/running-process-platform-internal/src/platform_linux_session_relay.rs b/crates/running-process-platform-internal/src/platform_linux_session_relay.rs index 13e0ccc3..574c0db9 100644 --- a/crates/running-process-platform-internal/src/platform_linux_session_relay.rs +++ b/crates/running-process-platform-internal/src/platform_linux_session_relay.rs @@ -35,8 +35,8 @@ impl Direction { destination: RawFd, committed: Arc, ) -> io::Result { - let source = AsyncFd::new(duplicate(source)?)?; - let destination = AsyncFd::new(duplicate(destination)?)?; + let source = register(duplicate(source)?)?; + let destination = register(duplicate(destination)?)?; let (pipe_read, pipe_write) = pipe()?; Ok(Self { source, @@ -115,6 +115,18 @@ fn injected_splice_error() -> io::Error { io::Error::other("injected SESSION splice failure") } +/// Register an owned descriptor with the reactor. +/// +/// tokio 1.54 deprecates the safe `AsyncFd::new` as unsound +/// (RUSTSEC-2026-0386): it trusted `as_raw_fd()` to stay valid and stable. +fn register(fd: OwnedFd) -> io::Result> { + // SAFETY: `OwnedFd` holds an open descriptor, returns that same descriptor + // from every `as_raw_fd()` call, and closes it only when dropped. The + // `AsyncFd` takes ownership of it, so it stays open for the `AsyncFd`'s + // whole lifetime. + unsafe { AsyncFd::register(fd) }.map_err(io::Error::from) +} + fn duplicate(fd: RawFd) -> io::Result { // SAFETY: fd is borrowed from a live socket half. fcntl either returns // a new independently owned descriptor or a negative error sentinel. From 5ba93c84d22eb604761658886730b7b57a165e2a Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 11:18:49 -0700 Subject: [PATCH 08/12] ci: give the Dylint job 60 minutes Windows x86 never reached the workspace gate before (the UI fixture failed first). With a cold compiler-unit cache, which every PR lane has because that cache is saved only from main, each of the gate's two passes took ~20 min and the 30-minute limit cancelled the second. Local-Gate: v1 tree=472df402f693387cc51a4c4828ecad321ce4c4bf secs=630 lanes=linux-quick:run Ci-Attestation: {"at":1793039359,"gate":"rust/all/fmt","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"fa24333a1f71f45d760322574bbf46db","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"python/all/static","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"0f5efcd7e0e5ac9c5f2c500a9f0e20b8","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"rust/x86_64-unknown-linux-gnu/check","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"f8b8056e2d17f875d8475ca2da7cc906","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"rust/x86_64-unknown-linux-gnu/dylint","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"31fb0e8030a261fd0222e48cb860b6a0","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"rust/x86_64-unknown-linux-gnu/test","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"5d99fbbcb7399327f43e6d8021b23a74","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"python/linux-x64/test","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"3258440eb1be289f8f36a4b60db2437f","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} Ci-Attestation: {"at":1793039359,"gate":"general/linux-x64/perf","host":"linux-x86_64","key":"6acbcf702ce21127bb8ba9fbb8ff61f39f6db5b0b5b441d52e9464aa60bac84d","lane":"linux-quick","parents":["83b6be3d9134f5a9fa35c15d63a4545e82b42c57"],"secs":630,"stamp":"fc668760165faa1cdc50842ba656852b","tree":"472df402f693387cc51a4c4828ecad321ce4c4bf","v":1,"via":"run"} --- .github/workflows/ci-preflight.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-preflight.yml b/.github/workflows/ci-preflight.yml index 6df8ea31..f7285099 100644 --- a/.github/workflows/ci-preflight.yml +++ b/.github/workflows/ci-preflight.yml @@ -346,7 +346,10 @@ jobs: name: dylint (${{ inputs.label }}) if: ${{ inputs.dylint }} runs-on: ${{ inputs.os }} - timeout-minutes: 30 + # Windows x86 with a cold compiler-unit cache spends ~20 min in each of the + # two workspace passes (2026-10-26, PR #1337), and that cache is saved + # only from main, so a PR lane is always cold. 30 cancelled the second pass. + timeout-minutes: 60 env: SOLDR_DYLINT_DRIVER_FALLBACK: "off" # The lint crates select dylint-link through cfg(all()). Soldr's From 78451f7d14b2b0e76b44ed3074a7bf4640b83dd2 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 13:35:02 -0700 Subject: [PATCH 09/12] test(daemon): answer ConPTY's cursor query in the TUI repaint test PSEUDOCONSOLE_INHERIT_CURSOR makes ConPTY open every session with a cursor-position query (ESC[6n) and hold the child's output until it is answered. The test's attachment stands in for a terminal but never answered, so on Windows its backlog was only ESC[6n after 30 s, in every all-features run since that suite was added. Answer each query as a real terminal would; Unix PTYs never ask, so nothing changes there. An earlier attempt answered from the daemon when no client is attached; CI showed the client is already attached when the query arrives, so that did not help and was dropped. Local-Gate: v1 tree=9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6 secs=876 lanes=linux-quick:run Ci-Attestation: {"at":1793047778,"gate":"rust/all/fmt","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"c6817cf7b52256c09508445c4192d04e","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"python/all/static","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"165e34ac9db694b21756a3856a96bf1f","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"rust/x86_64-unknown-linux-gnu/check","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"03a6d64a287a54168416e4a979e1438e","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"rust/x86_64-unknown-linux-gnu/dylint","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"8ae109476b920798db670ab4a0039889","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"rust/x86_64-unknown-linux-gnu/test","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"1bf62b016aecdc0ec17242de5243970a","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"python/linux-x64/test","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"dd56d3fc7bede7ae3d7bacb53137a8fe","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} Ci-Attestation: {"at":1793047778,"gate":"general/linux-x64/perf","host":"linux-x86_64","key":"cb4dacdc72ff33aa50421d3a71b94d449f6e309a91f803179bb873746d4bc6b8","lane":"linux-quick","parents":["5ba93c84d22eb604761658886730b7b57a165e2a"],"secs":876,"stamp":"3e521fb3a4b089f1d57ed8ae835f8ba8","tree":"9b1fb4e0ff69402a3d4b6a129419e2cad0ddfde6","v":1,"via":"run"} --- .../daemon_tui_repaint_test.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/running-process/tests/daemon_integration/daemon_tui_repaint_test.rs b/crates/running-process/tests/daemon_integration/daemon_tui_repaint_test.rs index f88ff6d4..3995c07b 100644 --- a/crates/running-process/tests/daemon_integration/daemon_tui_repaint_test.rs +++ b/crates/running-process/tests/daemon_integration/daemon_tui_repaint_test.rs @@ -100,13 +100,33 @@ fn start_server(scope: &str) -> (tokio::task::JoinHandle<()>, String) { /// Drain the attachment, concatenating every data frame into a single /// Vec for byte-exact assertions. Stops when the deadline passes /// or a frame other than `Data` arrives (e.g. SessionExited). +/// Answer every cursor-position query (`ESC[6n`) seen so far, as the real +/// terminal behind an attachment would. +/// +/// Windows ConPTY (`PSEUDOCONSOLE_INHERIT_CURSOR`) opens each session with +/// that query and forwards none of the child's output until it is answered, +/// so a client that never answers sees a backlog of just `ESC[6n` (#1337). +/// Unix PTYs never ask, so this is a no-op there. +fn answer_cursor_queries(att: &mut PtyAttachment, out: &[u8], answered: &mut usize) { + let asked = out.windows(4).filter(|w| *w == b"\x1b[6n").count(); + while *answered < asked { + let _ = att.send_input(b"\x1b[1;1R"); + *answered += 1; + } +} + fn drain_attachment(att: &mut PtyAttachment, deadline: Instant) -> Vec { let mut out = att.initial_backlog.clone(); + let mut answered = 0; + answer_cursor_queries(att, &out, &mut answered); while Instant::now() < deadline { let remaining = deadline.saturating_duration_since(Instant::now()); match att.recv_frame_with_timeout(remaining) { Ok(Some(frame)) => match frame.frame { - Some(StreamOneof::Output(bytes)) => out.extend_from_slice(&bytes), + Some(StreamOneof::Output(bytes)) => { + out.extend_from_slice(&bytes); + answer_cursor_queries(att, &out, &mut answered); + } // `MissedBytes` reports that the session ring dropped output // because this attachment fell behind. The daemon marks it // non-final (`encode_outbound`), so the stream continues and From e36c8135665068f4bb9958c806d5f53372273c1a Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 14:20:01 -0700 Subject: [PATCH 10/12] test(broker): print why a lifecycle backend launch keeps failing backend_crash_concurrent_reconnects fails on every Windows all-features run because the broker answers ErrorBackendSpawnFailed with a retry until the 20 s deadline, and the panic says only that the transition did not settle. Print the refusal reason so the lane shows what the launch tripped on. --- .../tests/broker/lifecycle_process_conformance.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/running-process/tests/broker/lifecycle_process_conformance.rs b/crates/running-process/tests/broker/lifecycle_process_conformance.rs index 2bdad754..be50056c 100644 --- a/crates/running-process/tests/broker/lifecycle_process_conformance.rs +++ b/crates/running-process/tests/broker/lifecycle_process_conformance.rs @@ -255,8 +255,14 @@ fn round_trip( Err(BrokerClientError::Refused { code: ErrorCode::ErrorBackendSpawnFailed, retry_after_ms, - .. + reason, }) if retry_after_ms > 0 => { + // Printed so a lane where the transition never settles shows why + // the broker could not launch the backend, not just that it + // kept asking for a retry. + eprintln!( + "lifecycle {service}: backend spawn failed, retry in {retry_after_ms} ms: {reason}" + ); return ReconnectOutcome::BackendTransition(Duration::from_millis(retry_after_ms)); } Err(BrokerClientError::Refused { From be9d77a9b0ea5e9cc570666ec5f1da708a940172 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 15:11:28 -0700 Subject: [PATCH 11/12] ci: give the Dylint job 120 minutes 60 was not enough either: the cold Windows x86 workspace gate took ~50 min on one run and was cancelled past 60 on the next. --- .github/workflows/ci-preflight.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-preflight.yml b/.github/workflows/ci-preflight.yml index f7285099..f237eb51 100644 --- a/.github/workflows/ci-preflight.yml +++ b/.github/workflows/ci-preflight.yml @@ -346,10 +346,11 @@ jobs: name: dylint (${{ inputs.label }}) if: ${{ inputs.dylint }} runs-on: ${{ inputs.os }} - # Windows x86 with a cold compiler-unit cache spends ~20 min in each of the - # two workspace passes (2026-10-26, PR #1337), and that cache is saved - # only from main, so a PR lane is always cold. 30 cancelled the second pass. - timeout-minutes: 60 + # Windows x86 with a cold compiler-unit cache spent 20-30 min in each of + # the two workspace passes (2026-10-26, PR #1337: 50 min once, over 60 + # the next time), and that cache is saved only from main, so a PR lane is + # always cold. 30 and then 60 cancelled the second pass. + timeout-minutes: 120 env: SOLDR_DYLINT_DRIVER_FALLBACK: "off" # The lint crates select dylint-link through cfg(all()). Soldr's From cb7764639bff60cd7366ce7f478b43a23430ae7b Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 26 Oct 2026 16:00:07 -0700 Subject: [PATCH 12/12] test(service): close clients before deleting the runtime dir unittest runs tearDown before addCleanup callbacks, so the runtime directory was removed while each ServiceClient was still open. Its supervisor saw the killed service, respawned one into the directory mid-rmtree, and teardown failed with ENOTEMPTY (local gate, 2026-10-26). The directory and the kills are now cleanups registered in setUp, so they run after every client.close. Local-Gate: v1 tree=c00e2a6a7beeaf255f41b3e18a1b191e2fe98327 secs=1644 lanes=linux-quick:run Ci-Attestation: {"at":1793061372,"gate":"rust/all/fmt","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"8b612f0a2c02fd33e6019afb9cbdf2e0","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"python/all/static","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"bafd182ebd8458626b57cc9b2443a00d","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"rust/x86_64-unknown-linux-gnu/check","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"1c46f7d926ea1ebee0f45c2c65e9ab7f","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"rust/x86_64-unknown-linux-gnu/dylint","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"b358a85fde202dc2a72ab7e28648ae41","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"rust/x86_64-unknown-linux-gnu/test","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"1ef4a4cd5791c15d211224c7892143ae","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"python/linux-x64/test","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"7132d5a640350eca374f2b8ae69def22","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} Ci-Attestation: {"at":1793061372,"gate":"general/linux-x64/perf","host":"linux-x86_64","key":"e7c5ae3ba9f2c8a41f34b767930af9dc97b6775d283ae54a922b4c40339cc4f1","lane":"linux-quick","parents":["be9d77a9b0ea5e9cc570666ec5f1da708a940172"],"secs":1644,"stamp":"6e386d04af8ec77ef21bca8f194d0efe","tree":"c00e2a6a7beeaf255f41b3e18a1b191e2fe98327","v":1,"via":"run"} --- tests/test_service.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/test_service.py b/tests/test_service.py index 20ea2554..d581c63a 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -44,9 +44,10 @@ class _Runtime(unittest.TestCase): def setUp(self) -> None: self._tmp = tempfile.TemporaryDirectory(prefix="rpsvc-") self.runtime = Path(self._tmp.name) - - def tearDown(self) -> None: - self._tmp.cleanup() + # Cleanups run last-registered-first, after tearDown. Registering the + # directory first makes it the very last thing removed: a client + # closed in its own cleanup can no longer respawn a service into it. + self.addCleanup(self._tmp.cleanup) def spec(self, name: str = "svc-test", **kwargs): from running_process_service import ServiceSpec @@ -255,14 +256,17 @@ def setUp(self) -> None: self.script = self.runtime / "service.py" self.script.write_text(SERVICE_SCRIPT, encoding="utf-8") self.pids: list[int] = [] + # Before the directory goes, after every client is closed (clients + # register their close later, so it runs first): otherwise a live + # supervisor sees the kill and respawns a service mid-rmtree. + self.addCleanup(self._kill_services) - def tearDown(self) -> None: + def _kill_services(self) -> None: for pid in self.pids: try: os.kill(pid, 9) except OSError: pass - super().tearDown() def spawns(self) -> list[int]: log = self.runtime / "spawns.log"