Bail unless `path` carries a Valid Authenticode signature. Catches the wrong-artifact case: e.g. someone drops the AppVeyor pre-signing bundle into dist/signed/ instead of the SignPath output. PowerShell's Get-AuthenticodeSignature works on both .exe and .msi.
(path: Path)
| 104 | |
| 105 | |
| 106 | def verify_authenticode(path: Path) -> None: |
| 107 | """Bail unless `path` carries a Valid Authenticode signature. |
| 108 | |
| 109 | Catches the wrong-artifact case: e.g. someone drops the AppVeyor |
| 110 | pre-signing bundle into dist/signed/ instead of the SignPath output. |
| 111 | PowerShell's Get-AuthenticodeSignature works on both .exe and .msi. |
| 112 | """ |
| 113 | if sys.platform != "win32": |
| 114 | print(f" (skipping Authenticode check for {path.name} on non-Windows)") |
| 115 | return |
| 116 | ps_cmd = ( |
| 117 | f"$sig = Get-AuthenticodeSignature -FilePath '{path}'; " |
| 118 | "Write-Output $sig.Status; " |
| 119 | "if ($sig.SignerCertificate) { Write-Output $sig.SignerCertificate.Subject }" |
| 120 | ) |
| 121 | result = subprocess.run( |
| 122 | ["powershell", "-NoProfile", "-Command", ps_cmd], |
| 123 | capture_output=True, |
| 124 | text=True, |
| 125 | check=False, |
| 126 | ) |
| 127 | lines = [line.strip() for line in result.stdout.splitlines() if line.strip()] |
| 128 | if result.returncode != 0 or not lines: |
| 129 | sys.exit( |
| 130 | f"Authenticode check for {path.name} failed to run.\n stderr: {result.stderr.strip()}" |
| 131 | ) |
| 132 | status = lines[0] |
| 133 | subject = lines[1] if len(lines) > 1 else "<no certificate>" |
| 134 | print(f" Authenticode: {status} ({subject})") |
| 135 | if status != "Valid": |
| 136 | sys.exit( |
| 137 | f"Authenticode check FAILED for {path.name}: status={status!r}. " |
| 138 | "Verify scenedetect-signed.zip is the SignPath output, not an " |
| 139 | "unsigned AppVeyor artifact." |
| 140 | ) |
| 141 | |
| 142 | |
| 143 | def extract_signed_bundle(signed_zip: Path, dest: Path) -> tuple[Path, Path]: |
no test coverage detected