Skip to content

Add gitlab-cloud-connector gem

Nikola Milojevic requested to merge extract-cloud-connector-to-gem into main

Create gitlab-cloud-connector ruby gem. The gem should contain:

  • The YML configuration per UP, similar to feature flags, that would contain all needed metadata per UP.
  • The business logic to read UP information.
  • The business logic for issuing JWT token with scopes based on UP configuration.
  • The gem should be designed to be used by both CDot and Gitlab.com
  • The dedicated tool to create new unit primitive definitions (similar to bin/featur_flag tool). The tool would ask various questions about the new unit primitive and then create a YAML definition in config/backend_services/[backend_service]/unit_primitives/[unit_primitive_name].yml file.

Usage in CDOT or Gitlab Rails

We would need to configure the Gitlab Cloud Connector gem. Create a class that inherits Gitlab::CloudConnector::PurchasableDecorator class and overrides the purchased? method

Example:

require 'gitlab/cloud_connector/unit_primitives'


class CustomPurchasableDecorator < Gitlab::CloudConnector::PurchasableDecorator
  extend ::Gitlab::Utils::Override
  
  override :purchased?
  def purchased?(namespace)
    add_on_purchases(namespace).any?
  end
  
  private

  def add_on_purchases(namespace = nil) 
    results = GitlabSubscriptions::AddOnPurchase
      .by_add_on_name(add_ons)
      .active
    results = results.by_namespace_id(namespace.self_and_ancestor_ids) if namespace
    
    results
  end
end

Create config/initializers/cloud_connector.rb initializer

# config/initializers/cloud_connector.rb

require 'gitlab/cloud_connector'
require 'custom_unit_primitives'


::CloudConnector::UnitPrimitives.reload!
Gitlab::CloudConnector::UnitPrimitives.register_hot_reloader! unless Rails.configuration.cache_classes

Gitlab::CloudConnector.configure do |config|
  config.purchasable_decorator_class = CustomPurchasableDecorator
  config.token_issuer = -> { Doorkeeper::OpenidConnect.configuration.issuer }
  config.subject = Gitlab::CurrentSettings.uuid
  config.gitlab_version = Gitlab::VERSION
end

The CloudConnector unit primitives are grouped by backend_services and by the way how they are delivered: delivered_by (trough common interface i.e Duo Chat).

Proposed RubyGem interface

To access specific unit primitive:

  code_suggestions = Gitlab::CloudConnector.unit_primitives[:code_suggestions]
  code_suggestions.min_gitlab_version
  code_suggestions.cut_off_date
  code_suggestions.add_ons
  code_suggestions.feature_categories
  code_suggestions.free_access?
  code_suggestions.supported_gitlab_version?('16.8')

You can group unit primitives by backend service that is hosting the unit primitive.

  ai_gateway = Gitlab::CloudConnector.backend_services[:ai_gateway]
  ai_gateway.min_gitlab_version # returns the smallest required gitlab version from all grouped unit primitives
  ai_gateway.cut_off_date # returns the latest cut-off-date from all grouped unit primitives
  ai_gateway.add_ons # returns uniq union of all add-on names bundled with grouped unit primitives
  ai_gateway.feature_categories # returns uniq union of all feature-categories that introduced grouped unit primitives 
  ai_gateway.delivered_by # return groups of unit primitives that are delivered together and hosted by this backend service
  ai_gateway.unit_primitives # return list of unit primitives that are hosted by this backend service

You can group unit primitives that are delivered together. The unit primitives can share common user interface. (i.e. Duo Chat)

  delivered_by = Gitlab::CloudConnector.delivered_by[:duo_chat]
  delivered_by.min_gitlab_version # returns the smallest required gitlab version from all grouped unit primitives
  delivered_by.cut_off_date # returns the latest cut-off-date from all grouped unit primitives
  delivered_by.add_ons # returns uniq union of all add-on names bundled with grouped unit primitives
  delivered_by.feature_categories # returns uniq union of all feature-categories that introduced grouped unit primitives 
  delivered_by.free_access? # checks if at least one UP in the group has free access
  delivered_by.supported_gitlab_version?('16.8') # checks if at least one UP in the group is supported by provided gitlab version
  delivered_by.unit_primitives # return list of unit primitives that are delivered together via duo_chat

To list all available add-ons for the instance:

  Gitlab::CloudConnector.add_ons

AccessTokens

You can issue an isntance access token that will contain all allowed scopes across all backend services. Note that audience header will contain the list of audiences, containing multiple supported backends, that can authenticate this JWT token.

   Gitlab::CloudConnector.instance_access_token(License.last, gitlab_version: '16.8')

You can issue a token per backend service, that will contain all allowed scopes for unit primitives that are hosted by specified backend service.

   Gitlab::CloudConnector.backend_services[:ai_gateway].access_token(License.last, gitlab_version: '16.8')

You can issue a token per delivered_by group, that will contain all allowed scopes for unit primitives that are delivered by a common user interface (i.e. Duo Chat)

   Gitlab::CloudConnector.delivered_by[:duo_chat].access_token(License.last, gitlab_version: '16.8')

Permission checks

You can call all public methods implemented in PurchasableDecorator on delivered_by group or on unit primitive level

If you want to check if the access to the group has free access

  Gitlab::CloudConnector.delivered_by[:duo_chat].free_access?

You can also call any other public method that is implemented by CloudConnector::PurchasableInterface

Or you can check for specific unit primitive:

  Gitlab::CloudConnector.unit_primitives[:documentation_search].free_access?
Edited by Nikola Milojevic

Merge request reports