Skip to content

ci: wire SignPath Authenticode signing behind secrets, pin publisher, document updater kill switch (fixes #71) - #74

Merged
amirlehmam merged 1 commit into
amirlehmam:masterfrom
Rajveerx11:fix/71-updater-signing
Jul 7, 2026
Merged

ci: wire SignPath Authenticode signing behind secrets, pin publisher, document updater kill switch (fixes #71)#74
amirlehmam merged 1 commit into
amirlehmam:masterfrom
Rajveerx11:fix/71-updater-signing

Conversation

@Rajveerx11

Copy link
Copy Markdown
Contributor

Fixes #71.

Release artifacts are unsigned and the auto-updater has no authenticity check — the 3-day quarantine window is currently the only defense. This PR wires the signing pipeline so it activates the moment the SignPath secrets exist, with no further code changes needed.

Changes

  • .github/workflows/release.yml — the commented-out SignPath steps are re-enabled, with three fixes over the original block:
    • Each step is gated on SIGNPATH_API_TOKEN / SIGNPATH_ORGANIZATION_ID being configured (mapped to job env, checked in step if:), so releases keep working unsigned while SignPath OSS approval is pending and signing turns on automatically once the secrets land.
    • The steps moved after rcedit. The original placement signed the exe before rcedit rewrote the PE (icon + version metadata), which would have invalidated the Authenticode signature on every release.
    • After downloading the signed artifact, the workflow verifies it with Get-AuthenticodeSignature and fails the release if the signature is not Valid — no silently shipping a bad artifact.
  • electron-builder.jsonwin.publisherName: ["SignPath Foundation"] (the cert subject SignPath OSS signs with), so electron-updater's publisher verification is pinned for signed exe/NSIS update flows. Please double-check the exact CN once the first signed build exists.
  • README.md — new Updates & security section documenting the quarantine window, the current signing status, and WMUX_DISABLE_UPDATER=1 / WMUX_MIN_RELEASE_AGE_DAYS as the interim mitigation for security-sensitive users (the code for both already exists in updater.ts).
  • src/main/updater.ts — header comment updated to reflect what is now wired vs. what remains open.

Honest scope note

electron-updater can only Authenticode-verify exe/NSIS update artifacts. wmux currently updates via a zip, which cannot carry an Authenticode signature — so even with signing live, the quarantine window remains the primary client-side control until the update artifact format changes (tracked as the natural follow-up). Signing still hardens the chain now: SmartScreen reputation, a verifiable artifact for users, and publisher pinning ready for the day the installer flow lands.

Testing

  • YAML validated (js-yaml), electron-builder.json parses, npm run build:main clean, npm test 158/158.
  • Workflow logic (guarded steps) is inert without the secrets — identical behavior to today's unsigned releases.

🤖 Generated with Claude Code

…amirlehmam#71)

Re-enables the SignPath signing steps in release.yml, gated on the
SIGNPATH_API_TOKEN / SIGNPATH_ORGANIZATION_ID secrets so releases keep
working while OSS approval is pending and signing turns on automatically
once the secrets are configured. The steps now run AFTER rcedit — the
previous (commented) placement signed the exe before rcedit rewrote the
PE, which would have invalidated the signature. The download step also
verifies the returned artifact with Get-AuthenticodeSignature and fails
the release if it is not validly signed.

electron-builder now pins win.publisherName to "SignPath Foundation"
so signed exe/NSIS update flows verify the publisher, and the README
documents WMUX_DISABLE_UPDATER=1 / WMUX_MIN_RELEASE_AGE_DAYS as the
interim mitigation until signing lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@amirlehmam

Copy link
Copy Markdown
Owner

Merged and released in v0.17.0 — thanks, and good catch moving the signing steps after rcedit; that would have bitten us on the very first signed release.

Two things I had to adjust post-merge, for the record:

  1. win.publisherNamewin.signtoolOptions.publisherName — electron-builder 26.15.3 rejects the top-level key (configuration.win should be one of these: null), it moved into signtoolOptions in v26.
  2. Non-fatal submission failures — the first live run hit 400 — Yearly quota for artifact size has been exceeded from SignPath OSS, which failed the whole release. The submit step is now continue-on-error (ships unsigned with a warning, matching your "releases keep working while approval is pending" intent), while the signature verification of a downloaded signed artifact stays fatal, per your design.

So: pipeline is live, secrets are set, and the first release after SignPath quota frees up will be signed automatically. Your honest scope note about the zip artifact not being Authenticode-verifiable client-side is captured in the release notes as the follow-up.

tawman added a commit to tawman/wmux that referenced this pull request Jul 7, 2026
Syncs the fork with upstream master (release v0.17.0) — the first sync
carrying third-party code, security-gate reviewed before merge (PASS):

- amirlehmam#73 (Rajveerx11) pipe auth — security-positive: V1 commands now require
  an "auth <token>" prefix (ping stays public) and hook.event/agent.activity
  leave the tokenless V2 allowlist; timing-safe compare reused, clients
  (CLI sendV1, PowerShell integration) updated coherently, +4 auth tests.
  Closes the unauthenticated-local-pipe-write gap our own review flagged.
- amirlehmam#74 + maintainer CI commits — SignPath signing wired behind secrets (only
  egress is app.signpath.io with the repo's own secrets; inert on the fork),
  publisherName pinned via win.signtoolOptions, README updater-security docs,
  asarUnpack narrowed to node-pty prebuilds.
- Our merged amirlehmam#75 content (cli-bin OOTB, orchestrator resolver, skills
  lessons) arrives as no-ops; electron-builder cli-bin extraResources lands.
- No dependency changes (lock diff = version fields only).

Base bump 0.16.0 -> 0.17.0; fork version resets to 0.17.0-local.1.
Conflicts resolved: version files; .gitattributes (fork superset);
README.md + orchestration-state.sh (fork copies kept — hardening superset).
Fork CI repo-guard on release.yml survived the auto-merge (verified).

Verified: build:main + vite build clean, 169/169 tests, 0 vulns (full +
--omit=dev), security-touched files byte-identical to upstream.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security: auto-updater installs unsigned artifacts with no authenticity verification (quarantine window is the only defense)

2 participants