-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
336 lines (299 loc) · 13.1 KB
/
Copy pathbuild-windows.yml
File metadata and controls
336 lines (299 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
name: Build Windows
on:
workflow_call:
inputs:
version:
required: true
type: string
build_type:
required: true
type: string
installer_base_name:
required: true
type: string
skip_signing:
description: "Skip code signing (e.g. for nightly builds)"
required: false
type: boolean
default: false
enable_ip_check:
description: "Enable public IP change validation in Windows smoke suite"
required: false
type: boolean
default: false
run_connect_smoke:
description: "Run Windows connect/disconnect smoke test"
required: false
type: boolean
default: true
run_split_tunnel_website_smoke:
description: "Run website split tunneling smoke test"
required: false
type: boolean
default: false
run_config_url_smoke:
description: "Run config URL smoke tests"
required: false
type: boolean
default: false
force_full_tunnel_smoke:
description: "Force full tunnel routing mode in smoke tests"
required: false
type: boolean
default: false
run_auth_smoke:
description: "Run auth smoke integration tests"
required: false
type: boolean
default: false
jobs:
build-windows:
env:
BUILD_TYPE: ${{ inputs.build_type }}
VERSION: ${{ inputs.version }}
SIGNPATH_SIGNING_POLICY: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG }}
permissions:
contents: "read"
id-token: "write"
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download pubspec.yaml
uses: actions/download-artifact@v4
with:
name: pubspec
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
cache: true
- name: Cache Flutter dependencies
uses: actions/cache@v4
timeout-minutes: 5
continue-on-error: true
with:
path: |
~/.pub-cache
key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
${{ runner.os }}-flutter-
- name: Install WebView2 Runtime
shell: pwsh
run: |
Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -OutFile "MicrosoftEdgeWebView2Setup.exe"
Start-Process -FilePath ".\MicrosoftEdgeWebView2Setup.exe" -ArgumentList "/silent", "/install" -Wait
- name: Set up MinGW
run: choco install mingw -y
- name: Install Flutter
uses: subosito/flutter-action@v2.22.0
with:
channel: stable
flutter-version-file: .github/flutter-version.yaml
- name: Enable Flutter Desktop Support
run: |
flutter config --enable-windows-desktop
- name: Decode APP_ENV
uses: timheuer/base64-to-file@v1.2
with:
fileName: "app.env"
fileDir: ${{ github.workspace }}
encodedString: ${{ secrets.APP_ENV }}
- name: Cache Dart pub global cache
uses: actions/cache@v4
with:
path: ~/.pub-cache
key: ${{ runner.os }}-dart-pub-cache-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
${{ runner.os }}-dart-pub-cache-
- name: Install Inno Setup 6
shell: pwsh
# The runner image preinstalls Inno Setup (currently 6.7.1). A bare
# --version=6.5.0 now fails ("a newer version is already installed; use
# --allow-downgrade"), so pin to 6.7.1 with --allow-downgrade: the install
# is deterministic and the Languages dir stays "Inno Setup 6". The vendored
# Farsi/ChineseSimplified .isl files are "6.5.0+" and message-key-identical
# to 6.7.1's Default.isl, so they remain valid as-is.
run: choco install -y innosetup --version=6.7.1 --allow-downgrade
- name: Install unofficial Inno Setup translations
shell: pwsh
# Chinese Simplified and Farsi/Persian are not bundled Inno translations;
# copy the vendored .isl files into Inno's Languages dir so inno_setup.iss
# can reference them as compiler:Languages\<name>.isl. (Russian is bundled;
# en is Default.isl.)
run: |
$langDir = "C:\Program Files (x86)\Inno Setup 6\Languages"
if (-not (Test-Path $langDir)) {
Write-Error "Inno Setup Languages dir not found: $langDir"
exit 1
}
foreach ($isl in 'ChineseSimplified.isl', 'Farsi.isl') {
Copy-Item "windows\packaging\exe\isl\$isl" "$langDir\$isl" -Force
Write-Host "Installed $isl -> $langDir"
}
- name: Read app version from pubspec.yaml
shell: pwsh
run: |
$version = (Select-String -Path 'pubspec.yaml' -Pattern '^version:\s*(.+)$').Matches[0].Groups[1].Value.Trim()
$name = (Select-String -Path 'pubspec.yaml' -Pattern '^name:\s*(.+)$').Matches[0].Groups[1].Value.Trim()
echo "APP_VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
echo "APP_NAME=$name" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
Write-Host "APP_NAME=$name"
Write-Host "APP_VERSION=$version"
- name: Build Windows binaries
shell: pwsh
run: |
dart pub global activate fastforge
make windows-release
if ($LASTEXITCODE -ne 0) {
Write-Error "make windows-release failed with exit code $LASTEXITCODE"
exit $LASTEXITCODE
}
Write-Host "=== Files in build/windows/x64/runner/Release/ ==="
if (Test-Path "build/windows/x64/runner/Release/") {
Get-ChildItem -Path "build/windows/x64/runner/Release/" -Recurse | Select-Object -First 20 FullName
} else {
Write-Warning "Release directory does not exist"
}
- name: Sign embedded binaries
if: ${{ !inputs.skip_signing }}
shell: pwsh
env:
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
run: |
$buildDir = Resolve-Path "build/windows/x64/runner/Release"
# Third-party binaries that are already signed by their vendors
$thirdParty = @(
'flutter_windows.dll', # Google/Flutter
'WebView2Loader.dll', # Microsoft
'WinSparkle.dll' # WinSparkle
)
# Discover all EXEs and DLLs, excluding third-party signed binaries
$binaries = @(
Get-ChildItem -Path $buildDir -Include '*.exe','*.dll' -Recurse -File |
Where-Object { $thirdParty -notcontains $_.Name }
)
if ($binaries.Count -eq 0) {
Write-Error "No binaries found to sign"
exit 1
}
# Stage binaries into a zip preserving relative paths (single signing request)
$stage = "$env:GITHUB_WORKSPACE\sign-stage"
foreach ($bin in $binaries) {
$rel = $bin.FullName.Substring($buildDir.Path.Length).TrimStart('\', '/')
$dest = Join-Path $stage $rel
New-Item -ItemType Directory -Path (Split-Path $dest) -Force | Out-Null
Copy-Item $bin.FullName $dest
Write-Host " staged: $rel"
}
$zipPath = "$env:GITHUB_WORKSPACE\binaries-to-sign.zip"
Compress-Archive -Path "$stage\*" -DestinationPath $zipPath -Force
Write-Host "Bundled $($binaries.Count) binaries into zip"
# Sign the zip as a single request
& ./scripts/ci/sign-windows.ps1 `
-FilePath $zipPath `
-SigningPolicy "${{ env.SIGNPATH_SIGNING_POLICY }}" `
-OrganizationId "${{ vars.SIGNPATH_ORG_ID }}" `
-ProjectSlug "${{ vars.SIGNPATH_PROJECT_SLUG }}" `
-ApiToken $env:SIGNPATH_API_TOKEN `
-ArtifactConfigurationSlug "zip-bundle" `
-Description "GitHub Actions build ${{ inputs.version }}"
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to sign binaries bundle"
exit 1
}
# Extract signed binaries back over originals
Expand-Archive -Path $zipPath -DestinationPath $buildDir -Force
# Verify each target binary has a valid Authenticode signature
$failedSigs = @()
foreach ($bin in $binaries) {
if (-not (Test-Path $bin.FullName)) {
Write-Error ("Signed binary not found after extraction: {0}" -f $bin.FullName)
$failedSigs += $bin.FullName
continue
}
$sig = Get-AuthenticodeSignature -FilePath $bin.FullName
if ($sig.Status -ne 'Valid') {
Write-Error ("Signature verification failed for {0}: Status={1}" -f $bin.FullName, $sig.Status)
$failedSigs += $bin.FullName
}
}
if ($failedSigs.Count -gt 0) {
Write-Error ("One or more binaries failed Authenticode verification after signing:`n{0}" -f ($failedSigs -join "`n"))
exit 1
}
Remove-Item -Recurse -Force $stage, $zipPath
Write-Host "All binaries signed successfully"
- name: Signing disabled for this run
if: ${{ inputs.skip_signing }}
shell: pwsh
run: |
Write-Host "Skipping embedded and installer signing for this run."
- name: Package installer
shell: pwsh
env:
FULL_INSTALLER_NAME: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}
run: |
fastforge package `
--platform=windows `
--targets=exe `
--skip-clean `
--build-dart-define=BUILD_TYPE=${{ env.BUILD_TYPE }} `
--build-dart-define=VERSION=${{ inputs.version }} `
--flutter-build-args=verbose
Write-Host ""
Write-Host "=== Contents of dist/$env:APP_VERSION/ ==="
Get-ChildItem -Path "dist/$env:APP_VERSION/" -Recurse | Select-Object FullName
Write-Host ""
Move-Item "dist/$env:APP_VERSION/$env:APP_NAME-$env:APP_VERSION-windows-setup.exe" "$env:FULL_INSTALLER_NAME.exe"
- name: Windows installer smoke suite
shell: pwsh
timeout-minutes: 30
env:
FULL_INSTALLER_NAME: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}
JOIN_SERVER_CONFIG_URLS: ${{ secrets.JOIN_SERVER_CONFIG_URLS }}
JOIN_SERVER_CONFIG_SERVER_NAME: ${{ vars.JOIN_SERVER_CONFIG_SERVER_NAME }}
JOIN_SERVER_CONFIG_SKIP_CERT_VERIFICATION: "true"
run: |
$installerPath = "$env:FULL_INSTALLER_NAME.exe"
$runSplitTunnelWebsiteSmoke = "${{ inputs.run_split_tunnel_website_smoke }}" -eq "true"
$runConfigUrlSmoke = "${{ inputs.run_config_url_smoke }}" -eq "true"
$forceFullTunnelSmoke = "${{ inputs.force_full_tunnel_smoke }}" -eq "true"
$enableIpCheck = "${{ inputs.enable_ip_check }}" -eq "true"
$runConnectSmoke = "${{ inputs.run_connect_smoke }}" -eq "true"
Write-Host "Windows smoke options: connect=$runConnectSmoke splitTunnelWebsite=$runSplitTunnelWebsiteSmoke configUrl=$runConfigUrlSmoke forceFullTunnel=$forceFullTunnelSmoke ipCheck=$enableIpCheck"
./.github/scripts/windows_smoke_suite.ps1 `
-UseInstaller `
-InstallerPath $installerPath `
-RunConnectSmoke:$runConnectSmoke `
-RunSplitTunnelWebsiteSmoke:$runSplitTunnelWebsiteSmoke `
-RunConfigUrlSmoke:$runConfigUrlSmoke `
-EnableIpCheck:$enableIpCheck `
-ForceFullTunnel:$forceFullTunnelSmoke
# Transitional fallback kept in place while the auth + connect smoke suite stabilizes.
- name: Windows UI auth smoke integration
if: ${{ inputs.run_auth_smoke }}
shell: pwsh
timeout-minutes: 15
run: |
flutter test integration_test/auth/auth_smoke_test.dart -d windows --reporter=expanded --dart-define=DISABLE_SYSTEM_TRAY=true
- name: Sign installer
if: ${{ !inputs.skip_signing }}
shell: pwsh
env:
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
FULL_INSTALLER_NAME: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}
run: |
./scripts/ci/sign-windows.ps1 `
-FilePath "$env:FULL_INSTALLER_NAME.exe" `
-SigningPolicy "${{ env.SIGNPATH_SIGNING_POLICY }}" `
-OrganizationId "${{ vars.SIGNPATH_ORG_ID }}" `
-ProjectSlug "${{ vars.SIGNPATH_PROJECT_SLUG }}" `
-ApiToken $env:SIGNPATH_API_TOKEN `
-Description "Installer - GitHub Actions build ${{ inputs.version }}"
- name: Upload Windows installer
uses: actions/upload-artifact@v4
with:
name: lantern-installer-exe
path: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe
retention-days: 2