-
Notifications
You must be signed in to change notification settings - Fork 354
feat(build): add reproducible Windows code-signing step #340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0153b04
f422ae0
ace2eb5
78130b8
4e5128a
23662b2
c18374b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Changelog | ||
|
|
||
| All notable changes to OpenMausBot are documented here. The format is based on | ||
| [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project | ||
| adheres to [Conventional Commits](https://www.conventionalcommits.org/). | ||
|
|
||
| ## [Unreleased] | ||
|
|
||
| ## [0.1.27] | ||
|
|
||
| ### Fixed | ||
| - **Windows build: extract Android Platform Tools under git-bash.** `scripts/prepare-android-tools.mjs` | ||
| now tries `unzip` and falls back to `tar`, and normalizes absolute Windows paths to | ||
| MSYS form (`C:\x` → `/c/x`) so `pnpm build:android-tools` / `pnpm package:win` | ||
| succeed on a stock git-bash install instead of failing with | ||
| `tar: Cannot connect to C: resolve failed`. ([#317](https://github.com/milind-soni/OpenMausBot/pull/317)) | ||
|
|
||
| ### Added | ||
| - **Reproducible Windows code-signing step.** `scripts/sign-win.ps1` signs the NSIS | ||
| installer and the inner `OpenMausBot.exe` with any PFX — a self-signed cert | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| (`build/omb-selfsigned.pfx`, gitignored) for pipeline verification, or a real | ||
| CA-issued Authenticode cert supplied via `CSC_LINK`/`CSC_KEY_PASSWORD`. | ||
|
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
rg -n 'CSC_LINK|CSC_KEY_PASSWORD|OMB_CERT_FILE|OMB_PFX_PASSWORD|sign-win\.ps1' electron-builder.yml scripts .githubRepository: milind-soni/OpenMausBot Length of output: 841 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- CHANGELOG.md ---'
cat -n CHANGELOG.md | sed -n '1,45p'
printf '%s\n' '--- scripts/sign-win.ps1 ---'
cat -n scripts/sign-win.ps1
printf '%s\n' '--- electron-builder.yml relevant section ---'
cat -n electron-builder.yml | sed -n '95,125p'
printf '%s\n' '--- release workflow signing references ---'
rg -n -C 5 'sign-win|CSC_LINK|CSC_KEY_PASSWORD|OMB_CERT_FILE|OMB_PFX_PASSWORD|certificateFile|certificatePassword|package:win' .github electron-builder.yml package.json scriptsRepository: milind-soni/OpenMausBot Length of output: 11557 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
script = Path("scripts/sign-win.ps1").read_text()
workflow_text = "\n".join(
p.read_text()
for p in Path(".github").rglob("*")
if p.is_file()
)
changelog = Path("CHANGELOG.md").read_text()
print("script_reads_OMB_CERT_FILE:", "$env:OMB_CERT_FILE" in script)
print("script_reads_OMB_PFX_PASSWORD:", "$env:OMB_PFX_PASSWORD" in script)
print("script_reads_CSC_LINK:", "$env:CSC_LINK" in script)
print("script_reads_CSC_KEY_PASSWORD:", "$env:CSC_KEY_PASSWORD" in script)
print("workflow_invokes_sign_win:", "sign-win.ps1" in workflow_text)
print("workflow_maps_CSC_to_OMB:", "OMB_CERT_FILE" in workflow_text and "OMB_PFX_PASSWORD" in workflow_text)
print("changelog_documents_CSC_variables:", "CSC_LINK`/`CSC_KEY_PASSWORD" in changelog)
print("script_has_self_signed_fallback:", "omb-selfsigned.pfx" in script and "omb-test-2026" in script)
PYRepository: milind-soni/OpenMausBot Length of output: 439 Align the documented certificate variables with
🤖 Prompt for AI Agents |
||
| `electron-builder.yml` documents the flow and intentionally keeps `publisherName` | ||
| unset so auto-update keeps working on the unsigned build. | ||
| Note: a self-signed cert validates only on machines that trust its root; a | ||
| CA-issued cert is still required for a SmartScreen-clean install. | ||
|
Comment on lines
+25
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- CHANGELOG.md ---'
cat -n CHANGELOG.md | sed -n '1,45p'Repository: milind-soni/OpenMausBot Length of output: 1878 🌐 Web query:
💡 Result: As of August 2026, Microsoft Defender SmartScreen no longer grants automatic reputation or bypasses to applications based on Extended Validation (EV) code signing certificates [1][2][3]. While EV certificates were historically associated with immediate trust, that behavior has been removed [1][4]. Key points regarding SmartScreen reputation: 1. EV vs. OV Equivalence: Both EV and OV (Organization Validation) certificates are treated equally by SmartScreen [5][3]. Neither provides an instant bypass for reputation warnings [1][2]. 2. Organic Reputation Building: SmartScreen reputation is built organically over time [2][6]. It is based on a combination of signals, including the file hash (SHA256), the publisher identity, and the accumulation of positive telemetry from users downloading and running the signed file without security incidents [1][5][7]. 3. Impact of Certificate Renewal: Because reputation is tied to specific signing keys and publisher identities, renewing an EV or OV certificate (which generates a new thumbprint/key) effectively treats the publisher as a new entity for reputation purposes [6][8]. Existing reputation does not automatically transfer to a new certificate, leading to a period where new binaries may trigger warnings until sufficient new telemetry is gathered [6][8]. 4. No Manual Bypass: There is no supported mechanism, engineering override, or "trusted list" to manually request, restore, or boost reputation for a specific certificate or binary [5][6][8]. 5. Microsoft Store Exception: Applications published and distributed through the Microsoft Store are re-signed by Microsoft, which grants them full, immediate reputation and prevents SmartScreen warnings [1]. In summary, code signing remains a critical security best practice for establishing publisher identity and ensuring compatibility with features like Windows Smart App Control, but it no longer serves as a shortcut to avoid SmartScreen warnings [1][7][4]. Software publishers must rely on organic adoption to build and maintain trust for their binaries [1][6]. Citations:
Qualify the SmartScreen guarantee. A CA-issued Authenticode certificate establishes publisher identity but does not guarantee a SmartScreen-clean install. SmartScreen can warn for valid OV and EV signatures until reputation accumulates. Update the note accordingly. 🤖 Prompt for AI Agents |
||
|
|
||
| [Unreleased]: https://github.com/milind-soni/OpenMausBot/compare/v0.1.27...HEAD | ||
| [0.1.27]: https://github.com/milind-soni/OpenMausBot/releases/tag/v0.1.27 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -265,6 +265,25 @@ pnpm package:win # Windows installer + zip → release/ | |
| pnpm package:linux # Ubuntu x64 .deb + AppImage → release/ | ||
| ``` | ||
|
|
||
| #### Code-signing the Windows build | ||
|
|
||
| `pnpm package:win` produces an **unsigned** installer (SmartScreen flags it as | ||
| "unknown publisher"). Sign it with Authenticode after the build: | ||
|
|
||
| ```sh | ||
| # self-signed test cert (pipeline verification only — still trips SmartScreen) | ||
| pwsh scripts/sign-win.ps1 | ||
|
|
||
| # real CA-issued cert (clean SmartScreen install) | ||
| CSC_LINK=path/to/cert.pfx CSC_KEY_PASSWORD=**** pwsh scripts/sign-win.ps1 | ||
| ``` | ||
|
|
||
| `scripts/sign-win.ps1` signs both `release/OpenMausBot-<ver>-setup.exe` and the | ||
| inner `OpenMausBot.exe` with an RFC-3161 timestamp (DigiCert), so the signature | ||
| outlives the cert. A self-signed cert validates only on machines that trust its | ||
| root; for a SmartScreen-clean install use a CA-issued Authenticode certificate | ||
| and set `win.certificateFile` / `CSC_*` in `electron-builder.yml`. | ||
|
Comment on lines
+278
to
+285
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
fd -t f -a 'README.md|sign-win.ps1|package.json|electron-builder.yml' .
printf '%s\n' '--- relevant README section ---'
sed -n '250,300p' README.md
printf '%s\n' '--- signer parameter/env references ---'
rg -n -C 4 'OMB_CERT_FILE|OMB_PFX_PASSWORD|CSC_LINK|CSC_KEY_PASSWORD|param\s*\(|Pfx|Password' scripts/sign-win.ps1 README.md package.json electron-builder.yml 2>/dev/null || true
printf '%s\n' '--- package scripts ---'
node - <<'JS'
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log(JSON.stringify(p.scripts, null, 2));
JSRepository: milind-soni/OpenMausBot Length of output: 10892 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- signer implementation ---'
cat -n scripts/sign-win.ps1
printf '%s\n' '--- builder signing configuration ---'
sed -n '100,125p' electron-builder.yml
printf '%s\n' '--- packaging and signing references ---'
rg -n -C 3 'package:win(:signed)?|sign-win\.ps1|CSC_LINK|CSC_KEY_PASSWORD|OMB_CERT_FILE|OMB_PFX_PASSWORD' --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' .
printf '%s\n' '--- shell assignment behavior (no repository code executed) ---'
env -i PATH="$PATH" bash -c 'CSC_LINK=path/to/cert.pfx CSC_KEY_PASSWORD=**** sh -c '\''printf "CSC_LINK=%s\nCSC_KEY_PASSWORD=%s\n" "$CSC_LINK" "$CSC_KEY_PASSWORD"'\'''
printf '%s\n' '--- PowerShell availability and parse behavior ---'
if command -v pwsh >/dev/null 2>&1; then
pwsh -NoProfile -Command 'try { [void][System.Management.Automation.Language.Parser]::ParseInput("CSC_LINK=path/to/cert.pfx CSC_KEY_PASSWORD=**** pwsh scripts/sign-win.ps1", [ref]$null, [ref]$null); "parsed" } catch { $_.Exception.Message; exit 1 }'
else
echo 'pwsh unavailable'
fiRepository: milind-soni/OpenMausBot Length of output: 10384 Pass the certificate to the post-build signer with the variables it reads.
$env:OMB_CERT_FILE = 'path\to\cert.pfx'
$env:OMB_PFX_PASSWORD = Read-Host 'PFX password'
pwsh scripts/sign-win.ps1Keep 🤖 Prompt for AI Agents |
||
|
|
||
| ### Routines and webhook triggers | ||
|
|
||
| Routines can run once or on selected weekdays, using either a MAUS's configured model/computer or the | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # sign-win.ps1 — sign the built Windows artifacts with Authenticode. | ||
| # | ||
| # Usage (after `pnpm package:win`): | ||
| # pwsh scripts/sign-win.ps1 | ||
| # pwsh scripts/sign-win.ps1 -Pfx build/omb-selfsigned.pfx -Password omb-test-2026 | ||
|
Comment on lines
+3
to
+5
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift Run the signing step in the Windows packaging workflow. The supplied Add certificate generation or CI-secret provisioning and invoke the script, or document this workflow as local-only. Also applies to: 25-26 🧰 Tools🪛 PSScriptAnalyzer (1.25.0)[warning] Missing BOM encoding for non-ASCII encoded file 'sign-win.ps1' (PSUseBOMForUnicodeEncodedFile) 🤖 Prompt for AI Agents |
||
| # | ||
| # For a REAL cert: pass -Pfx <real.pfx> -Password <real> (or set env | ||
| # OMB_CERT_FILE / OMB_PFX_PASSWORD). Requires the cert's private key. | ||
|
Comment on lines
+7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- target script ---'
cat -n scripts/sign-win.ps1
printf '%s\n' '--- references and workflows ---'
rg -n -C 3 'sign-win|OMB_CERT_FILE|OMB_PFX_PASSWORD|Set-AuthenticodeSignature|Read-Host|AsPlainText|Password' . \
-g '!node_modules' -g '!dist' -g '!build'Repository: milind-soni/OpenMausBot Length of output: 10226 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
p = Path("scripts/sign-win.ps1")
text = p.read_text()
for i, line in enumerate(text.splitlines(), 1):
if "Password" in line or "AsPlainText" in line or "Read-Host" in line or "Set-AuthenticodeSignature" in line:
print(f"{i}: {line}")
PYRepository: milind-soni/OpenMausBot Length of output: 701 Do not pass production certificate passwords as plaintext. Replace the 🧰 Tools🪛 PSScriptAnalyzer (1.25.0)[warning] Missing BOM encoding for non-ASCII encoded file 'sign-win.ps1' (PSUseBOMForUnicodeEncodedFile) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
| # | ||
| # NOTE: a self-signed cert only proves the pipeline works. It still shows | ||
| # "unknown publisher" on machines that don't trust its root. Add the root to | ||
| # Trusted Root CAs (CurrentUser) once to validate locally: | ||
| # $pfx = New-Object Security.Cryptography.X509Certificates.X509Certificate2($Pfx, $Password) | ||
| # $s = New-Object Security.Cryptography.X509Certificates.X509Store('Root','CurrentUser'); $s.Open('ReadWrite'); $s.Add($pfx); $s.Close() | ||
|
|
||
| param( | ||
| [string]$Pfx = $env:OMB_CERT_FILE, | ||
| [string]$Password = $env:OMB_PFX_PASSWORD, | ||
| [string]$Thumbprint, | ||
| [string]$TimestampServer = 'http://timestamp.digicert.com' | ||
| ) | ||
|
|
||
| $ErrorActionPreference = 'Stop' | ||
|
|
||
| if (-not $Pfx) { $Pfx = Join-Path $PSScriptRoot '..uild\omb-selfsigned.pfx' } | ||
| if (-not $Password) { $Password = 'omb-test-2026' } | ||
|
|
||
| $root = Resolve-Path (Join-Path $PSScriptRoot '..') | ||
| $ver = (node -p "require('./package.json').version" 2>$null) | ||
| if (-not $ver) { throw "Could not read package version from package.json" } | ||
|
|
||
| $installerPath = Join-Path $root "release\OpenMausBot-$ver-setup.exe" | ||
| $unpackedAppPath = Join-Path $root 'release\win-unpacked\OpenMausBot.exe' | ||
|
|
||
| $files = @($installerPath, $unpackedAppPath) | ||
|
|
||
| # Throw immediately if any of the required files are missing before signing | ||
| foreach ($f in $files) { | ||
| if (-not (Test-Path $f)) { | ||
| throw "Missing required build artifact for signing: $f" | ||
| } | ||
| } | ||
|
|
||
| if ($Thumbprint) { | ||
| $cert = Get-ChildItem "cert:\CurrentUser\My" | Where-Object { $_.Thumbprint -eq $Thumbprint } | ||
| if (-not $cert) { throw "cert with thumbprint $Thumbprint not in CurrentUser\My" } | ||
| } else { | ||
| $sec = ConvertTo-SecureString -String $Password -Force -AsPlainText | ||
| $cert = New-Object Security.Cryptography.X509Certificates.X509Certificate2($Pfx, $sec, 'PersistKeySet') | ||
| } | ||
|
|
||
| foreach ($f in $files) { | ||
| $r = Set-AuthenticodeSignature -FilePath $f -Certificate $cert -TimestampServer $TimestampServer | ||
| Write-Host ("{0,-60} {1}" -f $f, $r.Status) | ||
| if ($r.Status -ne 'Valid') { throw ("signing failed: " + $r.StatusMessage) } | ||
|
Comment on lines
+52
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(sign-win\.ps1|package\.json|electron-builder|.*workflow.*|.*ya?ml$)' | head -200
printf '%s\n' '--- sign-win.ps1 outline and relevant contents ---'
if command -v ast-grep >/dev/null 2>&1; then
ast-grep outline scripts/sign-win.ps1 --lang powershell 2>/dev/null || true
fi
wc -l scripts/sign-win.ps1
cat -n scripts/sign-win.ps1
printf '%s\n' '--- package/build configuration references ---'
rg -n -S -C 3 'package:win|sign-win|afterSign|afterPack|win-unpacked|nsis|electron-builder|build/omb-selfsigned|OpenMausBot\.exe' . \
-g '!node_modules' -g '!dist' -g '!build' | head -400
printf '%s\n' '--- workflows ---'
fd -i -t f 'ya?ml$' .github 2>/dev/null | sort | while read -r f; do
echo "### $f"
cat -n "$f"
doneRepository: milind-soni/OpenMausBot Length of output: 50379 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(sign-win\.ps1|package\.json|electron-builder|.*workflow.*|.*ya?ml$)' | head -200
printf '%s\n' '--- sign-win.ps1 ---'
wc -l scripts/sign-win.ps1
cat -n scripts/sign-win.ps1
printf '%s\n' '--- build and signing references ---'
rg -n -S -C 3 'package:win|sign-win|afterSign|afterPack|win-unpacked|nsis|electron-builder|build/omb-selfsigned|OpenMausBot\.exe' . \
-g '!node_modules' -g '!dist' -g '!build' | head -400
printf '%s\n' '--- workflows ---'
fd -i -t f 'ya?ml$' .github 2>/dev/null | sort | while read -r f; do
echo "### $f"
cat -n "$f"
doneRepository: milind-soni/OpenMausBot Length of output: 50381 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- electron-builder configuration ---'
cat -n electron-builder.yml | sed -n '1,180p'
printf '%s\n' '--- complete Windows workflow ---'
cat -n .github/workflows/package-win.yml
printf '%s\n' '--- package metadata and ignored build inputs ---'
cat -n package.json | sed -n '1,75p'
printf '%s\n' '--- gitignore entries relevant to signing ---'
rg -n -S 'build|pfx|release|win-unpacked' .gitignore .git/info/exclude 2>/dev/null || true
printf '%s\n' '--- exact signing/package call sites ---'
rg -n -S 'sign-win\.ps1|Set-AuthenticodeSignature|CSC_LINK|CSC_KEY_PASSWORD|certificateFile|signAndEditExecutable|afterSign|afterPack|package:win' \
--glob '!electron/vendor/**' --glob '!third_party/**' .
printf '%s\n' '--- read-only verifier for workflow order, hard-coded paths, and hook declarations ---'
python3 - <<'PY'
from pathlib import Path
import re
script = Path("scripts/sign-win.ps1").read_text()
workflow = Path(".github/workflows/package-win.yml").read_text()
builder = Path("electron-builder.yml").read_text()
package = Path("package.json").read_text()
checks = {
"script documents post-package usage": "Usage (after `pnpm package:win`)" in script,
"workflow invokes package:win": "run: pnpm package:win" in workflow,
"workflow invokes sign-win.ps1": "sign-win.ps1" in workflow,
"workflow has a signing hook declaration": bool(re.search(r"(?m)^\\s*afterSign\\s*:", builder)),
"builder has afterPack only": bool(re.search(r"(?m)^\\s*afterPack\\s*:", builder))
and not bool(re.search(r"(?m)^\\s*afterSign\\s*:", builder)),
"script signs win-unpacked executable": "release\\win-unpacked\\OpenMausBot.exe" in script,
"script signs installer": "release\\OpenMausBot-0.1.27-setup.exe" in script,
"script skips missing files": 'Write-Warning "skip (missing): $f"; continue' in script,
}
for name, result in checks.items():
print(f"{name}: {result}")
package_line = next((i for i, line in enumerate(workflow.splitlines(), 1)
if "run: pnpm package:win" in line), None)
sign_lines = [i for i, line in enumerate(workflow.splitlines(), 1)
if "sign-win.ps1" in line]
print("package:win workflow line:", package_line)
print("sign-win.ps1 workflow lines:", sign_lines)
print("hard-coded script artifact paths:",
re.findall(r"release\\\\[^'\\\"]+", script))
print("package version declaration:",
next((line.strip() for line in package.splitlines() if '"version"' in line), None))
PYRepository: milind-soni/OpenMausBot Length of output: 21025 🌐 Web query:
💡 Result: Yes, according to the official electron-builder documentation, the afterSign hook is designed to run after the application has been signed but before the distributable (e.g., DMG, NSIS, installer) is created [1][2][3]. While early versions of electron-builder had reported issues where the afterSign hook appeared to trigger before the code signing process [4][5], these were identified as bugs that have been addressed in later versions (e.g., via improvements to the macPackager signApp implementation) [6]. Key characteristics of the afterSign hook: 1. Timing: It executes after the signing process is complete, provided that signing was actually performed [1]. It will not fire if signing is skipped (e.g., if no certificate is configured) [1]. 2. Purpose: It is primarily intended for tasks that require the application to be signed, such as custom macOS notarization workflows [2][3][7]. 3. State of filesystem: At the point this hook runs, the staging directory contains the fully signed application bundle, and the final distributable files have not yet been generated [1][2]. If you are experiencing behavior where the hook seems to run before signing, ensure you are using a recent version of electron-builder [6]. You can also verify the hook's execution timing by placing console logs within your hook script [4]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- electron-builder configuration ---'
cat -n electron-builder.yml | sed -n '1,180p'
printf '%s\n' '--- complete Windows workflow ---'
cat -n .github/workflows/package-win.yml
printf '%s\n' '--- exact signing/package call sites ---'
rg -n -S 'sign-win\.ps1|Set-AuthenticodeSignature|CSC_LINK|CSC_KEY_PASSWORD|certificateFile|signAndEditExecutable|afterSign|afterPack|package:win' \
--glob '!electron/vendor/**' --glob '!third_party/**' .
printf '%s\n' '--- read-only verifier ---'
python3 - <<'PY'
from pathlib import Path
import re
script = Path("scripts/sign-win.ps1").read_text()
workflow = Path(".github/workflows/package-win.yml").read_text()
builder = Path("electron-builder.yml").read_text()
package = Path("package.json").read_text()
checks = {
"script documents post-package usage": "Usage (after `pnpm package:win`)" in script,
"workflow invokes package:win": "run: pnpm package:win" in workflow,
"workflow invokes sign-win.ps1": "sign-win.ps1" in workflow,
"builder declares afterSign": bool(re.search(r"(?m)^\s*afterSign\s*:", builder)),
"builder declares afterPack": bool(re.search(r"(?m)^\s*afterPack\s*:", builder)),
"script signs win-unpacked executable":
"release\\win-unpacked\\OpenMausBot.exe" in script,
"script signs installer":
"release\\OpenMausBot-0.1.27-setup.exe" in script,
"script skips missing files":
'Write-Warning "skip (missing): $f"; continue' in script,
}
for name, result in checks.items():
print(f"{name}: {result}")
package_line = next(
(i for i, line in enumerate(workflow.splitlines(), 1)
if "run: pnpm package:win" in line), None
)
sign_lines = [
i for i, line in enumerate(workflow.splitlines(), 1)
if "sign-win.ps1" in line
]
print("package:win workflow line:", package_line)
print("sign-win.ps1 workflow lines:", sign_lines)
print("hard-coded script artifact paths:",
re.findall(r"release\\\\[^'\"]+", script))
print("package version declaration:",
next((line.strip() for line in package.splitlines()
if '"version"' in line), None))
PYRepository: milind-soni/OpenMausBot Length of output: 15991 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- updater metadata and post-build mutation references ---'
rg -n -S -C 4 'latest\.yml|\.blockmap|sha512|regenerate-blockmaps|artifact.*hash|blockmap' \
scripts electron electron-builder.yml .github README.md \
-g '!electron/vendor/**' | head -300
printf '%s\n' '--- blockmap regeneration script ---'
if [ -f scripts/regenerate-blockmaps.mjs ]; then
cat -n scripts/regenerate-blockmaps.mjs
fi
printf '%s\n' '--- targeted verifier for signing order and metadata risk ---'
python3 - <<'PY'
from pathlib import Path
sign = Path("scripts/sign-win.ps1").read_text()
builder = Path("electron-builder.yml").read_text()
workflow = Path(".github/workflows/package-win.yml").read_text()
facts = {
"installer is signed by the standalone script": "release\\OpenMausBot-0.1.27-setup.exe" in sign,
"unpacked executable is signed by the standalone script": "release\\win-unpacked\\OpenMausBot.exe" in sign,
"installer and unpacked executable are processed in one post-build loop":
"$files = @(" in sign and "foreach ($f in $files)" in sign,
"workflow packages before artifact upload":
workflow.index("run: pnpm package:win") < workflow.index("uses: actions/upload-artifact"),
"workflow invokes standalone signing": "sign-win.ps1" in workflow,
"builder emits latest.yml": "latest.yml" in builder,
"workflow uploads latest.yml": "release/latest.yml" in workflow,
"workflow uploads blockmap": "release/*.exe.blockmap" in workflow,
"builder has no afterSign hook": "afterSign:" not in builder,
}
for key, value in facts.items():
print(f"{key}: {value}")
print("post-build standalone signing changes an artifact after metadata-producing package step:",
facts["installer is signed by the standalone script"]
and facts["workflow packages before artifact upload"]
and not facts["workflow invokes standalone signing"])
PYRepository: milind-soni/OpenMausBot Length of output: 15798 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- updater metadata and post-build mutation references ---'
rg -n -S -C 4 'latest\.yml|\.blockmap|sha512|regenerate-blockmaps|artifact.*hash|blockmap' \
scripts electron electron-builder.yml .github README.md \
-g '!electron/vendor/**' | head -300
printf '%s\n' '--- blockmap regeneration script ---'
if [ -f scripts/regenerate-blockmaps.mjs ]; then
cat -n scripts/regenerate-blockmaps.mjs
fi
printf '%s\n' '--- targeted verifier ---'
python3 - <<'PY'
from pathlib import Path
sign = Path("scripts/sign-win.ps1").read_text()
builder = Path("electron-builder.yml").read_text()
workflow = Path(".github/workflows/package-win.yml").read_text()
facts = {
"installer is signed by standalone script":
"release\\OpenMausBot-0.1.27-setup.exe" in sign,
"unpacked executable is signed by standalone script":
"release\\win-unpacked\\OpenMausBot.exe" in sign,
"installer and unpacked executable use one post-build loop":
"$files = @(" in sign and "foreach ($f in $files)" in sign,
"workflow packages before artifact upload":
workflow.index("run: pnpm package:win") <
workflow.index("uses: actions/upload-artifact"),
"workflow invokes standalone signing":
"sign-win.ps1" in workflow,
"builder emits latest.yml":
"latest.yml" in builder,
"workflow uploads latest.yml":
"release/latest.yml" in workflow,
"workflow uploads blockmap":
"release/*.exe.blockmap" in workflow,
"builder has no afterSign hook":
"afterSign:" not in builder,
}
for key, value in facts.items():
print(f"{key}: {value}")
PYRepository: milind-soni/OpenMausBot Length of output: 15647 Sign the application before NSIS creates the installer. The documented flow runs Configure electron-builder to sign the application during packaging. Use an enabled 🧰 Tools🪛 PSScriptAnalyzer (1.25.0)[warning] Missing BOM encoding for non-ASCII encoded file 'sign-win.ps1' (PSUseBOMForUnicodeEncodedFile) 🤖 Prompt for AI Agents |
||
| } | ||
| Write-Host "done." | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
Remove the unresolved merge-conflict marker.
Line 26 contains
>>>>>>> 8f1cea4 (feat(build): add reproducible Windows code-signing step). Remove it before merge.🤖 Prompt for AI Agents