Skip to content

Updating an Environment Variable's scope via API fails

ZD ticket: https://gitlab.zendesk.com/agent/tickets/114826

Problem to Solve

  1. Have Premium or higher
  2. Create a project.
  3. Add 2 environment variables:
    1. key1, value1, scope: staging
    2. key1, value2, scope: production
  4. Try to update the value via the API:
    • curl --request PUT --header "PRIVATE-TOKEN: $$$" HOST/api/v4/projects/7/variables/var_name --form "value=updatefromterm" --form "environment_scope=production" {"message":{"key":["(var_name) has already been taken"]}}

Issues with put

It looks like our logic is bad in the API for put:

https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/api/variables.rb#L83

We'll find the first instance of the key (find_by) and then we'll try and update it, but it fails validation because then it would match the "second" key in the scope:

Key1: value1, scope: scope1
Key2 value2, scope: scope2

find_by grabs key1 and says update it to:

Key1: newvalue, scope: scope2

but that conflicts because Key2 already exists with that scope.

Issues with delete

There is a similar problem with delete, where GitLab EE API supports CRUD operations on the Project Variables, however the DELETE action only takes "KEY" as argument. This means when have multiple Project Variables with the same KEY (just for a different environment scope), then the DELETE action deletes a random KEY.

Create variables:

curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value" --form "environment_scope=test"

Delete a variable:

curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE"

Proposal

Require provision of the scope, especially when it is ambiguous.

By default use environment_scope="*" (to make it as seemless as possible to existing users), but if we do not find variable, we might print error message: we did not find, maybe you need to set environemnt_scope=env-name

Edited by Furkan Ayhan