> ## Documentation Index
> Fetch the complete documentation index at: https://capy.sc/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Actions Secrets Management with Capy

> Push SECRETS_BLOB and PROJECT_KEY into your repo with capy deploy, then wrap any GitHub Actions step — builds, tests, deploys — with capy run. Repo- or environment-scoped tokens.

GitHub Actions runners are Node-capable containers. You can run `capy run` in any workflow step that needs decrypted secrets - builds, tests, deploys, anything that reads `process.env`.

Unlike a runtime platform, GitHub Actions is a CI vehicle: the two secrets live in your repo's Actions secret store, and each workflow step wraps its command with `capy run`. `capy deploy` has a built-in connector that pushes those secrets for you over the `gh` CLI - no copy-paste.

## Set it up with `capy deploy`

The connector uses the GitHub CLI you already have authenticated locally - Capy never sees a token. Make sure `gh` is installed and logged in first:

```bash theme={null}
gh --version       # https://cli.github.com if missing
gh auth status     # must be green
```

Then, from inside your repo:

```bash theme={null}
capy deploy
```

1. Pick **GitHub Actions** in the platform picker.
2. Choose **Push SECRETS\_BLOB + PROJECT\_KEY to GitHub secrets via gh**.
3. Pick a scope:
   * **Repository secrets** - every workflow and every environment can read them.
   * **Environment secrets** - scoped to one GitHub Actions environment (e.g. `production`). Pick an existing environment or create one on the spot.
4. Capy mints a fresh deploy token, runs `gh secret set` for `SECRETS_BLOB` and `PROJECT_KEY` in the scope you chose, and prints the workflow patch to paste plus the deploy id (for [revoking later](#revocation)).

The connector resolves the target repo from your current directory's git remote (`gh repo view`), so run it from inside the checkout you're deploying.

<Note>
  The Actions secrets are named `SECRETS_BLOB` and `PROJECT_KEY` - no `CAPY_` prefix. If you set them up under different names in the past, update the `env:` block in your workflow to match, or re-run `capy deploy` to overwrite them.
</Note>

## Workflow

Paste the patch the connector prints into your workflow. It looks like this:

```yaml theme={null}
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      SECRETS_BLOB: ${{ secrets.SECRETS_BLOB }}
      PROJECT_KEY: ${{ secrets.PROJECT_KEY }}
    steps:
      - uses: actions/checkout@v4

      - uses: oven-sh/setup-bun@v1

      - name: Install deps
        run: bun install

      - name: Install Capy CLI
        run: npm install -g @capysc/cli

      - name: Test
        run: capy run -- bun test

      - name: Build
        run: capy run -- bun run build

      - name: Deploy
        run: capy run -- <your deploy command>
```

Every step under the job's `env:` block inherits `SECRETS_BLOB` and `PROJECT_KEY`, so you don't have to repeat them per step.

## Per-environment secrets

When you pick **Environment secrets** scope, the secrets land on one GitHub Actions [environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment). Your deploy job must pin to that environment for `${{ secrets.* }}` to resolve - the connector reminds you of this in its output:

```yaml theme={null}
jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment: production       # must match the env you chose
    env:
      SECRETS_BLOB: ${{ secrets.SECRETS_BLOB }}
      PROJECT_KEY: ${{ secrets.PROJECT_KEY }}
    steps:
      - run: capy run -- <deploy cmd>
```

To deploy different secrets to different targets (production vs. staging), run `capy deploy` once per environment and point each deploy job at the matching environment.

## Non-interactive setup

Every prompt has a flag, so the connector runs unattended in scripts and CI bootstrap:

```bash theme={null}
# Repo-scoped, no prompts
capy deploy --platform github-actions --mode connector --scope repo --yes

# Environment-scoped (creates the env if it doesn't exist)
capy deploy --platform github-actions --mode connector \
  --scope env --env-name production --yes
```

| Flag                            | Effect                                                                                           |
| ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `--platform github-actions`     | Skip the platform picker.                                                                        |
| `--mode connector`              | Skip the mode picker (push secrets via `gh`). Use `--mode token` for the manual copy-paste path. |
| `--scope repo` \| `--scope env` | Repository vs. environment secrets.                                                              |
| `--env-name <name>`             | Environment name; required with `--scope env`. Created if missing.                               |
| `--yes`, `-y`                   | Skip the overwrite confirmation when the secrets already exist.                                  |

## Manual setup (without `gh`)

If you'd rather not use the connector - or `gh` isn't available - choose the token path and set the secrets yourself:

```bash theme={null}
capy deploy --platform github-actions --mode token   # prints the two values
```

Then add them under **Settings → Secrets and variables → Actions**, or:

```bash theme={null}
gh secret set SECRETS_BLOB --body "<value>"
gh secret set PROJECT_KEY --body "<value>"
```

The workflow is identical to the one above.

## One job, one decrypt

Each `capy run` invocation does its own service fetch. If you want to share a single decryption across steps, run `capy run` once to produce a file and have later steps read it. Example for Next.js builds that emit a `.capy/next-env.js` manifest:

```yaml theme={null}
- name: Build (emits .capy/next-env.js)
  run: capy run -- bun run build

- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: |
      .next/
      .capy/next-env.js
```

## Pull requests from forks

By default, GitHub Actions doesn't pass secrets to workflows triggered by PRs from forks - a security baseline. Forked-PR builds can't decrypt with Capy. Usually fine: run CI without decrypted secrets, use mock values, or gate deploy jobs on `github.event.pull_request.head.repo.full_name == github.repository`.

## Revocation

`capy deploy` prints a deploy id when it finishes. The `SECRETS_BLOB` + `PROJECT_KEY` stored in GitHub are long-lived, so revoke the token server-side to cut them off:

```bash theme={null}
capy deploy revoke <deploy-id>
```

Once revoked, the GitHub-stored blob is inert - new builds and cold starts can no longer decrypt. (Already-running processes that have reconstructed the key keep working until they recycle; see [Deploying → Revocation](/using/deploying#revocation).) The secrets stay in GitHub until you delete them; revoking just makes them useless.
