Skip to content

refactor(maker-appx)!: reimplement as a legacy wrapper over the MSIX maker - #4392

Open
claude[bot] wants to merge 17 commits into
mainfrom
maker-appx-legacy-msix-wrapper
Open

claude[bot] wants to merge 17 commits into
mainfrom
maker-appx-legacy-msix-wrapper

Conversation

@claude

@claude claude Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Requested by Erick Zhao · Slack thread

Before: @electron-forge/maker-appx shelled out to electron-windows-store (Desktop App Converter, MakeCert, makeappx.exe) and produced a .appx, with its own SDK discovery and dev-cert generation.

After: the package is a deprecated compatibility layer over the MSIX code path. make() maps MakerAppXConfig onto electron-windows-msix options (sharing toMsixArch from @electron-forge/maker-msix) and moves the resulting .msix to make/appx/<arch>/<packageName>.msix. Existing configs keep type-checking; the class and unmappable options carry @deprecated pointing at @electron-forge/maker-msix.

  • Drop electron-windows-store everywhere (appx optionalDependencies, root optionalDependencies, yarn.config.cjs, ambient typings, lockfile) plus the now-unused cross-spawn typings and bogus-private-key.pvk fixture.
  • Warn once per unsupported option and ignore it; throw on missing/invalid publisher and on non-Store-compatible versions (unless makeVersionWinStoreCompatible).
  • Export toMsixArch from @electron-forge/maker-msix.
  • Slow make spec no longer generates a MakeCert dev cert on Windows.
  • Docs: legacy notice on appx.md, makers index now cites MSIX, SUPPORT.md debug namespace updated.
AppX MSIX
assets / manifest / windowsKit packageAssets / appManifest / windowsKitPath
devCert / certPass / signtoolParams windowsSignOptions.{certificateFile,certificatePassword,signWithParams} (only when devCert set)
makePri (default off) createPri (default false, preserving AppX behaviour)
packageName (default: name without dashes) manifestVariables.packageIdentity + <packageName>.msix file name
packageDisplayName / packageDescription / packageBackgroundColor same-named manifestVariables
packageVersion (default <version>.0) manifestVariables.packageVersion, normalized via makeVersionWinStoreCompatible
packageExecutable (app\Name.exe) manifestVariables.appExecutable with the app\ prefix stripped (the library prepends it)
publisher (CN=…, validated as X.500 DN) manifestVariables.publisher unchanged (library accepts the CN= form)
containerVirtualization, createConfigParams, createPriParams, deploy, desktopConverter, expandedBaseImage, flatten, finalSay, makeappxParams none — warn and ignore

Compatibility with existing AppX configs (comparing electron-windows-store 2.1.0 against electron-windows-msix 2.0.4 / @electron/windows-sign 1.2.2):

  • Windows SDK lookup. The old maker searched Windows Kits\10\bin\x64 and every bin\10.*\x64 folder; electron-windows-msix only checks one hard-coded SDK version (10.0.26100.0) when no windowsKitPath is given, and with a custom manifest it derives the version from MinVersion (manifests based on the old template say 10.0.14316.0). When windowsKit is unset, make() now searches the default Windows Kits folders itself (unversioned first, then newest SDK, x64 fallback on ARM64 hosts) and only falls back to the library default if nothing is found.
  • Custom assets. The generated manifest references icon.png, Square44x44Logo.png and Square150x150Logo.png, not the old SampleAppx.*.png names, and the user's folder replaces the defaults. make() now fails early naming the missing files (and the old→new names) when assets is set without a custom manifest.
  • Documented only: devCert now needs certPass unless signtoolParams is passed (old MakeCert certs had no password); signing timestamps against timestamp.digicert.com by default (WINDOWS_TIMESTAMP_SERVER overrides); certPass/signtoolParams without devCert warn and are ignored.

Tests: packages/maker/appx/spec/MakerAppX.spec.ts rewritten against a mocked electron-windows-msix (72 tests: defaults, every mapping, publisher/version errors, per-option warnings, arch conversion, output path, Windows Kit search, asset validation); yarn lint, yarn build, yarn knip, yarn constraints pass.

