> For the complete documentation index, see [llms.txt](https://docs.tunnelhub.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tunnelhub.io/cli/ci-cd-deployments.md).

# Deploy via CI/CD

Esta página descreve o fluxo recomendado para publicar automações com a CLI em pipelines como GitHub Actions, GitLab CI e Jenkins, sem usar `tunnelhub login`.

O modelo recomendado usa credenciais CI/CD account-level com allowlist de ambientes. A credencial pertence à conta, mas só pode fazer deploy nos UUIDs de ambiente autorizados durante a criação.

## Pré-requisitos

Antes de configurar o pipeline, você precisa:

* ter uma automação já criada no TunnelHub;
* ter o `tunnelhub.yml` configurado com a automação que será publicada;
* saber o UUID de cada ambiente TunnelHub que o pipeline poderá publicar;
* ter permissão para acessar `Administration > Settings`;
* se for usar GitHub Actions, ter permissão para criar GitHub Environments, secrets e variables no repositório.

## 1. Gere a credencial no portal

No portal do TunnelHub:

1. acesse `Administration > Settings`;
2. abra a aba `CI/CD`;
3. clique em `Criar credencial CI/CD`;
4. informe um nome para a credencial;
5. selecione os ambientes autorizados para a credencial;
6. conclua a criação;
7. copie o `Client ID` e o `Client secret` exibidos.

Observações importantes:

* a credencial é da account, mas só pode fazer deploy nos ambientes autorizados na criação;
* você pode liberar ambientes específicos ou usar a opção de todos os ambientes;
* o `Client secret` é exibido apenas uma vez;
* se o secret for perdido ou exposto, use `Regenerar secret` ou `Revogar`;
* para produção, prefira credenciais separadas por ambiente para reduzir blast radius.

## 2. Salve secrets e variables do pipeline

No GitHub Actions, a separação recomendada é:

* `TH_CLIENT_ID`: GitHub Environment Secret;
* `TH_CLIENT_SECRET`: GitHub Environment Secret;
* `TH_ENVIRONMENT_ID`: GitHub Environment Variable;
* `TH_API_HOST`: repositório variable, GitHub Environment Variable ou valor fixo no workflow.

Exemplo de valores:

* `TH_API_HOST`: `https://api.tunnelhub.io`
* `TH_ENVIRONMENT_ID`: UUID de um ambiente TunnelHub autorizado para essa credencial

A automação publicada é inferida automaticamente a partir do `tunnelhub.yml` do projeto.

Se você usar outra plataforma de CI/CD, mantenha a mesma ideia:

* `TH_CLIENT_ID` e `TH_CLIENT_SECRET` como secrets;
* `TH_ENVIRONMENT_ID` como variável por ambiente;
* `TH_API_HOST` como variável ou valor fixo do pipeline.

## 3. Entenda GitHub Environment vs TunnelHub Environment

Esses dois conceitos são diferentes:

* GitHub Environment: controla approvals, protection rules, secrets e variables dentro do GitHub;
* TunnelHub Environment: é o UUID passado para `--environment-id` no deploy.

O vínculo entre os dois acontece pela variável `TH_ENVIRONMENT_ID`.

Exemplo:

* GitHub Environment `production` pode ter `TH_ENVIRONMENT_ID=<uuid-do-ambiente-production-no-tunnelhub>`;
* GitHub Environment `development` pode ter `TH_ENVIRONMENT_ID=<uuid-do-ambiente-development-no-tunnelhub>`.

## 4. Execute o deploy com a CLI

O deploy CI/CD usa a mesma CLI pública, mas autenticada com variáveis de ambiente M2M.

O parâmetro `--message` é obrigatório e deve carregar o contexto humano do deploy.

Os exemplos abaixo usam a mensagem completa do último commit e o e-mail do autor para preencher `--message`.

Antes de executar `deploy-automation`, o workflow precisa gerar o artefato ZIP configurado em `package.artifact` no `tunnelhub.yml`. Os exemplos abaixo usam `corepack` e detectam `pnpm`, `yarn` ou `npm` pelo lockfile do projeto. Ajuste os comandos se o seu repositório usar outro fluxo de build.

### Exemplo 1: `main` publica em `production`

Use este exemplo quando apenas a branch `main` deve publicar, mapeada para o GitHub Environment `production`.

```yaml
name: Deploy TunnelHub Automation

on:
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  deploy-production:
    if: github.ref_name == 'main'
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Enable Corepack
        run: corepack enable

      - name: Install dependencies
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm install --frozen-lockfile
          elif [ -f yarn.lock ]; then
            yarn install --immutable
          else
            npm ci
          fi

      - name: Build deployment artifact
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm build
          elif [ -f yarn.lock ]; then
            yarn build
          else
            npm run build
          fi

      - name: Install TunnelHub CLI
        run: npm install --global @tunnelhub/cli

      - name: Deploy automation
        env:
          TH_API_HOST: https://api.tunnelhub.io
          TH_CLIENT_ID: ${{ secrets.TH_CLIENT_ID }}
          TH_CLIENT_SECRET: ${{ secrets.TH_CLIENT_SECRET }}
          TH_ENVIRONMENT_ID: ${{ vars.TH_ENVIRONMENT_ID }}
        run: |
          COMMIT_EMAIL="$(git log -1 --pretty=format:'%ae')"
          COMMIT_MESSAGE="$(git log -1 --pretty=format:'%B')"
          COMMIT_SHA="$(git rev-parse --short HEAD)"
          DEPLOY_MESSAGE="${COMMIT_MESSAGE}

          Deploy ${COMMIT_SHA} by ${COMMIT_EMAIL}"

          tunnelhub deploy-automation \
            --environment-id "$TH_ENVIRONMENT_ID" \
            --message "$DEPLOY_MESSAGE"
```

### Exemplo 2: `develop` publica em `development` e `main` publica em `production`

Use este exemplo quando você quer separar ambientes por branch.

```yaml
name: Deploy TunnelHub Automation

on:
  push:
    branches:
      - develop
      - main
  workflow_dispatch:

jobs:
  deploy-development:
    if: github.ref_name == 'develop'
    runs-on: ubuntu-latest
    environment: development

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Enable Corepack
        run: corepack enable

      - name: Install dependencies
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm install --frozen-lockfile
          elif [ -f yarn.lock ]; then
            yarn install --immutable
          else
            npm ci
          fi

      - name: Build deployment artifact
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm build
          elif [ -f yarn.lock ]; then
            yarn build
          else
            npm run build
          fi

      - name: Install TunnelHub CLI
        run: npm install --global @tunnelhub/cli

      - name: Deploy automation
        env:
          TH_API_HOST: https://api.tunnelhub.io
          TH_CLIENT_ID: ${{ secrets.TH_CLIENT_ID }}
          TH_CLIENT_SECRET: ${{ secrets.TH_CLIENT_SECRET }}
          TH_ENVIRONMENT_ID: ${{ vars.TH_ENVIRONMENT_ID }}
        run: |
          COMMIT_EMAIL="$(git log -1 --pretty=format:'%ae')"
          COMMIT_MESSAGE="$(git log -1 --pretty=format:'%B')"
          COMMIT_SHA="$(git rev-parse --short HEAD)"
          DEPLOY_MESSAGE="${COMMIT_MESSAGE}

          Deploy ${COMMIT_SHA} by ${COMMIT_EMAIL}"

          tunnelhub deploy-automation \
            --environment-id "$TH_ENVIRONMENT_ID" \
            --message "$DEPLOY_MESSAGE"

  deploy-production:
    if: github.ref_name == 'main'
    runs-on: ubuntu-latest
    environment: production

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Enable Corepack
        run: corepack enable

      - name: Install dependencies
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm install --frozen-lockfile
          elif [ -f yarn.lock ]; then
            yarn install --immutable
          else
            npm ci
          fi

      - name: Build deployment artifact
        run: |
          if [ -f pnpm-lock.yaml ]; then
            pnpm build
          elif [ -f yarn.lock ]; then
            yarn build
          else
            npm run build
          fi

      - name: Install TunnelHub CLI
        run: npm install --global @tunnelhub/cli

      - name: Deploy automation
        env:
          TH_API_HOST: https://api.tunnelhub.io
          TH_CLIENT_ID: ${{ secrets.TH_CLIENT_ID }}
          TH_CLIENT_SECRET: ${{ secrets.TH_CLIENT_SECRET }}
          TH_ENVIRONMENT_ID: ${{ vars.TH_ENVIRONMENT_ID }}
        run: |
          COMMIT_EMAIL="$(git log -1 --pretty=format:'%ae')"
          COMMIT_MESSAGE="$(git log -1 --pretty=format:'%B')"
          COMMIT_SHA="$(git rev-parse --short HEAD)"
          DEPLOY_MESSAGE="${COMMIT_MESSAGE}

          Deploy ${COMMIT_SHA} by ${COMMIT_EMAIL}"

          tunnelhub deploy-automation \
            --environment-id "$TH_ENVIRONMENT_ID" \
            --message "$DEPLOY_MESSAGE"
```

O deploy deve informar `--environment-id` ou `--env` com UUID. O backend valida se esse ambiente está na allowlist da credencial.

## 5. Entenda o que fica salvo na revisão

No deploy via CI/CD, a revisão criada guarda dois tipos de informação:

* `createdBy`: identifica a credencial técnica que autorizou o deploy;
* `message`: registra o contexto humano e operacional do deploy.

Na prática:

* `createdBy` fica como `api-client:<clientId>`;
* `message` deve conter dados como a mensagem do commit, SHA, e-mail do autor, identificador da execução ou o nome do workflow quando isso fizer sentido.

Esse desenho preserva auditoria técnica sem perder rastreabilidade humana.

## 6. Rotação e revogação

Na mesma aba `Administration > Settings > CI/CD`, você pode:

* usar `Regenerar secret` para emitir um novo secret para a credencial existente;
* usar `Revogar` para bloquear novos deploys com essa credencial.

Após regenerar o secret, atualize imediatamente os secrets do pipeline.

Se você usa GitHub Environments separados, atualize cada environment que depende dessa credencial.

Se migrar para credenciais separadas por ambiente, revogue as credenciais antigas assim que o novo fluxo estiver validado.

## Veja também

* [Visão geral da CLI](/cli/cli.md)
* [Comandos e referência](/cli/commands.md)
* [Autenticação e ambientes](/cli/authentication-and-environments.md)
* [`tunnelhub.yml`](/cli/tunnelhub-yml.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tunnelhub.io/cli/ci-cd-deployments.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
