Integrating Unveilr within your company
This page is the practical adoption guide: how to wire Unveilr into your developers' workflow, your CI/CD, your pull requests, your cloud, your agents, and your security team's console — starting non-invasively and expanding as you gain confidence.
Integration experience goals: one-line install, observe-first CI, tenant-bound service-token auth, SARIF/CycloneDX interop, and a Gateway URL change for agents — not a rip-and-replace of your SDLC.
For the developer-facing contract, also read Developer experience and Why Unveilr.
A good rollout order:
- Developers & CI in Monitor Mode (observe) — zero risk, immediate visibility.
- Connect repos to the console — build the org-wide AI-BOM.
- PR checks — catch AI risk on the way in.
- Enforce on your highest-value repos.
- Agent Gateway — govern autonomous agents (Govern).
- Compliance attestation — Prove for auditors (Prove).
Console path: /onboarding
Capture: checklist used during partner / internal rollout.
See also: Screenshot guide.
1. Developer workflow (IDE & terminal)
Developers run the CLI locally — including inside AI IDEs like Cursor (it's just a terminal command). Nothing leaves their machine.
unveilr scan # scan the working tree
unveilr scan --json # for editor integrations / scripts
VS Code extension (apps/vscode-extension): surfaces findings inline in
the Problems panel — it runs unveilr scan --json and renders diagnostics
(severity-mapped, optional scan-on-save). Works in any VS Code-based editor
(incl. Cursor). Point unveilr.cliPath at the binary if it's not on PATH.
Where: Cursor / VS Code Problems panel with Unveilr diagnostics.
Filename: ide-problems.png
A pre-commit hook (optional):
# .pre-commit-config.yaml
- repo: local
hooks:
- id: unveilr
name: Unveilr AI-SDLC scan
entry: unveilr scan --mode enforce --fail-on critical
language: system
pass_filenames: false
2. CI/CD
Add the scan to any pipeline. Start in observe (never fails the build), then switch to enforce when ready.
GitHub Actions (recommended: the Unveilr Action)
The unveilr/scan-action runs the scan and posts findings inline on the PR
diff (via GitHub code scanning), with a Monitor-Mode gate you control:
name: Unveilr AI-SDLC
on: [pull_request]
permissions:
contents: read
security-events: write # required for inline SARIF annotations
jobs:
unveilr:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: unveilr/scan-action@v1
with:
mode: observe # never fails the build; switch to 'enforce' to gate
fail-on: high
Findings appear as annotations on the changed lines and in the Security → Code
scanning tab. Add upload: "true" (with api + a token secret) to also
stream results into your console. Full inputs: apps/scan-action/README.md.
Where: PR Files / Checks with Unveilr SARIF annotation; optional Actions run.
Filenames: pr-annotations.png, scan-action-yaml.png
GitHub Actions (raw CLI)
If you prefer not to use the Action, or want SARIF for another consumer:
name: unveilr
on: [push, pull_request]
jobs:
ai-sdlc-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Prefer unveilr/scan-action. Raw CLI: use the partner binary or operator CDN —
# get.unveilr.ai resolves only after the GA cut (see Installation).
- run: unveilr scan --mode enforce --fail-on high --sarif unveilr.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: unveilr.sarif }
unveilr scan --sarif FILE writes a SARIF 2.1.0 report — upload it to GitHub
code scanning (above), or feed it to any SARIF consumer. Prefer
unveilr/scan-action so jobs do not depend on a CDN host that is not live yet.
GitLab CI
Prefer installing a checksummed partner binary in the job image, or wait for the
GA CDN. Until get.unveilr.ai is live:
unveilr:
image: alpine
script:
- apk add --no-cache bash
# Place `unveilr` on PATH via your artifact store / partner binary.
- unveilr scan --mode enforce --fail-on high
Jenkins / generic
# Partner binary or operator CDN — get.unveilr.ai after GA only
unveilr scan --mode enforce --fail-on high # exit code gates the stage
Upload from CI (optional)
To feed CI results into the console, authenticate non-interactively with a service token and upload (see Production APIs and Authentication):
unveilr login --token "$UNVEILR_TOKEN" --api https://guard.unveilr.ai
unveilr scan --upload
Mint the token once in the console — Settings → API Tokens
(/settings/tokens) — and store it as a CI secret (UNVEILR_TOKEN). It's shown
in full only at creation; the console keeps just a hash. Tokens are
tenant-scoped, can be given an expiry, and are revocable at any time (a revoked
token is rejected immediately). A service token can upload scans but cannot
mint or revoke other tokens, so a leaked CI secret can't escalate.
Console path: /settings/tokens — never photograph a live secret value.
Filename: tokens.png
Via the API:
curl -X POST https://your-instance/v1/tokens \
-H "authorization: Bearer $ADMIN_TOKEN" -H 'content-type: application/json' \
-d '{"name":"github-actions","expiresInDays":90}' # → { "token": "uvt_…" } (once)
Ingest findings from other scanners
You already run tools — Semgrep, CodeQL, garak, and more. Unveilr can ingest their reports and treat those findings as first-class: they get the same blast-radius scoring, tamper-evident evidence, notifications, and compliance mapping as native scans. Unveilr becomes the governed control plane over your AI-security toolchain, not one more scanner competing with them.
Point a report at POST /v1/repos/{repoId}/ingest with a source:
# SARIF — Semgrep, CodeQL, claude-code-security-review, any SAST
semgrep --sarif --output out.sarif .
curl -X POST https://your-instance/v1/repos/$REPO_ID/ingest \
-H "authorization: Bearer $UNVEILR_TOKEN" -H 'content-type: application/json' \
-d "$(jq -Rs '{source:"sarif", report:.}' out.sarif)"
# garak — LLM red-teaming (jailbreaks, prompt injection, leakage)
curl -X POST https://your-instance/v1/repos/$REPO_ID/ingest \
-H "authorization: Bearer $UNVEILR_TOKEN" -H 'content-type: application/json' \
-d "$(jq -Rs '{source:"garak", report:.}' garak.report.jsonl)"
- Supported sources today:
sarif(the OASIS standard — one adapter covers a whole class of SAST tools) andgarak. Adding a feeder is one small adapter. - Additive & idempotent: ingesting is de-duplicated by fingerprint and never auto-resolves your native scanners' findings.
- Console: paste a report on a repo's page (Repositories → a repo → Ingest scanner report).
3. Pull-request checks
Judge a PR on the risk it introduces (added lines only).
Locally / in CI:
git fetch origin
git diff origin/$GITHUB_BASE_REF...HEAD > pr.diff
unveilr scan --diff pr.diff --mode enforce --fail-on high
Server-side (GitHub App): the API exposes a PR-check endpoint that returns a GitHub check-run conclusion + inline annotations, honoring Monitor Mode:
curl -X POST https://your-instance/v1/repos/$REPO_ID/pr-check \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"diff": "<unified diff>", "mode": "observe", "failOn": "high"}'
A GitHub App wires this to pull_request events and posts the result to the
Checks API. In observe, the check never fails — it posts advisory annotations.
Production GitHub App readiness
The console exposes Install GitHub App only after a fail-closed readiness
check succeeds. The API requires a numeric App ID, exact public slug, App client
ID and secret, strong webhook secret, and valid RSA private key, then authenticates to GitHub's
GET /app endpoint and confirms that the returned ID and slug match. Empty,
placeholder, partial, mismatched, or rejected credentials keep installation
disabled; no speculative install URL is returned.
The installation setup URL starts a PKCE-protected GitHub authorization and
verifies that the user can access the returned installation before binding it
to a workspace. This follows GitHub's warning that the setup
installation_id must not be trusted by itself.
The temporary user token is revoked immediately and never stored. Repositories
selected in the GitHub installation are registered in the workspace
automatically and private scans mint a fresh installation token; the platform
never falls back to a shared personal access token.
Platform super-admins create the global App from Settings → GitHub App. The console posts a least-privilege manifest directly to GitHub. Its short-lived, signed callback exchanges GitHub's one-time code for the App ID, PEM, webhook secret, and OAuth credentials, validates the owner and complete six-value set, stores it directly in the durable secret manager entry, and rolls only the API service. Credentials are never entered in or returned to the browser. Customer workspaces only install the resulting App. GitHub Actions and CLI upload remain independent integration paths, not demo substitutes.
Required App permissions (exact set the platform verifies):
| Permission | Level | Why |
|---|---|---|
| Checks | write | PR check runs / annotations |
| Contents | write | Branches + commits for fix PRs |
| Pull requests | write | Open remediation PRs |
| Metadata | read | Repository metadata |
If you raise permissions on the App after install, open the installation on
GitHub and Accept the update — otherwise clone may work while
Open fix PR returns 403 Forbidden.
The AWS deployment keeps this secret outside the disposable Terraform stack and the stack KMS key. After a legacy teardown that already deleted credentials for an existing App, generate a new private key and client secret and use the secure recovery wiring command; manifest creation cannot adopt an App that already exists. If the database was also recreated, use Add or update GitHub access in each affected workspace to rebind its existing installation.
Private clone failures
The scan API reports the failed layer without exposing credentials:
| Message | Action |
|---|---|
| GitHub App authentication is unavailable on this platform | Configure all six App values and roll the API service. |
| Private repository is not connected to this workspace | Install the App for that GitHub owner. |
| Connected App cannot access this repository | Add the repository to the existing installation or correct its URL. |
| Installation could not authenticate | Verify the App ID/private key pair; reinstall if the installation was removed. |
There is no shared personal-access-token fallback for GitHub. Each scan mints a short-lived token for the matching workspace installation and checks repository access before cloning.
4. The console (security team)
The console is where AppSec, platform, and the CISO work — mapped to the four pillars:
| Pillar | Console surfaces |
|---|---|
| Discover | Overview /, AI Inventory /inventory, Repos /repos, Identity Graph /identity, Agents /agents |
| Guard | Code Findings /findings, Remediation /remediation |
| Govern | Registry /registry, Policies /policies, Approvals /approvals, Sessions /sessions, Detections /detections |
| Prove | Compliance /compliance, Evidence /evidence |
| Ops | Notifications, Integrations (Jira/ServiceNow), API Tokens, SSO/SCIM, Identity Providers, GitHub App (platform) under /settings/* |
- Connect a repository: Repositories → Install GitHub App (or
unveilr scan --upload). - AI Inventory: org-wide Shadow-AI rollup — assets by kind, providers, shadow count. Export CycloneDX 1.6 ML-BOM per repo or org-wide for Dependency-Track / procurement. Promote to registry for discovered MCP servers.
- Findings: filter, triage, ignore, reopen; blast-radius sort; Open fix PR when the App installation has contents/PR write accepted.
- Agents / Registry / Policies: ownership, tool approval (incl. policy bulk approve), runtime rules; enterprise IdP bind on agent detail (Okta / Entra / OIDC).
- Evidence: verify the chain, export the audit trail.
- Compliance: coverage against 11 frameworks with human attestation per control — see Prove.
- Operator walkthrough: Console operators.
Capture at least: overview.png, inventory.png, findings.png, agents.png,
compliance.png, evidence.png. Full list: Screenshot guide.
AI-BOM as CycloneDX (interop)
The AI inventory is exportable as an OWASP CycloneDX 1.6 ML-BOM via the API:
curl -H "authorization: Bearer $UNVEILR_TOKEN" \
https://your-instance/v1/repos/$REPO_ID/aibom/cyclonedx # per repo
curl -H "authorization: Bearer $UNVEILR_TOKEN" \
https://your-instance/v1/aibom/cyclonedx # org-wide
Model refs map to machine-learning-model components, dependencies to library,
prompts to data, and agents/tools/MCP servers/AI services to application —
each annotated with unveilr:* properties (kind, status, path, provider).
Sign-in (SSO)
The console authenticates via your identity provider (WorkOS AuthKit → Okta, Entra ID, Google), with SCIM provisioning. Missing identity configuration fails closed; no local tenant is invented. See Self-hosting.
Agent identity (separate from console SSO)
Console SSO proves operators. Agent runtimes use a different credential
path: configure the agent's Okta/Entra/OIDC issuer under Settings → Identity
Providers, bind a subject on the agent, then present the IdP JWT to the
Gateway or POST /v1/govern/check. Full guide:
Enterprise agent identity.
CLI login
Developers connect the CLI with a tenant-bound service token:
unveilr login --token "$UNVEILR_TOKEN" --api "$UNVEILR_API"
unveilr scan --upload
4b. Notifications & alerts
Close the loop: when a scan turns up high-risk AI-SDLC findings, Unveilr posts a summary to Slack or a generic webhook so your team hears about it without watching the console.
Set it up in the console: Settings → Notifications
(/settings/notifications) → Add channel.
Console path: /settings/notifications
Filename: notifications.png
-
Slack — paste an incoming-webhook URL. You get a message like:
Unveilr scan — acme/payments-api: 4 AI-SDLC findings (1 critical, 3 high).• CRITICAL secrets: AWS access key committed [services/pay.py:41]• HIGH iac: Bedrock policy grants bedrock:* [infra/main.tf] -
Webhook — any HTTPS endpoint. It receives a structured envelope you can route on:
{ "source": "unveilr", "event": "scan.completed", "repo": "acme/payments-api","maxSeverity": "critical", "text": "…", "stats": { "findingsTotal": 4 } }
Each channel has a threshold (≥ high by default): a scan only alerts when its
highest finding meets or exceeds it, so low-signal noise stays out. Use the Test
button to confirm wiring. The webhook URL is a secret — the API never returns it
in full (it is masked in every response and in the UI). Delivery is best-effort:
a failing channel never fails a scan.
Via the API:
curl -X POST https://your-instance/v1/notifications \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"type":"slack","targetUrl":"https://hooks.slack.com/services/…","minSeverity":"high"}'
4c. Issue trackers — Jira & ServiceNow
Hand a finding straight to the tracker your teams already work in. Configure once
in the console (Settings → Integrations /settings/integrations): base URL,
user/email, and an API token (encrypted at rest — the API only ever returns
whether a secret is set, never the value). Test connection confirms the
wiring.
Console paths: /settings/integrations and a finding with “Open ticket”.
Filename: integrations-tickets.png
Then open a ticket from any finding — on the Code Findings or Remediation page, or via the API:
# open a Jira issue (or ServiceNow incident) for a finding
curl -X POST https://your-instance/v1/integrations/findings/$FINDING_ID/tickets \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"provider":"jira"}'
Severity maps to the tracker's priority (Jira) or impact/urgency (ServiceNow); the ticket links back to the finding, which moves to triaged. Every ticket is recorded in the evidence ledger.
5. Cloud AI discovery
Unveilr discovers cloud AI usage from your Infrastructure-as-Code — Bedrock,
SageMaker, Azure OpenAI, and Vertex resources, plus over-broad AI IAM (e.g.
bedrock:*). Just scan the repos that hold your Terraform / CloudFormation:
unveilr scan ./infra
These show up as AI services in the AI-BOM alongside app-level providers.
Live cloud-account discovery (read-only credentials to enumerate deployed AI endpoints and IAM) is on the roadmap; today, discovery is IaC- and config-based, which keeps it offline and reproducible.
6. Agent runtime — the Gateway
To govern autonomous agents, route their MCP tool calls through the Unveilr Gateway instead of letting them call tools directly. Full product detail: Govern.
Agent ──▶ Unveilr Gateway ──(allow/deny/approve/step-up/sanitize)──▶ MCP tool
Integration experience:
- Register the agent (owner required) and approve a tool scope — mints a scoped credential. Use On-ramp on the Agents page for copy-paste snippets.
- Path A (fastest):
POST /v1/govern/check— see Govern check — orpip install -e sdk/python(@govern/ LangChain / CrewAI / OpenAI adapters). - Path B: Point your MCP client at the Gateway URL:
https://gateway/mcp/{tenant}/{server}(often a one-line config change). - Install env policy packs (
GET /v1/policies/packs) — promotepack-dev-observe→pack-staging→pack-production. - Start every server in observe — records would-blocks; still sanitizes secrets/PII from responses; structural gates stay hard.
- Stream decisions to SIEM (Settings → Notifications → SIEM) or pull
GET /v1/evidence/export?since=…. - Flip high-value servers to enforce; revoke credentials for an instant kill switch.
Partner sessions must complete Path A or B — see repo docs/PARTNER.md.
The Gateway adds under 150 ms on cached decisions, so it won't slow your agents down.
Console paths: /agents, /registry, /policies, /approvals, /sessions
Filenames: see Priority 3 in Screenshot guide.
Rollout checklist
- Developers run
unveilr scanlocally / IDE / pre-commit. - CI runs
unveilr/scan-action(or CLI) in observe across all repos. - Repos connected to the console; AI-BOM reviewed with security.
- PR checks enabled (observe); CycloneDX export tested if you use SBOM tools.
- Slack / webhook notifications wired (threshold
≥ high). - Jira / ServiceNow connected for finding tickets (optional).
- Highest-value repos moved to enforce on
--fail-on critical. - Agents registered, scoped, and routed through Govern (observe → enforce) —
at least one
/v1/govern/checkor Gateway call in Evidence. - SIEM channel or incremental evidence export wired for SOC.
- Policy pack installed for staging (then production on promote).
- Compliance pack reviewed; first control attestations recorded.
- Evidence verify + export wired into your audit process.