This guide covers both tools in the Eclipse CSI Codesign project:
- Maven Plugin (
codesign-maven-plugin) — integrates artifact signing into Maven builds - CLI (
csi-codesign) — standalone binary for signing in any pipeline or shell
For contributor and developer documentation, see CONTRIBUTING.md.
Add the plugin to your pom.xml. No additional installation is required — Maven resolves it
from Maven Central.
Minimum requirements: Java 21, Maven 3.9.
<build>
<plugins>
<plugin>
<groupId>org.eclipse.csi</groupId>
<artifactId>codesign-maven-plugin</artifactId>
<version>VERSION</version>
</plugin>
</plugins>
</build>Replace VERSION with the latest release from
Maven Central.
Download the pre-built native binary for your platform from the GitHub Releases page.
| Platform | Binary name |
|---|---|
| Linux x86_64 | csi-codesign-linux-x86_64 |
| Linux aarch64 | csi-codesign-linux-aarch_64 |
| macOS Apple Silicon | csi-codesign-osx-aarch_64 |
| macOS Intel | csi-codesign-osx-x86_64 |
| Windows x86_64 | csi-codesign-windows-x86_64.exe |
# Linux / macOS: make executable and place on PATH
chmod +x csi-codesign-linux-x86_64
sudo mv csi-codesign-linux-x86_64 /usr/local/bin/csi-codesign
# Adapt the binary name for your platform (see table above)JVM alternative: if you prefer running on the JVM, the -bin fat JAR is published to Maven
Central alongside the native binaries:
java -jar csi-codesign-cli-<version>-bin.jar sign --helpBoth tools authenticate against the SignPath REST API using a Bearer API token.
The plugin resolves the token in this order (first non-blank value wins):
-
Maven
settings.xml— password of the server entry whose<id>matchescodesign(or the value of the<serverId>parameter):<!-- ~/.m2/settings.xml --> <servers> <server> <id>codesign</id> <password>YOUR_API_TOKEN</password> </server> </servers>
Passwords encrypted with
mvn --encrypt-passwordare supported. -
Environment variable —
CSI_CODESIGN_API_TOKEN. -
Config file —
api.tokenkey in~/.config/eclipse-csi-codesign/config.properties(or the path specified by<configFile>/-Dcsi.codesign.configFile). The file must not be readable by other users (POSIX mode600or equivalent Windows ACL). A warning is emitted if the file has insecure permissions.
If none are set, the build fails with an error listing all three options.
Security note: Prefer
settings.xmlor the environment variable over the config file for CI/CD environments. Never hard-code the token in the POM.
The CLI resolves the token in this order (first non-blank value wins):
-
CSI_CODESIGN_API_TOKENenvironment variable. -
Config file —
api.tokenkey in~/.config/eclipse-csi-codesign/config.properties(or the path specified by--config-file):api.token=YOUR_API_TOKEN_HERE
If none are set, the CLI prints a descriptive error and exits with code 2.
Security note: Prefer the environment variable or config file to avoid token exposure.
export CSI_CODESIGN_API_TOKEN=your-token-here
csi-codesign sign app.jar \
--organization-id my-org \
--project-id my-product \
--signing-policy release-signing \
--output app-signed.jarThe original app.jar is unchanged; app-signed.jar contains the signed binary.
Run signing from the command line without modifying your pom.xml:
mvn org.eclipse.csi:codesign-maven-plugin:codesign \
-Dcsi.codesign.organizationId=my-org \
-Dcsi.codesign.projectId=my-product \
-Dcsi.codesign.signingPolicy=release-signingThe main artifact of the current project is submitted for signing and downloaded in place
(assuming standard jar/war/etc. packaging; see File Selection).
Configure the plugin in pom.xml to sign files automatically during package:
<build>
<plugins>
<plugin>
<groupId>org.eclipse.csi</groupId>
<artifactId>codesign-maven-plugin</artifactId>
<version>VERSION</version>
<executions>
<execution>
<id>sign-binaries</id>
<phase>package</phase>
<goals>
<goal>codesign</goal>
</goals>
<configuration>
<!-- Required SignPath coordinates -->
<organizationId>${env.SIGNPATH_ORG_ID}</organizationId>
<projectId>my-product</projectId>
<signingPolicy>release-signing</signingPolicy>
<!-- artifactConfiguration is optional -->
<artifactConfiguration>default-binary-config</artifactConfiguration>
<!-- Optional metadata -->
<description>${project.artifactId} ${project.version}</description>
<parameters>
<buildNumber>${env.BUILD_NUMBER}</buildNumber>
<gitCommit>${env.GIT_COMMIT}</gitCommit>
</parameters>
<!-- Select files from ${project.build.directory} -->
<includes>
<include>*.jar</include>
<include>*.exe</include>
<include>*.dmg</include>
</includes>
<excludes>
<exclude>*-sources.jar</exclude>
<exclude>*-javadoc.jar</exclude>
</excludes>
<!-- Write signed files to a separate folder (omit to replace in place) -->
<outputDirectory>${project.build.directory}/signed</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>After mvn package, signed files are available in target/signed/.
Reference documentation is published on the project site:
- Maven Plugin parameters:
codesign:codesigngoal reference - CLI options: CLI man page
- Java API: API Javadoc
Documentation for past releases and for snapshot (built from the
mainbranch) are available.
| Variable | Tool | Description |
|---|---|---|
CSI_CODESIGN_API_TOKEN |
Both | SignPath API token. Lower priority than settings.xml (plugin); higher priority than the config file. |
CSI_CODESIGN_SKIP_SIGNING |
Plugin only | Set to 1, true, or yes (case-insensitive) to skip signing unconditionally. |
Two independent mechanisms are combined; their results are merged and deduplicated before signing:
-
File scan — walks
baseDirectoryrecursively, matching files against<includes>and<excludes>glob patterns. Patterns are matched against paths relative tobaseDirectory. The scan only runs when<includes>contains at least one pattern;<excludes>has no effect when<includes>is empty. -
Maven artifact signing — controlled by
signProjectArtifactandsignAttachedArtifacts:signProjectArtifact=auto(default): signs the main artifact forjar,war,ear,rar,ejb, andmaven-pluginpackaging; skips it forpompackaging and all other unrecognised types.signProjectArtifact=true: always includes the main artifact.signProjectArtifact=false: never includes the main artifact.signAttachedArtifacts=false(default): attached artifacts are not signed.signAttachedArtifacts=true: all attached artifacts are included.
When the combined result is empty, the plugin logs [WARNING] No files selected for signing
and exits without calling the SignPath API. Set <failOnNoFilesFound>true</failOnNoFilesFound>
to turn this into a build failure instead.
Maven Plugin:
<outputDirectory>set → each signed file is written to<outputDirectory>/<filename>.<outputDirectory>not set → each signed file replaces the original in place. The download is first written to a temporary file (.signing-tmpsuffix, same directory as the target), then moved atomically to replace the original.
CLI:
| Condition | Output location |
|---|---|
--output <path> (single input file) |
Written to the specified path |
--output-dir <dir> (any number of files) |
<dir>/<original-filename> for each file |
Neither --output nor --output-dir, with --force-overwrite |
In-place replacement (same directory, atomic rename) |
In all cases the download is first written to a .codesign-tmp temporary file in the same
directory as the destination. On platforms where atomic rename across filesystems is
unsupported, the CLI falls back to a non-atomic copy.
Maven Plugin — configured explicitly:
| Parameter | Default | Description |
|---|---|---|
pollInterval |
5 s | Delay between signing-status poll requests |
retryTimeout |
600 s | Maximum time window for HTTP retries |
retryInterval |
30 s | Delay between HTTP retry attempts |
maxRetries |
10 | Maximum number of HTTP retry attempts |
httpTimeout |
300 s | HTTP read/write timeout |
connectTimeout |
30 s | HTTP connect timeout |
CLI — all derived from --wait-for-completion-timeout (default: 600 s):
| Parameter | Formula | Example (600 s) |
|---|---|---|
| Poll interval | clamp(timeout/20, 2 s, 30 s) |
30 s |
| HTTP read/write timeout | clamp(timeout/10, 10 s, 60 s) |
60 s |
| Connect timeout | min(30 s, timeout) |
30 s |
| Retry timeout | max(10 s, timeout/4) |
150 s |
| Retry interval | clamp(timeout/20, 2 s, 30 s) |
30 s |
| Max retries | fixed | 5 |
Use --verbose to see the derived values for your chosen timeout.
HTTP retries are triggered by status codes 429, 502, 503, 504, and connection/read timeouts. Retries stop when either the retry count or the retry time window is exhausted, whichever comes first.
| Condition | Cause |
|---|---|
| No API token found | None of the three token sources is configured |
| HTTP error on submit | Non-201 response after all retries exhausted |
Missing Location header |
API returned HTTP 201 without a Location header |
| HTTP error on status poll | Non-2xx response after all retries exhausted |
| HTTP error on download | Non-2xx response when downloading the signed artifact |
| No signed artifact link | Status is Completed but signedArtifactLink is null |
| I/O error writing signed file | Disk/filesystem error during temp-file write or atomic rename |
| Directory scan error | I/O error while walking baseDirectory |
| Poll interrupted | Thread interrupted during the sleep between status polls |
| Status | Typical reason |
|---|---|
Failed |
Policy validation error or SignPath internal error |
Denied |
A required approval step was rejected by a reviewer |
Canceled |
Signing request was canceled before completion |
No files found (failOnNoFilesFound=true) |
No files matched the configured selection |
| Code | Meaning |
|---|---|
0 |
All files signed successfully |
1 |
Execution error (API failure, signing denied/failed/canceled, I/O error) |
2 |
Bad arguments (missing required option, incompatible flags) |
"No API token found"
No token source is configured. Add a codesign server entry to ~/.m2/settings.xml, set
CSI_CODESIGN_API_TOKEN in the environment, or store the token in
~/.config/eclipse-csi-codesign/config.properties (key api.token).
HTTP 401 Unauthorized The token is invalid, expired, or does not have permission to submit signing requests for the specified organization. Verify the token in the SignPath portal.
Signing status Failed
SignPath rejected the artifact — usually a policy violation (wrong file type, policy
mismatch) or a SignPath internal error. Check the workflowStatus field printed in the
build/CLI output. Review the signing policy and artifact configuration in the SignPath
portal.
Signing status Denied
A human approver rejected the signing request. This is expected when a policy requires
manual approval and the reviewer denied it.
Signing status Canceled
The signing request was canceled (e.g. via the SignPath portal) before it completed.
"No files selected for signing" warning Neither the file scan nor the Maven artifact selection produced any candidates.
- Verify that
<includes>patterns match files actually present in${project.build.directory}. - Check that
signProjectArtifactis notfalsewhen you expect the main artifact to be signed. - For
pom-packaging projects (aggregator modules),signProjectArtifact=auto(the default) produces no artifact. Either set<signProjectArtifact>false</signProjectArtifact>to suppress the warning, or remove the plugin configuration for that module entirely.
Signing is skipped unexpectedly
Check whether CSI_CODESIGN_SKIP_SIGNING is set to 1, true, or yes in the
environment. Also check <skip>true</skip> in the POM or -Dcsi.codesign.skip on the
command line.
Timeout waiting for signing completion
Signing took longer than the configured timeout. Increase --wait-for-completion-timeout
(CLI) or <retryTimeout> (plugin). Also check the SignPath portal — the request may be
waiting for manual approval.
"File(s) not found or not regular files" (CLI) The files passed as positional arguments do not exist at the given paths. Check paths and shell glob expansion. On Windows PowerShell, expand globs manually:
$files = Get-ChildItem target\*.jar | ForEach-Object { $_.FullName }
csi-codesign sign @files --organization-id ... --output-dir signed\--output rejected when multiple input files are given
--output is only valid for a single input file. Use --output-dir when signing multiple
files at once.
"No output specified … use --force-overwrite" (CLI)
When neither --output nor --output-dir is specified, the CLI requires --force-overwrite
as an explicit opt-in for in-place replacement. The same applies when --output points to
the same path as the input file.