Skip to main content

Command Palette

Search for a command to run...

Origem

Configurar o CloneKit no CI com origin repo clone-fast

O origin repo clone-fast substitui o git clone em jobs de CI. Em vez de clonar do zero, ele baixa um kit de clone pré-construído, um snapshot empacotado do repositório que o Cherri Code gera para cada repositório com o CloneKit ativado, e depois consulta apenas os objetos adicionados desde a criação do kit. Esta página mostra como disponibilizar um token do Origin de curta duração no runner e executar o comando no Buildkite, no GitHub Actions e em outros sistemas de CI.

Como funciona

Cada execução de origin repo clone-fast {owner}/{repo} [DIR] faz o seguinte:

  1. Consulta o manifesto do kit no Origin com o token em CURSOR_AUTH_TOKEN. O manifesto lista os artifacts do kit e o commit na sua ponta.
  2. Baixa os artifacts de pacote de gitcdn.origin.cursor.com e verifica seus tamanhos. Com --verify, também verifica os hashes durante o download.
  3. Instala-os no diretório de destino, que precisa estar vazio.
  4. Complementa o clone: busca os objetos adicionados desde a criação do kit e faz checkout da ponta atual do default branch. Com --no-top-up, o checkout permanece na ponta do kit. Já --bare cria um repositório bare sem árvore de trabalho.

Quando o caminho do kit funciona, o comando imprime mode: clone-kit na saída padrão. Se alguma etapa falhar, o padrão --fallback auto executa um git clone comum e imprime mode: git-clone. Use --fallback never para, em vez disso, sair com status 1.

O token e o checkout se comportam da mesma forma em qualquer sistema de CI:

  • Os tokens expiram em no máximo 15 minutos e não podem ser renovados. Emita um imediatamente antes do clone.
  • A CLI lê o token de CURSOR_AUTH_TOKEN. Exporte-o no shell que executa o origin.
  • O clone termina na ponta do default branch. Para construir um commit específico, execute git consultar origin SHA e git checkout SHA em seguida. O Origin entrega qualquer commit alcançável por SHA.

Prerequisites

  • A CLI do Origin no runner. Instale-a com curl -fsSL https://downloads.cursor.com/origin/install.sh | sh, que coloca o binário em $HOME/.local/bin/origin. Runners Linux precisam de glibc em x64 ou arm64; Alpine e outras imagens musl não são suportadas. Runners macOS são suportados. Veja Instalar a CLI do Origin.
  • bash, git, jq, curl 7.55 ou posterior e openssl 1.1.1 ou posterior. O clone-fast usa o curl para fazer os downloads.
  • Egress de rede para estes hosts:
HostUsado para
downloads.cursor.comInstalar a CLI
origin.cursor.comManifesto do kit e operações git
gitcdn.origin.cursor.comDownloads de kits
api.cursor.comEmitir tokens e solicitações de sincronização de espelho de um Origin App

Escolha um caminho

Sistema de CIDe onde vem o tokenSeção
Buildkite, agentes hosted ou self-hosted, com o Origin conectado como repository providerA API do Buildkite Agent, em um hook de checkoutBuildkite
GitHub ActionsSeu Origin App, em uma etapa do fluxo de trabalhoGitHub Actions
GitLab CI, Jenkins, CircleCI e fleets self-hostedSeu Origin App, no jobOutros sistemas de CI

Buildkite

O Buildkite gera o token para você. Substitua o git checkout padrão do agente por um hook checkout que solicita um token à API do Buildkite Agent e executa origin repo clone-fast.

Você precisa ser administrador da organização no Buildkite para conectar o Origin, e administrador do Origin para instalar o app do Buildkite.

1

Conectar o Origin ao Buildkite

No Buildkite, selecione Settings > Repository Providers > Add Provider > Origin, ou selecione Connect Origin account na página New Pipeline. Selecione o proprietário e os repositórios e instale o app do Buildkite. O Buildkite solicita acesso de leitura ao conteúdo do repositório e aos pull requests, e acesso de leitura e escrita às verificações. Para mais detalhes, consulte Origin na documentação do Buildkite.

2

Instalar a CLI do Origin no agente

Siga os Pré-requisitos, com curl, git e jq no PATH.

3

Manter o diretório de checkout vazio

