Skip to main content

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:

ParameterRequiredDefaultDescription
access-keyYes-sslTrus Access Key
access-secretYes-sslTrus Access Secret
cert-codeYes-Code signing certificate number
filesYes-Path to the file to be signed
nicsrsNofalseWhether to use the NICSRS service
dry-runNofalseUse a local test certificate to perform a test signature
timestamp-rfc3161NoautoRFC 3161 timestamp server; pass an empty value to disable timestamping
descriptionNo-Program description written to the Authenticode signature
description-urlNo-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:

FileSignatures
app.exe1
helper.dll1
uninstall.exe1
installer.msi1
Total4

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​

ScenarioRecommended Approach
GitHub Actions WorkflowGitHub Actions
Electron app buildsElectron Builder
MSI / EXE installer creationAdvanced Installer
General Shell / PowerShell automationSignTool CLI
Windows software with native KSP supportWindows Provider
Custom signing process developmentAPI 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.