Set up trusted publishing#
Trusted publishing is the recommended way to publish new releases for projects managed in GitHub or GitLab, because it removes the need to store a long-lived secret token in CI. It works by instead declaring to Sysand Index that you trust automation in GitHub Actions or GitLab CI to publish new releases of a project.
Instead of a reusable token that can leak and publish until revoked, each publish job authenticates with a fresh short-lived provider token, and the release is linked to the specific repository, workflow, environment, and protected Git ref that published it. For the full rationale and token exchange behavior, see Trusted publishing.
The same setup supports hosted github.com and gitlab.com, GitHub
Enterprise Server, and self-managed GitLab. For Enterprise or self-managed
providers, enter the provider hostname when adding the trusted publisher.
Before you start#
If you are publishing a project for the first time, first publish it with a quickly expiring account API token by following Publishing your first project.
You must have effective project Owner access on Sysand Index: only project owners see the trusted publishing tab used below. For organization projects, organization Owner access by itself is not enough; see Roles and permissions.
If you don’t version control your Sysand project yet, first set it up under GitHub or GitLab. Details on doing this are not part of this guide.
You need enough access to configure the CI environment and protect the branch or tag that runs publishing. On GitHub, this means repository admin access. On GitLab, Maintainer access is needed to protect branches or tags.
Add the trusted publisher#
Go to Projects, then click Manage on the project you want to configure, then click the trusted publishing tab.
Under the Add a new publisher header, choose the GitHub or GitLab tab, fill in the provider fields, and submit the form. For exact field rules and matching behavior, see Trusted publishing.
Fill in:
GitHub domain: leave blank for
github.com; otherwise enter the hostname of your GitHub Enterprise Server instance, such asgithub.example.comRepository full name: the GitHub owner and repository in
owner/repositoryform, such asmy-org/my-projectRepository ID: leave blank for a public repository
Workflow filename: the file name under
.github/workflows/, such asrelease.yamlEnvironment: the GitHub Actions environment name, such as
sysand
Press Add GitHub publisher.
Fill in:
GitLab domain: leave blank for
gitlab.com; otherwise enter the hostname of your GitLab instance, such asgitlab.example.comProject path: the full GitLab namespace and project path, including any subgroups, such as
my-org/my-subgroup/my-projectProject ID: leave blank for a public project
Pipeline file: the CI configuration file path; leave blank to use
.gitlab-ci.ymlEnvironment: the GitLab environment name, such as
sysand
Press Add GitLab publisher.
For a private repository or project, you need to enter the permanent provider ID yourself. See Private repository and project IDs for how to find it.
Create the CI environment#
GitHub and GitLab have a concept of CI environments, and we need to create one in the repository or project. Using environments helps constrain what parts of the CI automation should be allowed to publish to Sysand Index.
Go to your GitHub project and navigate through Settings -> Environments, and
then click the New environment button. You should now be at a URL looking
like https://github.com/my-org/my-project/settings/environments/new.
Fill in the name sysand and press Configure environment.
We recommend also configuring the environment to require manual approval.
Go to your GitLab project and navigate through Operate -> Environments, then click Create an environment.
Fill in the name sysand and press Save.
On GitLab Premium or Ultimate, we recommend also configuring the environment as
a protected environment with a manual approval step. Navigate through
Settings -> CI/CD, expand Protected environments, select the sysand
environment, configure who can deploy and who can approve deployments, and press
Protect.
Protect the release ref#
Sysand Index only accepts trusted publishing from protected branches or
protected tags. The examples in this guide publish when a tag such as
v1.2.3 is pushed, so protect the tag pattern v* before testing the
automation.
If your release workflow publishes from a branch instead of tags, protect that
branch, such as main, instead.
In GitHub, go to the repository, then open Settings -> Rules -> Rulesets.
Create a tag ruleset, set enforcement to active, and target tags matching
v*.
For teams publishing from a branch, create a branch ruleset for the release branch instead.
In GitLab, go to the project, then open Settings -> Repository. Expand
Protected tags, add the tag pattern v*, and allow only Maintainers to
create matching tags.
For teams publishing from a branch, use Protected branches on the same page and protect the release branch instead.
Add the CI configuration#
After adding the trusted publisher, copy the matching CI configuration example below into the repository that you registered as the trusted publisher.
The examples reference https://sysand.com, but you should update
SYSAND_INDEX_URL to for example https://test.sysand.com if that is where you
added the trusted publisher.
Each example grants the publish job access to the CI provider’s OIDC token.
With sysand 0.1.5 or later, sysand publish uses that token to perform
trusted publishing automatically. In the default auto mode, supported CI
trusted publishing is preferred over configured bearer-token credentials. For a
monorepo that publishes more than one Sysand project, run a separate
sysand publish command for each project.
Copy this example to .github/workflows/release.yaml.
# This is a GitHub workflow, defining a set of jobs each with a set of steps.
#
# The workflow will run when a git tag like v1.2.3 is pushed, and publish a
# release to the chosen sysand index using trusted publishing.
#
# trusted publishing reference: __SYSAND_DOCS_ROOT__/index/how-to/set-up-trusted-publishing/
# workflow config reference: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
# installation script reference: __SYSAND_DOCS_ROOT__/client/getting-started/installation/#installation-script
#
name: Release
on:
push:
tags: ["v*"]
env:
SYSAND_INDEX_URL: https://sysand.com
jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- name: Install sysand
run: |
curl -fsSL https://sysand.com/install.sh | SYSAND_VERSION=latest sh
- name: Check version in git tag matches the project's declared version
run: |
PROJECT_VERSION="$(sysand info version)"
TAG_VERSION="${GITHUB_REF_NAME#v}"
if [ "$PROJECT_VERSION" != "$TAG_VERSION" ]; then
echo "Project version ${PROJECT_VERSION} does not match tag ${GITHUB_REF_NAME}"
exit 1
fi
publish:
runs-on: ubuntu-latest
needs: [test]
environment: sysand
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6
- name: Install sysand
run: |
curl -fsSL https://sysand.com/install.sh | SYSAND_VERSION=latest sh
- name: Build and publish a project to the index
run: |
sysand build
sysand publish --index "${SYSAND_INDEX_URL}"
Copy this example to .gitlab-ci.yml.
# This is a GitLab pipeline configuration, defining a set of jobs grouped into
# stages.
#
# The pipeline will run when a git tag like v1.2.3 is pushed, and publish a
# release to the chosen sysand index using trusted publishing.
#
# The image used is based on Alpine's official image, with sysand, curl, and
# ca-certificates installed.
#
# trusted publishing reference: __SYSAND_DOCS_ROOT__/index/how-to/set-up-trusted-publishing/
# pipeline config reference: https://docs.gitlab.com/ci/yaml/
# sysand image reference: https://github.com/sensmetry/sysand/blob/main/Dockerfile
#
workflow:
rules:
- if: $CI_COMMIT_TAG
variables:
SYSAND_INDEX_URL: https://sysand.com
stages:
- test
- publish
test:
stage: test
image: ghcr.io/sensmetry/sysand:latest-alpine
script:
# check version in git tag matches the project's declared version
- |
PROJECT_VERSION="$(sysand info version)"
TAG_VERSION="${CI_COMMIT_TAG#v}"
if [ "$PROJECT_VERSION" != "$TAG_VERSION" ]; then
echo "Project version ${PROJECT_VERSION} does not match tag ${CI_COMMIT_TAG}"
exit 1
fi
publish:
stage: publish
environment:
name: sysand
url: https://sysand.com
id_tokens:
GITLAB_OIDC_TOKEN:
aud: sysand
image: ghcr.io/sensmetry/sysand:latest-alpine
script:
# build and publish a project to the index
- |
sysand build
sysand publish --index "${SYSAND_INDEX_URL}"
Test the automation#
Push a Git tag#
To test the publishing workflow, first update the Sysand project version to the version you want to publish, commit it, and push a tag. While this can be done in a few ways, here is one.
$ sysand info version --set 1.2.3
Commit that version change and push it to the registered repository:
$ git add .project.json
$ git commit -m "Release 1.2.3"
$ git push
Then create and push a matching tag:
$ git tag v1.2.3
$ git push origin v1.2.3
This should now trigger the configured CI automation to run.
Inspect the triggered CI automation#
After pushing the tag, inspect the CI run for the provider you configured.
Go to your GitHub project and click the Actions tab.
Open the Release workflow run for the tag you pushed, such as v1.2.3. If
the sysand environment requires approval, approve the deployment before the
publish job starts.
Open the test job and check that it verifies the tag version against the
declared Sysand project version. Then open the publish job and check that
the steps install sysand, build the project, and publish it.
Go to your GitLab project and navigate through Build -> Pipelines.
Open the pipeline for the tag you pushed, such as v1.2.3. If the sysand
environment requires deployment approval, approve the deployment before the
publish job starts.
Open the test job and check that it verifies the tag version against the declared Sysand project version. Then open the publish job and check that it builds and publishes the project.
When the publish step succeeds, go to Projects, then click the project.
Check that the new release appears and that the rendered README, changelog, licenses, and usages look correct.
If trusted publishing authentication fails#
Use the error message from the CI job to narrow the problem:
If the message says the branch or tag was not protected, protect the tag pattern or branch that triggers publishing and rerun the CI job from that ref.
If the message says no matching trusted publisher was found, compare the repository or project ID, workflow or pipeline file, environment, and provider domain with the trusted publisher you added.
If the message says the token has expired, make sure the workflow requests the provider token during the publish job.
If trusted publishing authentication succeeds but upload fails, troubleshoot it like any other publish failure. The short-lived token can only publish to the matched project, can be used for only one successful upload, and each version can be published only once. For the full exchange failure table, see Trusted publishing. For archive validation issues, see KPAR archive validation.