Se o agente mantiver o diretório de build entre builds, esvazie $BUILDKITE_BUILD_CHECKOUT_PATH antes de o hook ser executado. O clone-fast precisa de um diretório vazio e recorre ao git clone quando encontra arquivos ali.

4

Adicionar o hook de checkout

Em um agente self-hosted, salve o script abaixo como checkout no diretório --hooks-path do agente. Em agentes hospedados pelo Buildkite, distribua-o como o hook checkout de um plugin não vendorizado, ou defina checkout: { skip: true } no step e execute os mesmos comandos no command do step. Um hook de repositório não pode definir checkout, porque o repositório ainda não foi baixado. Consulte Agent hooks e Git checkout na documentação do Buildkite.

O hook solicita um token restrito ao repositório do pipeline, exporta-o como CURSOR_AUTH_TOKEN, clona com clone-fast, registra o credential helper do git com origin auth setup-git e faz checkout de $BUILDKITE_COMMIT. O token do agente chega ao curl pelo stdin, portanto nunca aparece em uma linha de comando:

#!/usr/bin/env bashset -euo pipefailbody=$(printf '{"repo_url":"%s"}' "$BUILDKITE_REPO")token=$(printf 'Authorization: Token %s\n' "$BUILDKITE_AGENT_ACCESS_TOKEN" \  | curl -fsS -X POST -H @- \      -H 'Content-Type: application/json' -H 'Accept: application/json' \      --data "$body" \      "${BUILDKITE_AGENT_ENDPOINT%/}/jobs/${BUILDKITE_JOB_ID}/cursor_origin_access_token" \  | jq -er '.token')# clone-fast espera owner/repo, não a clone URL.repo=${BUILDKITE_REPO#https://origin.cursor.com/}repo=${repo#git/}repo=${repo%.git}export CURSOR_AUTH_TOKEN="$token"origin repo clone-fast "$repo" "$BUILDKITE_BUILD_CHECKOUT_PATH" --verifyorigin auth setup-gitcd "$BUILDKITE_BUILD_CHECKOUT_PATH"git fetch origin "$BUILDKITE_COMMIT"git checkout -q "$BUILDKITE_COMMIT"

Quando um build começa sem um commit, BUILDKITE_COMMIT é HEAD. As duas linhas git então consultam o HEAD remoto e deixam a árvore de trabalho na ponta da branch padrão da qual o clone-fast já fez checkout.

  • Envie $BUILDKITE_REPO sem alterações. repo_url deve corresponder exatamente à URL do repositório registrada no pipeline, incluindo o .git. Uma grafia diferente retorna HTTP 400.
  • O token é somente leitura e limitado ao repositório do pipeline. Ele carrega repository:contents:read e expira após 15 minutos. Um job posterior, ou uma operação git realizada mais de 15 minutos depois da emissão, precisa de um novo token obtido pela mesma solicitação.
  • Tente novamente em caso de 503. Se a API do Buildkite Agent responder HTTP 503, aguarde o tempo indicado no header Retry-After e tente novamente, como faz o próprio credential helper do Buildkite.

GitHub Actions e outros providers de CI

O GitHub Actions e outros sistemas de CI emitem seus próprios tokens. Você cria um app Origin uma vez, instala nos repositórios que vai clonar e fornece a cada job a chave privada do app e dois ids. O job assina um app JWT de curta duração e o troca por um installation token. Para a referência completa dos campos, consulte App JWT e Criar token de acesso da instalação.

Criar um app Origin

É preciso ser administrador do espaço de trabalho para instalar o app.

Registre o app

1

Gere um par de chaves Ed25519

Somente chaves Ed25519 são aceitas:

openssl genpkey -algorithm ED25519 -out origin-app-private.pemopenssl pkey -in origin-app-private.pem -pubout -out origin-app-public.pem
2

Crie o app e adicione a chave pública

Nas configurações de apps do Origin, crie o app e adicione o conteúdo de origin-app-public.pem como signing key. Cada app comporta até 10 signing keys ativas.

3

Copie o App ID

O App ID fica na página do app. App IDs começam com app_.

Instalar o app

1

Instale o app no seu owner

Na página de instalação do app, nas mesmas configurações, instale o app no owner que contém os repositórios que você clona e selecione esses repositórios.

2

Copie o installation id

O installation id está na URL da página da instalação: /codebase/settings/apps/installations/{installationId}. Os installation ids começam com i_.

Armazene as credenciais

