Setting Up Trusted Publishing
Trusted publishing is the recommended way to publish new releases for projects managed in GitHub or GitLab, as it avoids needing to keep a secret token secret. 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.
Understand the Security Benefit¶
With an account or project API token, a CI system needs to store a long-lived secret that can publish releases until it is revoked. If that token leaks through logs, exported CI configuration, or a compromised developer machine, an attacker can publish malicious versions before you notice.
With trusted publishing, the CI system does not store a Sysand Index publishing token. Instead, GitHub Actions or GitLab CI requests a fresh short lived OpenID Connect token for the publish job. Sysand Index verifies that token against the trusted publisher configuration, then mints a short-lived upload token scoped to the matching project.
This also links each release to the configured repository, workflow or pipeline file, and environment. Users of your package can treat the release as having come from that trusted automation, rather than from anyone who once had access to a reusable token.
Before you continue¶
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.
If you don’t version control your Sysand project yet, first set it up under either GitHub or GitLab. Details on doing this are not part of this tutorial.
You need enough access to configure the CI environment before publishing. On GitHub, this means repository admin access. On GitLab, Developer access can create an unprotected environment, while Maintainer access is needed to protect the environment or configure deployment approvals.
Add the Trusted Publisher¶
Go to Projects, then click Manage on the project you want to configure, then click the publishing tab.
Under the Add a new publisher header, choose the GitHub or GitLab tab, and fill in and submit the relevant details as described below, also under a provider-specific tab.
Fill in:
Repository full name: the GitHub owner and repository in
owner/repositoryform, such asmy-org/my-projectWorkflow filename: the file name under
.github/workflows/, such asrelease.yamlEnvironment: the GitHub Actions environment name, such as
sysand
Press Add GitHub publisher.
Fill in:
Project path: the full GitLab namespace and project path, including any subgroups, such as
my-org/my-subgroup/my-projectPipeline file: the CI configuration file path; leave blank to use
.gitlab-ci.ymlEnvironment: the GitLab environment name, such as
sysand
Press Add GitLab publisher.
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.
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.
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: https://docs.sysand.com/tutorial/setting-up-trusted-publishing
# workflow config reference: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
# installation script reference: https://client.sysand.com/getting-started/installation#macos-and-linux
#
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://client.sysand.com/install.sh | sh -s -- --version latest
- 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://client.sysand.com/install.sh | sh -s -- --version latest
- name: Acquire and configure sysand index credentials
run: |
GITHUB_OIDC_TOKEN=$(
curl -s -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sysand" \
| grep -o '"value": *"[^"]*"' \
| cut -d'"' -f4 \
)
SYSAND_INDEX_TOKEN=$(
curl -s -X POST "${SYSAND_INDEX_URL}/api/v1/oidc/token" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${GITHUB_OIDC_TOKEN}\"}" \
| grep -o '"token": *"[^"]*"' \
| cut -d'"' -f4 \
)
echo "SYSAND_CRED_X=${SYSAND_INDEX_URL}/api/v1/**" >> "$GITHUB_ENV"
echo "SYSAND_CRED_X_BEARER_TOKEN=$SYSAND_INDEX_TOKEN" >> "$GITHUB_ENV"
- name: Build and publish a project to the index
run: |
sysand build --update-meta
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 ubuntu's official image, with sysand, curl, and
# ca-certificates installed.
#
# trusted publishing reference: https://docs.sysand.com/tutorial/setting-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
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
script:
# acquire and configure sysand index credentials
- |
TOKEN=$(
curl -s -X POST "${SYSAND_INDEX_URL}/api/v1/oidc/token" \
-H "Content-Type: application/json" \
-d "{\"token\": \"${GITLAB_OIDC_TOKEN}\"}" \
| grep -o '"token": *"[^"]*"' \
| cut -d'"' -f4 \
)
export SYSAND_CRED_X="${SYSAND_INDEX_URL}/api/v1/**"
export SYSAND_CRED_X_BEARER_TOKEN="$TOKEN"
# build and publish a project to the index
- |
sysand build --update-meta
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.3Commit that version change and push it to the registered repository:
git add .project.json
git commit -m "Release 1.2.3"
git pushThen create and push a matching tag:
git tag v1.2.3
git push origin v1.2.3This 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, acquire Sysand Index credentials, and publish the
project.
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 publish job and check that it acquires Sysand Index credentials 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 the Token Exchange Fails¶
Use the error message from the CI job to narrow the problem:
Invalid audience: the CI OIDC token was not requested with audience
sysandUnknown OIDC issuer: the token did not come from a supported provider; currently Sysand Index supports GitHub Actions and GitLab CI
No matching trusted publisher found: the repository, workflow or pipeline file, or environment does not match the trusted publisher configuration
Token has expired: the CI job tried to exchange or use an expired token; request a new provider token during the publish job
If the token exchange succeeds but upload fails, troubleshoot it like any other publish failure. The short-lived token can only publish to the matched project, and each version can be published only once. For archive validation issues, see KPAR archive validation.