Semantic release workflow breaks when push with CI Job token feature is enabled
Problem
Semantic release workflows fail to trigger new pipelines when the "push with CI Job token" feature is enabled in a project. This breaks automated release processes that depend on pipeline triggers after pushing version tags and release commits.
Root Cause
The issue arises during the semantic-release dry run phase. Semantic-release performs a dry run to test push permissions without using the provided GL_TOKEN
. This dry run is designed for SSH push scenarios where Git credentials aren't required separately. However, in GitLab CI, the git origin URL by default contains the CI Job token embedded in it.
When the CI Job token has push permissions enabled:
- The dry run succeeds using the embedded CI Job token (instead of failing as expected without explicit credentials)
- Semantic-release interprets this success as not needing the
GL_TOKEN
for subsequent operations - Actual pushes then use the CI Job token instead of the provided
GL_TOKEN
- Pushes authenticated with CI Job tokens intentionally do not trigger new pipelines (as a safety mechanism to prevent infinite pipeline loops)
This creates a conflict for semantic release workflows that:
- Provide a
GL_TOKEN
(Personal Access Token) specifically to trigger pipelines - Expect their pushes to trigger new pipelines for deployment or further processing
- Are undermined by the dry run's false positive success with the CI Job token
Current Behavior
- Semantic release job runs with CI Job token push permissions enabled
- Dry run phase tests push without using
GL_TOKEN
- Dry run succeeds due to embedded CI Job token in origin URL
- Semantic-release skips using
GL_TOKEN
for actual pushes based on dry run success -
git push
uses CI Job token for authentication (overriding the provided PAT) - Push is successful but no new pipeline is triggered
- Release workflow breaks as dependent processes expecting pipeline triggers fail
Expected Behavior
Semantic release workflows should:
- Correctly identify when a Personal Access Token (
GL_TOKEN
) is needed - Use the provided
GL_TOKEN
for pushes even when CI Job token permissions are available - Successfully trigger new pipelines when pushing commits/tags with proper authentication
Workaround
Manually configure a custom remote URL that bypasses CI Job token authentication:
git remote set-url origin https://gitlab.com/username/project.git
This forces git to use configured credentials (like PAT) instead of the CI Job token, ensuring the dry run fails appropriately and semantic-release uses the provided GL_TOKEN
.
Impact
- Breaks automated release workflows for projects using semantic-release
- Affects any CI/CD pipeline that needs to push code and trigger subsequent pipelines
Potential Solution Considerations
-
Semantic-release side: Modify the dry run logic to account for GitLab CI's embedded token behavior, ensuring
GL_TOKEN
is used when provided regardless of dry run results -
GitLab side: Trigger pipelines with appropriate safeguards
-
Documentation: Clearly document this interaction between semantic-release dry runs and GitLab's CI Job token to help users understand and avoid this issue
Technical Details
The semantic-release tool performs authentication in two phases:
- Dry run phase: Tests push permissions without credentials (works for SSH, problematic for GitLab CI)
- Actual push phase: Uses credentials only if dry run failed
This two-phase approach conflicts with GitLab CI's default git configuration where the origin URL includes: https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/...