Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
43eb57a
try signpath
jay-418 Feb 4, 2026
6119108
add temp todo
jay-418 Feb 4, 2026
dd3a932
reenable windows builds
jay-418 Feb 4, 2026
15627f8
reenable windows, finally, maybe
jay-418 Feb 4, 2026
988ad6b
update signpath action format
jay-418 Feb 4, 2026
d551109
connector
jay-418 Feb 4, 2026
822250d
try direct api to skip trusted build requirements
jay-418 Feb 4, 2026
976bb69
verify
jay-418 Feb 4, 2026
c13febd
install self sign cert for validation
jay-418 Feb 5, 2026
6ba6b61
bugfix
jay-418 Feb 5, 2026
d070d46
better comment
jay-418 Feb 5, 2026
7c30e9f
refactor build CI
jay-418 Feb 6, 2026
ce07a0c
pass both version and tag
jay-418 Feb 10, 2026
d5d55d2
correct build type tag bug
jay-418 Feb 10, 2026
164cadf
fix windows naming issue
jay-418 Feb 10, 2026
5be498c
fixes
jay-418 Feb 10, 2026
51dc961
handle error
jay-418 Feb 10, 2026
515d482
makefile changes
jay-418 Feb 10, 2026
7e5d046
accept platform tag
jay-418 Feb 10, 2026
eb146ec
Merge branch 'main' into jay/releases
jay-418 Feb 10, 2026
b88110d
better tag filtering
jay-418 Feb 10, 2026
710d553
use linux for android build
jay-418 Feb 10, 2026
cd04ba9
annotate
jay-418 Feb 10, 2026
13b45eb
filter with valid yaml
jay-418 Feb 10, 2026
f63b1c9
back to macos for android
jay-418 Feb 11, 2026
e128ce4
use correct ref
jay-418 Feb 11, 2026
f3fb5ba
review fixes: correct tag enforcement, concurrency guard
jay-418 Feb 11, 2026
77825a7
Merge branch 'main' into jay/releases
jay-418 Feb 14, 2026
30565d1
7 char hash for consistency
jay-418 Feb 14, 2026
54e3e51
update with main
jay-418 Feb 14, 2026
06c8e7a
windows
jay-418 Feb 14, 2026
40d97fe
update
jay-418 Feb 14, 2026
474c28b
remove nightly
jay-418 Feb 14, 2026
8d9dd51
update deps and env for windows
jay-418 Feb 14, 2026
cb7700d
consistent parsing of installer names for windows
jay-418 Feb 14, 2026
c299a2f
fix windows release notes
jay-418 Feb 14, 2026
999c93a
delete notes
jay-418 Feb 14, 2026
842ffe5
fixes for windows failures with debug
jay-418 Feb 14, 2026
41ab425
correct vars
jay-418 Feb 14, 2026
5eb060f
conflicts
jay-418 Feb 14, 2026
3747c62
fixes
jay-418 Feb 14, 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
162 changes: 144 additions & 18 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ on:
installer_base_name:
required: true
type: string
use-self-signed-cert:
description: "Use self-signed code signing certificate"
required: false
type: boolean
default: true # TODO: remove for prod

jobs:
build-windows:
env:
AC_USERNAME: ${{ secrets.AC_USERNAME }}
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
BUILD_TYPE: ${{ inputs.build_type }}
VERSION: ${{ inputs.version }}
permissions:
Expand Down Expand Up @@ -106,35 +109,158 @@ jobs:
run: |
dart pub global activate flutter_distributor
make windows-release

Write-Host "=== Files in build/windows/x64/runner/Release/ after make windows-release ==="
Get-ChildItem -Path "build/windows/x64/runner/Release/" -Recurse | Select-Object -First 20 FullName
Write-Host ""
Write-Host "=== Checking for wintun.dll and lanternsvc.exe ==="
if (Test-Path "build/windows/x64/runner/Release/wintun.dll") { Write-Host "✓ wintun.dll exists" } else { Write-Host "✗ wintun.dll NOT FOUND" }
if (Test-Path "build/windows/x64/runner/Release/lanternsvc.exe") { Write-Host "✓ lanternsvc.exe exists" } else { Write-Host "✗ lanternsvc.exe NOT FOUND" }
Write-Host ""

flutter_distributor 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/ after flutter_distributor ==="
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: Sign EXE with Azure Code Signing
uses: getlantern/trusted-signing-action@main
- name: Upload unsigned artifact for SignPath
id: upload-unsigned
uses: actions/upload-artifact@v4
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: https://wus2.codesigning.azure.net/
code-signing-account-name: code-signing
certificate-profile-name: Lantern
files-folder: ${{ github.workspace }}/
files-folder-filter: exe,dll,msix
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
name: unsigned-installer
path: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe
retention-days: 1

- name: Download unsigned artifact
uses: actions/download-artifact@v4
with:
name: unsigned-installer
path: ./unsigned