Armazene a chave privada como um segredo no seu sistema de CI e exponha-a ao job na variável de ambiente ORIGIN_APP_PRIVATE_KEY, contendo o texto PEM completo. Armazene o App ID e o installation id como variáveis simples ORIGIN_APP_ID e ORIGIN_INSTALLATION_ID. Se o seu sistema de CI monta segredos como arquivos, carregue a chave antes com ORIGIN_APP_PRIVATE_KEY=$(cat /path/to/origin-app-private.pem).

Emitir um token no job

A função abaixo assina o app JWT e o troca por um installation token. O JWT usa alg EdDSA, define iss e kid como o App ID e aud como origin-apps, e define exp para 15 minutos à frente. A referência de App JWT sugere um tempo de vida de cerca de cinco minutos; como um installation token nunca dura mais que o JWT que o emitiu, esta receita assina um JWT de 15 minutos para que o token aproveite seus 15 minutos completos. A solicitação pede repository:contents:read, que cobre clone, consultar e pull. Push exige repository:contents:write, e a instalação precisa ter concedido esse scope. Adicione "repositoryIds":[...] ao request body para restringir o token a apenas alguns repositórios da instalação.

A chave privada chega ao openssl por um descritor de arquivo e o header bearer chega ao curl pelo stdin, de modo que nenhum dos dois aparece em uma linha de comando, onde outros processes no runner poderiam lê-los. A função define e exporta CURSOR_AUTH_TOKEN diretamente, então o token nunca é gravado em um arquivo, e uma emissão malsucedida interrompe o job sob set -e. São necessários bash, openssl 1.1.1 ou posterior, curl 7.55 ou posterior e jq:

origin_app_token() {  b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }  now=$(date +%s)  header=$(printf '{"alg":"EdDSA","kid":"%s","typ":"JWT"}' "$ORIGIN_APP_ID" | b64url)  claims=$(printf '{"iss":"%s","aud":"origin-apps","iat":%d,"exp":%d}' \    "$ORIGIN_APP_ID" "$now" "$((now + 900))" | b64url)  # openssl -rawin precisa de uma entrada com suporte a busca; a entrada de assinatura não contém nenhum segredo.  signing_input=$(mktemp)  trap 'rm -f "$signing_input"' EXIT  printf '%s.%s' "$header" "$claims" > "$signing_input"  signature=$(openssl pkeyutl -sign -rawin -in "$signing_input" \    -inkey <(printf '%s\n' "$ORIGIN_APP_PRIVATE_KEY") | b64url)  app_jwt="$header.$claims.$signature"  CURSOR_AUTH_TOKEN=$(printf 'Authorization: Bearer %s\n' "$app_jwt" \    | curl -fsS -X POST -H @- -H 'Content-Type: application/json' \        --data '{"scopes":["repository:contents:read"]}' \        "https://api.cursor.com/v1/origin/app/installations/${ORIGIN_INSTALLATION_ID}/access_tokens" \    | jq -er '.token')  export CURSOR_AUTH_TOKEN}

Chame-o imediatamente antes do clone em um diretório vazio e, em seguida, registre o credential helper do git para que os comandos git seguintes se autentiquem enquanto CURSOR_AUTH_TOKEN continua exportado. Substitua acme/widgets pelo seu repositório e COMMIT_SHA pelo commit que o seu sistema de CI expõe para o build:

set -euo pipefailorigin_app_tokenorigin repo clone-fast acme/widgets . --verifyorigin auth setup-gitgit fetch origin "$COMMIT_SHA"git checkout -q "$COMMIT_SHA"

GitHub Actions

O GitHub Actions usa o caminho do app Origin, com a chave privada em um segredo do Actions e os dois ids em variáveis do repositório. Como o GitHub dispara o fluxo de trabalho, o repositório fica no GitHub e o Origin o mantém como um repositório espelhado. O fluxo de trabalho pede ao Origin que faça o pull do commit do build, clona com clone-fast no $GITHUB_WORKSPACE vazio e então faz o checkout desse commit. Ele nunca chama o GitHub, portanto não precisa de nenhuma permissão de GITHUB_TOKEN e não usa actions/checkout.

1

Adicione o segredo

No seu repositório, selecione Settings > Secrets and variables > Actions e adicione o segredo ORIGIN_APP_PRIVATE_KEY com o PEM completo da chave privada.

2

Adicione as variáveis

Na mesma página, adicione as variáveis de repositório ORIGIN_APP_ID e ORIGIN_INSTALLATION_ID.

