diff --git a/.github/workflows/ci-acp-sdk.yml b/.github/workflows/ci-acp-sdk.yml index 00a0fe50..d5681fd2 100644 --- a/.github/workflows/ci-acp-sdk.yml +++ b/.github/workflows/ci-acp-sdk.yml @@ -64,18 +64,18 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Run the pinned upstream Agent against this SDK run: bash scripts/gates/run-acp-official-v2-agent-gate.sh - name: Upload upstream interoperability evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-official-v2-agent path: | @@ -94,18 +94,18 @@ jobs: MSBUILDDISABLENODEREUSE: "1" steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Verify real stdio batches without skips run: bash scripts/gates/run-acp-batch-stdio-gate.sh Release - name: Upload stdio evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-batch-stdio path: artifacts/acp-batch-stdio/ @@ -119,12 +119,12 @@ jobs: # history (tags included) must be present. A shallow clone would pack a 0.0.0-alpha version # and the baseline guard in SalmonEgg.Acp.csproj would fail the pack. - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -141,7 +141,7 @@ jobs: run: ./scripts/gates/run-acp-sdk-tag-version-gate-selftest.sh - name: Upload ACP SDK package - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-sdk-package path: "${{ env.PACKAGE_OUTPUT }}/*.nupkg" @@ -153,15 +153,15 @@ jobs: timeout-minutes: 25 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Download ACP SDK package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: acp-sdk-package path: artifacts/acp-sdk-package diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index bde1efbb..7b74dfef 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -53,11 +53,11 @@ jobs: MSBUILDDISABLENODEREUSE: "1" steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Verify real cancellation transports without skips @@ -68,11 +68,11 @@ jobs: shell: bash run: | python3 -m venv "$RUNNER_TEMP/acp-bridge-venv" - "$RUNNER_TEMP/acp-bridge-venv/bin/pip" install acpremote==1.9.0 + "$RUNNER_TEMP/acp-bridge-venv/bin/pip" install acpremote==1.10.0 python3 scripts/gates/run-acp-published-bridge-gate.py --bridge "$RUNNER_TEMP/acp-bridge-venv/bin/acpremote" - name: Upload transport evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-cancellation-transports path: | @@ -86,12 +86,12 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -173,14 +173,14 @@ jobs: - name: Upload test results if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: test-results path: "${{ env.TEST_RESULTS_DIR }}/**/*.trx" - name: Upload coverage reports if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: coverage-report path: "**/coverage*.xml" @@ -196,7 +196,7 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 1 persist-credentials: false diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 5a39272b..ad083cf3 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -48,12 +48,12 @@ jobs: timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 70b6e82f..d75f60a7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -52,15 +52,15 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Initialize CodeQL - uses: github/codeql-action/init@42947a340483f03ba47bb1a039b2c519aab3df85 # v3.37.8 + uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: languages: csharp build-mode: manual @@ -97,6 +97,6 @@ jobs: done - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@42947a340483f03ba47bb1a039b2c519aab3df85 # v3.37.8 + uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: category: "/language:csharp" diff --git a/.github/workflows/gui-smoke-gates.yml b/.github/workflows/gui-smoke-gates.yml index b45eb1d2..874fc493 100644 --- a/.github/workflows/gui-smoke-gates.yml +++ b/.github/workflows/gui-smoke-gates.yml @@ -49,10 +49,10 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -79,7 +79,7 @@ jobs: - name: Upload ACP setup path evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-setup-path-smoke path: ${{ runner.temp }}/acp-setup-path-smoke @@ -97,7 +97,7 @@ jobs: - name: Upload native elicitation evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: native-elicitation-consent path: | @@ -135,10 +135,10 @@ jobs: if: github.event_name == 'workflow_dispatch' && vars.WINDOWS_GUI_SELF_HOSTED_RUNNER == 'true' steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json diff --git a/.github/workflows/macos-native-acceptance.yml b/.github/workflows/macos-native-acceptance.yml index 2566f9da..a8de99f9 100644 --- a/.github/workflows/macos-native-acceptance.yml +++ b/.github/workflows/macos-native-acceptance.yml @@ -36,7 +36,7 @@ jobs: UseSharedCompilation: 'false' steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Verify native observation readiness contracts @@ -45,7 +45,7 @@ jobs: timeout-minutes: 3 run: python3 scripts/gates/run-macos-desktop-input-probe.py - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Build the current native macOS application @@ -62,7 +62,7 @@ jobs: run: python3 scripts/gates/macos-elicitation-reverse-verification.py - name: Upload native desktop evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: macos-native-desktop-input path: | diff --git a/.github/workflows/native-android-acceptance.yml b/.github/workflows/native-android-acceptance.yml index da36ade1..75ad6bf8 100644 --- a/.github/workflows/native-android-acceptance.yml +++ b/.github/workflows/native-android-acceptance.yml @@ -38,12 +38,12 @@ jobs: SALMONEGG_ANDROID_REVERSE: ${{ github.event_name == 'workflow_dispatch' && inputs.reverse-verification || false }} steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -57,7 +57,7 @@ jobs: 'platforms;android-36' 'build-tools;36.0.0' platform-tools emulator 'system-images;android-36;google_apis;x86_64' echo "$ANDROID_SDK_ROOT/platform-tools" >> "$GITHUB_PATH" python3 -m venv "$RUNNER_TEMP/android-acp-tools" - "$RUNNER_TEMP/android-acp-tools/bin/python" -m pip install aiohttp==3.12.15 + "$RUNNER_TEMP/android-acp-tools/bin/python" -m pip install aiohttp==3.14.4 - name: Build current installable APK run: | @@ -133,7 +133,7 @@ jobs: - name: Upload acceptance evidence if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: android-installed-acp-acceptance path: artifacts/android-acp-acceptance diff --git a/.github/workflows/native-ios-acceptance.yml b/.github/workflows/native-ios-acceptance.yml index ddd4a008..20fe1835 100644 --- a/.github/workflows/native-ios-acceptance.yml +++ b/.github/workflows/native-ios-acceptance.yml @@ -29,28 +29,28 @@ concurrency: jobs: installed-ios: name: iOS Installed ACP UI - # Pair the repository's .NET 10 SDK with the published 10.0.300.3 Apple workload set. - # Xcode 26.5 / iOS 26.5 are both installed on this serviced native host. + # Pin the 10.0.401 workload set: its Apple workload (26.5.10318) requires Xcode 26.6, which this GA + # image carries. The band's later 10.0.401.1 set moves to Xcode 27, whose hosted image is a preview. runs-on: macos-26 - timeout-minutes: ${{ github.event_name == 'workflow_dispatch' && inputs.reverse-verification && 65 || 35 }} + timeout-minutes: ${{ github.event_name == 'workflow_dispatch' && inputs.reverse-verification && 80 || 35 }} env: DOTNET_PROCESSOR_COUNT: 2 DOTNET_CLI_USE_MSBUILD_SERVER: 0 MSBUILDDISABLENODEREUSE: 1 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Select matching Apple toolchain run: | - xcode_developer_dir="$(python3 -c 'import os; print(os.path.realpath("/Applications/Xcode_26.5.app/Contents/Developer"))')" + xcode_developer_dir="$(python3 -c 'import os; print(os.path.realpath("/Applications/Xcode_26.6.app/Contents/Developer"))')" test -d "$xcode_developer_dir" sudo xcode-select --switch "$xcode_developer_dir" xcodebuild -version @@ -58,8 +58,8 @@ jobs: uname -m xcrun --sdk iphonesimulator --show-sdk-path xcrun --sdk macosx --find actool - # https://github.com/dotnet/macios/releases/tag/dotnet-10.0.1xx-xcode26.5-10284 - dotnet workload install ios --version 10.0.300.3 --disable-parallel --no-http-cache + # https://github.com/dotnet/macios/releases/tag/dotnet-10.0.1xx-xcode26.5-10318 + dotnet workload install ios --version 10.0.401 --disable-parallel --no-http-cache dotnet workload list # Wait for CoreSimulatorService before actool / xcodebuild (runner-images #12777). xcrun simctl list runtimes @@ -77,7 +77,7 @@ jobs: - name: Install isolated test tooling run: | python3 -m venv "$RUNNER_TEMP/ios-acp-tools" - "$RUNNER_TEMP/ios-acp-tools/bin/python" -m pip install aiohttp==3.12.15 + "$RUNNER_TEMP/ios-acp-tools/bin/python" -m pip install aiohttp==3.14.4 curl --location --fail --silent --show-error \ https://github.com/yonaskolb/XcodeGen/releases/download/2.46.0/xcodegen.zip \ --output "$RUNNER_TEMP/xcodegen.zip" @@ -100,7 +100,7 @@ jobs: - name: Upload acceptance evidence if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ios-installed-acp-acceptance path: | @@ -109,6 +109,7 @@ jobs: artifacts/ios-acp-acceptance/product-logs/** artifacts/ios-acp-acceptance/results.xcresult artifacts/ios-acp-acceptance/test-attachments/** + artifacts/ios-acp-acceptance/hang-diagnostics/** artifacts/ios-acp-acceptance/reverse/*.json artifacts/ios-acp-acceptance/reverse/*.log artifacts/ios-acp-acceptance/reverse/red/*.json diff --git a/.github/workflows/platform-build-gates.yml b/.github/workflows/platform-build-gates.yml index 9ef87819..96c2e504 100644 --- a/.github/workflows/platform-build-gates.yml +++ b/.github/workflows/platform-build-gates.yml @@ -61,14 +61,14 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags # and would stamp 0.0.0 into every manifest and binary. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -118,14 +118,14 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags # and would stamp 0.0.0 into every manifest and binary. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -189,18 +189,19 @@ jobs: # packaging chain is not, so this gate builds the package unsigned on every change and asserts the # package actually carries what its manifest declares. name: Windows MSIX Package - runs-on: windows-latest + # Match the .NET 10.0.4xx SDK with the Visual Studio 2026 XAML/MSIX toolchain. + runs-on: windows-2025-vs2026 timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags # and would stamp 0.0.0 into every manifest and binary. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -290,14 +291,14 @@ jobs: timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags # and would stamp 0.0.0 into every manifest and binary. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -355,19 +356,20 @@ jobs: name: iOS Simulator # Heavy mobile build fast-gated out of standard PRs; runs on push, schedule, and workflow_dispatch. if: github.event_name != 'pull_request' - # Pin the OS image because .NET for iOS 26.0 requires Xcode 26.0, while macos-latest can roll forward independently. - runs-on: macos-15 + # Pin the 10.0.401 workload set: its Apple workload (26.5.10318) requires Xcode 26.6, which this GA + # image carries. The band's later 10.0.401.1 set moves to Xcode 27, whose hosted image is a preview. + runs-on: macos-26 timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags # and would stamp 0.0.0 into every manifest and binary. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -377,7 +379,7 @@ jobs: xcode_developer_dir="$(python3 - <<'PY' import os - print(os.path.realpath("/Applications/Xcode_26.0.app/Contents/Developer")) + print(os.path.realpath("/Applications/Xcode_26.6.app/Contents/Developer")) PY )" if [ ! -d "${xcode_developer_dir}" ]; then @@ -389,8 +391,8 @@ jobs: xcodebuild -version xcode_version="$(xcodebuild -version | awk 'NR == 1 { print $2 }')" case "${xcode_version}" in - 26.0*) ;; - *) echo "Expected Xcode 26.0.x, got ${xcode_version}." >&2; exit 1 ;; + 26.6*) ;; + *) echo "Expected Xcode 26.6.x, got ${xcode_version}." >&2; exit 1 ;; esac xcrun --sdk macosx --show-sdk-path xcrun --sdk iphonesimulator --show-sdk-path @@ -411,7 +413,8 @@ jobs: echo ".NET SDK ${dotnet_version}" - name: Install iOS workload - run: dotnet workload install ios --skip-manifest-update --disable-parallel --no-http-cache + # https://github.com/dotnet/macios/releases/tag/dotnet-10.0.1xx-xcode26.5-10318 + run: dotnet workload install ios --version 10.0.401 --disable-parallel --no-http-cache - name: Report iOS workload run: | diff --git a/.github/workflows/release-acp-sdk.yml b/.github/workflows/release-acp-sdk.yml index c309222a..a49b0b9e 100644 --- a/.github/workflows/release-acp-sdk.yml +++ b/.github/workflows/release-acp-sdk.yml @@ -31,12 +31,12 @@ jobs: # history (tags included) must be present. A shallow clone would pack a 0.0.0-alpha version # and the tag/version gate below would catch it - but only after the whole pack had run. - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -60,7 +60,7 @@ jobs: run: ./scripts/gates/run-acp-sdk-tag-version-gate.sh "${{ github.ref_name }}" "${{ env.PACKAGE_OUTPUT }}" - name: Upload ACP SDK package - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: acp-sdk-release-package path: | @@ -74,15 +74,15 @@ jobs: timeout-minutes: 25 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Download ACP SDK package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: acp-sdk-release-package path: artifacts/acp-sdk-package @@ -122,19 +122,19 @@ jobs: # Sparse: global.json is the only tracked file this job touches. The package it pushes comes # from the `pack` job's artifact, not from source. - name: Checkout for the SDK pin - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: sparse-checkout: global.json sparse-checkout-cone-mode: false fetch-depth: 1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Download ACP SDK package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: acp-sdk-release-package path: artifacts/acp-sdk-package diff --git a/.github/workflows/release-packaging.yml b/.github/workflows/release-packaging.yml index a17eef61..746c5875 100644 --- a/.github/workflows/release-packaging.yml +++ b/.github/workflows/release-packaging.yml @@ -37,12 +37,12 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -61,7 +61,7 @@ jobs: run: scripts/gates/run-release-artifact-contract-gate.sh wasm publish/wasm - name: Upload WebAssembly artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: wasm-build path: publish/wasm @@ -72,12 +72,12 @@ jobs: timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -223,7 +223,7 @@ jobs: (Join-Path $wixObjDir "Harvest.wixobj") - name: Upload Desktop artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-windows-build path: publish/desktop-windows @@ -260,23 +260,24 @@ jobs: [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($installer) } - name: Upload Windows Skia MSI artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-windows-skia-msi path: artifacts/installer/*.msi package-windows-msix: name: Package Windows MSIX - runs-on: windows-latest + # Match the .NET 10.0.4xx SDK with the Visual Studio 2026 XAML/MSIX toolchain. + runs-on: windows-2025-vs2026 timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -391,7 +392,7 @@ jobs: ./scripts/gates/run-msix-package-contract-gate.ps1 -Package $package.FullName - name: Upload Windows MSIX artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-windows-msix path: artifacts/msix/**/*.msix @@ -414,12 +415,12 @@ jobs: MACOS_NOTARY_PROFILE: ${{ secrets.MACOS_NOTARY_PROFILE }} steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -549,7 +550,7 @@ jobs: run: scripts/gates/run-macos-pkg-artifact-gate.sh "$PKG_PATH" - name: Upload macOS installer package artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-macos-pkg path: | @@ -558,14 +559,14 @@ jobs: if-no-files-found: error - name: Upload macOS bundle artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-macos-bundle path: publish/macos-bundle/* - name: Upload macOS .dmg artifact if: env.MACOS_APP_CODESIGN_KEY != '' && env.MACOS_DMG_CODESIGN_KEY != '' - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-macos-dmg path: publish/dmg/*.dmg @@ -576,14 +577,14 @@ jobs: timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: # The version identity is derived from git tags by MinVer; a shallow clone sees no tags and # would stamp 0.0.0 into the package version, which no later release could upgrade over. fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json @@ -621,7 +622,7 @@ jobs: run: scripts/gates/run-desktop-linux-package-smoke.sh "${{ steps.build-deb.outputs.deb-path }}" - name: Upload Linux desktop package artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: desktop-linux-deb path: | @@ -649,49 +650,49 @@ jobs: steps: - name: Download Windows MSIX artifact if: needs.package-windows-msix.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-windows-msix path: windows-msix - name: Download WebAssembly artifact if: needs.package-wasm.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: wasm-build path: wasm-build - name: Download Windows Skia MSI artifact if: needs.package-desktop.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-windows-skia-msi path: windows-skia-msi - name: Download macOS bundle artifact if: needs.package-macos.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-macos-bundle path: macos-bundle - name: Download macOS installer package artifact if: needs.package-macos.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-macos-pkg path: macos-pkg - name: Download macOS .dmg artifact if: needs.package-macos.outputs.dmg-produced == 'true' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-macos-dmg path: macos-dmg - name: Download Linux desktop package artifact if: needs.package-linux-desktop.result == 'success' - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: desktop-linux-deb path: linux-deb diff --git a/.github/workflows/terminal-auth-windows.yml b/.github/workflows/terminal-auth-windows.yml index 6da47248..739efd6c 100644 --- a/.github/workflows/terminal-auth-windows.yml +++ b/.github/workflows/terminal-auth-windows.yml @@ -25,11 +25,11 @@ jobs: MSBUILDDISABLENODEREUSE: 1 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Run actual ConPTY process and teardown gate @@ -37,7 +37,7 @@ jobs: run: ./scripts/gates/run-terminal-auth-windows-gate.ps1 - name: Upload terminal authentication results if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: terminal-auth-windows-results path: artifacts/terminal-auth-windows diff --git a/.github/workflows/wasm-smoke-gates.yml b/.github/workflows/wasm-smoke-gates.yml index 6b6a9080..c7e9a092 100644 --- a/.github/workflows/wasm-smoke-gates.yml +++ b/.github/workflows/wasm-smoke-gates.yml @@ -49,17 +49,17 @@ jobs: timeout-minutes: 45 steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Setup Node - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: - node-version: "24" + node-version: "26.10.0" - name: Install browser dependencies run: npx --yes playwright install --with-deps chromium diff --git a/.github/workflows/windows-packaged-gui-acceptance.yml b/.github/workflows/windows-packaged-gui-acceptance.yml index 4f342807..ca11e7dc 100644 --- a/.github/workflows/windows-packaged-gui-acceptance.yml +++ b/.github/workflows/windows-packaged-gui-acceptance.yml @@ -35,7 +35,8 @@ concurrency: jobs: packaged-gui: name: Windows Installed WinUI GUI - runs-on: windows-latest + # Match the .NET 10.0.4xx SDK with the Visual Studio 2026 XAML/MSIX toolchain. + runs-on: windows-2025-vs2026 timeout-minutes: 80 env: DOTNET_PROCESSOR_COUNT: '2' @@ -44,11 +45,11 @@ jobs: UseSharedCompilation: 'false' steps: - name: Checkout - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5.4.0 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: global-json-file: global.json - name: Verify the hosted interactive desktop with real input @@ -76,7 +77,7 @@ jobs: run: python scripts/gates/windows-elicitation-reverse-verification.py - name: Upload installed-product and desktop evidence if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: windows-packaged-gui-acceptance path: | diff --git a/BUILD_GUIDE.md b/BUILD_GUIDE.md index 021805b2..f1425c71 100644 --- a/BUILD_GUIDE.md +++ b/BUILD_GUIDE.md @@ -16,7 +16,7 @@ dotnet --version dotnet --info ``` -仓库通过 `global.json` 锁定 .NET SDK `10.0.302`,允许同一 feature band 内的 patch 前滚;Uno SDK 锁定为 `6.7.30`。版本不匹配时先安装 .NET 10 SDK,不要手改项目 TFM 或 `global.json`。 +仓库通过 `global.json` 锁定 .NET SDK `10.0.401`,允许同一 feature band 内的 patch 前滚;Uno SDK 锁定为 `6.7.30`。所有子目录共用根目录的 `global.json`。版本不匹配时先安装 .NET 10 SDK,不要手改项目 TFM 或 `global.json`。 ### 必需与可选依赖 @@ -24,7 +24,7 @@ dotnet --info |------|--------------| | Desktop / Core | .NET 10 SDK;Linux 还需要下方的原生库 | | BrowserWasm | .NET 10 SDK + `wasm-tools` workload | -| Windows MSIX | Visual Studio 18.8+ 或 Build Tools;MSBuild、C++ 构建工具、Windows SDK `10.0.26100.0`;`signtool` 使用 SDK `10.0.22621.0` | +| Windows MSIX | Visual Studio 18.9.3+ 或 Build Tools;MSBuild、C++ 构建工具、Windows SDK `10.0.26100.0`;`signtool` 使用 SDK `10.0.22621.0` | | Android | Android workload、Android SDK 和 Java JDK 17+;默认构建不启用 Android | | iOS | macOS、匹配的 Xcode 和 iOS workload;默认构建不启用 iOS | @@ -138,7 +138,7 @@ run.bat desktop ### 1. 环境要求 - **.NET SDK**: 10.0 或更高版本 - - 推荐版本:10.0.302(允许 patch 前滚) + - 推荐版本:10.0.401(允许 patch 前滚) - 下载地址: https://dotnet.microsoft.com/download/dotnet/10.0 - **操作系统**: @@ -163,7 +163,7 @@ Linux 桌面运行时依赖按能力分层(包名以 Debian/Ubuntu 为例) # 检查 .NET SDK 版本 dotnet --version -# 应该输出 10.0.302 或兼容的 10.0.3xx patch 版本 +# 应该输出 10.0.401 或兼容的 10.0.4xx patch 版本 ``` ### 3. 克隆代码(如果还没有) @@ -227,7 +227,7 @@ run.bat > 证书复用:`.tools/run-winui3-msix.ps1` 现在会复用同一张开发证书,不应再在每次 `run.bat msix` 时重建证书或反复要求安装证书。 > 历史根因:脚本曾使用 PowerShell 中不可靠的 `$Cert.GetRSAPrivateKey()` 调用来判断私钥可用性,导致有效的 RSA 私钥被误判为不可用,进而每次重建新证书;现已改为标准的 `RSACertificateExtensions.GetRSAPrivateKey(...)`。 > 工具链锁定:Windows SDK 10.0.26100.0,signtool 来自 SDK 10.0.22621.0。 -> Workload manifest:CI 应与 `global.json` 中的 .NET SDK feature band 保持一致;当前仓库锁定 10.0.302,并使用 `rollForward: latestPatch`。所有 GHA 均使用 `setup-dotnet` 官方支持的 `10.0.3xx` 语法,只在同一 feature band 内前滚 patch,避免 workload manifest 与 Xcode 独立漂移。 +> Workload manifest:CI 应与 `global.json` 中的 .NET SDK feature band 保持一致;当前仓库锁定 10.0.401,并使用 `rollForward: latestPatch`。所有 GHA 均使用 `setup-dotnet` 的 `global-json-file` 读取同一锁定文件。`global.json` 不设 `sdk.workloadVersion`:该字段会让 MSBuild 在未装 workload 的 runner 上直接解析失败,且与 `--skip-manifest-update` 互斥;workload 清单随 SDK feature band 走。iOS 编译与安装门禁在 `dotnet workload install ios` 上显式钉 workload set `10.0.401`(Apple workload 26.5.10318),共用 `macos-26` runner 上的 Xcode 26.6,对应 [Apple workload 发布说明](https://github.com/dotnet/macios/releases/tag/dotnet-10.0.1xx-xcode26.5-10318)。同 band 更新的 `10.0.401.1` 会切到要求 Xcode 27 的 27.0 workload,其托管镜像仍是 public preview,iOS 27 模拟器上安装与启动均不稳定,因此暂不跟进。 > 验证口径:`dotnet build -f net10.0-windows10.0.26100.0` 不是本仓库的权威 WinUI 3 / MSIX 门禁;Windows 原生包请以 `build.bat msix` 或 `.tools/run-winui3-msix.ps1 -SkipInstall` 为准。`dotnet build` 主要用于 Core/Skia/Desktop/Wasm 验证。 #### Linux Headless Desktop diff --git a/README.en.md b/README.en.md index 2be90e8e..a97724b0 100644 --- a/README.en.md +++ b/README.en.md @@ -51,7 +51,7 @@ Screenshots come from the store listing. In the app, **Settings → About** prov ## Tech Stack - Uno Platform 6.7+ (repo pin: `Uno.Sdk` 6.7.30) -- .NET 10 (repo pin: SDK 10.0.302, with 10.0.3xx patch roll-forward) +- .NET 10 (repo pin: SDK 10.0.401, with 10.0.4xx patch roll-forward) - WinUI 3 on Windows - Clean Architecture + MVVM @@ -78,8 +78,8 @@ For environment requirements and detailed build steps, start with [BUILD_GUIDE.m ### Requirements -- .NET SDK **10.0.302** or a compatible **10.0.3xx** patch (see `global.json`) -- Windows 10 1809+ / Windows 11 for WinUI 3 and MSIX validation; on Windows prefer Visual Studio **18.8+** +- .NET SDK **10.0.401** or a compatible **10.0.4xx** patch (see `global.json`) +- Windows 10 1809+ / Windows 11 for WinUI 3 and MSIX validation; on Windows prefer Visual Studio **18.9.3+** - Or an equivalent command-line toolchain (Linux/macOS can build Desktop / WASM) ### Common Commands diff --git a/README.md b/README.md index f1091117..cdb818ad 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Salmon Egg 已在 Microsoft Store 上架,免费下载。商店页面的正式 ## 技术栈 - Uno Platform 6.7+(仓库锁定 `Uno.Sdk` 6.7.30) -- .NET 10(仓库锁定 SDK 10.0.302,允许 10.0.3xx patch 前滚) +- .NET 10(仓库锁定 SDK 10.0.401,允许 10.0.4xx patch 前滚) - WinUI 3(Windows) - Clean Architecture + MVVM @@ -80,8 +80,8 @@ iOS 原生 UIKit 在当前 Uno 6.7.103 下使用平台内的官方导航模板 ### 环境要求 -- .NET SDK **10.0.302** 或兼容的 **10.0.3xx** patch(见 `global.json`) -- Windows 10 1809+ / Windows 11(WinUI 3 / MSIX);Windows 建议 Visual Studio **18.8+** +- .NET SDK **10.0.401** 或兼容的 **10.0.4xx** patch(见 `global.json`) +- Windows 10 1809+ / Windows 11(WinUI 3 / MSIX);Windows 建议 Visual Studio **18.9.3+** - 或等效命令行工具链(Linux/macOS 可构建 Desktop / WASM) ### 常用命令 diff --git a/SalmonEgg/Directory.Packages.props b/SalmonEgg/Directory.Packages.props index e3a7018c..d4ce11d5 100644 --- a/SalmonEgg/Directory.Packages.props +++ b/SalmonEgg/Directory.Packages.props @@ -18,11 +18,12 @@ - - - - - + + + + + diff --git a/SalmonEgg/global.json b/SalmonEgg/global.json deleted file mode 100644 index 2e1711d9..00000000 --- a/SalmonEgg/global.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - // To update the version of Uno please update the version of the Uno.Sdk here. See https://aka.platform.uno/upgrade-uno-packages for more information. - "msbuild-sdks": { - "Uno.Sdk": "6.7.30" - }, - "sdk": { - "allowPrerelease": false - } -} diff --git a/docs/release-guide.md b/docs/release-guide.md index e7cecf47..e0b65233 100644 --- a/docs/release-guide.md +++ b/docs/release-guide.md @@ -21,7 +21,7 @@ ### 通用要求 - .NET 10.0 SDK 或更高版本 -- Visual Studio 18.8+ 或 Visual Studio Code +- Visual Studio 18.9.3+ 或 Visual Studio Code - Git ### 平台特定要求 diff --git a/global.json b/global.json index 44af54c7..971e0cd6 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "Uno.Sdk": "6.7.30" }, "sdk": { - "version": "10.0.302", + "version": "10.0.401", "rollForward": "latestPatch", "allowPrerelease": false }, diff --git a/scripts/gates/ios-elicitation-reverse-verification.py b/scripts/gates/ios-elicitation-reverse-verification.py index 8ebff0ad..35dd64ab 100644 --- a/scripts/gates/ios-elicitation-reverse-verification.py +++ b/scripts/gates/ios-elicitation-reverse-verification.py @@ -18,9 +18,10 @@ def run(command, root, log_path, timeout): return process.wait(timeout=timeout) finally: # The child gate handles SIGTERM by deleting its own Simulator and reaping its peer. + # macOS answers EPERM, not ESRCH, when the group is left with only zombies. try: os.killpg(process.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, PermissionError): pass try: process.wait(timeout=120) @@ -28,7 +29,7 @@ def run(command, root, log_path, timeout): pass try: os.killpg(process.pid, signal.SIGKILL) - except ProcessLookupError: + except (ProcessLookupError, PermissionError): pass process.wait(timeout=5) @@ -53,7 +54,7 @@ def main(args): try: source.write_bytes(mutant) assert run(build, root, output / "mutant-build.log", 600) == 0, "The mutated app did not build" - red_exit = run([*gate, str(output / "red")], root, output / "red.log", 900) + red_exit = run([*gate, str(output / "red")], root, output / "red.log", 1200) assert red_exit != 0 and "The product opened a URL without consent." in (output / "red.log").read_text(), \ "The installed mutant was not rejected for its actual unconsented Safari visit" red = json.loads((output / "red/peer-state.json").read_text()) @@ -62,7 +63,7 @@ def main(args): source.write_bytes(original) assert source.read_bytes() == original assert run(build, root, output / "restored-build.log", 600) == 0, "The restored app did not rebuild" - assert run([*gate, str(output / "restored")], root, output / "restored.log", 900) == 0 + assert run([*gate, str(output / "restored")], root, output / "restored.log", 1200) == 0 baseline = json.loads((output.parent / "provenance.json").read_text()) red = json.loads((output / "red/provenance.json").read_text()) restored = json.loads((output / "restored/provenance.json").read_text()) diff --git a/scripts/gates/run-acp-published-bridge-gate.py b/scripts/gates/run-acp-published-bridge-gate.py index d7599b9d..99c7d474 100644 --- a/scripts/gates/run-acp-published-bridge-gate.py +++ b/scripts/gates/run-acp-published-bridge-gate.py @@ -33,7 +33,7 @@ def main(): output.mkdir(parents=True, exist_ok=True) bridge_path = shutil.which(args.bridge) if bridge_path is None: - raise SystemExit("Install acpremote==1.9.0 in an isolated environment before running this gate.") + raise SystemExit("Install the acpremote version pinned in .github/workflows/ci-core.yml in an isolated environment before running this gate.") with socket.socket() as listener: listener.bind(("127.0.0.1", 0)) port = listener.getsockname()[1] diff --git a/scripts/gates/run-ios-elicitation-gate.py b/scripts/gates/run-ios-elicitation-gate.py index 7a3102cb..25630bbb 100644 --- a/scripts/gates/run-ios-elicitation-gate.py +++ b/scripts/gates/run-ios-elicitation-gate.py @@ -25,6 +25,37 @@ def output(command): return subprocess.check_output(command, text=True, timeout=90).strip() +def capture_hang_evidence(artifacts, simulator, executable): + """Record where a stalled product is stuck before cleanup terminates it. + + The app log stops at the first line it cannot get past, which names neither the thread nor the + frame; a host stack sample, the device's unified log and any crash report do. + """ + diagnostics = artifacts / "hang-diagnostics" + diagnostics.mkdir(exist_ok=True) + # Simulator apps run as host processes launched from the device's own bundle container. + pattern = f"{simulator}/data/Containers/Bundle/Application/[^ ]*/{executable}.app/{executable}" + commands = [] + try: + pids = subprocess.run(["pgrep", "-f", pattern], capture_output=True, text=True, timeout=10).stdout.split() + except subprocess.TimeoutExpired: + pids = [] + commands += [(f"sample-{pid}.txt", ["sample", pid, "5"], 60) for pid in pids] + commands.append(("device-log.txt", ["xcrun", "simctl", "spawn", simulator, "log", "show", "--last", "20m", + "--style", "compact", "--predicate", f'process == "{executable}"'], 90)) + for name, command, timeout in commands: + with (diagnostics / name).open("w") as log: + try: + subprocess.run(command, stdout=log, stderr=subprocess.STDOUT, timeout=timeout, check=False) + except subprocess.TimeoutExpired: + log.write(f"\n[ios-gate] timed out after {timeout}s\n") + except OSError as error: + log.write(f"\n[ios-gate] could not run: {error!r}\n") + for report in (Path.home() / "Library/Logs/DiagnosticReports").glob(f"{executable}*"): + shutil.copyfile(report, diagnostics / report.name) + print(f"[ios-gate] hang diagnostics: {len(pids)} product process(es) sampled", flush=True) + + def seed(container, endpoint): root = container / "Library/Application Support/SalmonEgg" (root / "config/servers").mkdir(parents=True) @@ -64,6 +95,7 @@ def main(args): test_process = None root = None installed = False + passed = False try: # Start the peer before first-boot CoreSimulator work competes for the host CPU. with socket.socket() as reservation: @@ -99,8 +131,16 @@ def main(args): with (artifacts / "simulator-boot.log").open("w") as boot_log: run(["xcrun", "simctl", "bootstatus", simulator, "-b"], timeout=300, stdout=boot_log, stderr=subprocess.STDOUT) - run(["open", "-a", "Simulator", "--args", "-CurrentDeviceUDID", simulator]) - run(["xcrun", "simctl", "install", simulator, str(app)]) + # Open the selected Xcode's simulator host by path rather than by LaunchServices name. Xcode 27 + # replaced Developer/Applications/Simulator.app with Contents/Applications/DeviceHub.app. + developer = Path(output(["xcode-select", "-p"])) + candidates = [developer / "Applications/Simulator.app", developer.parent / "Applications/DeviceHub.app"] + simulator_app = next((path for path in candidates if path.is_dir()), None) + assert simulator_app is not None, ("The selected Xcode has no simulator host app: " + + ", ".join(f"{path.parent}={sorted(p.name for p in path.parent.glob('*.app'))}" for path in candidates)) + run(["open", "-a", str(simulator_app), "--args", "-CurrentDeviceUDID", simulator]) + # The Debug interpreter bundle took ~130 s to install on macos-26 and over 5 min on the Xcode 27 host. + run(["xcrun", "simctl", "install", simulator, str(app)], timeout=600) installed = True container = Path(output(["xcrun", "simctl", "get_app_container", simulator, bundle_id, "data"])) root = seed(container, endpoints["endpoint"]) @@ -141,7 +181,9 @@ def main(args): test_process = subprocess.Popen(["xcodebuild", "test-without-building", *test_arguments, "-resultBundlePath", str(artifacts / "results.xcresult")], env=env, stdout=log, stderr=subprocess.STDOUT, start_new_session=True) - test_exit = test_process.wait(timeout=420) + # Measured end to end: ~240 s on Xcode 26.5, ~460 s on Xcode 26.6 (runner launch, + # the test itself and the result bundle are each slower there). + test_exit = test_process.wait(timeout=600) if test_exit: print((artifacts / "xcuitest.log").read_text(errors="replace")[-18000:]) assert test_exit == 0, "The installed product XCUITest failed" @@ -162,16 +204,27 @@ def main(args): "systemSafari": True, "browserVisits": 2, "acceptWithoutContent": True, "formAnswer": True, "formResponses": 3, "noExternalDataPersistence": True}, indent=2) + "\n") print("iOS installed product: consent, form, Safari isolation and completion passed") + passed = True finally: + if installed and not passed: + # Sample while the product is still alive: every later step terminates it. + try: + capture_hang_evidence(artifacts, simulator, binary.name) + except Exception as error: # Evidence is best-effort; never mask the gate's own failure. + print(f"[ios-gate] hang diagnostics failed: {error!r}", flush=True) if test_process is not None: + # macOS answers EPERM, not ESRCH, when the group is left with only zombies. try: os.killpg(test_process.pid, signal.SIGTERM) - except ProcessLookupError: + except (ProcessLookupError, PermissionError): pass try: test_process.wait(timeout=10) except subprocess.TimeoutExpired: - os.killpg(test_process.pid, signal.SIGKILL) + try: + os.killpg(test_process.pid, signal.SIGKILL) + except (ProcessLookupError, PermissionError): + pass test_process.wait(timeout=5) results = artifacts / "results.xcresult" if results.exists(): diff --git a/src/SalmonEgg.Infrastructure.Desktop/SalmonEgg.Infrastructure.Desktop.csproj b/src/SalmonEgg.Infrastructure.Desktop/SalmonEgg.Infrastructure.Desktop.csproj index 97d4fccf..4df4c7a8 100644 --- a/src/SalmonEgg.Infrastructure.Desktop/SalmonEgg.Infrastructure.Desktop.csproj +++ b/src/SalmonEgg.Infrastructure.Desktop/SalmonEgg.Infrastructure.Desktop.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/SalmonEgg.Infrastructure/SalmonEgg.Infrastructure.csproj b/src/SalmonEgg.Infrastructure/SalmonEgg.Infrastructure.csproj index 065acb49..9e33300f 100644 --- a/src/SalmonEgg.Infrastructure/SalmonEgg.Infrastructure.csproj +++ b/src/SalmonEgg.Infrastructure/SalmonEgg.Infrastructure.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/SalmonEgg.Acp.Tests/SalmonEgg.Acp.Tests.csproj b/tests/SalmonEgg.Acp.Tests/SalmonEgg.Acp.Tests.csproj index 5b410f3e..bdbdd38b 100644 --- a/tests/SalmonEgg.Acp.Tests/SalmonEgg.Acp.Tests.csproj +++ b/tests/SalmonEgg.Acp.Tests/SalmonEgg.Acp.Tests.csproj @@ -15,9 +15,9 @@ - + - + diff --git a/tests/SalmonEgg.Application.Tests/SalmonEgg.Application.Tests.csproj b/tests/SalmonEgg.Application.Tests/SalmonEgg.Application.Tests.csproj index 40a10e18..c2431dcc 100644 --- a/tests/SalmonEgg.Application.Tests/SalmonEgg.Application.Tests.csproj +++ b/tests/SalmonEgg.Application.Tests/SalmonEgg.Application.Tests.csproj @@ -11,9 +11,9 @@ - + - + diff --git a/tests/SalmonEgg.Cli.Tests/SalmonEgg.Cli.Tests.csproj b/tests/SalmonEgg.Cli.Tests/SalmonEgg.Cli.Tests.csproj index d809fca8..844b9ad9 100644 --- a/tests/SalmonEgg.Cli.Tests/SalmonEgg.Cli.Tests.csproj +++ b/tests/SalmonEgg.Cli.Tests/SalmonEgg.Cli.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/tests/SalmonEgg.Domain.Tests/SalmonEgg.Domain.Tests.csproj b/tests/SalmonEgg.Domain.Tests/SalmonEgg.Domain.Tests.csproj index 4d34ce76..3e2bb8da 100644 --- a/tests/SalmonEgg.Domain.Tests/SalmonEgg.Domain.Tests.csproj +++ b/tests/SalmonEgg.Domain.Tests/SalmonEgg.Domain.Tests.csproj @@ -9,7 +9,7 @@ - + diff --git a/tests/SalmonEgg.GuiTests.Windows/SalmonEgg.GuiTests.Windows.csproj b/tests/SalmonEgg.GuiTests.Windows/SalmonEgg.GuiTests.Windows.csproj index 9db1d889..23ad6c95 100644 --- a/tests/SalmonEgg.GuiTests.Windows/SalmonEgg.GuiTests.Windows.csproj +++ b/tests/SalmonEgg.GuiTests.Windows/SalmonEgg.GuiTests.Windows.csproj @@ -10,7 +10,7 @@ - + diff --git a/tests/SalmonEgg.Infrastructure.Tests/SalmonEgg.Infrastructure.Tests.csproj b/tests/SalmonEgg.Infrastructure.Tests/SalmonEgg.Infrastructure.Tests.csproj index 18bf656e..fb60519c 100644 --- a/tests/SalmonEgg.Infrastructure.Tests/SalmonEgg.Infrastructure.Tests.csproj +++ b/tests/SalmonEgg.Infrastructure.Tests/SalmonEgg.Infrastructure.Tests.csproj @@ -11,10 +11,10 @@ - + - + diff --git a/tests/SalmonEgg.Presentation.Core.Tests/SalmonEgg.Presentation.Core.Tests.csproj b/tests/SalmonEgg.Presentation.Core.Tests/SalmonEgg.Presentation.Core.Tests.csproj index 2d6f173b..6729728c 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/SalmonEgg.Presentation.Core.Tests.csproj +++ b/tests/SalmonEgg.Presentation.Core.Tests/SalmonEgg.Presentation.Core.Tests.csproj @@ -9,8 +9,8 @@ - - + + diff --git a/tests/SalmonEgg.Presentation.Core.Tests/WasmStartupAssetsTests.cs b/tests/SalmonEgg.Presentation.Core.Tests/WasmStartupAssetsTests.cs index 9ecf3e18..aeb5752e 100644 --- a/tests/SalmonEgg.Presentation.Core.Tests/WasmStartupAssetsTests.cs +++ b/tests/SalmonEgg.Presentation.Core.Tests/WasmStartupAssetsTests.cs @@ -317,12 +317,14 @@ public void PlatformBuildGate_IsolatesMobileRestoreGraphsAndPinsIosToolchain() Assert.True( gate.IndexOf("Verify iOS .NET SDK", StringComparison.Ordinal) < gate.IndexOf("Install iOS workload", StringComparison.Ordinal)); - Assert.Contains("runs-on: macos-15", gate, StringComparison.Ordinal); - Assert.Contains("os.path.realpath(\"/Applications/Xcode_26.0.app/Contents/Developer\")", gate, StringComparison.Ordinal); + Assert.Contains("runs-on: macos-26", gate, StringComparison.Ordinal); + // The band's newest workload set requires Xcode 27; the pinned set keeps the job on the GA image. + Assert.Contains("dotnet workload install ios --version 10.0.401 ", gate, StringComparison.Ordinal); + Assert.Contains("os.path.realpath(\"/Applications/Xcode_26.6.app/Contents/Developer\")", gate, StringComparison.Ordinal); Assert.Contains("sudo xcode-select --switch \"${xcode_developer_dir}\"", gate, StringComparison.Ordinal); - Assert.DoesNotContain("xcode-select --switch /Applications/Xcode_26.0.app/Contents/Developer", gate, StringComparison.Ordinal); + Assert.DoesNotContain("xcode-select --switch /Applications/Xcode_", gate, StringComparison.Ordinal); Assert.Contains("xcodebuild -version", gate, StringComparison.Ordinal); - Assert.Contains("26.0*)", gate, StringComparison.Ordinal); + Assert.Contains("26.6*)", gate, StringComparison.Ordinal); Assert.Contains("xcrun --sdk macosx --show-sdk-path", gate, StringComparison.Ordinal); Assert.Contains("xcrun --sdk iphonesimulator --show-sdk-path", gate, StringComparison.Ordinal); Assert.Contains("xcrun --sdk macosx --find actool", gate, StringComparison.Ordinal); @@ -357,7 +359,6 @@ public void DotnetWorkflows_PinRepositorySdkFeatureBand() @".github\workflows\wasm-smoke-gates.yml" ]; - Assert.Contains("\"version\": \"10.0.302\"", globalJson, StringComparison.Ordinal); Assert.Contains("\"rollForward\": \"latestPatch\"", globalJson, StringComparison.Ordinal); foreach (var workflowPath in workflowPaths) {