Trusted publishing#
Trusted publishing lets a configured GitHub Actions workflow or GitLab CI
pipeline exchange a provider OIDC token for a short-lived Sysand Index upload
token. Hosted github.com and gitlab.com, GitHub Enterprise Server, and
self-managed GitLab are supported through the provider domain fields. This page
lists the exact provider configuration and token exchange behavior.
Trusted publishing removes the need to store a long-lived publishing secret in CI, where a leaked account or project API token could publish releases until revoked. Instead, each publish job presents a fresh short-lived provider OIDC token, which Sysand Index exchanges for a single-use upload token scoped to the matching project. Each release is thereby linked to the configured repository, workflow or pipeline file, environment, and protected Git ref that published it.
For a step-by-step setup path, see Set up trusted publishing.
Access#
Only effective project Owners can view, add, or remove trusted publishers for a project. Organization Owner access by itself is not enough; see Roles and permissions.
GitHub publisher fields#
Field |
Required |
Meaning |
|---|---|---|
GitHub domain |
No |
Hostname for GitHub. Blank means |
Repository full name |
Yes |
Repository owner and name in |
Repository ID |
Required for private repositories |
Permanent numeric GitHub repository ID. Public repositories can be resolved by Sysand Index when the publisher is added. |
Workflow filename |
Yes |
File name under |
Environment |
Yes |
GitHub Actions environment name. |
GitHub owner names use letters, numbers, or internal single hyphens. Repository names may also use underscores or dots.
GitLab publisher fields#
Field |
Required |
Meaning |
|---|---|---|
GitLab domain |
No |
Hostname for GitLab. Blank means |
Project path |
Yes |
Full GitLab namespace and project path, including subgroups. |
Project ID |
Required for private projects |
Permanent numeric GitLab project ID. Public projects can be resolved by Sysand Index when the publisher is added. |
Pipeline file |
No |
CI configuration file path. Blank means |
Environment |
Yes |
GitLab environment name. |
Each GitLab path segment uses letters, numbers, hyphens, underscores, or dots.
Segments cannot start or end with punctuation, contain consecutive
punctuation, or end in .git or .atom.
Private repository and project IDs#
Public GitHub repositories and GitLab projects are resolved through the configured provider API when the trusted publisher is added. Private repositories and projects cannot be resolved by Sysand Index, so the permanent provider ID must be entered manually.
For a private GitHub repository, run:
$ gh repo view OWNER/REPOSITORY --json databaseId --jq .databaseId
If you cannot use GitHub CLI, a temporary GitHub Actions workflow can print the
same value from $GITHUB_REPOSITORY_ID.
For a private GitLab project, open the project in GitLab. The project ID is shown near the top of the project overview page.
OIDC token exchange#
The exchange endpoint is:
POST /api/v1/oidc/token
It accepts JSON:
{ "token": "<oidc_jwt>" }
When verification succeeds, the response contains a short-lived upload token:
{ "token": "sysand_oidc_...", "expires_at": "..." }
The token starts with sysand_oidc_, expires after 15 minutes, and is consumed
after the first successful release upload. Failed upload attempts do not consume
it.
Matching rules#
Sysand Index verifies the provider JWT signature, issuer, audience sysand,
and expiration before matching it to a trusted publisher.
GitHub Actions tokens match by:
provider domain
permanent repository ID
workflow filename
environment
protected branch or protected tag evidence
GitLab CI tokens match by:
provider domain
permanent project ID
pipeline file
environment
protected branch or protected tag evidence
The provider OIDC claim ref_protected must be true. Trusted publishing does
not accept releases from unprotected branches or tags.
Supported issuers#
Provider |
Issuer |
|---|---|
GitHub Actions |
|
GitHub Enterprise Server Actions |
|
GitLab CI |
|
Exchange failures#
Error |
Meaning |
|---|---|
Invalid audience |
The provider token was not requested for audience |
Unknown OIDC issuer |
The token did not come from a supported GitHub Actions or GitLab CI issuer. |
Trusted publishing requires a protected branch or protected tag |
The provider did not report the Git ref as protected. Protect the tag pattern or branch that triggers publishing, then rerun CI. |
No matching trusted publisher found |
The provider domain, permanent repository or project ID, workflow or pipeline file, or environment did not match a configured trusted publisher. |
Token has expired |
The provider JWT or Sysand Index upload token was used after it expired. Request a fresh provider token during the publish job. |
OIDC exchange requests are rate limited per IP address before JWT processing.
Rate-limit responses use HTTP 429 with a Retry-After header.
Audit data#
Sysand Index stores only minimized post-exchange claim metadata on the issued upload token while it exists. The retained data includes the issuer, immutable provider repository or project ID, workflow or pipeline file, environment, protected-ref evidence, and JWT issue and expiry timestamps.
Other provider claims, such as arbitrary custom claims, are not stored on the upload token.