Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 17 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
- package-ecosystem: cargo
directory: /src-tauri
schedule:
interval: weekly
open-pull-requests-limit: 5
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
144 changes: 144 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write
id-token: write
attestations: write

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
windows-release:
runs-on: windows-latest
env:
WINDOWS_SIGNING_CERTIFICATE_BASE64: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_BASE64 }}
WINDOWS_SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PASSWORD }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
- run: rustup default stable
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
with:
workspaces: src-tauri
- name: Require Windows signing credentials
shell: pwsh
run: |
if ([string]::IsNullOrWhiteSpace($env:WINDOWS_SIGNING_CERTIFICATE_BASE64)) {
throw 'WINDOWS_SIGNING_CERTIFICATE_BASE64 is required; unsigned releases are forbidden.'
}
if ([string]::IsNullOrWhiteSpace($env:WINDOWS_SIGNING_CERTIFICATE_PASSWORD)) {
throw 'WINDOWS_SIGNING_CERTIFICATE_PASSWORD is required; unsigned releases are forbidden.'
}
- run: npm ci
- run: npm run verify
- name: Import signing certificate and configure Tauri
shell: pwsh
run: |
$pfxPath = Join-Path $env:RUNNER_TEMP 'hpm-signing.pfx'
[System.IO.File]::WriteAllBytes(
$pfxPath,
[Convert]::FromBase64String($env:WINDOWS_SIGNING_CERTIFICATE_BASE64)
)
$password = ConvertTo-SecureString $env:WINDOWS_SIGNING_CERTIFICATE_PASSWORD -AsPlainText -Force
$certificate = Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\CurrentUser\My -Password $password
if (-not $certificate -or -not $certificate.Thumbprint) {
throw 'Windows signing certificate import failed.'
}
@{
bundle = @{
windows = @{
certificateThumbprint = $certificate.Thumbprint
digestAlgorithm = 'sha256'
timestampUrl = 'http://timestamp.digicert.com'
}
}
} | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath 'src-tauri\tauri.windows.conf.json' -Encoding UTF8
"HPM_SIGNING_THUMBPRINT=$($certificate.Thumbprint)" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
"HPM_SIGNING_PFX=$pfxPath" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
- run: npm run tauri:build
- name: Verify Authenticode signatures
shell: pwsh
run: |
$signedFiles = @(
Get-ChildItem -LiteralPath 'dist\release\installers' -File |
Where-Object { $_.Extension -in @('.exe', '.msi') }
)
$appExecutable = Get-ChildItem -LiteralPath 'src-tauri\target\release' -File |
Where-Object { $_.Name -in @('https-proxy-manager.exe', 'app.exe') } |
Select-Object -First 1
if ($appExecutable) { $signedFiles += $appExecutable }
if ($signedFiles.Count -eq 0) { throw 'No signed Windows release files were found.' }
foreach ($file in $signedFiles) {
$signature = Get-AuthenticodeSignature -LiteralPath $file.FullName
if ($signature.Status -ne 'Valid') {
throw "Invalid Authenticode signature for $($file.FullName): $($signature.Status)"
}
}
- name: Verify checksums
run: node scripts/verify-release-artifacts.js
- name: Generate CycloneDX SBOMs
shell: pwsh
run: |
New-Item -ItemType Directory -Path 'dist\release\sbom' -Force | Out-Null
$npmSbom = npm sbom --sbom-format cyclonedx --sbom-type application --omit dev
if ($LASTEXITCODE -ne 0) { throw 'npm SBOM generation failed.' }
[System.IO.File]::WriteAllLines(
(Resolve-Path 'dist\release\sbom').Path + '\npm-sbom.cdx.json',
[string[]]$npmSbom
)
cargo install cargo-cyclonedx --version 0.5.9 --locked
if ($LASTEXITCODE -ne 0) { throw 'cargo-cyclonedx installation failed.' }
cargo cyclonedx --manifest-path src-tauri/Cargo.toml --format json --spec-version 1.5 --override-filename rust-sbom.cdx
if ($LASTEXITCODE -ne 0) { throw 'Rust SBOM generation failed.' }
$rustSbom = Get-ChildItem -LiteralPath 'src-tauri' -File |
Where-Object { $_.Name -like 'rust-sbom.cdx*.json' } |
Select-Object -First 1
if (-not $rustSbom) { throw 'Rust CycloneDX SBOM output was not found.' }
Move-Item -LiteralPath $rustSbom.FullName -Destination 'dist\release\sbom\rust-sbom.cdx.json' -Force
foreach ($sbom in Get-ChildItem -LiteralPath 'dist\release\sbom' -Filter '*.json') {
$parsed = Get-Content -LiteralPath $sbom.FullName -Raw | ConvertFrom-Json
if ($parsed.bomFormat -ne 'CycloneDX') { throw "Invalid CycloneDX SBOM: $($sbom.FullName)" }
}
- name: Installer smoke test
shell: pwsh
run: ./scripts/smoke-test-nsis.ps1 -InstallerDirectory 'dist\release\installers'
- uses: actions/attest@36051bcae73b7c2a8a6945a48cbf80953c6baa35 # v4
with:
subject-path: dist/release/**/*
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: signed-windows-release-${{ github.ref_name }}
path: dist/release
if-no-files-found: error
- name: Publish GitHub release
shell: pwsh
env:
GH_TOKEN: ${{ github.token }}
run: |
$assets = @(
Get-ChildItem -LiteralPath 'dist\release' -Recurse -File |
ForEach-Object { $_.FullName }
)
if ($assets.Count -eq 0) { throw 'No release assets were produced.' }
gh release create $env:GITHUB_REF_NAME --verify-tag --generate-notes @assets
- name: Remove signing material
if: always()
shell: pwsh
run: |
if ($env:HPM_SIGNING_THUMBPRINT) {
Remove-Item -LiteralPath "Cert:\CurrentUser\My\$env:HPM_SIGNING_THUMBPRINT" -Force -ErrorAction SilentlyContinue
}
if ($env:HPM_SIGNING_PFX) {
Remove-Item -LiteralPath $env:HPM_SIGNING_PFX -Force -ErrorAction SilentlyContinue
}
Remove-Item -LiteralPath 'src-tauri\tauri.windows.conf.json' -Force -ErrorAction SilentlyContinue
43 changes: 33 additions & 10 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@ jobs:
node-quality:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run check:syntax
- run: npm run lint
- run: npm run release:check
- run: npm run frontend:check
- run: npm run test:frontend
- run: npm run frontend:build
- run: npm audit --audit-level=high

unit-tests:
runs-on: windows-latest
Expand All @@ -33,19 +35,30 @@ jobs:
TEST_SHARD_COUNT: 4
TEST_SHARD_INDEX: ${{ matrix.shard }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run test:unit

coverage:
runs-on: windows-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run test:coverage

integration-tests:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
Expand All @@ -57,9 +70,19 @@ jobs:
rust-tests:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 22
cache: npm
- run: rustup default stable
- uses: Swatinem/rust-cache@42dc69e1aa15d09112580998cf2ef0119e2e91ae # v2
with:
workspaces: src-tauri
- run: cargo test --manifest-path src-tauri/Cargo.toml
- run: npm ci
- run: npm run release:prepare
- run: cargo fmt --manifest-path src-tauri/Cargo.toml -- --check
- run: cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets -- -D warnings
- run: npm run test:rust
- run: cargo install cargo-audit --version 0.22.2 --locked
- run: cargo audit --file src-tauri/Cargo.lock
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Dependencies
node_modules/
coverage/

# Local config and secrets
proxy.config.json
Expand Down
Loading
Loading