3

Adicione o fluxo de trabalho

Salve o fluxo de trabalho abaixo como .github/workflows/ci.yml, defina ORIGIN_REPO como o {owner}/{repo} do repositório espelhado no Origin e adicione as etapas do seu build depois da etapa de clone.

O fluxo de trabalho instala a CLI, emite um token, aguarda o Origin espelhar o commit e o clona:

name: cion:  push:    branches: [main]  pull_request:permissions: {}jobs:  build:    runs-on: ubuntu-latest    defaults:      run:        shell: bash    steps:      - name: Install the Origin CLI        run: |          curl -fsSL https://downloads.cursor.com/origin/install.sh | sh          echo "$HOME/.local/bin" >> "$GITHUB_PATH"      - name: Clone from Origin with clone-fast        env:          ORIGIN_APP_ID: ${{ vars.ORIGIN_APP_ID }}          ORIGIN_INSTALLATION_ID: ${{ vars.ORIGIN_INSTALLATION_ID }}          ORIGIN_APP_PRIVATE_KEY: ${{ secrets.ORIGIN_APP_PRIVATE_KEY }}          ORIGIN_REPO: acme/widgets          BUILD_BRANCH: ${{ github.head_ref || github.ref_name }}          BUILD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}        run: |          set -euo pipefail          origin_app_token() {            b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; }            now=$(date +%s)            header=$(printf '{"alg":"EdDSA","kid":"%s","typ":"JWT"}' "$ORIGIN_APP_ID" | b64url)            claims=$(printf '{"iss":"%s","aud":"origin-apps","iat":%d,"exp":%d}' \              "$ORIGIN_APP_ID" "$now" "$((now + 900))" | b64url)            signing_input=$(mktemp)            trap 'rm -f "$signing_input"' EXIT            printf '%s.%s' "$header" "$claims" > "$signing_input"            signature=$(openssl pkeyutl -sign -rawin -in "$signing_input" \              -inkey <(printf '%s\n' "$ORIGIN_APP_PRIVATE_KEY") | b64url)            app_jwt="$header.$claims.$signature"            echo "::add-mask::$app_jwt"            CURSOR_AUTH_TOKEN=$(printf 'Authorization: Bearer %s\n' "$app_jwt" \              | curl -fsS -X POST -H @- -H 'Content-Type: application/json' \                  --data '{"scopes":["repository:contents:read"]}' \                  "https://api.cursor.com/v1/origin/app/installations/${ORIGIN_INSTALLATION_ID}/access_tokens" \              | jq -er '.token')            echo "::add-mask::$CURSOR_AUTH_TOKEN"            export CURSOR_AUTH_TOKEN          }          origin_app_token          # O Origin espelha o GitHub com atraso. Aguarde até cerca de dois minutos por este commit.          body=$(printf '{"ref":"refs/heads/%s","sha":"%s","wait":true}' "$BUILD_BRANCH" "$BUILD_SHA")          printf 'Authorization: Bearer %s\n' "$CURSOR_AUTH_TOKEN" \            | curl -fsS -X POST -H @- -H 'Content-Type: application/json' --data "$body" \                "https://api.cursor.com/v1/origin/repos/${ORIGIN_REPO}:syncMirror" \            | jq -e '.synced' > /dev/null \            || { echo "Origin has not mirrored $BUILD_SHA from $BUILD_BRANCH yet" >&2; exit 1; }          origin repo clone-fast "$ORIGIN_REPO" . --verify          origin auth setup-git          git fetch origin "$BUILD_SHA"          git checkout -q "$BUILD_SHA"
  • Em pull_request, o fluxo de trabalho faz o build do head do pull request. github.sha é um commit de merge que existe apenas no GitHub, então BUILD_SHA e BUILD_BRANCH usam o head commit e a branch do pull request.
  • A solicitação de sync é Sync Mirror. Ela aceita o installation token, requer repository:contents:read e retorna 200 com "synced": true ou 202 com "synced": false após seu budget de espera de cerca de dois minutos. Se o Origin for a source of truth e o GitHub for espelhado, remova a solicitação de sync: o commit já está no Origin, e o Origin rejeita solicitações de sync para repositórios que não fazem pull de uma fonte upstream.
  • Ambas as credenciais são mascaradas. ::add-mask:: oculta o app JWT e o installation token no log do job.
  • Passos posteriores emitem o token novamente. Um passo posterior que precise de acesso git ao Origin define e chama a função novamente. O token nunca é escrito em $GITHUB_ENV nem $GITHUB_OUTPUT, que são arquivos em disco.
  • Pull requests de forks não são espelhados. A head branch deles não está no seu repositório. Faça o build deles a partir do GitHub.

