# GitLab.com connection setup

Guide URL: `https://docs.usefulmachinery.com/agent/gitlab-setup.md`

GitLab setup currently uses the CLI and authenticated API only. There are no web GitLab
controls. **GitLab.com credential activation is available for qualified group access
and service-account tokens; GitLab run admission remains closed.** Submitting a token
alone does not make GitLab execution available. Do not move production
workloads to GitLab on the strength of a pending or verified candidate. Self-managed
GitLab setup is postponed (UM-2618). This guide does not promise a stable outbound
IP/CIDR allowlist.

Before creating a connection, use a **dedicated automation identity** with Developer
access to the intended group/projects. The person creating group tokens or service
accounts may need GitLab group Owner or administrator authority; the bot itself
needs only Developer access. Provision a finite, future token expiry and
plan replacement before expiry; non-expiring or unknown-expiry tokens are rejected.
GitLab.com reports a date-only expiry: the token expires at **00:00:00 UTC at the
start of the displayed date**, not at its end. Review the exact UTC instant shown
by the CLI before activation.

The 100-connection organization limit counts *all* retained records, including
locally disconnected connections; disconnect does not free a slot. Local disconnect
also **does not revoke the GitLab token**: revoke it separately in GitLab. Cloud
holds the supplied token; no management response returns it.

## Choose a credential

* **Group access token** (`group_access_token`): create in the intended GitLab.com
  group's **Settings > Access tokens** with Developer role, a dated expiry and the
  legacy `api` scope. Group settings and tier may restrict creation. Do not assume a
  fine-grained group access token creation API.
* **Service account PAT** (`personal_access_token`, `service_account`): provision a
  GitLab.com group service account and **invite it to the selected group or
  projects as Developer**; an uninvited service account cannot see those projects.
  Create a dated personal access token for that account with `api`.
  A service account can have a non-expiring token by default; choose a finite expiry
  explicitly. Service-account fine-grained PAT creation through the legacy `scopes`
  API is **not qualified**. Do not rely on it as a supported provisioning method.
* **Dedicated user PAT** (`personal_access_token`, `dedicated_user`): not yet
  supported for activation, even with `api`. A genuine automation account has
  not been qualified. Do not submit a personal account as a dedicated user.

Only the classic `api` profile (`granular: false`) is currently supported.
Fine-grained profiles are not yet supported for activation. Additional legacy `read_api`,
`read_user`, or `write_repository` scopes are not separately required for an `api`
token. Do not substitute a broader scope silently for a failed read. No token
type grants Useful Machinery unrestricted upstream use: selection, role, scope
and operation authority all apply.

See GitLab's [group token](https://docs.gitlab.com/user/group/settings/group_access_tokens/),
[service account](https://docs.gitlab.com/user/profile/service_accounts/),
[PAT](https://docs.gitlab.com/user/profile/personal_access_tokens/) and
[fine-grained token](https://docs.gitlab.com/auth/tokens/fine_grained_access_tokens/)
guides for the current creation controls and availability.

## CLI review workflow

Sign in with `um auth login`, then create and show the connection. The token must
come from an owned, regular non-symlink file with **exact mode 0600**, or from
standard input (`--token-file -`). Never put a token in a shell argument or a
workflow input. The CLI does not launch a browser or poll candidate validation.

```sh
um connection gitlab create ORG https://gitlab.com --json
um connection gitlab list ORG --json
um connection gitlab show ORG CONNECTION --json
um connection gitlab credential create ORG CONNECTION --expected-version VERSION \
  --kind group-access-token --token-file /path/to/private-token --json
um connection gitlab credential show ORG CONNECTION CANDIDATE --json
```

A candidate can remain `pending`; show it again later to inspect its status.
Activation requires explicit review of the verified provider username/ID, account
kind, permission profile, expiry, and previous identity. An interactive terminal
asks for the verified provider user ID and a literal dedication attestation;
noninteractive clients must provide both `--expected-provider-user-id ID` and
`--dedicated-automation`. Only the two qualified GitLab.com paths above can
activate; other candidates fail with a safe diagnostic. To abandon a candidate,
use `um connection gitlab credential cancel ORG CONNECTION CANDIDATE`.
A successful cancel request acknowledges the operation, including when the candidate
was already terminal; it does not undo activation or revoke an upstream token.
For local disconnect, run:

```sh
um connection gitlab remove ORG CONNECTION --expected-version VERSION --yes
```

Then separately revoke the token at GitLab. Mutations accept
`--idempotency-key KEY` so an uncertain response can be replayed with the same key;
otherwise the CLI generates one and reports it, including after an ambiguous
transport failure. Check the resource before replaying an interrupted operation.
If an activation already succeeded but its response was lost, replay with the
**same** key, `--expected-provider-user-id ID`, and `--dedicated-automation`;
this works even after candidate metadata expires, while the server retains its
replay receipt. Reuse the original reviewed identity and attestation; a new
activation still requires review of a verified candidate.

## Select repositories and bind a project

After the connection is active, discover GitLab projects using their numeric provider
IDs. Discovery requires an available GitLab credential; use `--selected` to read the
retained selection even when upstream discovery is unavailable. `--search TEXT`,
`--repository-id ID`, and `--selected` are mutually exclusive list filters.
Use `--limit` (up to 200) and the returned `--cursor` to page through results.
The list shows the provider ID, full path, default branch, selection and availability.
A repository must be selected **before** a project can bind to it; selection alone
does not make it runnable.

```sh
um connection gitlab repository list ORG CONNECTION --json
um connection gitlab repository list ORG CONNECTION --selected --json
um connection gitlab repository list ORG CONNECTION --repository-id REPOSITORY --json
um connection gitlab repository link ORG CONNECTION --repository-id REPOSITORY --expected-version VERSION --json
um project create ORG --name PROJECT_NAME --gitlab-connection-id CONNECTION \
  --repository-id REPOSITORY --json
um project repository set ORG PROJECT --gitlab-connection-id CONNECTION \
  --repository-id REPOSITORY --json
um connection gitlab repository remove ORG CONNECTION --repository-id REPOSITORY \
  --expected-version VERSION --yes --json
```

Use the current connection `version` from `connection gitlab show` for each link
or remove; a stale version conflicts rather than silently changing selection.
Repeat `--repository-id REPOSITORY` to apply multiple project IDs in one link/remove
command atomically. An invalid or inaccessible addition changes none of the selections.
These mutations accept `--idempotency-key KEY` for uncertain-response replay and
`--delegator-principal-id PRINCIPAL` for authorized service-action attribution.
The GitLab option on project create/set is mutually exclusive with
`--installation-id` (GitHub); project repository IDs are provider IDs, not
connection IDs. Review `um project show` or `um project repository show` for the
binding and its availability. A GitLab project remains blocked by closed run
admission even after selection and binding; this page does not promise live
GitLab execution or a stable outbound IP allowlist.
