Skip to content

Protected packages: Allow standalone wildcard in protection rules

What does this MR do and why?

Enables PyPI and NPM package protection rules to accept a standalone * wildcard pattern that matches all packages, bringing them in line with tag and branch protection behavior.

Previously, both NPM and PyPI protection regex patterns required at least one structural character due to the + quantifier, preventing the use of * alone to protect all packages in a project. This created an inconsistency where administrators could not apply blanket protection to all packages.

Technical implementation:

  • Uses regex alternation (?:\*|...) to match either * OR the existing package name pattern with wildcards
  • Maintains backward compatibility with all existing patterns
  • SQL matching via ILIKE already supports * conversion to %
  • No model or database changes required

This consistent behavior allows administrators to protect all packages with a single rule, then add exceptions as needed.

🛠️ with ❤️ at Siemens

References

Screenshots or screen recordings

N/A - Backend regex validation change only

It is now possible to store only a stand-alone wildcard character (*) in the protected_packages settings UI. image

How to set up and validate locally

Quick validation (regex and API)

  1. Start your GitLab development environment
  2. Test via Rails console:
    # Verify the regex accepts standalone wildcard
    Gitlab::Regex::Packages::Protection::Rules.protection_rules_npm_package_name_pattern_regex.match?('*')
    # => true
    
    # Test PyPI as well
    Gitlab::Regex::Packages::Protection::Rules.protection_rules_pypi_package_name_pattern_regex.match?('*')
    # => true
    
    # Verify SQL matching works
    project = Project.find_by(name: "Your Project")
    rule = Packages::Protection::Rule.create!(
      project: project,
      package_type: :npm,
      package_name_pattern: '*',
      minimum_access_level_for_push: :maintainer
    )
    
    # Should match any package name
    project.package_protection_rules.for_package_name('@scope/any-package').include?(rule)
    # => true
  3. Test via REST API:
    curl -X POST "http://localhost:3000/api/v4/projects/123/protected_packages" \
      -H "PRIVATE-TOKEN: your-token" \
      -H "Content-Type: application/json" \
      -d '{
        "package_name_pattern": "*",
        "package_type": "npm",
        "minimum_access_level_for_push": "maintainer"
      }'
  4. Test via Web UI:

End-to-end validation (PyPI package push)

  1. Create a protection rule with standalone wildcard:

    project = Project.find_by(name: "Your Project")
    Packages::Protection::Rule.create!(
      project: project,
      package_name_pattern: '*',  # Standalone wildcard - protects ALL packages
      package_type: :pypi,
      minimum_access_level_for_push: :maintainer
    )
  2. Prepare a PyPI package for testing:

    • Create a directory with pyproject.toml
    • Set package name to any name (e.g., "test-package")
    • Configure .pypirc for your local GitLab registry:
      [distutils]
      index-servers =
          gdk
      
      [gitlab_gdk_test]
      repository = http://gdk.local:3000/api/v4/projects/<project-id>/packages/pypi
      username = <your-username>
      password = <your-personal-access-token>
  3. Build and attempt to push the package as a developer (below maintainer):

    rm -rf dist/* &&
    python3 -m build &&
    python3 -m twine upload --verbose --repository gdk dist/*
  4. Verify protection enforcement:

    • The push should be blocked with an error (any package name is now protected)
    • Try pushing as a maintainer or owner - it should succeed
    • This demonstrates the wildcard * pattern protects all packages
  5. Verify existing patterns still work (e.g., @scope/package-*)

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)
Edited by Gerardo Navarro

Merge request reports

Loading