- name: Sign EXE with SignPath (REST API)
id: sign
shell: pwsh
run: |
# Use test signing policy if self-signed cert is enabled, otherwise use production policy
$signingPolicy = if ("${{ inputs.use-self-signed-cert }}" -eq "true") {
"${{ vars.SIGNPATH_SIGNING_POLICY_SLUG_TEST }}"
} else {
"${{ vars.SIGNPATH_SIGNING_POLICY_SLUG }}"
}

Write-Host "=== SignPath Configuration ==="
Write-Host "use-self-signed-cert input: ${{ inputs.use-self-signed-cert }}"
Write-Host "Organization ID/Slug: ${{ vars.SIGNPATH_ORG_ID }}"
Write-Host "Project Slug: ${{ vars.SIGNPATH_PROJECT_SLUG }}"
Write-Host "Selected Signing Policy Slug: $signingPolicy"
Write-Host "=============================="

if ([string]::IsNullOrWhiteSpace($signingPolicy)) {
Write-Error "Signing policy slug is empty! Check your GitHub variables configuration."
exit 1
}

$response = Invoke-WebRequest -Method POST `
-Uri "https://app.signpath.io/API/v1/${{ vars.SIGNPATH_ORG_ID }}/SigningRequests" `
-Headers @{ "Authorization" = "Bearer ${{ secrets.SIGNPATH_API_TOKEN }}" } `
-Form @{
"ProjectSlug" = "${{ vars.SIGNPATH_PROJECT_SLUG }}"
"SigningPolicySlug" = $signingPolicy
"Artifact" = Get-Item "./unsigned/${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe"
"Description" = "GitHub Actions build - ${{ inputs.version }}"
}

if ($response.StatusCode -eq 201) {
$signRequestUrl = $response.Headers.Location
Write-Host "Signing request submitted: $signRequestUrl"
echo "signing_request_url=$signRequestUrl" >> $env:GITHUB_OUTPUT
} else {
Write-Error "Failed to submit signing request"
exit 1
}

- name: Wait for signing completion and download
shell: pwsh
run: |
$signRequestUrl = "${{ steps.sign.outputs.signing_request_url }}"
$maxAttempts = 60
$attempt = 0

Write-Host "Waiting for signing to complete..."

while ($attempt -lt $maxAttempts) {
Start-Sleep -Seconds 10
$attempt++

$status = Invoke-RestMethod -Method GET `
-Uri $signRequestUrl `
-Headers @{ "Authorization" = "Bearer ${{ secrets.SIGNPATH_API_TOKEN }}" }

Write-Host "Status: $($status.Status) (attempt $attempt/$maxAttempts)"

if ($status.Status -eq "Completed") {
Write-Host "Signing completed successfully!"

# Download signed artifact
New-Item -ItemType Directory -Force -Path "./signed"
Invoke-WebRequest -Method GET `
-Uri "$signRequestUrl/SignedArtifact" `
-Headers @{ "Authorization" = "Bearer ${{ secrets.SIGNPATH_API_TOKEN }}" } `
-OutFile "./signed/${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe"

Write-Host "Downloaded signed artifact"

# Import test certificate for validation if using self-signed cert
if ("${{ inputs.use-self-signed-cert }}" -eq "true") {
$certPem = "${{ vars.SIGNPATH_SELF_SIGN_CERT }}"
$certPath = "test-cert.pem"
$certPem | Out-File -FilePath $certPath -Encoding ASCII

Import-Certificate -FilePath $certPath -CertStoreLocation Cert:\LocalMachine\Root
Import-Certificate -FilePath $certPath -CertStoreLocation Cert:\LocalMachine\TrustedPublisher

Write-Host "✓ Test certificate imported to Trusted Root (for self-signed cert validation)"
}

# Verify signature
$sig = Get-AuthenticodeSignature -FilePath "./signed/${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe"
Write-Host "=== Signature Verification ==="
Write-Host "Status: $($sig.Status)"
Write-Host "Status Message: $($sig.StatusMessage)"
Write-Host "Signer Certificate Subject: $($sig.SignerCertificate.Subject)"
Write-Host "Timestamp: $($sig.TimeStamperCertificate.NotBefore)"
Write-Host "Certificate Thumbprint: $($sig.SignerCertificate.Thumbprint)"
Write-Host "=============================="

if ($sig.Status -ne "Valid") {
Write-Error "Signature verification failed! Status: $($sig.Status)"
exit 1
}

Write-Host "✓ Signature verified successfully!"
exit 0
} elseif ($status.Status -eq "Failed" -or $status.Status -eq "Denied") {
Write-Error "Signing failed with status: $($status.Status)"
exit 1
}
}

Write-Error "Timeout waiting for signing to complete"
exit 1

- name: Upload Windows installer
uses: actions/upload-artifact@v4
env:
FULL_INSTALLER_NAME: ${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}
with:
name: lantern-installer-exe
path: ${{ env.FULL_INSTALLER_NAME }}.exe
path: signed/${{ inputs.installer_base_name }}${{ inputs.build_type != 'production' && format('-{0}', inputs.build_type) || '' }}.exe
retention-days: 2
24 changes: 23 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ jobs:
build_type: ${{ needs.set-metadata.outputs.build_type }}
installer_base_name: ${{ needs.set-metadata.outputs.installer_base_name }}

