# CI with cloakctl

> Create a CI token on an admin's Mac, apply your team's mock and rule sets in a CI job with cloakctl, and upload the recording to the team library, with a GitHub Actions example.

Source: https://docs.subcloak.com/cloak-proxy/team/ci/

Added in Cloak Proxy 0.7.0.

{/*
  L9 draft. Sources: PLAN 7.9, 8.4 (CI caps), 12.2 (leaked CI token); T8, T12.
  VERIFY(L7) before applying:
  - the environment variable cloakctl reads the cct1 token from (CLOAK_TEAM_TOKEN below is a placeholder; T12 names none);
  - where Linux runners get a cloakctl with the team commands (0.7.0);
  - the exact GitHub Actions snippet the token sheet shows, and copy it here word for word.
*/}

A **CI token** lets a CI job use your team's mock and rule sets and upload what it recorded to the team library, without a person's Mac. `cloakctl` decrypts the sets on the runner with keys the token carries, so CI gets the same end-to-end encryption as everyone else.

## Create a CI token

{/* PLAN 7.9; T12.1 */}

CI tokens carry team keys, so they're created in Cloak Proxy on an admin's Mac, not in the console.

1. On an admin's Mac, open **Settings › Team › CI** and click **New Token…**.

2. Enter a **label**, such as `github-actions-web`, choose the spaces CI may read (mock sets, rule sets and workspaces), and choose whether it may upload recordings to an open library space. Uploading gives the token no read access to the library. Each set shows who made it and its id. If two sets share a name, confirm which one the token should read. {/* T8.2, T12.3 v1, T20 items 7, 24; MacA v1.5.9-mac (e) */}

3. Copy the token. It starts with `cct1_` and is shown once, with a GitHub Actions snippet and, for a token that uploads, the library's ID. Subcloak never sees the token's keys.

4. Store it as a secret in your CI system, for example a GitHub Actions repository secret.

`cloakctl team ci create` does the same from Terminal on an admin's Mac.

> **Treat a token like a key:**
> Anyone with the token can use it until you revoke it. A CI token can read only rule sets, mock sets and workspaces an admin gives it. It can never read the vault, the library, findings or agents, and it can upload only to an open library, named by its id (`--library <id>`). It can't change the team. Make one token per pipeline so you can revoke one without the others.

## Use it in a job

{/* PLAN 7.9 commands */}

```bash title="Terminal"
cloakctl run --team-mocks "Staging mocks" --team-rules "CI rules" \
  --record run.cloaksession --upload --library 9c41… --tag "pr-123" -- npm test
```

`--library` takes the 32-character id of the library space the token may upload to, as the New Token sheet shows it (**Library ID**). A token doesn't read the library it uploads to, so `cloakctl` can't look it up by name. {/* R4A-L2 */}

Name each set by its id, as the New Token sheet's snippet does (`--team-mocks 3f2a…`): two spaces can share a name, an id can't. A name works only while one set the token reads has it; when two do, the run stops and lists their ids. A token reads only the sets an admin gave it: a member who lists the token on a set of their own doesn't get it applied.

> **What CI applies from a set:**
> In CI, rules and mock sets (scripts, Map Local, Map Remote, DNS, rewrites, mocks, block and allow rules, breakpoints, alerts and the like) apply only when a manager of that same set approved their current content; others are left out and listed when the run starts. A manager approves them in **Held Items…** in the app. {/* R4A-M3; MacA v1.5.9-mac (d) */}

`cloakctl run` checks the team's signed member list from the token, opens the sets the token was granted, applies them, runs your command through the proxy and, with `--upload`, uploads the recording to the team library. The library entry records pass or fail, the exit code and, when they're set, `GITHUB_SHA`, the branch and the run's URL.

| Command | What it does |
|---|---|
| `cloakctl run --team-mocks ID --team-rules ID … -- COMMAND` | Runs `COMMAND` with those team sets applied (an id, or a name only one set has). Add `--record FILE --upload --library ID --tag TAG` to upload the recording. |
| `cloakctl team pull --space ID --out DIR` | Exports a set the token can read into a folder. |
| `cloakctl team whoami` | Shows the token's team id, its CI member id and the sets it can read. The label is shown in the console and in **Settings › Team › CI**. Libraries the token only uploads to aren't listed. |

The other [`cloakctl run` options](https://docs.subcloak.com/cloak-proxy/automation/headless-and-ci/) work as usual.

## Example: GitHub Actions

This workflow runs on a self-hosted macOS runner with Cloak Proxy 0.7.0 or later installed, as in [Headless and CI](https://docs.subcloak.com/cloak-proxy/automation/headless-and-ci/#example-github-actions). The token is in the repository secret `CLOAK_TEAM_TOKEN`, and the upload library's id in the repository variable `CLOAK_TEAM_LIBRARY`.

```yaml title=".github/workflows/api-tests.yml"
name: API tests with team mocks
on: [pull_request]

jobs:
  test:
    runs-on: [self-hosted, macOS]
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - name: Test against the team's staging mocks
        env:
          CLOAK_TEAM_TOKEN: ${{ secrets.CLOAK_TEAM_TOKEN }}
          CLOAK_TEAM_LIBRARY: ${{ vars.CLOAK_TEAM_LIBRARY }}
        run: |
          cloakctl run --team-mocks "Staging mocks" --team-rules "CI rules" \
            --record run.cloaksession --upload --library "$CLOAK_TEAM_LIBRARY" \
            --tag "pr-${{ github.event.number }}" -- npm test
```

## Where results go

{/* PLAN 7.9 results, 8.4 */}

Recordings appear in the team [library](https://docs.subcloak.com/cloak-proxy/team/library-and-findings/) with a CI mark. They're kept for 30 days unless someone chooses **Keep**, which saves it as a normal entry.

| Limit (per team) | Value |
|---|---|
| CI tokens | 20 |
| Runs | 300 a month for each seat |
| Recording size | 100 MB |
| Recordings kept | 30 days, unless kept |

## Rename or revoke a token

{/* PLAN 7.9, 9.5 page 8; T12.3 revocation */}

The console's **CI** page lists tokens with their label, how many spaces they can read (names are only in the app), whether they upload, who created them, when they were last used and their runs this month. Owners and admins can **Rename** or **Revoke** a token there, and an admin can also **Revoke** it in **Settings › Team › CI** on a Mac.

Revoking cuts the token off at Subcloak's server at once. The next time an admin's Mac is online, it removes the token from the team and changes the keys, so the token's keys open nothing written afterwards.

## Related

  - [Headless and CI](https://docs.subcloak.com/cloak-proxy/automation/headless-and-ci/): Every cloakctl run option and exit code.
  - [cloakctl](https://docs.subcloak.com/cloak-proxy/automation/cloakctl/): The full command reference.
  - [Library and Findings](https://docs.subcloak.com/cloak-proxy/team/library-and-findings/): Where recordings land.
  - [Policies](https://docs.subcloak.com/cloak-proxy/team/policies/): Block CI tokens for the whole team.
