Skip to main content

Onboarding

Follow these steps to create a new tenant from scratch and onboard into the CI platform.

Create a tenant

Pick your control plane API URL; we'll reference this in $NA_CTRL_URL.

TenantProductRegionURL
InternalSaaSUShttps://ctrl.dev.null.autos/api/v1
InternalSaaSEUhttps://ctrl.eu.null.autos/api/v1

Use the nullctl CLI to create the tenant.

nullctl auth api \
--base $NA_CTRL_URL
--json '{
"name": "test-eu",
"keycloak_realm": "test-eu"
}'

This returns details about the tenant as well as a temp admin password.

{
"tenant": {
"id": "e6e1c60f-8f28-47d3-a318-f3258b9e7672",
"name": "test-eu",
"description": null,
"keycloak_realm": "test-eu",
"keycloak_admin_user_id": "4ae62f2a-df7e-4bcd-88b5-6be0ca83cc74",
"created_at": "2026-01-22T16:04:05.282355Z",
"updated_at": "2026-01-22T16:04:05.282355Z",
"deleted_at": null
},
"temp_admin_password": "<random chars>"
}

TODO: tenant creation should also create a client in Keycloak, which needs to be included in the redirect flow. Client ID needs to be associated with the tenant in the ctrl database.

Setup OIDC Login

We build a link to the console which directs the user to login for the first time on their newly created realm with the admin user and temp password.

TODO: how are we going to share this?

https://app.eu.null.autos/onboarding/init#tenantId=$TENANT_ID&clientId=$CLIENT_ID&tempAdminPassword=$TEMP_ADMIN_PASSWORD

Setup VCS Provider

Once the user fills out the Keycloak admin account page, they're redirected back to the console to configure their VCS for the first time. The user has to fill out a form:

Input TypeNameDefaultDescriptionValue(s)
Radiovcs_typegitlab_saasthe VCS type configured for the tenantgitlab_saas, gitlab_selfhosted
TextInputvcs_urlhttps://gitlab.comthe url for the VCSdisabled if vcs_type is gitlab_saas
TextInputvcs_oauth_client_idour client ID for gitlab.comthe client ID for the GitLab app
Passwordvcs_oauth_client_secretour client secret for gitlab.comthe client secret for the GitLab app

This creates the following JSON payload:

{
"provider_type": "gitlab",
"name": "gitlab",
"base_url": vcs_url,
"client_id": vcs_oauth_client_id,
"client_secret": vcs_oauth_client_secret,
"enabled": true,
"scopes": [
"api", "read_user", "create_runner", "manage_runner",
"read_repository", "openid", "profile", "email",
"write_repository"
]
}

When the user clicks submit, we post this JSON to the control plane API:

curl -s \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $NA_TOKEN" \
--data $JSON_PAYLOAD \
$NA_CTRL_URL/tenants/$TENANT_ID/vcs-providers

This returns an ID for the newly created VCS.

Authenticate Against VCS

Now that the user has configured their VCS provider, we authenticate them the first time. This will take them to an onboarding status page.

$NA_CTRL_URL/tenants/$TENANT_ID/link/$VCS_ID?redirect_uri=https://app.eu.null.autos/onboarding/status

Onboarding Wizard

We need to collect some additional information from the user before we start to onboard:

Input TypeNameDefaultDescriptionValue(s)
AutocompleteTextInputrunner_group_idUser types in the name of a group we can see in their GitLab, we use that to find an ID and store it
AutocompleteTextInputnull_parent_group_idUser picks a group under which we create a null-autos group to hold projects we create

The status page looks like a wizard with a series of timeline steps (really the entire onboarding flow should work this way).


Bootstrap

Once we come back to the status page, we'll hit this API to confirm setup:

$NA_CTRL_URL/tenants/$TENANT_ID/bootstrap/operations

This consists of several steps:

NameDescriptionSuccess
CreateRunnersCreates GitLab runners under runner_group_idRunner Helm chart installs in our infra without issues
CreateNullAutosGroupCreates GitLab subgroup under null_parent_group_idNew group exists and can be read via API
CreateNullAutosAgentsProjectCreates GitLab agent configs under new project in Null Autos subgroupAgent configs are commited in main branch in project
InstallNullAutosAgentHelmChartInstalls agent helm charts in our K8s cluster for these agentsHelm chart installed successfully
ApproveWorkspacesAccessForAgentWe need to approve agent access for workspaces in the groupAgent is approved

NOTE: we only need one agent config with access to both deploy and create workspaces.

TODO: we need to figure out the build + deploy flows for Android + Cuttlefish across ours and customer's infra.