doc/development/organization/_index.md
The Organization initiative focuses on reaching feature parity between GitLab.com and GitLab Self-Managed.
The current development focus is achieving feature parity for organizations. This means ensuring that existing features work for groups inside organizations so users who transfer to an organization don't lose functionality.
Organizations is not yet ready for new features. Any new features should continue to target:
Guidance on building new features on organizations, or migrating existing features from top-level group to organizations, will come in the future.
Please contact the team on Slack (#g_organizations) if you wish to informally discuss this.
The Organizations team are implementing changes which will automatically include support for:
organization_id to Sidekiq worker parameters: Sidekiq workers will inherit the Current Organization from the scheduling context/o/<organization> prefix) will be available.Teams do not need to implement these, unless there are specific reasons.
See the sharding guidelines.
Current.organizationThe application maps incoming requests to an organization through Current.organization. This context is automatically set in the request layer and should be used to ensure data is properly scoped to the current organization.
Current.organization is availableCurrent.organization is available in the following contexts. Some are set up automatically, while others require you to call set_current_organization explicitly.
Set automatically (platform-wide):
ApplicationController includes a before_action :set_current_organization that runs for every request.GraphqlController inherits from ApplicationController, so the same before_action applies automatically.Requires developer setup:
Grape API endpoints — Current.organization is not set automatically. Call the set_current_organization helper in a before block for each API class that needs it:
before do
authenticate_non_get!
set_current_organization
end
If there is application logic that needs the Current.organization, it should be passed from the request layer:
# In controllers
def create
@group = Groups::CreateService.new(
current_user,
group_params.with_defaults(organization_id: Current.organization.id)
).execute
end
There will be a ActiveRecord extension that will provide Organization Scoping.
Organization-scoped routes use the /o/:organization_path/ pattern (for example, /o/my-org/projects).
Always use regular, unscoped Rails URL helpers like projects_path and GitLab automatically routes based on Current.organization. This ensures switching between organization-scoped routes and global routes automatically.
# Recommended: Use global route helpers
projects_path # Automatically becomes /o/my-org/projects if Current.organization is set
project_issues_path(@project) # Automatically becomes /o/my-org/namespace/project/-/issues
The organization URL helper system is implemented in Routing::OrganizationsHelper::MappedHelpers. When routes are loaded, the system:
/o/:organization_path)projects_path, groups_url, etc.) to be organization-awareCurrent.organization is present and the organization has scoped paths enabled, the helpers automatically use the organization-scoped version of the routeroot_path and root_url as unscoped_root_path and unscoped_root_urlThis approach preserves organization context throughout the request lifecycle. For example, GET /o/my-org/projects routes to ProjectsController#index (same as /projects) with the organization context available via Current.organization.
Use explicit organization helpers only when you need to generate a URL for a specific organization that differs from Current.organization, or when working outside the request layer (services, workers, Rake tasks) where Current.organization is not available:
# Explicit organization helpers
organization_projects_path(organization_path: 'my-org') # /o/my-org/projects
organization_project_issues_path(@project, organization_path: 'my-org') # /o/my-org/namespace/project/-/issues
Some routes are not currently available under the organization scope:
Enable the following feature flags to test organizations:
ui_for_organizationsorganization_switchingWhen making features organization-aware, pay special attention to areas where cross-organization data leakage could occur. Examples include:
A helpful convention for manual testing in your development environment is to create an organization with an obvious name and prefix all its associated data. This makes it easy to visually confirm whether data from other organizations has accidentally been exposed.
Create an Organization named Secret Tanuki and prefix all its associated data with this name:
Secret TanukiSecret Tanuki User Bob, Secret Tanuki User AliceSecret Tanuki Project X, Secret Tanuki Project YSecret Tanuki Issue #42, Secret Tanuki Issue #99Secret Tanuki GroupSecret Tanuki MR: Add featureWhen testing for data leaks, search your UI or API responses for Secret Tanuki. If you find it where it shouldn't be,
you've discovered a cross-organization data leak. This is particularly useful when:
For automated testing strategies, see Testing with Organizations.
Providing the current organization context to REST API and GraphQL requests does not require any additional arguments. Behind the scenes the current organization is passed via the X-GitLab-Organization-ID header in axios_utils.js#L15 and graphql.js#L183.
Do not hardcode or construct URLs on the frontend as they will not support organization routing. See URLs in GitLab for guidelines on how to generate URLs on the frontend.
The current organization context is available on the frontend via window.gon.current_organization. Behind the scenes this is exposed to the frontend in gon_helper.rb#L69.