build-windows:
needs: [set-metadata, release-create]
uses: ./.github/workflows/build-windows.yml
secrets: inherit
if: ${{ needs.set-metadata.outputs.platform == 'all' || contains(needs.set-metadata.outputs.platform, 'windows') }}
with:
version: ${{ needs.set-metadata.outputs.version }}
build_type: ${{ needs.set-metadata.outputs.build_type }}
installer_base_name: ${{ needs.set-metadata.outputs.installer_base_name }}

build-linux:
needs: [set-metadata, release-create]
uses: ./.github/workflows/build-linux.yml
Expand Down Expand Up @@ -262,10 +272,19 @@ jobs:
--notes "Build [in progress](${WORKFLOW_URL})..."

upload-s3:
needs: [set-metadata, build-macos, build-linux, build-android, build-ios]
needs:
[
set-metadata,
build-macos,
build-windows,
build-linux,
build-android,
build-ios,
]
if: |
!cancelled() &&
(needs.build-macos.result == 'success' || needs.build-macos.result == 'skipped') &&
(needs.build-windows.result == 'success' || needs.build-windows.result == 'skipped') &&
(needs.build-linux.result == 'success' || needs.build-linux.result == 'skipped') &&
(needs.build-android.result == 'success' || needs.build-android.result == 'skipped') &&
(needs.build-ios.result == 'success' || needs.build-ios.result == 'skipped')
Expand Down Expand Up @@ -333,6 +352,7 @@ jobs:
set-metadata,
release-create,
build-macos,
build-windows,
build-linux,
build-android,
build-ios,
Expand All @@ -341,6 +361,7 @@ jobs:
!cancelled() &&
needs.release-create.result == 'success' &&
(needs.build-macos.result == 'success' || needs.build-macos.result == 'skipped') &&
(needs.build-windows.result == 'success' || needs.build-windows.result == 'skipped') &&
(needs.build-linux.result == 'success' || needs.build-linux.result == 'skipped') &&
(needs.build-android.result == 'success' || needs.build-android.result == 'skipped') &&
(needs.build-ios.result == 'success' || needs.build-ios.result == 'skipped')
Expand Down Expand Up @@ -390,6 +411,7 @@ jobs:
}

upload_if_exists "lantern-installer-dmg/${FULL_NAME}.dmg"
upload_if_exists "lantern-installer-exe/${FULL_NAME}.exe"
upload_if_exists "lantern-installer-apk/${FULL_NAME}.apk"
upload_if_exists "lantern-installer-deb/${FULL_NAME}.deb"
upload_if_exists "lantern-installer-rpm/${FULL_NAME}.rpm"
Expand Down
8 changes: 8 additions & 0 deletions scripts/ci/format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ release-notes)
echo "- [macOS (.dmg)](${LATEST_URL}/${FULL_INSTALLER_NAME}.dmg) ([permalink](${VERSION_URL}/${FULL_INSTALLER_NAME}.dmg))"
fi

if should_include "windows"; then
echo "- [Windows (.exe)](${LATEST_URL}/${FULL_INSTALLER_NAME}.exe) ([permalink](${VERSION_URL}/${FULL_INSTALLER_NAME}.exe))"
fi

if should_include "android"; then
echo "- [Android (.apk)](${LATEST_URL}/${FULL_INSTALLER_NAME}.apk) ([permalink](${VERSION_URL}/${FULL_INSTALLER_NAME}.apk))"
fi
Expand Down Expand Up @@ -94,6 +98,10 @@ slack)
text="${text}\n• macOS <${LATEST_URL}/${FULL_INSTALLER_NAME}.dmg|${FULL_INSTALLER_NAME}.dmg> (<${VERSION_URL}/${FULL_INSTALLER_NAME}.dmg|permalink>)"
fi

if should_include "windows"; then
text="${text}\n• Windows <${LATEST_URL}/${FULL_INSTALLER_NAME}.exe|${FULL_INSTALLER_NAME}.exe> (<${VERSION_URL}/${FULL_INSTALLER_NAME}.exe|permalink>)"
fi

if should_include "android"; then
text="${text}\n• Android <${LATEST_URL}/${FULL_INSTALLER_NAME}.apk|${FULL_INSTALLER_NAME}.apk> (<${VERSION_URL}/${FULL_INSTALLER_NAME}.apk|permalink>)"
fi
Expand Down
2 changes: 0 additions & 2 deletions windows/packaging/exe/inno_setup.iss
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,6 @@ Name: "{#ProgramDataDir}"; Permissions: users-modify

[Files]
Source: "{{SOURCE_DIR}}\\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "{{SOURCE_DIR}}\\wintun.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{{SOURCE_DIR}}\\lanternsvc.exe"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{autoprograms}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}"
Expand Down
Loading