Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
20c9be2
Upgrade teams to enterprise via Ibis API [WPB-22420]
markbrockhoff Jul 16, 2026
87bc2e2
Merge pull request #9715 from wireapp/main
zskhan Jul 30, 2026
39c1891
Merge pull request #9716 from wireapp/staging
zskhan Jul 30, 2026
530687e
Merge pull request #9703 from wireapp/mb/refactor-enterprise-upgrades
screendriver Aug 3, 2026
2e6721f
Increase timeout for multiple accounts e2e test
iskvortsov Aug 17, 2026
e1ba98c
Merge pull request #9721 from wireapp/chore/WPB-28071_increasing_time…
iskvortsov Aug 17, 2026
d603894
feat(windows): build native MSI installer
adamlow-wire Aug 18, 2026
36b9f2c
fix(windows): show assisted MSI installer UI
adamlow-wire Aug 18, 2026
32203de
feat(windows): brand MSI wizard for managed deployment
adamlow-wire Aug 18, 2026
105d89b
fix(windows): sharpen MSI wizard branding
adamlow-wire Aug 18, 2026
68b50ca
fix(windows): harden MSI release pipeline
adamlow-wire Aug 18, 2026
736e10b
fix(windows): detect Windows 10 correctly in MSI
adamlow-wire Aug 19, 2026
a3be121
fix(windows): publish MSI alongside Squirrel
adamlow-wire Aug 19, 2026
b595c11
feat(windows): configure managed endpoint from MSI
adamlow-wire Aug 19, 2026
5e98762
fix(windows): keep Squirrel feed promotion with MSI
adamlow-wire Aug 24, 2026
3588bc9
fix(windows): presign MSI from its S3 path
adamlow-wire Aug 24, 2026
d045c5d
fix(windows): require complete installer outputs
adamlow-wire Aug 24, 2026
69d1412
fix(windows): reject ambiguous artifact selection
adamlow-wire Aug 24, 2026
19268e6
Centralize desktop log infrastructure
screendriver Aug 24, 2026
d051014
Fix desktop log rotation, retention and directory organization
screendriver Aug 24, 2026
8e4120c
Fix unsafe SSO log error formatting
screendriver Aug 24, 2026
0e2ce16
fix(windows): preserve Squirrel packaging semantics
adamlow-wire Aug 24, 2026
255bdd5
fix(windows): require Squirrel before MSI deployment
adamlow-wire Aug 24, 2026
e548ede
Merge pull request #9722 from wireapp/feature/WPB-5221-windows-native…
screendriver Aug 25, 2026
277ee43
Merge pull request #9724 from wireapp/logs
screendriver Aug 26, 2026
dce4c28
Prune desktop logs and validate account directories
screendriver Aug 26, 2026
1781c33
Coordinate asynchronous log maintenance
screendriver Aug 26, 2026
8872a5b
Coordinate bounded desktop log writes
screendriver Aug 26, 2026
302d927
Coordinate desktop log export
screendriver Aug 26, 2026
9244eff
Sequence desktop log startup maintenance
screendriver Aug 26, 2026
9f0ecab
Remove stale active-file tracking from log cleanup
screendriver Aug 26, 2026
bd61f11
Merge pull request #9729 from wireapp/harden-desktop-log-lifecycle
screendriver Aug 27, 2026
8e4aa52
fix(windows): detect supported OS from registry
adamlow-wire Aug 27, 2026
6eed77d
Merge pull request #9730 from adamlow-wire/fix/WPB-5221-windows-versi…
screendriver Aug 27, 2026
f5a2ce3
Add streaming export dependencies
screendriver Aug 28, 2026
e83d6f1
Separate download destination selection
screendriver Aug 28, 2026
035aae9
Stream desktop log exports from snapshots
screendriver Aug 28, 2026
465f9da
Cover streaming desktop log exports
screendriver Aug 28, 2026
3c78dd5
Rename export arguments to options
screendriver Aug 28, 2026
2906d28
Infer object literal method returns
screendriver Aug 28, 2026
f2fb21b
Inject log export dependencies
screendriver Aug 28, 2026
c8ac863
Observe log export failures safely
screendriver Aug 28, 2026
8d4d461
Fix log export lifecycle and upgrade adm-zip
screendriver Aug 28, 2026
753e833
Make log export dependencies explicit
screendriver Aug 28, 2026
ea52c8b
Merge pull request #9731 from wireapp/log-export
screendriver Aug 28, 2026
7019b94
Merge pull request #9733 from wireapp/staging
zskhan Aug 31, 2026
30c1c2e
Register webview handlers before log cleanup
screendriver Sep 2, 2026
6f9b6a9
Merge pull request #9736 from wireapp/logs
screendriver Sep 2, 2026
4bbd557
Expose the system regional locale to the WebApp
screendriver Sep 3, 2026
4ee56f0
feat: remove device enrollment check [WPB-28485]
e-maad Sep 3, 2026
7ea0ebf
Merge pull request #9739 from wireapp/fix/remove-enrollment-logic-WPB…
e-maad Sep 3, 2026
d72ec14
ci: remove Linux Jenkins build pipeline
screendriver Sep 4, 2026
0f59bdc
chore: disable Dependabot updates in favor of Renovate
screendriver Sep 4, 2026
083fe35
Adjust desktop log retention size limit
screendriver Sep 4, 2026
4cfa295
Use Hosted Dev for desktop smoke tests
screendriver Sep 4, 2026
e271815
Merge pull request #9744 from wireapp/environments
screendriver Sep 4, 2026
72d7770
Merge pull request #9743 from wireapp/logfile-size
screendriver Sep 4, 2026
4f12b9c
Merge pull request #9742 from wireapp/disable-dependabot
screendriver Sep 4, 2026
363e26b
Merge pull request #9741 from wireapp/linux-build
screendriver Sep 4, 2026
c474d07
Merge pull request #9738 from wireapp/locale
screendriver Sep 4, 2026
816e9ef
Merge remote-tracking branch 'refs/remotes/origin/staging' into staging
e-maad Sep 4, 2026
62b5603
feat: remove device enrollment check [WPB-28485]
e-maad Sep 3, 2026
6ca46fd
Merge pull request #9745 from wireapp/cherry-pick-WPB-28485
e-maad Sep 4, 2026
305882a
chore: Update translations
crowdin-bot Sep 8, 2026
d212410
Merge pull request #9636 from wireapp/chore/update-translations
zskhan Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Renovate is the only dependency-update automation used by this repository.
#
# `open-pull-requests-limit: 0` disables Dependabot version-update pull
# requests. The wildcard ignore rule is also required because security-update
# pull requests are not subject to that limit.

