CI/CD and Build Tools
sslTrus remote code signing service can be integrated into CI/CD, application build, and installation package creation workflows, automatically performing code signing on release artifacts after compilation or packaging is completed.
Currently supported typical integration scenarios include:
- GitHub Actions
- Electron Builder
- Advanced Installer
Depending on the capabilities of the build tool, you can directly use the sslTrus GitHub Action, invoke the SignTool CLI, or complete the integration through custom signing interfaces provided by the build tool.
GitHub Actions
sslTrus provides an official GitHub Action:
ssltrus-official/code-sign-action
Source code and version notes are available at ssltrus-official/code-sign-action. The current stable usage relies on the major-version tag @v1.
You can directly perform remote code signing on build artifacts within a GitHub Actions workflow.
The Action calls the sslTrus remote code signing service to complete the signing and directly updates the specified file, and it works on Linux, macOS, and Windows runners.
Preparing GitHub Secrets
It is recommended to save remote code signing credentials in GitHub Actions Secrets:
SSLTRUS_ACCESS_KEY
SSLTRUS_ACCESS_SECRET
SSLTRUS_CERT_CODE
Do not write the Access Secret directly into the Workflow file.
Basic Configuration
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: build/app.exe
After signing succeeds, build/app.exe is directly replaced by the signed file.
Signing multiple files
files supports configuring multiple files using multiple lines:
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
build/installer.msi
You can also use comma-separated file paths.
Duplicate file paths are processed only once.
Complete Configuration
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
build/installer.msi
dry-run: false
timestamp-rfc3161: http://timestamp.acs.microsoft.com
description: Example Application
description-url: https://example.com
Main parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
access-key | Yes | - | sslTrus Access Key |
access-secret | Yes | - | sslTrus Access Secret |
cert-code | Yes | - | Code signing certificate number |
files | Yes | - | Path to the file to be signed |
nicsrs | No | false | Whether to use the NICSRS service |
dry-run | No | false | Use a local test certificate to perform a test signature |
timestamp-rfc3161 | No | auto | RFC 3161 timestamp server; pass an empty value to disable timestamping |
description | No | - | Program description written to the Authenticode signature |
description-url | No | - | Program URL written to the Authenticode signature |
Complete Workflow Example
The following is an example of compiling, signing, and uploading build artifacts on a Windows Runner:
name: Build and Sign
on:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: windows-latest
steps:
- name: Check out repository
uses: actions/checkout@v7
- name: Build
run: |
# 在这里执行实际构建命令
- name: Sign files
uses: ssltrus-official/code-sign-action@v1
with:
access-key: ${{ secrets.SSLTRUS_ACCESS_KEY }}
access-secret: ${{ secrets.SSLTRUS_ACCESS_SECRET }}
cert-code: ${{ secrets.SSLTRUS_CERT_CODE }}
files: |
build/app.exe
build/library.dll
timestamp-rfc3161: http://timestamp.acs.microsoft.com
- name: Upload signed files
uses: actions/upload-artifact@v7
with:
name: signed-files
path: |
build/app.exe
build/library.dll
It is recommended to place the signing step at:
Compile → Package → Code signing → Release
Before the publishing step in the workflow.
Multi-platform Runner
GitHub Actions can be invoked on different runners:
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
Therefore, even if the build task runs on Linux or macOS, the same Action can be used to complete remote signing of supported files.
Dry Run
If you need to validate the Workflow and file processing logic, you can enable:
dry-run: true
This mode uses a local test certificate and does not call the remote code signing service.
For example:
- name: Test signing
uses: ssltrus-official/code-sign-action@v1
with:
access-key: dummy
access-secret: dummy
cert-code: dummy
files: build/app.exe
dry-run: true
dry-run will still modify the target file, so do not interpret it as a preview mode that does not modify files at all.
Electron Builder
Electron Builder can call the sslTrus SignTool CLI through a custom signing function, thereby automatically completing the signing of Windows executable files and installation packages during the Electron application build process.
Typical workflow:
Electron Builder
↓
customSign
↓
SignTool CLI
↓
sslTrus 远程代码签名服务
↓
云端 HSM
Prerequisites
Before you begin, make sure you have:
- An available sslTrus remote code signing service.
- Obtained the Access Key and Access Secret.
- Obtained the code signing certificate number.
- The Electron project is built using
electron-builder. - The build environment can run the sslTrus SignTool CLI, which can be downloaded from the sslTrus client releases page.
Configuring Credentials
You can pass credentials to the build script using environment variables:
Linux and macOS:
export SIGNTOOL_ACCESS_KEY="YOUR_ACCESS_KEY"
export SIGNTOOL_ACCESS_SECRET="YOUR_ACCESS_SECRET"
export SIGNTOOL_CERT_CODE="YOUR_CERT_CODE"
Windows PowerShell:
$env:SIGNTOOL_ACCESS_KEY = "YOUR_ACCESS_KEY"
$env:SIGNTOOL_ACCESS_SECRET = "YOUR_ACCESS_SECRET"
$env:SIGNTOOL_CERT_CODE = "YOUR_CERT_CODE"
These variables are read by the Electron custom signing script and then passed to the SignTool CLI.
Configuring Electron Builder
In:
electron-builder.mjs
Or in the actual Electron Builder configuration file used by the project, set a custom signing function for Windows:
export default {
win: {
target: [
{
target: 'nsis',
arch: ['x64'],
},
],
sign: customSign,
signingHashAlgorithms: ['sha256'],
},
};
Among them, win.sign is the custom signing entry provided by Electron Builder officially. For details, please refer to the Electron Builder Windows Code Signing Documentation.
customSign
Responsible for invoking the sslTrus SignTool CLI.
Custom Signing Function
Example:
import { execFileSync } from 'node:child_process';
async function customSign(configuration) {
const {
SIGNTOOL_ACCESS_KEY,
SIGNTOOL_ACCESS_SECRET,
SIGNTOOL_CERT_CODE,
} = process.env;
if (
!SIGNTOOL_ACCESS_KEY ||
!SIGNTOOL_ACCESS_SECRET ||
!SIGNTOOL_CERT_CODE
) {
throw new Error('Missing sslTrus signing credentials');
}
execFileSync(
'./signtool',
[
'sign',
'--access-key',
SIGNTOOL_ACCESS_KEY,
'--access-secret',
SIGNTOOL_ACCESS_SECRET,
'--cert-code',
SIGNTOOL_CERT_CODE,
'--file',
configuration.path,
'--override=true',
'--sha1=false',
'--sha2=true',
'--timestamp-rfc3161=http://timestamp.acs.microsoft.com',
],
{
stdio: 'inherit',
},
);
}
It is recommended to invoke child processes with a parameter array instead of concatenating a full Shell command, to reduce issues with path escaping and special character handling.
Electron Builder will call the signing function once for each hash algorithm in signingHashAlgorithms. The example above enables only SHA-256, so each file is processed once.
Running the Build
After configuration is complete, run Electron Builder normally:
npx electron-builder build \
--config electron-builder.mjs \
--win \
--x64
Electron Builder automatically invokes customSign when it needs to sign files.
A single Electron build may sign multiple files, for example:
MyApp.exe
helper.dll
update.exe
uninstall.exe
MyApp Setup.exe
Therefore, it should not be simply understood as "one Electron packaging run produces only one signature."
The actual number of signature events depends on how many files undergo remote signing during the build process.
Advanced Installer
Advanced Installer is an installation package creation tool based on Windows Installer technology.
You can use Advanced Installer's custom signing tool feature to invoke the sslTrus SignTool CLI, allowing MSI, EXE, CAB, and other build artifacts to be automatically remotely code-signed during the packaging process.
Prerequisites
You need to prepare:
- sslTrus SignTool CLI, downloadable from the sslTrus client release page.
- Access Key.
- Access Secret.
- Certificate ID.
- A configured Advanced Installer project.
Configure the Custom Signing Tool
Open the following in your Advanced Installer project:
Digital Signature
Configuration page.
After enabling code signing, set the signing tool to:
Custom
Signature tool path is set to the sslTrus SignTool CLI executable file.
For example:
C:\Tools\sslTrus\signtool.exe
Custom parameters require calling:
sign
Subcommand, and pass to the client:
- Access Key
- Access Secret
- Cert Code
- SHA-2 signature settings
- Timestamp server
- File path
It is recommended to provide the Access Key and Access Secret through secure means first, avoiding saving the long-term valid Access Secret in plaintext in publicly accessible project files.
SignTool parameter example
The corresponding signing logic is similar to:
signtool.exe sign ^
--access-key="YOUR_ACCESS_KEY" ^
--access-secret="YOUR_ACCESS_SECRET" ^
--cert-code="YOUR_CERT_CODE" ^
--nest=true ^
--sha1=false ^
--sha2=true ^
--timestamp-rfc3161=http://timestamp.acs.microsoft.com ^
--desc="Example Application" ^
--override=true ^
--file "app.exe"
In Advanced Installer, the actual file path should be passed in by its custom signing tool mechanism, and should not be hardcoded as the example app.exe.
Build Configuration
If you use Advanced Installer to automatically sign files inside the installation package, you need to check both the build and compression methods simultaneously.
Depending on the actual project configuration, certain CAB archiving methods may affect the custom signing process, so you should confirm that the files ultimately requiring signing can be invoked at the corresponding stage.
After the configuration is complete, you can check it on the digital signature page in Advanced Installer:
Files configured for signing
This confirms which files will be signed during the build process.
Number of Signatures
Advanced Installer may sign multiple files separately during a single installation package build.
For example:
| File | Signatures |
|---|---|
app.exe | 1 |
helper.dll | 1 |
uninstall.exe | 1 |
installer.msi | 1 |
| Total | 4 |
Therefore:
一次构建 ≠ 一次签名
The number should be calculated based on the actual number of files remotely signed or the count of signing actions performed.
Number of Signatures
CI/CD and build tools typically handle multiple artifacts automatically, so special attention should be paid to the number of signatures.
Basic principles:
签名次数 = 实际成功完成的签名动作数量
For example:
app.exe → 1 次
library.dll → 1 次
installer.msi → 1 次
If all three files are successfully signed:
合计 = 3 次
Electron Builder and Advanced Installer and other build tools may also automatically generate and sign:
- Main program.
- DLLs.
- Updater.
- Uninstaller.
- MSI.
- EXE installation packages.
- Other auxiliary executables.
Therefore, the number of signing operations should be confirmed based on the build logs and actual signed artifacts, rather than estimated by the number of Pipeline or Build executions.
For more rules, refer to Reference Materials.
Timestamp
For officially released software, it is usually recommended to add a trusted timestamp.
GitHub Actions, Electron Builder, and Advanced Installer integrations can all use RFC 3161 timestamps, for example:
http://timestamp.acs.microsoft.com
Timestamps are not part of new code signing operations and do not independently increase the code signing count.
For protocol support and usage limitations of different TSAs, please refer to Reference Materials.
Credential Security
In automated environments, special attention should be paid to protecting the following:
Access Key
Access Secret
Cert Code
Among them, Access Secret should be managed as a Secret and must not:
- Be committed to a Git repository.
- Be written in plaintext into a public Workflow.
- Be output to build logs.
- Be written into a public Docker image.
- Be passed to third-party build systems in an insecure manner.
For GitHub Actions, it is recommended to use:
GitHub Actions Secrets
For other CI/CD systems, use their corresponding Secret, Credential, or Variable management mechanisms.
How to Choose
| Scenario | Recommended Approach |
|---|---|
| GitHub Actions Workflow | GitHub Actions |
| Electron app builds | Electron Builder |
| MSI / EXE installer creation | Advanced Installer |
| General Shell / PowerShell automation | SignTool CLI |
| Windows software with native KSP support | Windows Provider |
| Custom signing process development | API integration |
If the build system can directly invoke command-line programs, use SignTool CLI; if the tool already provides standard Windows KSP/CSP interfaces, prioritize the corresponding Windows Provider integration approach.