Skip to content

Publish packages from GitLab CI/CD

Create an automation token owned by the same personal account or organization as the repository. Add it under Settings → CI/CD → Variables as RVS_TOKEN.

Mark the value Masked. Mark it Protected when only protected branches or tags should publish packages.

.gitlab-ci.yml
publish-python:
image: python:3.13-slim
stage: deploy
rules:
- if: $CI_COMMIT_TAG
before_script:
- apt-get update && apt-get install -y --no-install-recommends ca-certificates curl
- curl -fsSL https://ravenstash.com/install.sh | RVS_INSTALL_METHOD=portable RVS_INSTALL_VERSION=0.15.1 bash
- export PATH="$HOME/.local/bin:$PATH"
- python -m pip install build twine
script:
- python -m build
- |
RVS_PUBLISH_URL=$(rvs art endpoint \
--target platform/packages \
--format pypi \
--access publish)
RVS_NATIVE_TOKEN=$(rvs art token mint \
--target platform/packages \
--format pypi \
--access publish)
unset RVS_TOKEN
export TWINE_USERNAME=rvs
export TWINE_PASSWORD="$RVS_NATIVE_TOKEN"
export TWINE_REPOSITORY_URL="$RVS_PUBLISH_URL"
export TWINE_NON_INTERACTIVE=1
python -m twine upload dist/*

Replace platform/packages with the namespace and repository names shown in Ravenstash.

The installer settings pin the job to one verified rvs release in a user-local directory instead of configuring APT. Raise RVS_INSTALL_VERSION deliberately after reading the CLI release notes.

Do not enable shell tracing in the publish job. RVS_TOKEN is available only while rvs discovers the endpoint and mints the derivative; Twine receives only the short-lived token.

Use the same boundary for other formats: run rvs art token mint with --format npm or --format maven and --access publish, remove RVS_TOKEN, then expose the result as RVS_NATIVE_TOKEN to the native package tool.

The rvs npm and rvs mvn wrappers are also safe for CI: they perform the exchange internally, strip RVS_TOKEN from the child process, and pass only the short-lived token.

The package-type publish guides contain the native configuration:

Run the pipeline against a new package version, inspect it in Ravenstash, and resolve that exact version through the corresponding download host. Delete a replaced token only after every protected release path succeeds.