From f4b5281501f327eb4b66b560e30d0267e89cdbbd Mon Sep 17 00:00:00 2001 From: BlackSpirits Date: Sun, 6 Sep 2026 14:01:31 +0100 Subject: [PATCH 1/4] chore: add temporary yt-dlp checksum patch helper --- .github/scripts/upl_ytdlp_checksum_patch.py | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/scripts/upl_ytdlp_checksum_patch.py diff --git a/.github/scripts/upl_ytdlp_checksum_patch.py b/.github/scripts/upl_ytdlp_checksum_patch.py new file mode 100644 index 00000000000..e05b322a3d4 --- /dev/null +++ b/.github/scripts/upl_ytdlp_checksum_patch.py @@ -0,0 +1,48 @@ +from pathlib import Path + +service_path = Path("src/ui/Logic/Download/YtDlpDownloadService.cs") +service = service_path.read_text(encoding="utf-8-sig") +old = ''' var assetName = Path.GetFileName(filePath); + if (!KnownSha256.TryGetValue(version, out var byAsset) || +''' +new = ''' var assetName = Path.GetFileName(filePath); + if (assetName.EndsWith(".part", StringComparison.Ordinal)) + { + assetName = assetName[..^".part".Length]; + } + + if (!KnownSha256.TryGetValue(version, out var byAsset) || +''' +assert service.count(old) == 1, service.count(old) +service = service.replace(old, new) +service_path.write_text(service, encoding="utf-8") + +test_path = Path("tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs") +test = test_path.read_text(encoding="utf-8-sig") +anchor = ''' [Fact] + public async Task VerifyChecksumAsync_UnknownAsset_IsNoOp_AndKeepsFile() +''' +regression = ''' [Fact] + public async Task VerifyChecksumAsync_PartFile_Mismatch_ThrowsAndDeletesFile() + { + var dir = Path.Combine(Path.GetTempPath(), "VerifyPartMismatch_" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(dir); + var path = Path.Combine(dir, "yt-dlp.exe.part"); + await File.WriteAllTextAsync(path, "this is not really yt-dlp", TestContext.Current.CancellationToken); + try + { + await Assert.ThrowsAsync(() => + YtDlpDownloadService.VerifyChecksumAsync(path, YtDlpDownloadService.CurrentVersion, TestContext.Current.CancellationToken)); + + Assert.False(File.Exists(path), "A downloaded .part binary that fails verification must be deleted."); + } + finally + { + Directory.Delete(dir, recursive: true); + } + } + +''' +assert test.count(anchor) == 1, test.count(anchor) +test = test.replace(anchor, regression + anchor) +test_path.write_text(test, encoding="utf-8") From 23e76d002b55754a22ba300cb46de3cc88b7b124 Mon Sep 17 00:00:00 2001 From: BlackSpirits Date: Sun, 6 Sep 2026 14:01:44 +0100 Subject: [PATCH 2/4] chore: add temporary yt-dlp checksum regression gate --- .../upl-ytdlp-checksum-regression.yml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .github/workflows/upl-ytdlp-checksum-regression.yml diff --git a/.github/workflows/upl-ytdlp-checksum-regression.yml b/.github/workflows/upl-ytdlp-checksum-regression.yml new file mode 100644 index 00000000000..d939f76915b --- /dev/null +++ b/.github/workflows/upl-ytdlp-checksum-regression.yml @@ -0,0 +1,45 @@ +name: UPL yt-dlp checksum regression + +on: + push: + branches: + - upl/fix-ytdlp-checksum-work + pull_request: + branches: + - upl/upstream-main-05cd5a7 + +permissions: + contents: write + +jobs: + patch-and-test: + if: github.ref_name == 'upl/fix-ytdlp-checksum-work' || github.head_ref == 'upl/fix-ytdlp-checksum-work' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + with: + ref: upl/fix-ytdlp-checksum-work + + - name: Setup .NET + uses: actions/setup-dotnet@v5 + with: + dotnet-version: '10.0.x' + + - name: Apply checksum fix and regression + run: python .github/scripts/upl_ytdlp_checksum_patch.py + + - name: Targeted regression tests + run: dotnet test tests/UI/UITests.csproj --filter YtDlpDownloadServiceTests + + - name: Full solution tests + run: dotnet test SubtitleEdit.sln + + - name: Commit verified patch + run: | + git config user.name 'BlackSpirits' + git config user.email 'blackspirits@gmail.com' + git add src/ui/Logic/Download/YtDlpDownloadService.cs tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs + if ! git diff --cached --quiet; then + git commit -m 'Verify yt-dlp temporary downloads before install' + git push origin HEAD:upl/fix-ytdlp-checksum-work + fi From d81afa54434989658a8013bfa30546a55801c7c3 Mon Sep 17 00:00:00 2001 From: BlackSpirits Date: Sun, 6 Sep 2026 13:06:20 +0000 Subject: [PATCH 3/4] Verify yt-dlp temporary downloads before install --- src/ui/Logic/Download/YtDlpDownloadService.cs | 5 +++++ .../Download/YtDlpDownloadServiceTests.cs | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/ui/Logic/Download/YtDlpDownloadService.cs b/src/ui/Logic/Download/YtDlpDownloadService.cs index 1b3e9c4043e..43a8b01524d 100644 --- a/src/ui/Logic/Download/YtDlpDownloadService.cs +++ b/src/ui/Logic/Download/YtDlpDownloadService.cs @@ -197,6 +197,11 @@ public async Task DownloadYtDlp(IProgress? progress, CancellationToken ca internal static async Task VerifyChecksumAsync(string filePath, string version, CancellationToken cancellationToken) { var assetName = Path.GetFileName(filePath); + if (assetName.EndsWith(".part", StringComparison.Ordinal)) + { + assetName = assetName[..^".part".Length]; + } + if (!KnownSha256.TryGetValue(version, out var byAsset) || !byAsset.TryGetValue(assetName, out var expected)) { diff --git a/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs b/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs index c1781ba55d8..4431ba57c16 100644 --- a/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs +++ b/tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs @@ -162,6 +162,26 @@ await Assert.ThrowsAsync(() => } } + [Fact] + public async Task VerifyChecksumAsync_PartFile_Mismatch_ThrowsAndDeletesFile() + { + var dir = Path.Combine(Path.GetTempPath(), "VerifyPartMismatch_" + Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(dir); + var path = Path.Combine(dir, "yt-dlp.exe.part"); + await File.WriteAllTextAsync(path, "this is not really yt-dlp", TestContext.Current.CancellationToken); + try + { + await Assert.ThrowsAsync(() => + YtDlpDownloadService.VerifyChecksumAsync(path, YtDlpDownloadService.CurrentVersion, TestContext.Current.CancellationToken)); + + Assert.False(File.Exists(path), "A downloaded .part binary that fails verification must be deleted."); + } + finally + { + Directory.Delete(dir, recursive: true); + } + } + [Fact] public async Task VerifyChecksumAsync_UnknownAsset_IsNoOp_AndKeepsFile() { From cebf58b92467297a139f7d311081dd25f9aee715 Mon Sep 17 00:00:00 2001 From: BlackSpirits Date: Mon, 7 Sep 2026 12:21:40 +0100 Subject: [PATCH 4/4] test: revalidate yt-dlp checksum fix on current upstream --- .../upl-ytdlp-checksum-regression.yml | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/upl-ytdlp-checksum-regression.yml b/.github/workflows/upl-ytdlp-checksum-regression.yml index d939f76915b..2aad6e7d475 100644 --- a/.github/workflows/upl-ytdlp-checksum-regression.yml +++ b/.github/workflows/upl-ytdlp-checksum-regression.yml @@ -4,30 +4,34 @@ on: push: branches: - upl/fix-ytdlp-checksum-work - pull_request: - branches: - - upl/upstream-main-05cd5a7 permissions: contents: write jobs: patch-and-test: - if: github.ref_name == 'upl/fix-ytdlp-checksum-work' || github.head_ref == 'upl/fix-ytdlp-checksum-work' runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 with: - ref: upl/fix-ytdlp-checksum-work + ref: fix/ytdlp-part-checksum-current + fetch-depth: 0 + + - name: Apply checksum fix and regression + run: | + git fetch origin upl/fix-ytdlp-checksum-work:refs/remotes/origin/upl/fix-ytdlp-checksum-work + git show refs/remotes/origin/upl/fix-ytdlp-checksum-work:.github/scripts/upl_ytdlp_checksum_patch.py > "$RUNNER_TEMP/upl_ytdlp_checksum_patch.py" + python "$RUNNER_TEMP/upl_ytdlp_checksum_patch.py" + expected=$'src/ui/Logic/Download/YtDlpDownloadService.cs\ntests/UI/Logic/Download/YtDlpDownloadServiceTests.cs' + actual="$(git diff --name-only HEAD | sort)" + test "$actual" = "$expected" || { echo "Unexpected changed files:"; printf '%s\n' "$actual"; exit 1; } + git diff --check HEAD - name: Setup .NET uses: actions/setup-dotnet@v5 with: dotnet-version: '10.0.x' - - name: Apply checksum fix and regression - run: python .github/scripts/upl_ytdlp_checksum_patch.py - - name: Targeted regression tests run: dotnet test tests/UI/UITests.csproj --filter YtDlpDownloadServiceTests @@ -39,7 +43,5 @@ jobs: git config user.name 'BlackSpirits' git config user.email 'blackspirits@gmail.com' git add src/ui/Logic/Download/YtDlpDownloadService.cs tests/UI/Logic/Download/YtDlpDownloadServiceTests.cs - if ! git diff --cached --quiet; then - git commit -m 'Verify yt-dlp temporary downloads before install' - git push origin HEAD:upl/fix-ytdlp-checksum-work - fi + git commit -m 'Verify yt-dlp temporary downloads before install' + git push origin HEAD:fix/ytdlp-part-checksum-current