Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/scripts/http-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ case "$group" in
bun --no-env-file scripts/test-assistant-actions-e2e.ts
;;
organization-search)
GITLAB_CSV_E2E_BASE_URL="$local_app_url" \
GITLAB_CSV_E2E_REPORT_PATH="$report_dir/gitlab-csv-permissions-http-report.json" \
bun --no-env-file scripts/test-gitlab-csv-permissions-e2e.ts
ORGANIZATION_SEARCH_E2E_BASE_URL="$local_app_url" \
ORGANIZATION_SEARCH_E2E_DATABASE_URL="$DATABASE_URL" \
ORGANIZATION_SEARCH_E2E_AUTH_SECRET="$BETTER_AUTH_SECRET" \
Expand Down
68 changes: 68 additions & 0 deletions apps/docs/content/docs/cli/organizations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,74 @@ sim organizations members remove <userId> [options]

API request and response schemas: [removeOrganizationMember](/api-reference/organizations/removeOrganizationMember).

## GitLab Search permissions

### Get GitLab search permission revision

OAuth login or personal API key required.

```bash
sim organizations gitlab-permissions get <sourceId> [options]
```

**Arguments**

<CommandTable>

| Argument | Required | Description |
| --- | --- | --- |
| `sourceId` | Yes | Identifier of the configured GitLab Search source. |

</CommandTable>

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--organization <value>` | Yes | Organization identifier. |

</CommandTable>

API request and response schemas: [getGitLabSearchPermissions](/api-reference/organizations/getGitLabSearchPermissions).

### Replace GitLab search permission CSVs

OAuth login or personal API key required.

This replaces both GitLab permission files. Readers omitted from the new grants lose access.

```bash
sim organizations gitlab-permissions replace <sourceId> [options]
```

**Arguments**

<CommandTable>

| Argument | Required | Description |
| --- | --- | --- |
| `sourceId` | Yes | Identifier of the configured GitLab Search source. |

</CommandTable>

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--organization <value>` | Yes | Organization identifier. |
| `--expected-revision <value>` | Yes | Current permission revision obtained before generating this snapshot. |
| `--user-mapping <json\|@file>` | Yes | GitLab user IDs and their verified Sim email addresses. (JSON, or @path / @- to read a file or stdin). |
| `--project-permissions <json\|@file>` | Yes | GitLab project paths and the IDs of users granted access. (JSON, or @path / @- to read a file or stdin). |
| `-y, --yes` | Yes | Confirm this operation. |

</CommandTable>

API request and response schemas: [replaceGitLabSearchPermissions](/api-reference/organizations/replaceGitLabSearchPermissions).

## Invitations

### List organization invitations
Expand Down
66 changes: 66 additions & 0 deletions apps/docs/content/docs/cli/reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4288,6 +4288,72 @@ sim organizations sso policy update [options]

API request and response schemas: [updateSsoPolicy](/api-reference/organizations/updateSsoPolicy).

### sim organizations gitlab-permissions get

Get GitLab search permission revision (OAuth login or personal API key required)

```bash
sim organizations gitlab-permissions get <sourceId> [options]
```

**Arguments**

<CommandTable>

| Argument | Required | Description |
| --- | --- | --- |
| `sourceId` | Yes | Identifier of the configured GitLab Search source. |

