Skip to content

Installing NPM package from different namespace with CI_JOB_TOKEN fails with 404

Summary

If you pull/install an NPM package from a public project with the CI_JOB_TOKEN, then it will fail with 404. Without that token, it will succeed.

Steps to reproduce

user2 tries to download/install the @root/somepackage, which is a public project.

# this line would suffice, since the project is public
@root:registry=https://<gitlab-url>/api/v4/packages/npm/

# but, by adding the following line, you'll a 404 error when you try to install
//<gitlab-url>/api/v4/packages/npm/:_authToken=${CI_JOB_TOKEN}

And then install in a job, i.e. npm install @root/somepackage

What is the expected correct behavior?

You should be able to pull it, especially since that works when you do not specify an authToken.

Root cause

Users can consume packages from the GitLab package registry in their CI pipelines. Packages belong to projects. It is common for users to authenticate using a CI_JOB_TOKEN when working in CI jobs.

Currently, if a user consumes/installs a package from a public project in a pipeline for a different project, the package is successfully installed because the request is anonymous, and the code will check Ability.allowed?(nil, :read_package, public_project) and Ability.allowed?(nil, :read_project, public_project). Anonymous users have both :read_package and :read_project permissions for public projects, so both will return true and the CI job will succeed.

However, if a job is authenticated using the CI_JOB_TOKEN, the code will check Ability.allowed?(ci_job_token, :build_read_project, public_project), which will return false, and despite being a public project, the package installation will fail.

So why are we checking :build_read_project instead of :read_project (which will return true for the ci_job_token)?

In the find_project! helper, when dealing with CI job token authentication, we try to limit the permissions of the job user. This happens here: https://gitlab.com/gitlab-org/gitlab/-/blob/572bb8c0fe055eb32030a8b48764113d8fe2aa6f/ee/lib/ee/api/helpers.rb#L93. You can see that when a user is present, we check :read_project, but when a CI_JOB_TOKEN is present, we check :build_read_project.

The Fix

Update the permissions to also allow :build_read_project for public projects.

Edited by Tim Rizzi