Skip to content

Protected packages: Npm package push protection for admin user

  • Please check this box if this contribution uses AI-generated content (including content generated by GitLab Duo features) as outlined in the GitLab DCO & CLA

What does this MR do and why?

Admin users should be able to publish npm packages regardless if the package is protected or not, see quote from GitLab permission guide GitLab administrators have all permissions. Unfortunately, the current implementation does not bypass the package push protection for admin users, see collapsed section below. This MR wants to tackle and considers the admin mode and admin user when pushing an npm package.

Open console output
➜ git:(main) source .env && NPM_TOKEN=$PAT_ADMIN_USER_WITH_SCOPE_ADMIN_MODE npm publish
npm verb cli /Users/client-siemens/.asdf/installs/nodejs/20.12.2/bin/node /Users/client-siemens/.asdf/installs/nodejs/20.12.2/bin/npm
npm info using npm@10.5.0
npm info using node@v20.12.2
npm verb title npm publish
npm verb argv "publish"
npm verb logfile logs-max:10 dir:/Users/client-siemens/.npm/_logs/2024-06-16T08_46_27_779Z-
npm verb logfile /Users/client-siemens/.npm/_logs/2024-06-16T08_46_27_779Z-debug-0.log
npm verb publish [ '.' ]
npm notice 
npm notice 📦  @npm-package-push-protection-bugfix-user-role-admin/npm-package-3@1.0.3
npm notice === Tarball Contents === 
npm notice 15B  .tool-versions
npm notice 439B README.md     
npm notice 261B package.json  
npm notice === Tarball Details === 
npm notice name:          @npm-package-push-protection-bugfix-user-role-admin/npm-package-3         
npm notice version:       1.0.3                                                                     
npm notice filename:      npm-package-push-protection-bugfix-user-role-admin-npm-package-3-1.0.3.tgz
npm notice package size:  552 B                                                                     
npm notice unpacked size: 715 B                                                                     
npm notice shasum:        b02e9ca6e65875f2ab908d111afafbfc53f1d21a                                  
npm notice integrity:     sha512-SihCVW5cpulq0[...]2G75AU4xWvbdQ==                                  
npm notice total files:   3                                                                         
npm notice 
npm notice Publishing to http://gdk.test:3000/api/v4/projects/39/packages/npm/ with tag latest and default access
npm http fetch PUT 403 http://gdk.test:3000/api/v4/projects/39/packages/npm/@npm-package-push-protection-bugfix-user-role-admin%2fnpm-package-3 6413ms
npm verb stack HttpErrorGeneral: 403 Forbidden - PUT http://gdk.test:3000/api/v4/projects/39/packages/npm/@npm-package-push-protection-bugfix-user-role-admin%2fnpm-package-3 - Package protected.
npm verb stack     at /Users/client-siemens/.asdf/installs/nodejs/20.12.2/lib/node_modules/npm/node_modules/npm-registry-fetch/lib/check-response.js:95:15
npm verb stack     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
npm verb stack     at async publish (/Users/client-siemens/.asdf/installs/nodejs/20.12.2/lib/node_modules/npm/node_modules/libnpmpublish/lib/publish.js:53:15)
npm verb stack     at async otplease (/Users/client-siemens/.asdf/installs/nodejs/20.12.2/lib/node_modules/npm/lib/utils/otplease.js:4:12)
npm verb stack     at async Publish.exec (/Users/client-siemens/.asdf/installs/nodejs/20.12.2/lib/node_modules/npm/lib/commands/publish.js:126:7)
npm verb stack     at async module.exports (/Users/client-siemens/.asdf/installs/nodejs/20.12.2/lib/node_modules/npm/lib/cli-entry.js:61:5)
npm verb statusCode 403
npm verb pkgid @npm-package-push-protection-bugfix-user-role-admin/npm-package-3@1.0.3
npm verb cwd /Users/client-siemens/Development/protected-packages-examples/npm_package-@npm-package-push-protection-bugfix-user-role-admin
npm verb Darwin 23.5.0
npm verb node v20.12.2
npm verb npm  v10.5.0
npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT http://gdk.test:3000/api/v4/projects/39/packages/npm/@npm-package-push-protection-bugfix-user-role-admin%2fnpm-package-3 - Package protected.
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy, or
npm ERR! 403 on a server you do not have access to.
npm verb exit 1
npm verb code 1

🛠 with at Siemens

MR acceptance checklist

Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

MR Checklist (@gerardo-navarro)

Screenshots or screen recordings

Before

An admin user is not able to publish a package that is protected.

