Skip to content

Commit 69aba89

Browse files
docs(tutorials/gitlab_ci): address review findings on Access Token guide
- Add note that Project Access Tokens require Premium/Ultimate on GitLab.com - Clarify that creating the token requires the Maintainer role; the Developer role mentioned is the bot user's role - Refine the CI_JOB_TOKEN warning (it can clone, just cannot push) - Note that write_repository implies read_repository - Inline the authenticated push URL in before_script instead of a top-level variables block to avoid leaking the token via derived strings - Add workflow:rules to avoid duplicate branch+MR pipelines - Document log-masking caveat (CI_DEBUG_TRACE / set -x) - Document non-standard HTTPS port handling (CI_SERVER_FQDN / CI_SERVER_PORT) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2d02ab7 commit 69aba89

1 file changed

Lines changed: 29 additions & 9 deletions

File tree

docs/tutorials/gitlab_ci.md

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,19 +128,25 @@ After merging the new changes into master, we have the final result:
128128

129129
If you cannot or do not want to manage SSH keys (for example, when your runners do not have an SSH client, or when SSH egress is blocked), you can let the runner push back over `HTTPS` using a [GitLab Project Access Token](https://docs.gitlab.com/user/project/settings/project_access_tokens/). This keeps everything inside the GitLab UI — no key generation, no deploy keys.
130130

131+
!!! note "Availability on GitLab.com"
132+
On **GitLab.com**, Project Access Tokens require a **Premium or Ultimate** subscription. They are available with any license on GitLab Self-Managed and GitLab Dedicated. If you are on the Free tier of GitLab.com, use Option A (SSH key) or a Personal Access Token instead.
133+
131134
!!! note "Group / personal tokens"
132135
The same approach works with [Group Access Tokens](https://docs.gitlab.com/user/group/settings/group_access_tokens/) (handy when several projects share automation) and [Personal Access Tokens](https://docs.gitlab.com/user/profile/personal_access_tokens/). Project Access Tokens are usually preferred because they are scoped to a single project.
133136

134137
!!! warning "`CI_JOB_TOKEN` is not enough"
135-
GitLab's built-in `CI_JOB_TOKEN` cannot push to the repository. You need a Project (or Group / Personal) Access Token with at least the `Developer` role and the `write_repository` scope.
138+
GitLab's built-in `CI_JOB_TOKEN` can clone/fetch the repository, but it cannot `git push`. You need a Project (or Group / Personal) Access Token with the `write_repository` scope and a role that can push to your protected branch (typically `Developer` or higher).
136139

137140
#### Step 1: Create a Project Access Token
138141

142+
!!! info "Prerequisite"
143+
You need at least the **Maintainer** role on the project to open `Settings > Access Tokens` and create a token. The `Developer` role mentioned in step 2 below is the role *assigned to the bot user* (i.e. the token's effective permission level when pushing), **not** the role you yourself need to create the token.
144+
139145
1. In your GitLab project, go to `Settings > Access Tokens`.
140146
2. Create a new token:
141147
- **Name**: e.g. `commitizen-bump`.
142-
- **Role**: `Developer` (or higher) — required to push to protected branches and tags.
143-
- **Scopes**: tick `write_repository`. `read_repository` is implied.
148+
- **Role**: `Developer` (or higher) — this is the bot user's role and must be allowed to push to your protected branches and tags.
149+
- **Scopes**: tick `write_repository` (it grants both pull and push; `read_repository` does not need to be ticked separately).
144150
- **Expiration date**: pick a date that suits your rotation policy.
145151
3. Click `Create project access token` and **copy the token immediately** — GitLab only shows it once.
146152

@@ -169,9 +175,15 @@ The pipeline below mirrors the SSH example but authenticates over HTTPS using th
169175
```yaml
170176
image: python:3.10
171177
172-
variables:
173-
# Use the project URL exposed by GitLab so this works for any fork/mirror.
174-
REPO_URL: "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
178+
# Run a single pipeline per push or merge request to avoid duplicate pipelines
179+
# when a branch with an open MR is pushed.
180+
workflow:
181+
rules:
182+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
183+
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
184+
when: never
185+
- if: $CI_COMMIT_BRANCH
186+
- if: $CI_COMMIT_TAG
175187
176188
stages:
177189
- test
@@ -185,7 +197,7 @@ test:
185197
- pip install -e .
186198
- python -m pytest
187199
rules:
188-
# Run on every branch and merge request, but skip the bump commit itself.
200+
# Skip the bump commit itself; otherwise run on every branch and MR.
189201
- if: $CI_COMMIT_MESSAGE =~ /^bump:/
190202
when: never
191203
- when: on_success
@@ -196,8 +208,10 @@ bump:
196208
- pip install -U commitizen
197209
- git config --global user.email "${CI_EMAIL}"
198210
- git config --global user.name "${CI_USERNAME}"
199-
# Replace the default fetch URL with one that includes the token so we can push.
200-
- git remote set-url origin "${REPO_URL}"
211+
# Build the authenticated push URL inline so the token is not stored in a
212+
# CI/CD variable that is visible to project Maintainers, and is not written
213+
# into git config on disk via a top-level `variables:` block.
214+
- git remote set-url origin "https://oauth2:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git"
201215
script:
202216
# Re-attach HEAD to the branch (GitLab checks out a detached commit by default).
203217
- git checkout -B "${CI_COMMIT_REF_NAME}"
@@ -236,3 +250,9 @@ How the pipeline is wired:
236250

237251
!!! tip "Token rotation"
238252
Project Access Tokens expire. Set a calendar reminder before the expiration date to rotate the token and update the `GITLAB_TOKEN` CI/CD variable; otherwise the `bump` job will start failing with `403`/`401` errors.
253+
254+
!!! warning "Keep the token out of job logs"
255+
GitLab's log masking hides the raw value of `GITLAB_TOKEN`, but it does **not** mask derived strings such as the full HTTPS URL `https://oauth2:<token>@…`. Avoid enabling runner debug tracing (`CI_DEBUG_TRACE: "true"`) and avoid `set -x` inside the `bump` job — git error messages or shell traces would otherwise print the URL with the token in clear text. The example above keeps the URL inside `git remote set-url` so it is never assigned to a CI/CD variable.
256+
257+
!!! note "Self-managed instances on a non-standard port"
258+
`CI_SERVER_HOST` is the hostname **without protocol or port**. If your GitLab instance listens on a non-standard HTTPS port (for example `gitlab.example.com:8443`), replace `${CI_SERVER_HOST}` with `${CI_SERVER_HOST}:${CI_SERVER_PORT}` (or use the `CI_SERVER_FQDN` predefined variable on GitLab 16.10+).

0 commit comments

Comments
 (0)