teriac server Drift checks

Drift checks

Scheduled, read-only drift checks that alert Slack, Teams, Discord, Google Chat or any webhook, and tag who changed each resource.

Drift checks run read-only plans on a schedule and tell your team when what's deployed no longer matches the code.

Set up a schedule

channels:                                # in repos.yaml; secrets stay in env vars
  infra-alerts: { type: slack, channel: "#infra-drift", token_env: TERIAC_SLACK_TOKEN }
  ops-teams:    { type: teams, webhook_url_env: TERIAC_TEAMS_WEBHOOK }
people:                                  # optional: git/GitHub → chat identity
  - { name: Bob Martins, github: bob-m, slack: U04BOBM, teams: bob@acme.onmicrosoft.com }

repos:
  - id: github.com/acme/infra
    drift:                               # or under `drift:` in the repo's teriac.yaml
      - name: prod-nightly
        projects: ["envs/prod", "live/prod/**"]
        branch: main
        schedule: "0 6 * * 1-5"
        timezone: Europe/Berlin
        notify: [infra-alerts, ops-teams]

Drift schedules in repos.yaml need an exact repo id, not a glob. A repo can also keep its own schedules under drift: in teriac.yaml (turn that off with allow_repo_schedules: false).

Schedule fields

Field Default
name Shown in alerts and the dashboard
projects required Project names, folders or globs
branch the repo's default branch Branch to check
schedule required Cron, e.g. 0 6 * * 1-5 (06:00 on weekdays)
timezone UTC An IANA name, e.g. Europe/Berlin
notify required Channel names from channels
notify_when changed changed: only when findings change. always: every run
include_pending true Also report changes that were merged but never applied
fix_pr false Open a PR that updates the code to match what's running. See fix PRs

Channels

Alerts go to Slack, Teams, Discord, Google Chat or any webhook. Keep tokens and webhook URLs in env vars and name them with token_env or webhook_url_env.

type Settings Mentions
slack token_env + channel (recommended), or webhook_url_env @ the person, by people or email lookup (bot token)
teams webhook_url_env By people.teams
discord webhook_url_env By people.discord
googlechat webhook_url_env Names in bold
webhook webhook_url_env JSON payload, see below
channels:
  infra-alerts: { type: slack, channel: "#infra-drift", token_env: TERIAC_SLACK_TOKEN }
  ops-teams:    { type: teams, webhook_url_env: TERIAC_TEAMS_WEBHOOK }
  dev-discord:  { type: discord, webhook_url_env: TERIAC_DISCORD_WEBHOOK }
  gchat:        { type: googlechat, webhook_url_env: TERIAC_GCHAT_WEBHOOK }
  pagerduty:    { type: webhook, webhook_url_env: TERIAC_DRIFT_WEBHOOK }

A Slack bot token needs chat:write, plus users:read.email to find people by email.

Webhook payload

The webhook type posts JSON you can route anywhere:

{
  "event": "teriac.drift",
  "report": { "projects": [ … ] },
  "people": [
    { "project": "live/prod/vpc", "people": [ { "name": "Bob Martins", "person": { … } } ] }
  ]
}

People

people maps code and platform identities to chat users, so alerts mention the right person:

people:
  - name: Bob Martins
    github: bob-m
    emails: [bob@acme.com, bob.martins@users.noreply.github.com]
    slack: U04BOBM                       # Slack member ID
    teams: bob@acme.onmicrosoft.com      # Teams UPN
    discord: "123456789012345678"        # Discord user ID

Without an entry, Slack (with a bot token) is asked to find the person by their commit email.

With Helm

Put the same config under repos, and load the tokens with extraEnvFrom:

repos:
  channels:
    infra-alerts: { type: slack, channel: "#infra-drift", token_env: TERIAC_SLACK_TOKEN }
  repos:
    - id: github.com/acme/infra
      drift:
        - { name: prod-nightly, projects: ["prod/**"], schedule: "0 6 * * 1-5", timezone: Europe/Berlin, notify: [infra-alerts] }
extraEnvFrom:
  - secretRef: { name: teriac-chat-tokens }   # holds TERIAC_SLACK_TOKEN

What a check reports

Each run checks the branch with read-only plans (-refresh-only -lock=false) and reports:

  • changes made outside Terraform, such as a security group edited in the console;
  • changes that were merged but never applied.

Each drifted resource tags the last person who changed its code, found from the git history of its block, plus the last person who applied that project. Matching to chat users uses people, or Slack's lookup by email.

When it notifies

A message goes out only when the findings change. Set notify_when: always to send one every run. Failed checks always notify.

Fix PRs

New in 0.2.0.

With fix_pr: true on a schedule, teriac opens a PR that updates the code to match what is running, and links it in the drift message.

drift:
  - { name: prod-nightly, projects: ["prod/**"], schedule: "0 6 * * 1-5", notify: [infra-alerts], fix_pr: true }
  • It only edits values written plainly in the resource block (a string, number or true/false) that still match the last applied value.
  • Values from variables, expressions, modules and nested blocks are listed in the PR for a person to handle, with who last changed them.
  • Accept the change: merge the PR. Undo it: close the PR and apply the base branch, which puts things back.
  • One PR per project at a time, on the branch teriac/drift-fix/<project>.

The GitHub App needs Contents: read & write for this (read is enough otherwise).

Running and pausing

  • Turn all schedules off with TERIAC_DRIFT=false.
  • Admins can start a check from the dashboard, or with POST /api/drift/run?key=… (keys are listed by GET /api/drift/schedules).
  • Findings and history are in the dashboard's Drift page and GET /api/drift.