From 31e5ebea2e89c502fb28a73e9a3df13098be90fc Mon Sep 17 00:00:00 2001 From: Jer Miller Date: Wed, 22 Jul 2026 21:44:27 -0600 Subject: [PATCH] fix(release): accept real macOS swift --version banner shapes parse_macos_swift_banner rejected the real host output: swift --version emits two lines with trailing `Target: arm64-apple-macosx26.0`, and the macOS build-host channel adapter flattens them with `tr '\n' ' '` into one line ending in ` Target: ...`. Both forms were refused, failing a correctly pinned host. Extend `_MACOS_SWIFT_BANNER_RE` with an optional trailing `Target: ` segment using a single space or single newline separator. Continue parsing only the `(version, swiftlang, clang)` triple and comparing it against the unchanged `MACOS_SWIFT_PIN`. `parse_macos_swift_banner` now fullmatches the raw value, and the swift dispatch in `parse_host_variant_tool_banner` moves above the single-line gate. The uv path is untouched. Add `MACOS_SWIFT_TARGET_LINE`, `MACOS_SWIFT_RAW_BANNER`, and `MACOS_SWIFT_FLATTENED_BANNER` fixtures derived from the byte-identical `MACOS_SWIFT_FIXTURE_BANNER`. No pin values change. Tests move the raw two-line case to accepts, add direct parser red-proofs for both real forms plus a mutation-still-refused check, and make the channel-adapter boundary fake emit the real flattened-with-Target output. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/release_tool_pins.py | 14 ++++---- tests/test_channel_adapters.py | 6 ++-- tests/test_check_release_preflight.py | 39 ++++++++++++++++++++++- tests/test_check_rust_release_manifest.py | 10 ++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/scripts/release_tool_pins.py b/scripts/release_tool_pins.py index 6bea63205..38dddbe43 100644 --- a/scripts/release_tool_pins.py +++ b/scripts/release_tool_pins.py @@ -52,6 +52,9 @@ MACOS_SWIFT_FIXTURE_BANNER = ( "Apple Swift version 6.3.3 " "(swiftlang-6.3.3.1.3 clang-2100.1.1.101)" ) +MACOS_SWIFT_TARGET_LINE = "Target: arm64-apple-macosx26.0" +MACOS_SWIFT_RAW_BANNER = f"{MACOS_SWIFT_FIXTURE_BANNER}\n{MACOS_SWIFT_TARGET_LINE}" +MACOS_SWIFT_FLATTENED_BANNER = f"{MACOS_SWIFT_FIXTURE_BANNER} {MACOS_SWIFT_TARGET_LINE}" MACOS_CODESIGN_PATH = "/usr/bin/codesign" MACOS_CODESIGN_PUBLIC_PIN = "codesign pinned-path verified" # xcrun notarytool --version prints the bare grounded output, with no tool prefix. @@ -69,7 +72,7 @@ _MACOS_SWIFT_BANNER_RE = re.compile( r"^(?:swift-driver version: (?P\d+(?:\.\d+){2}) )?" r"Apple Swift version (?P\d+(?:\.\d+){2}) " r"\(swiftlang-(?P\d+(?:\.\d+){4}) " - r"clang-(?P\d+(?:\.\d+){3})\)$" + r"clang-(?P\d+(?:\.\d+){3})\)(?:[ \n]Target: \S+)?$" ) SwiftToolIdentity = tuple[str, str, str] HostVariantToolIdentity = str | SwiftToolIdentity @@ -106,10 +109,7 @@ def _single_stripped_line(value: str) -> str | None: def parse_macos_swift_banner(value: str) -> SwiftToolIdentity | None: - line = _single_stripped_line(value) - if line is None: - return None - match = _MACOS_SWIFT_BANNER_RE.fullmatch(line) + match = _MACOS_SWIFT_BANNER_RE.fullmatch(value) if match is None: return None return (match["version"], match["swiftlang"], match["clang"]) @@ -118,11 +118,11 @@ def parse_macos_swift_banner(value: str) -> SwiftToolIdentity | None: def parse_host_variant_tool_banner( tool: str, value: str ) -> HostVariantToolIdentity | None: + if tool == "swift": + return parse_macos_swift_banner(value) line = _single_stripped_line(value) if line is None: return None - if tool == "swift": - return parse_macos_swift_banner(line) parts = line.split(" ", 2) if len(parts) != 3: return None diff --git a/tests/test_channel_adapters.py b/tests/test_channel_adapters.py index 00c7d1606..f987a3b0a 100644 --- a/tests/test_channel_adapters.py +++ b/tests/test_channel_adapters.py @@ -23,7 +23,7 @@ from scripts.check_release_preflight import expected_presign_lane_tool_evidence from scripts.release_digest import candidate_digest from scripts.release_tool_pins import ( HOST_VARIANT_TOOL_KEYS, - MACOS_SWIFT_FIXTURE_BANNER, + MACOS_SWIFT_FLATTENED_BANNER, UV_MACOS_FIXTURE_BANNER, ) @@ -93,7 +93,7 @@ def _tool_stdout(*, uv: str = UV_MACOS_FIXTURE_BANNER) -> str: observed = { **expected, "uv": uv, - "swift": MACOS_SWIFT_FIXTURE_BANNER, + "swift": MACOS_SWIFT_FLATTENED_BANNER, } return ( "\n".join(f"{key}\t{observed[key]}" for key in sorted(observed)) @@ -448,7 +448,7 @@ def test_macos_tool_evidence_derives_from_rail_pins( assert set(evidence) == set(expected) assert evidence["uv"] == UV_MACOS_FIXTURE_BANNER - assert evidence["swift"] == MACOS_SWIFT_FIXTURE_BANNER + assert evidence["swift"] == MACOS_SWIFT_FLATTENED_BANNER for key in set(expected) - set(HOST_VARIANT_TOOL_KEYS): assert evidence[key] == expected[key] diff --git a/tests/test_check_release_preflight.py b/tests/test_check_release_preflight.py index b88c74715..264856d98 100644 --- a/tests/test_check_release_preflight.py +++ b/tests/test_check_release_preflight.py @@ -331,6 +331,8 @@ def test_host_variant_uv_non_string_evidence_fails_closed(uv_value: object) -> N ( pins.MACOS_SWIFT_FIXTURE_BANNER, pins.MACOS_SWIFT_PIN, + pins.MACOS_SWIFT_RAW_BANNER, + pins.MACOS_SWIFT_FLATTENED_BANNER, ), ) def test_host_variant_swift_evidence_accepts_strict_identity( @@ -348,6 +350,42 @@ def test_host_variant_swift_evidence_accepts_strict_identity( ) +@pytest.mark.parametrize( + "swift_banner", + ( + pins.MACOS_SWIFT_RAW_BANNER, + pins.MACOS_SWIFT_FLATTENED_BANNER, + ), +) +def test_parse_macos_swift_banner_accepts_real_host_forms( + swift_banner: str, +) -> None: + assert pins.parse_macos_swift_banner(swift_banner) == ( + "6.3.3", + "6.3.3.1.3", + "2100.1.1.101", + ) + assert ( + pins.check_host_variant_tool_pin("swift", pins.MACOS_SWIFT_PIN, swift_banner) + is True + ) + + +def test_check_host_variant_swift_pin_rejects_mutated_flattened_identity() -> None: + mutated = pins.MACOS_SWIFT_FLATTENED_BANNER.replace( + "Apple Swift version 6.3.3", "Apple Swift version 6.3.4" + ) + assert pins.parse_macos_swift_banner(mutated) == ( + "6.3.4", + "6.3.3.1.3", + "2100.1.1.101", + ) + assert ( + pins.check_host_variant_tool_pin("swift", pins.MACOS_SWIFT_PIN, mutated) + is False + ) + + @pytest.mark.parametrize( "swift_value", ( @@ -355,7 +393,6 @@ def test_host_variant_swift_evidence_accepts_strict_identity( "exit 1", "", " ", - f"{pins.MACOS_SWIFT_FIXTURE_BANNER}\nTarget: arm64-apple-macosx26.0", "swift 6.3.3", "swift-driver 1.148.6 Apple Swift version 6.3.3 (swiftlang-6.3.3.1.3 clang-2100.1.1.101)", f"{pins.MACOS_SWIFT_FIXTURE_BANNER} extra", diff --git a/tests/test_check_rust_release_manifest.py b/tests/test_check_rust_release_manifest.py index 6081d7d49..ef851a236 100644 --- a/tests/test_check_rust_release_manifest.py +++ b/tests/test_check_rust_release_manifest.py @@ -139,6 +139,16 @@ def test_macos_swift_pin_requires_exact_canonical_grounded_output() -> None: assert pins.MACOS_SWIFT_PIN == exact assert checker.validate_public_evidence_text("swift", pins.MACOS_SWIFT_PIN) == [] + assert ( + checker.validate_public_evidence_text("swift", pins.MACOS_SWIFT_RAW_BANNER) + == [] + ) + assert ( + checker.validate_public_evidence_text( + "swift", pins.MACOS_SWIFT_FLATTENED_BANNER + ) + == [] + ) assert not any( line.startswith("MACOS_SWIFT_VERSION") for line in Path(pins.__file__).read_text(encoding="utf-8").splitlines() -- 2.51.2