Skip to content

CI Gate

The Forgecroft gate is a GitHub Actions composite action (forgecroft/forgecroft) that evaluates a PR against your organization’s Controls before it merges. On each pull request, the action downloads the forgecroft-gate binary, computes the diff between the PR base and head SHAs (git diff BASE..HEAD), and POSTs it to the Forgecroft API at POST /evaluate with kind=pr_diff. The call is deterministic — no LLM inference, no variable cost, sub-second latency. The gate posts a sticky PR comment with the verdict (go / conditional_go / no_go / insufficient_context) and exits non-zero only on a no_go verdict or a blocker-severity finding. Forgecroft being unavailable is fail-open by default.

  • A Forgecroft API key with evaluate:read scope, stored as a repository or organization secret named FORGECROFT_API_KEY. The key is passed via environment variable only — never echoed to logs, never placed in command arguments.
  • A published v* release of forgecroft/forgecroft. The action downloads the forgecroft-gate binary from GitHub Releases; until at least one release tag exists, the download step fails open (PRs are not blocked, but no gate verdict is posted).

Drop the following workflow file into your repository at .github/workflows/forgecroft-gate.yml.

name: Forgecroft Gate
on:
pull_request:
branches:
- main # Adjust to your default branch name if different
permissions:
contents: read
pull-requests: write # Required for the sticky PR comment
jobs:
forgecroft-gate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# fetch-depth: 0 is required — the gate computes a git diff between
# the PR base SHA and head SHA. A shallow clone (depth 1) will not
# have the base commit present and the diff will fail.
fetch-depth: 0
- name: Run Forgecroft gate
# Pin both the action ref and binary version to the same release tag.
uses: forgecroft/forgecroft@v0.1.0
with:
api-key: ${{ secrets.FORGECROFT_API_KEY }}
version: "v0.1.0"
github-token: ${{ github.token }}
# api-url: "https://api.forgecroft.com" # omit to use the default
# strict: "false" # set to "true" to hard-fail on infra errors

The pull-requests: write permission is required for the sticky PR comment step. If you omit github-token, the comment step is skipped — the gate still runs and fails on no_go; the verdict appears in the GitHub Actions step summary.

The gate reads an optional .forgecroft file from your repository root. It is a simple key = value file; every key is optional and absent keys fall back to the default. The API key is never stored here — it lives in a CI secret or environment variable.

# .forgecroft — all keys optional; shown with their defaults
# api_url = https://api.forgecroft.com # Forgecroft API base URL
# key_env = FORGECROFT_API_KEY # env var / CI secret holding the API key
# mode = block # block (default) or warn (non-blocking)
# severity_floor = blocker # blocker (default) or concern

Commit this file alongside the workflow to change api_url, key_env, mode, or severity_floor without editing the workflow itself.

By default (strict: 'false'), the gate never blocks CI for infrastructure reasons:

Conditionstrict: falsestrict: true
Unsupported OS or architecturepasses (gate skipped)hard failure
Binary or checksums.txt download failspasses (gate skipped)hard failure
FORGECROFT_API_KEY absent or API unreachablepasses (gate skipped)hard failure
cosign not installed or .sig/.pem not downloadableproceeds on sha256 onlyhard failure
cosign verify-blob returns non-zero (mismatch or tamper)hard failure alwayshard failure always
sha256 checksum mismatchpasses (gate skipped)hard failure
Empty diff (no changes between base and head)passespasses
no_go verdict or blocker-severity findingthe gate blocksthe gate blocks
go, conditional_go, or insufficient_context verdictpassespasses

A cosign verify-blob failure — where cosign is available, both signature artifacts downloaded successfully, and the signature does not match — is always fatal regardless of strict. It indicates a tampered or substituted binary and the gate is never run.

Warn mode: Set mode = warn in your .forgecroft file to have the gate report its verdict without failing the build. In warn mode, the gate exits success even on no_go or blocker findings. This is useful during onboarding to observe verdicts before enforcing them.