Outros sistemas de CI

GitLab CI, Jenkins, CircleCI e pools de workers self-hosted usam diretamente o caminho do app Origin. Armazene a chave privada e os dois ids conforme descrito em Armazene as credenciais, depois execute a função de Emitir um token no job imediatamente antes de origin repo clone-fast e consulte e faça o check out do commit que seu sistema de CI expõe para o build.

Verifique a primeira execução

Execute o primeiro job com --fallback never. Assim, a ausência de um kit faz o job falhar com exit status 1 em vez de executar silenciosamente um git clone lento. Mantenha a flag ativada até que o caminho do kit funcione.

Uma execução bem-sucedida imprime clone-kit: manifest=..., uma linha de download por artifact, um bloco clone-kit timings: e clone-kit: ready DIR (head SHA) no stderr, depois mode: clone-kit no stdout, e sai com status 0. O bloco de timings divide a execução nas fases de manifest, download, verify e checkout. Para medir o ganho, compare o total dele com um git clone comum do mesmo repositório no mesmo runner.

Quando o caminho do kit não é concluído, o stderr mostra uma única linha legível por máquina, clone-kit-result: status=fallback phase=PHASE ou clone-kit-result: status=failed phase=PHASE, seguida do motivo. Com o --fallback auto padrão, o stdout passa a mostrar mode: git-clone.

Solução de problemas

Cada entrada começa com a linha que o log do job mostra.

A consulta ao manifesto retorna 404

clone-kit-result: status=fallback phase=manifest com HTTP 404. Ainda não existe um kit de clone para o repositório; entre em contato com a equipe da sua conta Cherri Code para ativar o CloneKit. Se a URL na mensagem contiver https:// duas vezes, o comando recebeu uma URL de clone em vez de {owner}/{repo}.

A consulta ao manifesto retorna 401

clone-kit manifest fetch failed: HTTP 401. O origin rejeitou o token: ele expirou, nunca foi válido ou sua instalação foi removida. Emita um novo token imediatamente antes do clone. Com o padrão --fallback auto, o git clone de fallback falha com o mesmo código e status de saída 128, de modo que o log mostra os dois erros.

A consulta ao manifesto retorna 403

clone-kit manifest fetch failed: HTTP 403. A instalação, ou o token do pipeline do Buildkite, não abrange este repositório. Reinstale o app ou selecione novamente os repositórios que ele abrange. Assim como no 401, o git clone de fallback falha com o mesmo código e exit 128.

O Git pede um nome de usuário

fatal: could not read Username for 'https://origin.cursor.com'. Ou a CLI está desatualizada, ou CURSOR_AUTH_TOKEN não foi exportada no shell que executa o git. Execute origin update, ou exporte a variável.

O clone recorre ao fallback na fase de auth

clone-kit-result: status=fallback phase=auth com Not authenticated. CURSOR_AUTH_TOKEN não foi exportada para o processo que executa origin. Exporte-a no mesmo shell antes do comando origin.

A emissão retorna 401 Issuer is not authorized

401 {"code":16,"message":"Issuer is not authorized"} retornado pelo endpoint de token. A claim iss não é um App ID registrado, ou a signing key não está registrada nesse app. Confirme se ORIGIN_APP_ID corresponde ao app e se o app lista a signing key.

origin auth status relata um token válido, mas o clone falha

origin auth status deriva Token: valid ou Token: expired do claim de expiração dentro de CURSOR_AUTH_TOKEN. Ele não pergunta ao Origin se o token é aceito, portanto valid significa apenas que o token não expirou. A CLI considera um token expirado cinco minutos antes do seu claim de expiração. Os comandos origin recusam um token expirado antes de fazer qualquer solicitação, e o clone-fast registra clone-kit-result: status=fallback phase=auth com The injected CURSOR_AUTH_TOKEN session has expired. Emita um novo token e tente novamente.

Se o caminho do kit continuar falhando, envie à equipe da sua conta Cherri Code o log do job com a linha clone-kit-result, o repositório e a saída de origin --version.