Open questions

  • Output is .msix under make/appx/<arch>/ (kept the legacy folder so existing publish pipelines still find it).
  • Unsupported options warn and are ignored rather than throwing.
  • createDefaultCertificate is removed with electron-windows-store. Without devCert, electron-windows-msix signs with a self-signed dev cert, which the maker now keeps next to the .msix as dev_cert.cer / dev_cert.pfx (matching the base maker's behaviour; maker-msix itself does not persist it).
  • A missing required asset throws rather than merging the library's placeholder icons under the user's folder, so a Store build never silently ships placeholders.

🤖 Generated with Claude Code

https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg


Generated by Claude Code

…maker

`@electron-forge/maker-appx` no longer depends on `electron-windows-store`
(and its Desktop App Converter / MakeCert tooling). It now maps
`MakerAppXConfig` onto `electron-windows-msix` options and packages through
the same code path as `@electron-forge/maker-msix`, so existing Forge
configs keep type-checking and building. The class and the ignored config
options are marked `@deprecated` in favour of `@electron-forge/maker-msix`.

`toMsixArch` is exported from `@electron-forge/maker-msix` so the
ia32 -> x86 mapping is shared. `electron-windows-store` and its ambient
typings are removed from the repo, and the slow make spec no longer
generates a MakeCert dev certificate on Windows.

BREAKING CHANGE: `@electron-forge/maker-appx` now produces a `.msix` file
(under `make/appx/<arch>/`) instead of `.appx`, and depends on
`electron-windows-msix` instead of `electron-windows-store`. The
`containerVirtualization`, `createConfigParams`, `createPriParams`,
`deploy`, `desktopConverter`, `expandedBaseImage`, `flatten`, `finalSay`
and `makeappxParams` options are ignored with a warning. The maker no
longer creates a development certificate next to the output when `devCert`
is unset (signing falls through to `electron-windows-msix`), the
`createDefaultCertificate` export is gone, and a missing publisher (no
`publisher` option and no `author.name` in package.json) is now an error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg
@github-actions github-actions Bot added the next label Sep 13, 2026
@claude
claude Bot marked this pull request as ready for review September 13, 2026 20:49
@claude
claude Bot requested a review from a team as a code owner September 13, 2026 20:49

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beyond the inline findings, I also checked a couple of other candidate issues and ruled them out: finalSay is now handled the same as the other listed UNSUPPORTED_OPTIONS (warned and ignored, matching the PR's stated intent, not silently dropped without warning), and toMsixArch throwing for architectures outside x64/arm64/ia32 mirrors the same validation already present in the sibling maker-msix package rather than being a new regression unique to this PR.

Extended reasoning...

This change reworks @ electron-forge/maker-appx into a thin compatibility shim over electron-windows-msix, sharing toMsixArch with maker-msix, and removes the old electron-windows-store/cross-spawn/SDK-discovery implementation along with its dependencies, typings, and test fixture. Three confirmed findings are already queued as inline comments: a catastrophic-backtracking-prone ported X.500 DN regex, a behavior change making publisher validation unconditional (previously only enforced when generating a default cert), and a missing directory-clearing step before move() that can cause repeat electron-forge make runs to fail. These are substantive enough that a human should look regardless of anything I add here, so I am not restating them.

I additionally reviewed two items from the ruled-out candidate list to confirm they are not additional bugs: the finalSay option is folded into the same UNSUPPORTED_OPTIONS warn-and-ignore path as the other legacy hooks (consistent, not a silent behavior change), and toMsixArch's throw on unsupported target architectures is inherited directly from the existing maker-msix implementation, not new logic introduced by this PR that would uniquely need scrutiny here.

Given the confirmed findings already flag the security- and correctness-relevant risk areas (regex DoS surface, validation regression, packaging idempotency), and this PR touches deprecated packaging code with dependency and lockfile changes, human review remains warranted. I am not duplicating the inline findings in this body per instructions, and I have nothing further beyond the two ruled-out items above to add.

Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
Comment thread packages/maker/appx/src/MakerAppX.ts
Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
…ore move

Addresses three review findings on the legacy MSIX wrapper:

- Rewrite the ported X.500 DN regex so the quoted-value sub-pattern has no
  nested overlapping quantifiers ("[^"]*" instead of
  "[^"\\]*(?:[^"][^"\\]*)*"). The accepted language is unchanged, but an
  unterminated quoted value can no longer trigger catastrophic backtracking.
- Only run the publisher DN validation when no devCert is configured,
  matching the base-branch gating (isValidPublisherName only ran inside
  createDefaultCertificate). With a devCert the publisher is forwarded
  verbatim. The missing/empty-publisher error stays unconditional.
- Restore this.ensureDirectory(outPath) for make/appx/<arch> before moving
  the .msix in, so re-running `electron-forge make` overwrites the previous
  artifact instead of failing with "dest already exists".

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
Comment thread packages/maker/appx/src/MakerAppX.ts
Resolve the yarn.lock conflict between the removal of the
electron-windows-store dependency tree on this branch and the new
ink-based multi-logger dependencies on next by taking the lockfile from
next and regenerating it with the pinned yarn 4.18.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg
The merge commit carried the lockfile from next verbatim; regenerate it
with the pinned yarn 4.18.0 so the pruned electron-windows-store tree
from this branch stays removed alongside the new multi-logger entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional findings (outside the current diff — GitHub can't attach inline comments there):

  • 🔴 yarn.lock — Merge commit 7025482 resolved the yarn.lock conflict by keeping the pre-refactor @ electron-forge/maker-appx entry: it still lists cross-spawn and electron-windows-store (with electron-windows-store marked optional) instead of @ electron-forge/maker-msix and electron-windows-msix. This contradicts packages/maker/appx/package.json, which now declares dependencies on @ electron-forge/maker-msix and electron-windows-msix ("^2.0.4") and no longer depends on cross-spawn or electron-windows-store. A lockfile/manifest mismatch like this makes yarn install --immutable (used in CI) fail, and even a mutable install won't link electron-windows-msix into maker-appx's node_modules. Fix: regenerate yarn.lock (e.g. yarn install) so the maker-appx entry matches its package.json dependencies.

    Extended reasoning...

    The merge commit's message says the lockfile conflict was resolved by "taking the lockfile from next and regenerating it with the pinned yarn 4.18.0", but the regenerated maker-appx entry in yarn.lock (lines 843-857) still shows dependencies cross-spawn ^7.0.3 and electron-windows-store ^2.1.0 with electron-windows-store marked optional -- the pre-refactor dependency set. Meanwhile packages/maker/appx/package.json (checked directly) lists @ electron-forge/maker-msix workspace:* and electron-windows-msix ^2.0.4, with no cross-spawn or electron-windows-store. Running yarn install --immutable in CI compares package.json manifests against yarn.lock and fails because the appx workspace's declared dependency set (per package.json) doesn't match the lockfile entry. Even without --immutable, yarn install on node-modules linker (.yarnrc.yml: nodeLinker: node-modules) would not create a node_modules/electron-windows-msix link scoped correctly for this workspace's own resolution record, and MakerAppX.ts's import { packageMSIX } from 'electron-windows-msix' and `import { toMsixArch } from '@…

    Verification: normal. This change introduces a lockfile-vs-package.json mismatch that the base branch does not have. At base (5fb2088), the maker-appx workspace entry in yarn.lock (lines 843-857) matched its package.json: cross-spawn: "npm:^7.0.3" and electron-windows-store: "npm:^2.1.0" (optional). package.json at base also declared exactly those (cross-spawn dependency + electron-windows-store…

@claude

claude Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

Re the yarn.lock finding on the merge commit 7025482: already addressed in 92c2841, which regenerates the lockfile with the pinned Yarn 4.18.0. At head the @electron-forge/maker-appx entry depends on @electron-forge/maker-msix and electron-windows-msix only, electron-windows-store has zero entries, yarn install --immutable passes, and the lint-and-build check is green on that head.


Generated by Claude Code

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good — the three issues flagged in my previous review (unconditional/backtracking-prone publisher validation, and the missing ensureDirectory before move()) have all been fixed in commit 3c51ff1 and are now covered by dedicated regression tests (including a timing assertion against catastrophic backtracking). The subsequent commits only merge/regenerate the lockfile from next with no further changes to the maker-appx code. The two optional nits I raised (finally-block rm potentially masking a successful return, and no warning for signtoolParams/certPass without devCert) remain unaddressed but are minor.

Extended reasoning...

This is a follow-up review of a PR I've already reviewed three times. In the second round I raised three high-severity findings on MakerAppX.ts: (1) make() no longer cleared the output directory before move(), which would fail on re-runs; (2) the ported validDNRegex had an overlapping-quantifier shape vulnerable to catastrophic backtracking on unterminated quoted publisher values; (3) publisher validation ran unconditionally even when a user-supplied devCert was set, unlike the old gated behavior. I verified via git show 3c51ff1 that all three were fixed: ensureDirectory(outPath) is now called before the temp-folder work begins, the quoted-value regex was rewritten to "[^"]*" (no overlapping stars) with an explanatory comment, and the validation check is now gated behind !this.config.devCert. The spec file was extended with tests exercising each fix, including a 50,000-character unterminated-quote publisher with an explicit sub-1-second timing assertion, confirming the backtracking fix actually works rather than just changing behavior superficially.

Two commits landed after the fix commit (7025482 and 92c2841), but both are pure merges from the next branch plus a lockfile regeneration — git show --stat confirms no changes touched packages/maker/appx/src/* in either. So nothing new was introduced to re-review in the maker-appx logic itself.

Two optional (yellow) findings from my third review round remain open in the code: the finally block still unconditionally awaits fs.rm(tmpFolder, ...), which could theoretically mask a successful return if cleanup throws (e.g., a locked file on Windows), and signtoolParams/certPass are still silently dropped without a warning when devCert isn't set (unlike other unsupported options, which are listed and warned). These are edge-case/polish issues rather than functional bugs affecting the main success path, and both were explicitly called out as "(optional)" in my prior review. This run's bug hunt also found no new issues. Given the critical correctness issues are fixed and verified with tests, and no third-party reviewer has an outstanding CHANGES_REQUESTED or unaddressed objection (all prior review activity is from this same automated review identity), I'm comfortable approving while noting the two still-open minor nits in the body for transparency.

`next` was renamed to `main`; bring the branch up to date with the new base.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg
Pick up the zizmor cache-poisoning fixes from #4401 so the required
workflow audit passes on this PR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pull request has been reviewed before and this review found new issues. Where they share a root cause, one fix may close them together.

Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
Comment thread packages/maker/appx/src/MakerAppX.ts Outdated
…nd dev cert

Addresses three review findings on the legacy MSIX wrapper:

- Remove the remaining catastrophic-backtracking paths from the ported X.500
  DN regex. Unquoted values now exclude the `;` separator (and `=`/`"`), and
  whitespace before a separator is owned by the value (or the quoted
  alternative) instead of also by the separator, so inputs like
  `C=;C=;C=...` or `C= , C= , C=...` are rejected in linear time. All
  well-formed publisher forms are still accepted.
- Strip the legacy `app\` / `app/` prefix from `packageExecutable`
  case-insensitively, so `App\MyApp.exe` no longer ends up as
  `app\App\MyApp.exe` in the manifest.
- When no `devCert` is configured, move the `dev_cert.cer` / `dev_cert.pfx`
  that electron-windows-msix writes into its `outputDir` next to the `.msix`
  before the temp folder is deleted, so the self-signed certificate can be
  trusted on a test device like the old maker's dev cert could. The returned
  artifacts are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg
Also keep a failed temp-folder cleanup from turning a successful make() into an error.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread docs/config/makers/appx.md Outdated
Comment thread packages/maker/appx/src/MakerAppX.ts
The .msix is already in place when the generated dev_cert.* files are moved next
to it, so a failed move now only warns. Docs, README and the devCert JSDoc all
describe the saved development certificate and its password source.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg
Close two gaps between the old electron-windows-store maker and the
electron-windows-msix wrapper that would have broken existing configs:

- When `windowsKit` is unset, search the default Windows Kits install
  folders for makeappx.exe, makepri.exe and signtool.exe (unversioned
  folder first, then the newest SDK, with the x64 fallback on ARM64
  hosts) instead of relying on the single hard-coded SDK version that
  electron-windows-msix falls back to. This also covers custom manifests
  whose MinVersion does not match an installed SDK.
- Fail early with the expected file names when a custom `assets` folder
  lacks icon.png, Square44x44Logo.png or Square150x150Logo.png, which the
  generated manifest refers to, rather than letting makeappx.exe fail on
  folders that use the old SampleAppx.*.png names.
- Document the certificate password, timestamp server, asset naming and
  Windows Kit lookup differences in the migration notice and config docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9pxG5QqvZqoCqacKSpXRN
… host SDK

The MakerAppX spec mocked `pathExists` and `fs.readdir` as pass-throughs to
the real filesystem, so on GitHub's windows-latest runners (which ship a
real Windows 10 SDK) `findWindowsKit()` located
`C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64` and the
default-config tests expecting `windowsKitPath` to be undefined failed.

Make the mock defaults hermetic: anything under the Windows Kit roots is
reported as missing (`pathExists` -> false, `readdir` -> ENOENT) while other
paths still pass through, so the generated dev-certificate tests keep using
their real temp folder. Tests that need an SDK still install fake kits via
installWindowsKits() or mock fs.readdir explicitly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Resolves the yarn.lock conflict from the dependency bump in #4408 by
taking main's lockfile and regenerating it with the pinned Yarn 4.18.0;
`yarn install --immutable` passes on the result.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9pxG5QqvZqoCqacKSpXRN

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016NS1e4vLnWtkyAYGs2Mrmg

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant