# Wiring solforge into GitHub Actions

This recipe shows how to integrate `solforge` into a GitHub Actions workflow that runs on every pull request. The recipe assumes a repository structure with the program source under `programs/<name>/`, the IDL emitted to `target/idl/<name>.json` by an Anchor build step, and an existing CI workflow that performs that build.

The goal is to add three checks to the workflow: a fork that warms the cache, a security scan whose failure threshold matches the project's policy, and a fuzz run scoped tight enough to fit in a CI minute budget.

## A minimal workflow

```yaml
name: solforge

on:
  pull_request:
    branches: [main]

jobs:
  solforge:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with: { node-version: 20 }

      - name: Install solforge
        run: npm i -g solanatestforge

      - name: Build IDL
        run: anchor build

      - name: Fork devnet
        run: solforge fork devnet ${{ vars.PROGRAM_ID }}

      - name: Security scan
        run: solforge security ${{ vars.PROGRAM_ID }}

      - name: Fuzz
        run: solforge fuzz ${{ vars.PROGRAM_ID }} --iterations 200
```

## Notes on each step

The fork step is intentionally first. It both validates that the configured RPC is reachable and writes a snapshot that subsequent steps reuse. If the fork step fails, the run terminates without consuming a fuzz budget.

The security step exits non-zero if any finding meets or exceeds the failure threshold configured in `.solforge.toml`. If the project does not yet have a `.solforge.toml`, the default threshold is `high`; the recommendation in the configuration reference applies here as well — pin a threshold explicitly so that a future framework default change does not silently widen the gate.

The fuzz step caps `--iterations` at 200, which is far below the default of 1000. This is a CI-specific compromise: 200 iterations is enough to catch a regression in roughly 80% of the cases the engine handles, while staying inside a one-minute step on the GitHub-hosted runner. Local development should not lower the iteration count.

## Caching the snapshot

The recipe above re-fetches the snapshot on every run. If the program is large or the RPC is slow, caching is appropriate:

```yaml
      - uses: actions/cache@v4
        with:
          path: .solforge/snapshots
          key: solforge-${{ vars.PROGRAM_ID }}-${{ hashFiles('target/idl/*.json') }}
```

The cache key incorporates the IDL hash so that an IDL change forces a fresh fork. This trade-off is the right default for most projects: snapshots are cheap to store and cheap to invalidate, and a stale snapshot will produce a misleading report that is hard to debug.

## Choosing an RPC

The public devnet endpoint is rate-limited. For repositories that run on every pull request, a paid RPC endpoint (Helius, QuickNode, Triton) is recommended. The endpoint is configured in `.solforge.toml`:

```toml
[rpc]
devnet = "https://devnet.helius-rpc.com/?api-key=…"
```

The API key should be stored as a repository secret and injected at runtime; do not commit the URL with the key inline.

## When this recipe stops being enough

Two situations call for more than the workflow above. First, if the fuzz engine produces an interesting run that needs to be reproduced, follow [Reproducing mainnet bugs locally](/solanatestforge-docs/part-iii-recipes/reproducing-mainnet-bugs.md) — the fuzz output emits a seed and a reproducer that fit naturally into a regression test. Second, if the security catalogue is missing a rule that the project's threat model requires, follow [Authoring a custom security check](/solanatestforge-docs/part-iii-recipes/authoring-custom-checks.md) — a custom rule lives next to the program source and is evaluated on every run.


---

# Agent Instructions: 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:

```
GET https://solanatestforge.gitbook.io/solanatestforge-docs/part-iii-recipes/github-actions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