version: 2

updates:
- package-ecosystem: 'npm'
directories:
- '**/*'
schedule:
interval: 'monthly'
open-pull-requests-limit: 0
ignore:
- dependency-name: '*'
Comment on lines +10 to +17

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue, but thinks it may be safe to ignore.
This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown

Why this might be safe to ignore:

The rule correctly identifies missing cooldown settings, but this repository explicitly disables Dependabot version-update pull requests and uses Renovate instead. Adding a Dependabot cooldown would not meaningfully affect the active dependency-update process.

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by dependabot-missing-cooldown.

You can view more details about this finding in the Semgrep AppSec Platform.


- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'monthly'
open-pull-requests-limit: 0
ignore:
- dependency-name: '*'
Comment on lines +19 to +25

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue, but thinks it may be safe to ignore.
This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown

Why this might be safe to ignore:

Dependabot version-update pull requests are disabled for this entry with open-pull-requests-limit: 0 and a wildcard ignore rule, while the repository uses Renovate instead. Adding a Dependabot cooldown would not meaningfully affect the configured update workflow.

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by dependabot-missing-cooldown.

You can view more details about this finding in the Semgrep AppSec Platform.


- package-ecosystem: 'docker'
directories:
- '**/*'
schedule:
interval: 'monthly'
open-pull-requests-limit: 0
ignore:
- dependency-name: '*'
Comment on lines +27 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue, but thinks it may be safe to ignore.
This Dependabot configuration does not set a cooldown period. Newly published packages can be malicious or unstable. Add a cooldown block with default-days: 7 to each package-ecosystem entry under updates to wait 7 days before proposing updates to newly published package versions. Reference: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#cooldown

Why this might be safe to ignore:

Dependabot version-update pull requests are disabled for every ecosystem with open-pull-requests-limit: 0 and a wildcard ignore rule; the repository explicitly uses Renovate instead. Adding a Dependabot cooldown would not meaningfully affect the dependency-update workflow here.

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by dependabot-missing-cooldown.

You can view more details about this finding in the Semgrep AppSec Platform.

Binary file added bin/build-tools/assets/msi-banner.bmp
Binary file not shown.
21 changes: 18 additions & 3 deletions bin/build-tools/build-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@
*
*/

import {LogFactory} from '@wireapp/commons';
import {program as commander} from 'commander';
import * as electronBuilder from 'electron-builder';

import path from 'path';

import {logEntries} from '../bin-utils';
import {LogFactory} from '@wireapp/commons';

