New to Kestra?
Use blueprints to kickstart your first workflows.
Detect Terragrunt drift on a schedule with Kestra. run-all plan with detailed exit codes flags pending changes and alerts Discord when drift appears.
Infrastructure drifts, someone clicks in a console, a provider changes a default, a hotfix never lands in the repo. This blueprint turns terragrunt run-all plan -detailed-exitcode into a daily watchdog for the whole estate. Terraform's detailed exit code contract is precise: 0 means no changes, 1 means an error, 2 means the plan found pending changes. The flow captures that code instead of letting it fail the task, publishes it through Kestra's outputs protocol, and branches on it, Discord hears about drift, a clean estate stays quiet, and a broken check raises its own distinct alert.
The demo estate ships inline through inputFiles with two local_file units, so the flow runs without cloud credentials. Because the demo starts from empty state, the very first execution reports drift by design, which conveniently proves the alert path works.
detect_drift (io.kestra.plugin.terragrunt.cli.TerragruntCLI) materializes the repo layout and runs terragrunt run-all plan --non-interactive --working-dir live -detailed-exitcode, capturing the log to plan.log.|| ec=$? so exit code 2 never fails the task, then emitted through the outputs protocol as {{ outputs.detect_drift.vars.plan_exit }}.errors block instead of masquerading as drift.evaluate_drift (io.kestra.plugin.core.flow.If) branches on the code: alert_drift posts to Discord when it equals 2, log_clean writes a quiet all-clear otherwise.plan.log artifact attached to every execution for immediate triage.A cron job running run-all plan can tell you the exit code, but nothing else: no history of when drift started, no stored plan output, no alert routing, no distinction between drift and breakage. Kestra keeps every check as an execution with its log artifact, exposes the exit code as structured output for branching, routes drift and failure to different messages, and the schedule, the check, and the alerting live in one reviewable YAML file.
namespaceFiles or a Git clone, use your real remote state, and pass provider credentials through the task env from {{ secret('...') }}.DISCORD_WEBHOOK_URL: Discord incoming webhook URL.DISCORD_WEBHOOK_URL secret to your Kestra namespace.disabled: false on the daily trigger.inputFiles with namespaceFiles so the check runs against your real repository from namespace storage.plan.log to an AI summarization task so the Discord alert says what drifted, not just that something did.--working-dir, as shown in the Terragrunt environment promotion blueprint.