Skip to content

Add new query API to expose workspace variables in GraphQL

Issue: Expose workspace_variables in graphQL API (#473138 - closed)

What does this MR do and why?

Why this is needed?

On workspace creation a user can specify variables(key/value) that get injected into a workspace. We store these in the workspace_variables table along with some static variables that are created by default on workspace creation.

We want to expose the workspace_variables table data through a graphQL API for the following reasons:

  1. Making the data available to third-party integrations or user automations/scripting/reporting
  2. Facilitating QA/E2E testing
  3. Enable frontend to access this data for any future UI features for workspace variables.

This is a similar use case to CiProjectVariable

What it does

With this MR we are introducing a query for workspaceVariables and the following changes

  1. Migration to add a new field user_provided and backfill. This is needed because currently we don't have a way to distinguish between static variables that get injected by default and variables that the user specified. We already have a list of all static type variables, so based on this we can determine which variables were added by users and set the flag for those records. database

  2. Adds a new Type.WorkspaceVariable and field to the Type.Workspace which returns a list of all user provided variables associated with the workspace. User provided workspace_variables are preloaded as the association :user_provided_workspace_variables in the workspaces resolver if the field is selected in the query. GraphQL

  3. Introduces a new WorkspaceVariableTypeEnum that can be used to in both Type.WorkspaceVariableInput and Type.WorkspaceVariable for determining the type of the workspace_variable. GraphQL

  4. Adds a new authorization policy for Type.WorkspaceVariable which delegates authorization to the workspace. Any user with the read_workspace ability is able to query workspaceVariables

  5. Introduces resolve_with_lookahead in the workspaces resolvers to preload workspace_variables. Refactors common code for workspaces resolvers into a base resolver that all workspaces resolvers inherit from. Category:Workspaces

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.

Screenshots or screen recordings

Screenshots are required for UI changes, and strongly recommended for all other merge requests.

This MR does not contain any UI changes

GraphQL

Query.workspaces.workspaceVariables Query.currentUser.workspaces.workspaceVariables Query.workspace.workspaceVariables
workspaces current_user workspace

The above queries don't suffer from the N+1 problem, running Query.currentUser.workspaces.workspaceVariables results in only 2 queries:

Screenshot_2025-01-08_at_4.01.31_PM

Database Review

We are doing the backfill operation in a regular migration because the application code relies on the user_provided field to be present.

Total records for workspace_variables => 48949 on production as of 01.08.2025 out of which only 70 need to be updated

Screenshot_2025-01-08_at_4.57.22_PM

How to set up and validate locally

Numbered steps to set up and validate the change are strongly suggested.

  1. Setup workspaces locally following this guide

  2. Run the migration bin/rails db:migrate

  3. Navigate to http://gdk.test:3000/-/remote_development/workspaces/ and create a new workspace with some variables (Add variable button)

  4. In the rails console validate authorization policy for workspace_variables

    workspace_variable = RemoteDevelopment::WorkspaceVariable.where(workspace_id: workspace.id).last
    
    #User is an admin
    admin_user = User.where(admin: true).first
    policy = RemoteDevelopment::WorkspaceVariablePolicy.new(admin_user, workspace_variable)
    policy.debug(:read_workspace_variable)
    
    ## Output
    @enabled=true,
    @prevented=false
    
    
    #User is the workspace owner
    policy = RemoteDevelopment::WorkspaceVariablePolicy.new(workspace_variable.workspace.user, workspace_variable)
    policy.debug(:read_workspace_variable)
    
    ## Output
    @enabled=true,
    @prevented=false
    
    #Unauthorized User
    unauthorized_user = User.second # any non-admin user that is not associated with the workspace
    policy = RemoteDevelopment::WorkspaceVariablePolicy.new(unauthorized_user, workspace_variable)
    policy.debug(:read_workspace_variable)
    
    ## Output
    @enabled=false,
    @prevented=true
  5. Go to the GraphQL Explorer, http://gdk.test:3000/-/graphql-explorer, and run the following query

    query {
     currentUser {
       workspaces {
         nodes {
           name
           workspaceVariables {
             nodes {
               id
               key
               value
               variableType
               createdAt
               updatedAt
             }
           }
         }
       }
     }
    }

Troubleshooting The value field on the workspace_variables is an encrypted field. If during testing the API returns an error response related to attr_encrypted gem. Check and validate whether the value field on the RemoteDevelopment::WorkspaceVariable can be decrypted by using the current secrets locally.

Ref: Integrity Check

bundle exec rake gitlab:doctor:secrets RAILS_ENV=production

Edited by Daniyal Arshad

Merge request reports

Loading