import {buildLinuxConfig, buildLinuxWrapper} from './lib/build-linux';
import {buildMacOSConfig, buildMacOSWrapper} from './lib/build-macos';
import {buildWindowsConfig, buildWindowsWrapper} from './lib/build-windows';
import {buildWindowsInstaller, buildWindowsInstallerConfig} from './lib/build-windows-installer';
import {buildWindowsMsi, buildWindowsMsiConfig} from './lib/build-windows-msi';

import {logEntries} from '../bin-utils';

const toolName = path.basename(__filename).replace('.ts', '');
const logger = LogFactory.getLogger(toolName, {forceEnable: true, namespace: '@wireapp/build-tools'});
Expand All @@ -34,7 +39,7 @@ const appSource = path.join(__dirname, '../../');
commander
.name(toolName)
.description(
'Build the Wire wrapper for your platform.\n\nValid values for platform are: "windows", "windows-installer", "macos", "linux".',
'Build the Wire wrapper for your platform.\n\nValid values for platform are: "windows", "windows-installer", "windows-msi", "macos", "linux".',
)
.option('-e, --env-file <path>', 'Specify the env file path', path.join(appSource, '.env.defaults'))
.option(
Expand Down Expand Up @@ -71,6 +76,16 @@ const platform = (commander.args[0] || '').toLowerCase();
return buildWindowsInstaller(wireJson, envFile, wInstallerOptions);
}

case 'windows-msi': {
const {builderConfig, windowsMsiConfig} = await buildWindowsMsiConfig(wireJson, envFile, manualSign);
const msiArchitecture = architecture ? electronBuilder.archFromString(architecture) : undefined;

logEntries(windowsMsiConfig, 'windowsMsiConfig', toolName);
logEntries(builderConfig, 'builderConfig', toolName);

return buildWindowsMsi(builderConfig, packageJson, wireJson, envFile, msiArchitecture);
}

case 'mac':
case 'macos': {
const {macOSConfig, packagerConfig} = await buildMacOSConfig(wireJson, envFile, manualSign, architecture);
Expand Down
7 changes: 7 additions & 0 deletions bin/build-tools/lib/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,10 @@ export interface WindowsInstallerConfig {
installerIconUrl: string;
loadingGif: string;
}

export interface WindowsMsiConfig {
appId: string;
artifactName: string;
manufacturer: string;
upgradeCode: string;
}
26 changes: 25 additions & 1 deletion bin/build-tools/lib/build-windows-installer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@
*/

import * as assert from 'assert';
import fs from 'fs-extra';
import os from 'os';
import * as path from 'path';
import type {Options as ElectronWinstallerOptions} from 'electron-winstaller';

import {buildWindowsInstallerConfig} from './build-windows-installer';
import {buildWindowsInstaller, buildWindowsInstallerConfig} from './build-windows-installer';
import {generateUUID} from '../../bin-utils';

const wireJsonPath = path.join(__dirname, '../../../electron/wire.json');
Expand All @@ -39,4 +42,25 @@ describe('build-windows-installer', () => {
delete process.env.WIN_URL_ICON_INSTALLER;
});
});

describe('buildWindowsInstaller', () => {
it('rejects when Squirrel packaging fails and restores wire.json', async () => {
const temporaryDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'wire-squirrel-installer-test-'));
const temporaryWireJsonPath = path.join(temporaryDirectory, 'wire.json');
const originalWireJson = await fs.readFile(wireJsonPath, 'utf8');
await fs.writeFile(temporaryWireJsonPath, originalWireJson);

try {
await assert.rejects(
buildWindowsInstaller(temporaryWireJsonPath, envFilePath, {
appDirectory: path.join(temporaryDirectory, 'missing-app-directory'),
outputDirectory: path.join(temporaryDirectory, 'output'),
} as ElectronWinstallerOptions),
);
assert.strictEqual(await fs.readFile(temporaryWireJsonPath, 'utf8'), originalWireJson);
} finally {
await fs.remove(temporaryDirectory);
}
});
});
});
5 changes: 3 additions & 2 deletions bin/build-tools/lib/build-windows-installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ export async function buildWindowsInstaller(
logger.log(`Built installer in "${buildDir}"`);
} catch (error) {
logger.error(error);
throw error;
} finally {
await restoreFiles(backup);
}

await restoreFiles(backup);
}
196 changes: 196 additions & 0 deletions bin/build-tools/lib/build-windows-msi.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
* Wire
* Copyright (C) 2026 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
*/

import fs from 'fs-extra';

