Under Settings → DevOps you connect your CI/CD providers to FixControl. Once connected, FixControl receives that host's deployment and pipeline events, verifies their signature, scores each one for risk through the policy engine, and writes a hash-chained, append-only log (protected against edits in the database).
Observe-and-govern by default. For most providers FixControl scores and logs your deployments — it does not trigger or roll anything back on its own. Where configured — each off by default, per organisation — three execution paths exist, and every one of them runs only after a recorded human decision: Argo Rollouts promotion (an approved gate promotes a paused rollout), CI/CD deployment gates (pilot — an approved gate releases a deployment your pipeline paused itself; a rejection leaves it held), and a governed workload restart (a monitoring or deployment event that policy scores as approval-required opens an approval bound to one exact workload; approving restarts that workload, and nothing happens without the approval). There is no autonomous deploy: FixControl never starts a pipeline or a deployment, nothing is released through FixControl without a recorded human decision, and each executed verdict is audited.
Only admins of your organization can manage this page, and everything on it is scoped to your organization.
How a connection works
A connection is the binding between one CI/CD host and your tenant. Each connection has a kind that determines how it authenticates and how its webhooks are verified:
| Kind | Example | How you connect |
|---|---|---|
| GitHub App | GitHub Actions | Install the FixControl GitHub App — verified by an App-level secret, no per-tenant secret to copy. |
| OAuth app | GitLab CI | Connect over OAuth (reuses your existing GitLab connection) + project ID. |
| Manual | Jenkins, Azure DevOps, Argo CD, Vercel, Terraform Cloud, Kubernetes | FixControl mints a webhook secret shown once; you set it on the host's webhook. |
All eight providers are available for observe-and-govern. Each connection shows its live status:
not connected → connecting → connected → degraded → invalid credentials → revoked
- Degraded — connected, but the last event errored (transient).
- Invalid credentials — a permanent auth failure (token revoked / app uninstalled).
- Revoked — you disconnected it; webhooks are refused and stored credentials cleared.
The providers
| Provider | Kind | Webhook verification | How you connect |
|---|---|---|---|
| GitHub Actions | GitHub App | HMAC-SHA256, App-level secret | Install the GitHub App |
| GitLab CI | OAuth | Shared token (X-Gitlab-Token) | Connect GitLab (OAuth) + project ID |
| Jenkins | Manual (legacy) | HMAC-SHA256 (X-FixControl-Signature) | Manual + Notification webhook |
| Azure DevOps | Manual | HTTP Basic auth (password = secret) | Manual + Service Hook |
| Argo CD | Manual | Bearer token (Authorization: Bearer) | Manual + notifications webhook |
| Vercel | Manual | HMAC-SHA1 (x-vercel-signature) | Manual + Vercel webhook |
| Terraform Cloud | Manual | HMAC-SHA512 (X-TFE-Notification-Signature) | Manual + Run notification |
| Kubernetes | Manual | HMAC-SHA256 + X-FixControl-Account (cluster ID) | Manual + rollout forwarder |
Connecting a provider
The shape is the same for every provider:
- Open Settings → DevOps and pick the provider.
- GitHub: click Install GitHub App. GitLab: click Connect GitLab and enter the numeric project ID. Manual: enter the instance/job identifier (and optionally an API token).
- For a manual (or GitLab) connection, FixControl shows a webhook secret — copy it now, it's shown only once.
- Paste the webhook URL (shown on the card) into the host's webhook settings, and set the secret in the right field/header (the card gives the exact per-provider hint).
- Run a real pipeline or deploy. The connection lists recent governed runs as soon as the first one arrives.
If the card shows no webhook URL, ask your FixControl contact. Without a webhook URL, a host can't reach FixControl.
Example: GitLab CI
- In FixControl → Settings → DevOps → Connect GitLab, enter the project ID. Copy the shown secret.
- In the GitLab project → Settings → Webhooks: add the webhook URL, paste the secret as Secret token, and enable Pipeline events, Deployment events and Merge request events. Merge request events keep the delivery state of FixControl's merge requests up to date (see Git providers); there is no second webhook to create.
Outbound webhooks — FixControl pushing its own events to your systems — are a different surface and live under Settings → Channels → Webhooks & API → Outbound webhooks. See Webhooks.
Example: Jenkins (legacy)
Jenkins has no signed-webhook standard, so FixControl verifies an HMAC you configure on a Notification webhook yourself. Prefer GitHub or GitLab where available. If you do use Jenkins: fill the Jenkins form, copy the secret, and have Jenkins POST the build JSON with the header X-FixControl-Signature: sha256=<HMAC of the body>.
The exact steps for the remaining providers (Azure DevOps, Argo CD, Vercel, Terraform Cloud, Kubernetes) follow the same pattern: connect manually, copy the one-time secret, and wire the host's webhook to the shown URL with the header from the card hint. If you need deeper setup help for a specific host, ask your FixControl contact.
CI/CD deployment gates (pilot)
Where configured, a pause your pipeline is already holding opens a FixControl deployment gate. What a gate may do is set by an admin of your organization under Settings → AI & approvals → Approvals → Deployment capabilities. Every capability there is off by default:
- Open gates for your own deployments — open a gate for a deploy that has no FixControl-authored change behind it. This only records a decision; it writes nothing.
- Carry the verdict back to the CI/CD host — let an approve or reject reach the pipeline holding the pause (GitHub Actions, GitLab CI or Jenkins).
- Promote a paused Argo Rollout — let an approve promote the next step of a paused rollout.
- Hand the verdict to an fc-agent in your cluster — publish the verdict for your own agent to fetch, instead of FixControl calling into your network.
With gates open but nothing armed to write, FixControl is observe-only: decisions are recorded, and no verdict leaves FixControl. Arming a capability asks for a reason, which is recorded in the audit trail.
Once armed, this is what each host's pause becomes:
| Host | The pause | Approve executes | Reject |
|---|---|---|---|
| GitHub Actions | An environment protected by required reviewers | The environment review is answered as approved | The review is answered as rejected; the run stays held |
| GitLab CI | A deployment approval, or a when: manual deploy job | The approval is granted, or the manual job is played | A deployment approval is answered as rejected; for a manual job nothing is written — the unplayed job is the enforced refusal (see Honest limits) |
| Jenkins | An input step | The input is proceeded | The input is aborted; the build ends visibly |
The mechanics, plainly:
- Your pipeline reaches the pause it already had. FixControl did not start the pipeline and cannot start one.
- The host's webhook event reaches FixControl, which opens a deployment gate — an approval with the run, the environment and the risk context attached.
- Someone on your team decides. The decision is recorded with actor, role, channel and evidence.
- The verdict is carried out through the host's own primitive (the table above) — never through a side channel. On failure it retries from the delivery queue and surfaces on the timeline; it does not fail invisibly.
- Gates open only on a pause the host reports. Providers without a pause primitive stay observe-only.
Self-hosted and private hosts. A self-hosted GitLab or Jenkins that is reachable from FixControl connects with its base_url. A host that is not publicly reachable connects through the [FC Agent](/docs/en/admin/fc-agent): the verdict then travels as a signed, expiring, single-use operation that the agent fetches outbound and executes from inside your network. The agent carries the verdict back; the pipeline event still reaches FixControl through the host's own signed webhook, so the CI host itself needs outbound HTTPS to FixControl (or a proxy that does). Kubernetes, Argo, Jenkins and GitLab do not need to be exposed publicly to FixControl.
Honest limits. A GitLab deployment held by a manual job has no rejection primitive — the fork is by lane, not by GitLab edition. A reject writes nothing to GitLab: the job stays unplayed, and that unplayed job is the refusal taking effect. FixControl records the decision with a message saying exactly that. Deployment approvals, where your GitLab tier offers them, do carry a real rejection. GitHub Actions gate execution requires a user-attributed GitHub credential (a GitHub App cannot act as a reviewer).
What your pipeline said about the delivered commit
An approval gate in FixControl already carries the sandbox verdict. What it did not carry is your own pipeline's opinion of the same commit — and those two can legitimately disagree. FixControl's sandbox proves the change in an isolated environment; your pipeline runs it under your organisation's own build, with your own steps.
So when a CI run for a commit that FixControl delivered finishes, FixControl captures what that run did and freezes it alongside the sandbox verdict on the approval.
What is captured, within fixed caps and nothing beyond them:
- the run itself — provider, id, link, outcome, the commit it was about, and when the capture was taken;
- its jobs (up to 20, failed ones first): name, outcome, the host's own word for that outcome, timings, link;
- a short log tail for failed jobs only — the last few kilobytes, masked for secrets before it is stored, for at most three jobs;
- a test summary where the provider has one (GitLab's test report, or JUnit XML). GitHub Actions does not parse test results, and FixControl does not download artifacts to find them, so a GitHub capture has no test summary rather than a guessed one;
- artifact metadata only — name, size, digest, expiry. Artifacts are never downloaded.
Everything is capped and the capture says when it was capped: how many jobs, artifacts, failed tests and logs were left out. A bounded record that admits its bounds is evidence; one that looks complete is not.
How it is captured. Nothing polls. A finished run arrives on the webhook you already configured, and a job does the capture once per commit and run — at most once, even if the webhook is delivered twice. A capture that fails never turns a webhook non-2xx and never changes a verdict.
What does not happen:
- A cancelled run produces no evidence at all. "Cancelled" is not a verdict about the code, and recording it as one would invite reading a cancellation as a pass.
- It changes nothing. No gate reads it, no verdict moves because of it, and an approval is neither granted nor blocked by it. It is captured, frozen into the decision record, and available afterwards.
- Two providers do it. GitHub Actions and GitLab CI. Jenkins, Azure DevOps, Argo CD, Vercel, Terraform Cloud and the Kubernetes connection capture nothing today — connected, but silent on this.
Today the capture is readable through the patch's CI status and is frozen into the decision record; it does not yet have a panel of its own on the approval screen.
Terraform Cloud pauses are not turned into a gate
Terraform Cloud declares a human-approval pause like GitHub Actions, GitLab CI, Jenkins and Argo Rollouts do — but unlike them, FixControl has no way to answer it. The connection is webhook-in only: it carries a signature-verification secret, not an API credential, so there is nothing to dial and nothing to report back.
So FixControl deliberately does not open an approval gate on a Terraform Cloud pause. A gate would have let someone approve a terraform apply, recorded that approval, and left the run sitting there waiting for a confirmation that was never sent. An approval that does nothing while looking like it did something is worse than no approval. Terraform Cloud events are still ingested, scored and logged like every other provider's; they simply do not produce a decision FixControl cannot honour.
If a way to carry a verdict back to Terraform Cloud is added later, gates start opening on their own — the rule is written against "is there a path to answer this?", not against the provider's name.
What you see after connecting
- On the connection card: the connected account, scopes, webhook health (last event, count, last error), and the Rotate secret and Disconnect actions.
- Under Operations (AI operations governance): governed CI/CD activity, the risk distribution, the infrastructure risk heatmap, and the approval queue. Each event gets an outcome — Auto, Draft only, Approval required, or Blocked — according to your policy.
Security
- Encrypted at rest — tokens and webhook secrets are stored encrypted (per-tenant key envelope). The API exposes only booleans (has secret yes/no); a freshly minted secret is shown exactly once.
- Signature-first — the webhook route refuses any payload that doesn't verify (
401) and audits it as a rejected event. - Tenant isolation — every table is fail-closed RLS; inbound webhooks resolve the tenant safely before anything is written.
- Admin-only — connect, disconnect, and rotate secret require
settings.edit. - Audit trail — connect, disconnect, secret rotation, and every accepted and rejected event are hash-chained and append-only, kept for the audit retention window (365 days on the hosted service, never less than 90 — the window is platform-wide, not per organisation).
- No autonomous execution — ingestion on its own never triggers an outbound action; what it can do is open a gate a human then decides. The three execution paths — Argo Rollouts promotion, CI/CD deployment gates and the governed workload restart, each where configured and each off by default — run solely after that decision, and every executed verdict is hash-chained into the audit trail.
Roadmap
Human-approved Argo Rollouts promotion and CI/CD deployment gates (GitHub Actions, GitLab, Jenkins — pilot) are live where configured. A governed workload restart is available the same way, off by default, and needs an Argo Rollouts capability on the Kubernetes connection plus the project permission infrastructure.workload.restart. If your organisation runs CI/CD without FixControl missions behind the deployments, switch on Open gates for your own deployments under Deployment capabilities — otherwise every gate is skipped for want of a mission to attach to. Extending gate coverage to more providers, and richer rollout controls, follow the pilot programme. Deployment execution beyond a verdict on an existing pause does not exist and is not planned as autonomous behavior — FixControl does not start, create or roll back deployments. See Governance & policy for how events are scored for risk.
See also: Integrations overview · Governance & policy · Security & audit.