The gate runs inside your GitHub Actions runner. It sends a JSON payload containing only the unified diff of your PR to the Forgecroft API over TLS:

{"kind": "pr_diff", "diff": "<unified diff text>"}

Your full repository source tree, build artifacts, and environment variables never leave your runner.

Honest caveat: A diff line can contain a secret if your change adds or modifies a file that contains one — the same risk as any CI scanner (CodeQL, Semgrep, truffleHog) that inspects diffs. The gate does not mitigate accidental secret commits; use a dedicated secret-scanning tool for that.

Pass --offline to evaluate your diff against the embedded best-practice packs with no network call and no API key. The diff never leaves your runner — not even to the Forgecroft API — making this suitable for air-gapped environments, pre-flight checks before you configure an API key, or local runs before opening a pull request.

When the gate runs offline, the step summary and PR comment include this notice:

OFFLINE MODE — evaluated against the embedded best-practice packs only; no org Controls, Exceptions, or blast radius were consulted.

An offline go verdict is not equivalent to a hosted go. It means your diff passed the generic pack rules — not that it passed your organization’s Controls. A change that is go offline can still be blocked by a Control in hosted mode. Org-specific Controls, Exception waivers, and blast-radius scoring all require the hosted path.

Capability--offlineHosted (default)
Diff leaves your runnerNo — fully localDiff only (to the Forgecroft API)
API key requiredNoYes
Embedded best-practice packsYesYes
Org Controls evaluatedNoYes
Exception waivers appliedNo (stricter — no waivers)Yes (active, non-expired Exceptions)
Blast-radius scoringNoYes
Verdict thresholdsIdentical to hostedIdentical to offline
OFFLINE MODE banner in summaryYesNo

Offline mode covers the embedded pack rules only. It does not replace a hosted evaluation against your org’s Controls.

The following table lists all inputs accepted by the forgecroft/forgecroft action. For the authoritative definition, see action.yml in the Forgecroft repository.

InputRequiredDefaultDescription
api-keyyesForgecroft API key. Pass via ${{ secrets.FORGECROFT_API_KEY }}. Never echoed or placed in command arguments.
versionyesRelease tag of the forgecroft-gate binary to download (e.g. v0.1.0). Must match a published release.
api-urlnohttps://api.forgecroft.comOverride the API base URL. Omit to use the default.
strictnofalseWhen true, treat Forgecroft being unavailable (download failure, network error, missing key) as a hard failure instead of fail-open.
github-tokenno''GitHub token for posting the sticky PR comment (pull-requests: write required on the calling workflow). Pass ${{ github.token }}. When absent, the comment step is skipped.

Seeding your system map for richer blast-radius

Section titled “Seeding your system map for richer blast-radius”

First verdicts are instant — the gate runs the moment the action is wired up. Because your system map has not yet been seeded, Forgecroft reports an honest empty blast-radius via coverage notes (import_graph_not_built / no_components_resolved_for_diff). Controls still match and gate. That is the under-10-minute milestone.

For richer blast-radius reflecting your real code structure, seed your system map:

  1. Derive — walk your source tree locally to produce a seed_proposals.json artifact. The derivation runs client-side (no LLM, no network); your source tree stays in your CI runner.
  2. Import — submit the artifact via POST /proposals/import with a codebases:write-scoped key.
  3. Approve — review and approve the pending proposals in the Console or via POST /proposals/{id}/decision. Approval is org-admin-gated. Once approved and applied, the gate’s blast-radius reflects your real import graph.

For the full step-by-step guide including tooling, key scopes, and bulk-approve notes, contact your Forgecroft onboarding contact or reach out via the in-app chat.

  • CI Usage — gating with the forgecroft-gate command from any CI system
  • Coding Agents — in-loop MCP self-correction for autonomous agents
  • API Keys — creating and scoping API keys
  • action.yml — authoritative inputs definition