Test performance `FPROF=1` before branch
=> FPROF=1 bundle exec rspec spec/services/packages/npm/create_package_service_spec.rb
[TEST PROF INFO] FactoryProf enabled (simple mode)
Run options: include {:focus=>true}

All examples were filtered out; ignoring {:focus=>true}
[TEST PROF INFO] No factories detected
[TEST PROF INFO] No factories detected
[TEST PROF INFO] No factories detected
[TEST PROF INFO] No factories detected
[TEST PROF INFO] No factories detected
[TEST PROF INFO] No factories detected

Test environment set up in 2.781266 seconds
...................................................................................................................................................................................................................

Finished in 42.4 seconds (files took 21.88 seconds to load)
211 examples, 0 failures

[TEST PROF INFO] Time spent in factories: 00:09.153 (19.19% of total time)
[TEST PROF INFO] Factories usage

 Total: 156
 Total top-level: 51
 Total time: 00:09.153 (out of 00:56.799)
 Total uniq factories: 10

   total   top-level     total time      time per call      top-level time               name

      42          12        0.2786s            0.0066s             0.0676s       organization
      27           3        2.6944s            0.0998s             0.7630s          namespace
      27           3        6.1647s            0.2283s             0.8113s            project
      24          24        7.0818s            0.2951s             7.0818s           ci_build
      24           0        6.2791s            0.2616s             0.0000s        ci_pipeline
       3           3        0.3253s            0.1084s             0.3253s               user
       3           3        0.0811s            0.0270s             0.0811s        npm_package
       3           0        0.0394s            0.0131s             0.0000s       package_file
       2           2        0.0123s            0.0062s             0.0123s package_protection_rule
       1           1        0.0108s            0.0108s             0.0108s            license

After

An admin user is able to publish a package that is protected.

Test performance `FPROF=1` after branch
=> FPROF=1 bundle exec rspec spec/services/packages/npm/create_package_service_spec.rb
Test environment set up in 2.451375 seconds
.............................................................................................................................................................................................................................................................

Finished in 47.8 seconds (files took 19.09 seconds to load)
253 examples, 0 failures

[TEST PROF INFO] Time spent in factories: 00:10.072 (19.23% of total time)
[TEST PROF INFO] Factories usage

 Total: 221
 Total top-level: 61
 Total time: 00:10.072 (out of 01:00.789)
 Total uniq factories: 12

   total   top-level     total time      time per call      top-level time               name

      52          15        0.3185s            0.0061s             0.0858s       organization
      33           3        2.7125s            0.0822s             0.6441s          namespace
      33           3        7.1272s            0.2160s             0.8141s            project
      30          30        8.0441s            0.2681s             8.0441s           ci_build
      30           0        7.1824s            0.2394s             0.0000s        ci_pipeline
      30           0        0.1171s            0.0039s             0.0000s           ci_stage
       3           3        0.3369s            0.1123s             0.3369s               user
       3           3        0.0770s            0.0257s             0.0770s        npm_package
       3           0        0.0392s            0.0131s             0.0000s       package_file
       2           2        0.0131s            0.0065s             0.0131s package_protection_rule
       1           1        0.0462s            0.0462s             0.0462s              admin
       1           1        0.0116s            0.0116s             0.0116s            license

How to set up and validate locally

  1. Enabled the feature flag : Feature.enable(:packages_protected_packages)
  2. Create new project with a non-admin user
  3. Ensure that the existing admin user (e.g. root) is not a member of this newly created project
  4. Create a package protection rule for packages in this project, see Settings => Package and registries => Protected packages
  5. Try to publish a package with the admin user; in other words, use the personal access token (pat) of the admin user that includes the scope :admin_mode to publish the package; please ensure the field :package_name_pattern defined in the package protection rule matches the package name that is published
    source .env && NPM_TOKEN=$PAT_ADMIN_USER_WITH_SCOPE_ADMIN_MODE npm publish
  6. The package should have been published successfully because the user is an admin and even though the admin user is not a member of the project.
  7. When you use another personal access token of the admin user that does not include the scope :admin_mode, then pushing a package will fail because the admin user is not a project member 💥; please ensure that you have enabled the admin mode for your instance, see https://docs.gitlab.com/ee/administration/settings/sign_in_restrictions.html#use-the-rails-console-to-enable-admin-mode
    source .env && NPM_TOKEN=$PAT_ADMIN_USER_WITHOUT_SCOPE_ADMIN_MODE npm publish

Related to #323970

Edited by Gerardo Navarro

Merge request reports