Integrations

Overview

An Integration sends SnapCd events — job lifecycle transitions and Mission milestones — to an external system. Slack is the first supported type; chat / alerting / ticketing sinks follow. Integrations are an Enterprise-tier feature.

Whether a given event reaches a given integration is decided by a supply ∩ demand model (the same shape used for Agents and Missions):

  • Supply — which scopes an integration serves (supplies, or the org-wide flag).
  • Demand — which trigger on which scope should notify an integration (an Integration Event).

A notification is delivered only when both hold: an Integration Event subscribes a trigger→integration on a scope, and that integration is supplied to that scope.

Integration

The connection itself. Credentials and config are stored encrypted in the secret backend, never on the row — the API returns secret fields masked.

Because it carries a write-only bot token, an Integration is created and managed in the SnapCd UI, not by Terraform. In Terraform it is a data source (like Service Principal) — look one up by name and reference its id:

data "snapcd_integration" "alerts" {
  name = "alerts"
}

Data source attributes:

FieldDescription
nameUnique name (within type, per organization) — the lookup key
idThe integration’s id — reference it from supplies, role assignments, and events
integration_typee.g. Slack
enabledWhen false, no deliveries are sent
is_supplied_to_all_modulesOrg-wide supply — the integration serves every module

The connection (credentials) — for Slack the bot token and default channel — is set in the UI and stored encrypted in the secret backend. It is never exposed by this data source (not even masked) and never lands in Terraform state.

Full specification: snapcd_integration data source.

Slack setup

  1. Create a Slack app and add a Bot Token Scope of chat:write.
  2. Install the app to the workspace and copy the Bot User OAuth Token (xoxb-…).
  3. Invite the bot to the target channel.
  4. Set bot_token + default_channel on the integration. Use Test connection in the UI (or the POST {id}/test endpoint) to verify.

Supply

Before an integration can be notified for a Module, it must be supplied to that module’s scope:

MethodDescription
is_supplied_to_all_modules on the IntegrationServes every module in the org
snapcd_integration_stack_supplyServes every module under the stack
snapcd_integration_namespace_supplyServes every module in the namespace
snapcd_integration_module_supplyServes that single module

There is deliberately no organization-scope supply — org-wide supply is the flag.

Access control (RBAC)

Integration management mirrors the Agent permission model exactly:

  • Organization roles IntegrationCreator / IntegrationContributor / IntegrationReader govern the integration entity (alongside Owner / Contributor / Reader).
  • Per-integration roles IntegrationRole (Owner / Contributor / Reader / IdentityAccessManager) — granted to a user, group, or service principal via snapcd_integration_role_assignment — govern the integration’s child resources (its role assignments), resolved directly or transitively through group membership.

Full specification: snapcd_integration_role_assignment.

Operator notes

  • Secrets — each integration’s connection is one encrypted blob in the org’s input vault at integration--{organizationId}--{id}. The integration row holds only identity/routing; deletes remove the blob too.
  • Credential cache — the send path caches each integration’s connection (credentials) in a per-instance in-memory cache (15-minute TTL) so it doesn’t read the secret backend on every event. It is invalidated cross-instance by a fanout consumer on integration CRUD, so a rotated token is never served stale.
  • Dispatch — a single competing consumer per server pool turns saga/mission events into deliveries; delivery is idempotent per (occurrence, subscription). Each attempt is recorded as an IntegrationDelivery audit row (status, error, sink message id).
Last updated on