---
title: "Connect your security and ticket tools"
description: "Push assure evidence to your GRC tool, run privacy requests from Transcend or OneTrust, send SBOM and VEX to your vulnerability tool, and open one ticket per failure."
section: "guides"
status: "Building for 1.2"
spec: "connectors"
canonical: "https://mainsdk.dev/docs/guides/use-connectors"
updated: "2026-10-28"
---

# Connect your security and ticket tools

> Push assure evidence to your GRC tool, run privacy requests from Transcend or OneTrust, send SBOM and VEX to your vulnerability tool, and open one ticket per failure.

Status: Building for 1.2 · Canonical: https://mainsdk.dev/docs/guides/use-connectors · Updated: 2026-10-28

You will send MainSDK's evidence to the tools your security team uses: control results to ServiceNow IRM, one GitHub issue per failure, and the SBOM and VEX to Dependency-Track. It takes about 30 minutes.

> **Note:** `connectors` is beta (spec `connectors`) and runs from the repository; it is not published to npm. The `assure` engine that produces runs is not built yet, so you supply the run.

## You need

- A MainSDK app with `secrets`, and an `assure` run to push (a `standard` and a list of control results).
- A token for each tool, stored as a secret.

## 1. Declare the connectors

```yaml title="main.yaml"
connectors:
  grc:     { driver: servicenow-irm, instance: https://acme.service-now.com, auth: secret:SN_TOKEN }
  vulns:   { driver: dependency-track, url: https://dt.acme.internal, auth: secret:DT_KEY }
  tickets: { driver: github, repo: acme/web, auth: secret:GH_TOKEN }
```

Always write `auth: secret:NAME`. A literal token fails `mainsdk check`.

## 2. Test them without writing

```text
mainsdk connectors test
```

Each connector is pinged and nothing is written.

## 3. Push a run

```ts
import { app } from "mainsdk";
import {
  type AssureRun,
  type ConnectorsConfig,
  connectorsFrom,
  httpOver,
  pushAssure,
  syncTickets,
} from "mainsdk/connectors";

const a = app();
const c = connectorsFrom(a.config.connectors as ConnectorsConfig, {
  http: httpOver(fetch),
  secrets: (name) => a.secrets.get(name),
  log: (entry) => a.log.info("connector call", { ...entry }),
});

export async function push(run: AssureRun) {
  if (c.grc) await pushAssure(c.grc, run);
  if (c.tickets) await syncTickets(c.tickets, run, { owner: "web-team" });
}
```

Running it twice opens each issue once. Pass `previous` (the controls that failed last time) so a fixed control closes its issue.

## 4. Send a release

```ts
import type { Connector, VexStatement } from "mainsdk/connectors";
import { importFindings, pushRelease } from "mainsdk/connectors";

export async function send(vulns: Connector, sbom: Record<string, unknown>, vex: VexStatement[]) {
  await pushRelease(vulns, { app: "web", release: "1.4.0", sbom, vex });
  return importFindings(vulns, "1.4.0");
}
```

A CVE the VEX marks `not_affected` comes back suppressed, with its justification.

## Check it worked

- `pnpm mainsdk check` passes with no `MAIN-SECRET-0002` or `MAIN-CONNECTOR-0001` finding.
- `mainsdk connectors test` reports each connector `ok`.
- The audit log has one line per call, and none holds a token.

## If it fails

- `MAIN-SECRET-0002`: `auth` is a literal. Move the token to secrets and write `secret:NAME`.
- `MAIN-CONNECTOR-0001`: the driver is not one of the listed ones, or the address is not https.
- `MAIN-CONNECTOR-0002`: the tool refused a call. The audit line names the operation and status.

## Prompt for your coding agent

> Wire my app's assure results into our tools with MainSDK's `connectors` interface. Push control results to ServiceNow IRM, open one GitHub issue per failure that closes when fixed, send the SBOM and VEX to Dependency-Track, and keep every token in secrets.
