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 github.com; GitHub Enterprise Server uses its hostname, such as github.example.com.

Repository full name

Yes

Repository owner and name in owner/repository form.

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 .github/workflows/, such as release.yaml.

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 gitlab.com; self-managed GitLab uses its hostname, such as gitlab.example.com.

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 .gitlab-ci.yml.

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

https://token.actions.githubusercontent.com

GitHub Enterprise Server Actions

https://<provider-domain>/_services/token

GitLab CI

https://<provider-domain>

Exchange failures#

Error

Meaning

Invalid audience

The provider token was not requested for audience sysand.

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.