Determinate on GitLab
GitLab CI/CD is compatible with Determinate Nix, FlakeHub, and FlakeHub Cache. From a GitLab pipeline you can:
Both rely on the OpenID Connect (OIDC) tokens that GitLab issues to your jobs, so you never need to store a static credential in your project’s CI variables.
Onboarding
To allow authentication from GitLab to FlakeHub, you must:
-
Find your GitLab group’s numeric ID. To copy it from the UI, open your group, select Actions (the vertical ellipsis) in the upper-right corner of the group overview page, then select Copy Group ID.
You can also fetch it from the GitLab API:
Query the GitLab API for your group ID# Add curl and jq to your current shell session nix shell "https://flakehub.com/f/NixOS/nixpkgs/0.1#curl" "https://flakehub.com/f/NixOS/nixpkgs/0.1#jq" gitlab_group="my-group" # Your GitLab group's path curl "https://gitlab.com/api/v4/groups/${gitlab_group}" | jq -r '.id' -
Contact our support with your GitLab group ID and your FlakeHub organization name. If you run a self-managed GitLab instance rather than gitlab.com, include your instance’s URL as well, because that determines the token issuer that FlakeHub needs to trust.
How authentication works
Every job that talks to FlakeHub requests its own OIDC token using GitLab’s id_tokens keyword.
Set the audience (aud) to api.flakehub.com:
build:
id_tokens:
FLAKEHUB_GITLAB_CI_TOKEN:
aud: "api.flakehub.com"You can name the variable whatever you like.
Pass that name, without a $ prefix, to determinate-nixd login gitlab-pipeline:
determinate-nixd login gitlab-pipeline \
--jwt-env-var FLAKEHUB_GITLAB_CI_TOKENOur flakehub-push component handles all of this for you, so you only need to write this out by hand when you’re pushing to FlakeHub Cache.
Publishing flakes to FlakeHub
To publish a flake from GitLab, include our flakehub-push component.
It requests its own OIDC token, installs Determinate Nix, and pushes the flake, so this is the entire configuration:
stages:
- "release"
include:
- component: "gitlab.com/DeterminateSystems/flakehub-push/component@main"
inputs:
stage: "release"
visibility: "unlisted" # Could also be `public` or `private`By default the component publishes a rolling release every time your default branch is updated.
To publish tagged releases from your Git tags instead, set tagged to true and rolling to false:
stages:
- "release"
include:
- component: "gitlab.com/DeterminateSystems/flakehub-push/component@main"
inputs:
stage: "release"
tagged: true
rolling: falseThese are the inputs you’re most likely to reach for:
| Input | Description | Default |
|---|---|---|
stage | The pipeline stage in which the job runs. | release |
visibility | public, unlisted, or private. | public |
rolling | Publish rolling releases from your default branch. | true |
rolling-minor | The SemVer minor version for rolling releases. | 1 |
tagged | Publish using the current Git tag. | false |
name | Publish under a name other than {group}/{project}. The group must match your GitLab root group. | ${CI_PROJECT_PATH} |
directory | The path of your flake relative to the repository root, for subflakes. | The repository root |
labels | Comma-separated labels to attach to the flake. | None |
spdx-expression | An SPDX license expression for your flake. | None |
include-output-paths | Register each flake output’s store paths with FlakeHub. | false |
Pushing store paths to FlakeHub Cache
To push to FlakeHub Cache, install Determinate Nix, log in with the job’s OIDC token, and run Magic Nix Cache, which watches Determinate Nixd’s post-build events and uploads each store path as it’s built.
stages:
- "build"
build:
stage: "build"
image: "ubuntu:24.04"
# Request an OIDC token from GitLab for FlakeHub
id_tokens:
FLAKEHUB_GITLAB_CI_TOKEN:
aud: "api.flakehub.com"
variables:
MAGIC_NIX_CACHE_CLOSURE_URL: "https://install.determinate.systems/magic-nix-cache-closure/branch/main/X64-Linux?ci=gitlab"
MAGIC_NIX_CACHE_LISTEN: "127.0.0.1:37515"
MAGIC_NIX_CACHE_STARTUP_FILE: "/tmp/mnc-startup"
before_script:
- apt-get update && apt-get install --yes curl xz-utils
script:
# Install Determinate Nix and start Determinate Nixd. Containers don't run
# systemd, so install with `--init none` and start Determinate Nixd yourself
- |
curl --proto '=https' --tlsv1.2 -sSf -L "https://install.determinate.systems/nix?ci=gitlab" \
| sh -s -- install linux --no-confirm --init none
nohup /usr/local/bin/determinate-nixd daemon &>/tmp/dnixd.log &
export NIX_REMOTE="daemon"
export PATH="${PATH}:/nix/var/nix/profiles/default/bin"
for n in {1..100}; do
if determinate-nixd status &>/dev/null; then
echo "Determinate Nixd started up after ${n} attempt(s)"
break
fi
sleep 0.1
done
# Fail the job if Determinate Nixd never became ready
determinate-nixd status
# Log in to FlakeHub using the token that GitLab issued for this job
- determinate-nixd login gitlab-pipeline --jwt-env-var FLAKEHUB_GITLAB_CI_TOKEN
# Acquire the `magic-nix-cache` executable, start it, and wait for it to come up
- |
mnc_closure="$(curl -L "${MAGIC_NIX_CACHE_CLOSURE_URL}" \
| xz -d \
| nix-store --import \
| tail -n1)"
ln -sf "${mnc_closure}/bin/magic-nix-cache" /usr/bin/magic-nix-cache
nohup magic-nix-cache \
--listen "${MAGIC_NIX_CACHE_LISTEN}" \
--use-flakehub \
--startup-notification-file "${MAGIC_NIX_CACHE_STARTUP_FILE}" \
&>/tmp/mnc.log &
for n in {1..30}; do
if [ -e "${MAGIC_NIX_CACHE_STARTUP_FILE}" ]; then
echo "Magic Nix Cache started up after ${n} attempt(s)"
break
fi
echo "Waiting on Magic Nix Cache; attempt ${n}"
sleep 2
done
if [ ! -e "${MAGIC_NIX_CACHE_STARTUP_FILE}" ]; then
echo "Magic Nix Cache didn't start up within 60 seconds; exiting"
exit 1
fi
# Build whatever you like. Everything built from here on is pushed to FlakeHub Cache
- nix build ".#packages.x86_64-linux.default"
# Drain any remaining store paths to FlakeHub Cache
- curl --fail -XPOST "http://${MAGIC_NIX_CACHE_LISTEN}/api/workflow-finish"GitLab issues a job’s OIDC token once, when the job starts, and provides no way to request a fresh one mid-job. Magic Nix Cache therefore can’t refresh its FlakeHub credentials on GitLab, unlike on GitHub Actions or Buildkite. Keep jobs that push to FlakeHub Cache short enough to finish before the token expires.
The example above targets a Docker-based runner, which is what gitlab.com’s shared runners use (they run the docker+machine executor).
On a shell executor running on a systemd host, you can install with --init systemd, source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh, and skip starting Determinate Nixd by hand.