Add new post endpoint to test virtual registry upstreams with overrides

What does this MR do and why?

Adds a new POST API endpoint that tests existing upstream configuration or if overrides are provided uses the updated url + creds.

We have a bug in the Maven virtual registry upstream edit form. Updated url or credentials are not being used when clicking the test upstream button. More details here #565897

We have 2 existing test upstream endpoints. A POST endpoint under group, to test new connections, and a GET endpoint to test existing connections.

The upstream edit form, is using the GET endpoint. Which will only test the persisted url + creds for the upstream being edited. So if a user is updating the credentials or url and clicks on test upstream, these updated values do not get tested, this leads to incorrect results.

The GET endpoint is also used when linking an existing upstream.

To reduce complexity on the frontend, this new endpoint can be used for testing the upstream when linking a new upstream (use existing creds), or when testing updated creds in the edit form (pass overrides).

There will be a follow up MR to update the frontend to use the new endpoint, this will need to be added in the next milestone due to multi version compatibility issues between backend an frontend.

The existing GET endpoint will be deprecated in a later milestone.

The new endpoint has the following logic:

  • If no overrides are provided, then it will test the existing upstream configuration (i.e what is persisted in the db)
  • If url override is provided, then there must be either username & password, or neither. The reason for this is, we don't want to forward the existing credentials to a new url, potentially leaking them. Background here.
  • If username and password overrides are provided, tests existing url with new credentials
  • If existing url and existing username are provided, then tests existing upstream configuration. This covers the case in the edit form, when a user may edit a non credential/url field, such as description and decide to click on test upstream. The existing url and username would be sent, but the password would be an empty string.

The underlying model validation handles the checks for making sure there is both a username and password provided, or there is neither.

References

Screenshots or screen recordings

See validation steps

How to set up and validate locally

We'll use the below projects as test upstreams.

Setup

We will need to setup an upstream and PAT's and export them as env vars.

This will set us up to run through each of the curl commands to validate.

  1. In the rails console, enable the Maven virtual registry feature flag
Feature.enable(:maven_virtual_registry)
  1. Setup PAT
root = User.find_by_username('root')
token = root.personal_access_tokens.create!(
  name: 'Maven Virtual Registry Test',
  scopes: ['api'],
  expires_at: 5.days.from_now
)
  1. Create a registry and upstream for the top level group.

group = Group.find_by_full_path('twitter')

registry = VirtualRegistries::Packages::Maven::Registry.create!(
  group: group,
  name: 'test-registry',
  description: 'Test Maven Virtual Registry'
)
upstream = VirtualRegistries::Packages::Maven::Upstream.create!(
  group: group,
  name: 'public-project-upstream',
  description: 'Public GitLab Project Upstream',
  url: 'https://gitlab.com/api/v4/projects/issue-reproduce/packages/maven/parent-group/subgroup2/project2',
  username: nil,
  password: nil,
  cache_validity_hours: 24,
  metadata_cache_validity_hours: 24
)
VirtualRegistries::Packages::Maven::RegistryUpstream.create!(
  registry: registry,
  upstream: upstream,
  position: 1
)
puts upstream.id
puts token.token

Copy the token and upstream id.

  1. Create a PAT in gitlab.com for your user account. This will be to access the private project above.
  2. Add the following env vars.
export GITLAB_URL=http://gdk.test:3000
export TOKEN=<your token from above>
export UPSTREAM_ID=<your upstream id>

# Public project (no auth required)
export PUBLIC_MAVEN_URL=https://gitlab.com/issue-reproduce/packages/maven/parent-group/subgroup2/project2

# Private project (auth required)
export PRIVATE_MAVEN_URL=https://gitlab.com/api/v4/projects/issue-reproduce/demo-virtual-registry/packages/maven
export GITLAB_USERNAME="your-gitlab-username"
export GITLAB_PAT="your-gitlab-pat"

Validation:

1. No overrides (uses existing upstream): should return success.

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json"

Result:

Screenshot_2025-12-09_at_5.07.10_pm

2. URL override to private project (no credentials): Should return 401

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PRIVATE_MAVEN_URL\"
  }"

Result:

Screenshot_2025-12-09_at_5.35.23_pm

3. URL override to private project + valid credentials. Should be successful

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PRIVATE_MAVEN_URL\",
    \"username\": \"$GITLAB_USERNAME\",
    \"password\": \"$GITLAB_PAT\"
  }"

Result:

Screenshot_2025-12-09_at_5.34.07_pm

4. URL override to private project + invalid credentials. Should return 401

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PRIVATE_MAVEN_URL\",
    \"username\": \"wrong-user\",
    \"password\": \"wrong-password\"
  }"

Result:

Screenshot_2025-12-09_at_5.36.03_pm

5. URL override + new username (no password) - validation error

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PRIVATE_MAVEN_URL\",
    \"username\": \"new-username\",
    \"password\": \"\"
  }"

Result:

Screenshot_2025-12-09_at_5.36.31_pm

6. URL override + new password (no username) - validation error

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PRIVATE_MAVEN_URL\",
    \"username\": \"\",
    \"password\": \"some-password\"
  }"

Result:

Screenshot_2025-12-09_at_5.40.15_pm

8. Credentials override - new username (no password) - validation error

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"username\": \"new-username\",
    \"password\": \"\"
  }"

Result:

Screenshot_2025-12-09_at_5.41.04_pm

9. Credentials override - no username (new password) - validation error

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"username\": \"\",
    \"password\": \"some-password\"
  }"

Result:

Screenshot_2025-12-09_at_5.41.38_pm

10. Invalid URL - empty string

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": ""
  }'

Result:

Screenshot_2025-12-09_at_5.42.43_pm

11. In the same terminal we exported the env vars in, open up the rails console and update the upstream to the private upstream url with credentials.

upstream = VirtualRegistries::Packages::Maven::Upstream.find_by_id(ENV['UPSTREAM_ID'].to_i)
upstream.update!(
  id: ENV['UPSTREAM_ID'],
  url: ENV['PRIVATE_MAVEN_URL'],
  username: ENV['GITLAB_USERNAME'],
  password: ENV['GITLAB_PAT']
)

12. Credentials override - existing username (no password) - uses existing upstream. Should return success

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
     \"username\": \"$GITLAB_USERNAME\",
    \"password\": \"\"
  }"

**Result: **

Screenshot_2025-12-09_at_6.04.48_pm

13. Credentials override - existing username and existing password - uses existing upstream. Should return success.

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"username\": \"$GITLAB_USERNAME\",
    \"password\": \"$GITLAB_PAT\"
  }"

Result:

Screenshot_2025-12-09_at_6.48.29_pm

14. URL override + existing username (no password) - validation error:

curl -X POST "$GITLAB_URL/api/v4/virtual_registries/packages/maven/upstreams/$UPSTREAM_ID/test" \
  -H "PRIVATE-TOKEN: $TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"url\": \"$PUBLIC_MAVEN_URL\",
    \"username\": \"$GITLAB_USERNAME\",
    \"password\": \"\"
  }"

Result:

Screenshot_2025-12-09_at_6.07.15_pm

MR acceptance checklist

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

Related to #565897

Edited by Fiona McCawley

Merge request reports

Loading