</CommandTable>

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--organization <value>` | Yes | Organization identifier. |

</CommandTable>

API request and response schemas: [getGitLabSearchPermissions](/api-reference/organizations/getGitLabSearchPermissions).

### sim organizations gitlab-permissions replace

Replace GitLab search permission CSVs (OAuth login or personal API key required)

This replaces both GitLab permission files. Readers omitted from the new grants lose access.

```bash
sim organizations gitlab-permissions replace <sourceId> [options]
```

**Arguments**

<CommandTable>

| Argument | Required | Description |
| --- | --- | --- |
| `sourceId` | Yes | Identifier of the configured GitLab Search source. |

</CommandTable>

**Options**

<CommandTable>

| Option | Required | Description |
| --- | --- | --- |
| `--organization <value>` | Yes | Organization identifier. |
| `--expected-revision <value>` | Yes | Current permission revision obtained before generating this snapshot. |
| `--user-mapping <json\|@file>` | Yes | GitLab user IDs and their verified Sim email addresses. (JSON, or @path / @- to read a file or stdin). |
| `--project-permissions <json\|@file>` | Yes | GitLab project paths and the IDs of users granted access. (JSON, or @path / @- to read a file or stdin). |
| `-y, --yes` | Yes | Confirm this operation. |

</CommandTable>

API request and response schemas: [replaceGitLabSearchPermissions](/api-reference/organizations/replaceGitLabSearchPermissions).

### sim organizations get

Get organization (OAuth login or personal API key required)
Expand Down
44 changes: 40 additions & 4 deletions apps/docs/content/docs/search/gitlab.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ GitLab Search uses **Service account** mode, with one self-managed project per s
| --- | --- | --- |
| Token owner | Active instance administrator | Account that can read the project's content |
| PAT scopes | `read_api`; `admin_mode` when Admin Mode is enabled | `read_api` |
| Reader authorization | Current GitLab identity, membership, roles, and supported restrictions | Admin-uploaded email mapping and project grants |
| Membership changes | Checked during the request | Admin updates the CSV files |
| Reader authorization | Current GitLab identity, membership, roles, and supported restrictions | Email mapping and project grants supplied by your organization |
| Membership changes | Checked during the request | After the next successful CSV update |
| Confidential issues | Only when supported permissions allow the reader | Always excluded |

The administrator path requires self-managed GitLab 17.4 or later and its administrator identity/settings APIs. A project Maintainer or group Owner is not an instance administrator. Non-admin mode does not require those administrator APIs.
Expand Down Expand Up @@ -69,22 +69,58 @@ Use the full namespace path even if **Project** contains a numeric ID. Include i
- Use UTF-8 CSV, at most 4 MiB and 100,000 data rows per file. The full request must fit 10 MiB.
- Identical rows are deduplicated. Conflicting user-ID/email mappings and malformed rows are rejected.

These grants are admin-managed authorization. A granted reader can search allowed non-confidential content; Sim does not infer that person's actual GitLab role, restrictions, or membership from the non-admin token. Update both files when access changes.
In this example, Alice can search `engineering/platform` because the files link GitLab user `123` to both that project and `alice@example.com`. Sim checks that Alice is a current organization member and that her verified Sim email uniquely matches the grant. It checks again when she opens a result. GitLab receives the request under the source's read-only service account; Alice does not sign in to GitLab or authorize Sim individually.

Saving the CSVs grants the access listed in them. Changing a membership in GitLab alone does not change these grants. Replace the CSVs to add or revoke access; the change applies to the next search or read without re-indexing.

## Access checks

The source token retrieves content. Administrator mode proves the reader's current GitLab identity from verified Sim email, then checks project/group membership and policy during the request. Unsupported restrictions fail closed.

Non-admin mode uses saved source-local CSV grants and revalidates the token's current host/project identity. Confidential issues are excluded, including issues that became confidential after search.

Reads recheck current settings, permissions, and metadata. A reference from another member, account, organization, project, or host cannot authorize a read. Live Search does not use a stored content or permission index.
Reads recheck current settings, permissions, and metadata. A reference from another member, account, organization, project, or host cannot authorize a read. Sim fetches content live from GitLab. In CSV mode, Sim stores the uploaded mappings and resulting project grants.

## Update permissions or rotate the token

In project settings, replace either CSV file, retaining the other when appropriate. Sim validates the resulting pair before saving. Invalid or stale updates preserve saved grants. Removed readers lose access on the next operation.

To rotate the PAT, supply its replacement in source settings. A blank token retains the saved token. Changing host, project, or permission strategy requires valid configuration for the new identity.

### Automate updates with GitLab CI

After an admin configures a source in **Non-admin token** mode, a job can [read its revision](/api-reference/organizations/getGitLabSearchPermissions) and [replace both CSVs](/api-reference/organizations/replaceGitLabSearchPermissions). Copy `SIM_ORG_ID` and `SIM_SOURCE_ID` from the source settings URL: `/o/<organizationId>/settings/integrations/sources/<sourceId>`. Set `SIM_BASE_URL` to your Sim origin (for hosted Sim, `https://www.sim.ai`).

Store an organization admin's [personal Sim API key](/api-reference/authentication) as a [masked, protected GitLab CI variable](https://docs.gitlab.com/ci/variables/) named `SIM_API_KEY`. A personal key inherits its owner's access. This endpoint can only read the revision or replace both CSVs; it cannot change the GitLab PAT, host, or project.

This example runs on a schedule against a protected branch. Replace `./ci/export-gitlab-permissions` with your existing export command. It must write a fresh, complete `users.csv` and `project-permissions.csv` and exit nonzero if it cannot finish.

```yaml title=".gitlab-ci.yml"
sync_gitlab_permissions:
image: alpine:3.22
resource_group: "sim-permissions-$SIM_SOURCE_ID"
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule" && $CI_COMMIT_REF_PROTECTED == "true"'
before_script:
- apk add --no-cache curl jq
script:
- |
set -eu
url="${SIM_BASE_URL%/}/api/v2/organizations/$SIM_ORG_ID/search/sources/$SIM_SOURCE_ID/gitlab-permissions"
auth="X-API-Key: $SIM_API_KEY"
current=$(curl --fail --silent --show-error -H "$auth" "$url")
revision=$(printf '%s' "$current" | jq -er '.data.revision')
./ci/export-gitlab-permissions
jq -n --argjson rev "$revision" \
--rawfile users users.csv --rawfile grants project-permissions.csv \
'{expectedRevision: $rev, userMapping: {filename: "users.csv", content: $users},
projectPermissions: {filename: "project-permissions.csv", content: $grants}}' > update.json
curl --fail --silent --show-error --request PUT -H "$auth" \
-H 'Content-Type: application/json' --data-binary @update.json "$url"
```

A successful update returns the new revision. A `409 Conflict` means someone updated the source after the job read its revision. Rerun the job from the beginning so it exports current grants. An invalid or header-only export leaves the previous grants in place. Alert on failed jobs so revocations aren't missed. If the project should have no readers, choose **Pause search** in the source settings. You can update the grants while the source is paused, then resume search when the grants are correct.

## Troubleshooting

| Problem | Check |
Expand Down
Loading
Loading