import assert from 'node:assert';
import os from 'node:os';
import path from 'node:path';

import {buildWindowsMsiConfig, customizeMsiProject, validateWindowsMsiAppDirectory} from './build-windows-msi';

const wireJsonPath = path.join(__dirname, '../../../electron/wire.json');
const envFilePath = path.join(__dirname, '../../../.env.defaults');
const originalEnvironment = {
appEnvironment: process.env.APP_ENV,
appName: process.env.APP_NAME,
manufacturer: process.env.WIN_MSI_MANUFACTURER,
upgradeCode: process.env.WIN_MSI_UPGRADE_CODE,
};

function restoreEnvironmentVariable(name: string, value?: string): void {
if (value === undefined) {
delete process.env[name];
} else {
process.env[name] = value;
}
}

describe('build-windows-msi', () => {
afterEach(() => {
restoreEnvironmentVariable('APP_ENV', originalEnvironment.appEnvironment);
restoreEnvironmentVariable('APP_NAME', originalEnvironment.appName);
restoreEnvironmentVariable('WIN_MSI_MANUFACTURER', originalEnvironment.manufacturer);
restoreEnvironmentVariable('WIN_MSI_UPGRADE_CODE', originalEnvironment.upgradeCode);
});

describe('buildWindowsMsiConfig', () => {
it('builds a per-machine MSI with a stable production upgrade identity', async () => {
const {builderConfig, windowsMsiConfig} = await buildWindowsMsiConfig(wireJsonPath, envFilePath, true);

assert.strictEqual(windowsMsiConfig.appId, 'com.squirrel.wire.wire');
assert.strictEqual(windowsMsiConfig.manufacturer, 'Wire Swiss GmbH');
assert.strictEqual(windowsMsiConfig.upgradeCode, '620FCDDD-30CB-4241-A347-D34CF682A358');
assert.deepStrictEqual(builderConfig.extraMetadata?.author, {name: windowsMsiConfig.manufacturer});
assert.strictEqual(builderConfig.msi?.oneClick, false);
assert.strictEqual(builderConfig.msi?.perMachine, true);
assert.strictEqual(builderConfig.msi?.runAfterFinish, false);
assert.strictEqual(builderConfig.msi?.upgradeCode, windowsMsiConfig.upgradeCode);
assert.strictEqual(typeof builderConfig.win?.signtoolOptions?.sign, 'function');
});

it('keeps the standard product upgrade identities distinct', async () => {
process.env.APP_ENV = 'internal';
process.env.APP_NAME = 'WireInternal';
const internal = await buildWindowsMsiConfig(wireJsonPath, envFilePath);

process.env.APP_ENV = 'wire-gov';
process.env.APP_NAME = 'WireGov';
const wireGov = await buildWindowsMsiConfig(wireJsonPath, envFilePath);

assert.strictEqual(internal.windowsMsiConfig.upgradeCode, '673C5C7F-2923-483B-8EDB-34EDBDFCFF8A');
assert.strictEqual(wireGov.windowsMsiConfig.upgradeCode, '0FC26EF0-E415-4263-9C73-89D05BCD4E1A');
assert.notStrictEqual(internal.windowsMsiConfig.upgradeCode, wireGov.windowsMsiConfig.upgradeCode);
});

it('honors and normalizes a configured upgrade code', async () => {
process.env.WIN_MSI_UPGRADE_CODE = '{C88AA646-1E4B-FC0A-005A-8BB72BBADBBB}';

const {windowsMsiConfig} = await buildWindowsMsiConfig(wireJsonPath, envFilePath);

assert.strictEqual(windowsMsiConfig.upgradeCode, 'C88AA646-1E4B-FC0A-005A-8BB72BBADBBB');
});

it('honors a configured manufacturer', async () => {
process.env.WIN_MSI_MANUFACTURER = 'Customer Corporation';

const {builderConfig, windowsMsiConfig} = await buildWindowsMsiConfig(wireJsonPath, envFilePath);

assert.strictEqual(windowsMsiConfig.manufacturer, 'Customer Corporation');
assert.strictEqual(builderConfig.extraMetadata?.author?.name, windowsMsiConfig.manufacturer);
});

it('rejects an invalid configured upgrade code', async () => {
process.env.WIN_MSI_UPGRADE_CODE = 'not-a-guid';

await assert.rejects(buildWindowsMsiConfig(wireJsonPath, envFilePath), /Invalid Windows MSI upgrade code/);
});

it('requires a dedicated upgrade code for a custom-branded product', async () => {
process.env.APP_NAME = 'CustomerWire';

await assert.rejects(buildWindowsMsiConfig(wireJsonPath, envFilePath), /must define a permanent/);
});
});

describe('customizeMsiProject', () => {
it('regression: detects Windows 10 and later from the actual registry build number', () => {
const project = `<Product>
<Condition Message="Windows 7 and above is required"><![CDATA[Installed OR VersionNT >= 601]]></Condition>
<Component>
<File Name="Wire.exe" Id="mainExecutable">
<Shortcut Id="desktopShortcut" Directory="DesktopFolder" Name="Wire"/>
</File>
</Component>
</Product>`;

const result = customizeMsiProject(project, 'wire', 'com.squirrel.wire.wire', 'Wire', 'msi-banner.bmp');

assert.match(result, /Property Id="WIRE_WINDOWS_BUILD" Secure="yes"/);
assert.match(
result,
/RegistrySearch Id="WireWindowsBuild" Root="HKLM" Key="SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" Name="CurrentBuildNumber" Type="raw" Win64="yes"/,
);
assert.match(result, /Installed OR WIRE_WINDOWS_BUILD >= 10240/);
assert.doesNotMatch(result, /VersionNT >= 603 AND WindowsBuild >= 10240/);
});

it('brands the assisted UI and makes the URL protocol and desktop shortcut identity MSI-owned', () => {
const project = `
<Product Name="Wire">
<Condition Message="Windows 7 and above is required"><![CDATA[Installed OR VersionNT >= 601]]></Condition>
<Component>
<File Name="Wire.exe" Id="mainExecutable">
<Shortcut Id="desktopShortcut" Directory="DesktopFolder" Name="Wire"/>
</File>
</Component>
</Product>`;

const result = customizeMsiProject(project, 'wire', 'com.squirrel.wire.wire', 'Wire', 'msi-banner.bmp');

assert.match(result, /WixVariable Id="WixUIBannerBmp" Value="msi-banner\.bmp"/);
assert.match(result, /Windows 10 or above is required/);
assert.match(result, /ShortcutProperty Key="System\.AppUserModel\.ID" Value="com\.squirrel\.wire\.wire"/);
assert.match(result, /RegistryKey Root="HKLM" Key="Software\\Classes\\wire"/);
assert.match(result, /Value="&quot;\[#mainExecutable\]&quot; &quot;%1&quot;"/);
assert.match(result, /Property Id="WIRE_WEBAPP_URL" Secure="yes"/);
assert.match(result, /Property Id="WIRE_CLEAR_WEBAPP_URL" Secure="yes"/);
assert.match(
result,
/RegistrySearch Id="WireExistingWebAppUrl" Root="HKLM" Key="Software\\Wire\\Wire" Name="WebAppUrl" Type="raw" Win64="yes"/,
);
assert.match(result, /SetProperty Id="WIRE_WEBAPP_URL" Value="\[WIRE_EXISTING_WEBAPP_URL\]"/);
assert.match(result, /NOT WIRE_WEBAPP_URL AND NOT WIRE_CLEAR_WEBAPP_URL AND WIRE_EXISTING_WEBAPP_URL/);
assert.match(result, /RegistryValue Name="WebAppUrl" Type="string" Value="\[WIRE_WEBAPP_URL\]"/);
});

it('fails if electron-builder no longer generates the expected main executable component', () => {
assert.throws(
() => customizeMsiProject('<Product/>', 'wire', 'com.squirrel.wire.wire', 'Wire', 'msi-banner.bmp'),
/Could not find the main executable/,
);
});

it('fails if electron-builder no longer generates the expected desktop shortcut', () => {
const project = `<Product>
<Condition Message="Windows 7 and above is required"><![CDATA[Installed OR VersionNT >= 601]]></Condition>
<Component><File Name="Wire.exe" Id="mainExecutable"/></Component>
</Product>`;

assert.throws(
() => customizeMsiProject(project, 'wire', 'com.squirrel.wire.wire', 'Wire', 'msi-banner.bmp'),
/Could not find the desktop shortcut/,
);
});
});

describe('validateWindowsMsiAppDirectory', () => {
it('rejects a directory already mutated by Squirrel packaging', async () => {
const appDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'wire-msi-app-directory-'));
try {
await fs.ensureFile(path.join(appDirectory, 'Wire.exe'));
await fs.ensureFile(path.join(appDirectory, 'Squirrel.exe'));

await assert.rejects(validateWindowsMsiAppDirectory(appDirectory, 'Wire'), /contains the Squirrel updater/);
} finally {
await fs.remove(appDirectory);
}
});
});
});
Loading
Loading