Status icon
OutputValues icon
Switch icon
Log icon
Patch icon
SlackIncomingWebhook icon
Schedule icon

Argo CD Application Target Revision Drift Auto-Patch Gate

Detect Argo CD targetRevision drift, alert Slack or auto-patch it back to the approved revision, and log the result for platform teams.

Categories
Infrastructure

Argo CD enforces that the cluster matches whatever targetRevision an Application's spec currently points to, but it has no opinion on whether that targetRevision itself is still the one your team approved. Someone with cluster or Argo CD UI access can point an Application at a different branch, a stale tag, or a one-off commit, and Argo CD will happily sync to it, fully "Synced" and "Healthy" the entire time. This blueprint checks the live spec against the revision you expect, and only corrects it once you have explicitly said this flow is allowed to.

This blueprint was created by Mohit Jeswani.

How it works

  1. check_app_spec (io.kestra.plugin.argocd.apps.Status) reads the full Application object via argocd app get --output json. The task only parses sync/health state into typed outputs, so evaluate reads the live spec.source.targetRevision back out of rawOutput.
  2. evaluate (io.kestra.plugin.core.output.OutputValues) compares the live targetRevision against expected_target_revision and classifies the result as ALIGNED, DRIFT_AUTO_PATCH, DRIFT_NEEDS_HUMAN, or UNREACHABLE, folding confirm_patch into the drifted classification itself.
  3. route (io.kestra.plugin.core.flow.Switch):
    • ALIGNED: logs that the application is pinned to the approved revision.
    • DRIFT_AUTO_PATCH: runs io.kestra.plugin.argocd.apps.Patch with a merge patch restoring spec.source.targetRevision (the safe remediation, since it restores the already-approved value), then posts a Slack notice that it happened automatically.
    • DRIFT_NEEDS_HUMAN / UNREACHABLE: posts a Slack alert instead of acting.
  4. summary logs the severity, closing the governance cycle.
  5. errors alerts Slack if the flow itself fails, for example a revoked Argo CD token.

What you get

  • A drift check that looks at the GitOps policy itself, not just whether the cluster matches whatever the Application currently points to.
  • A patch that only ever restores a revision your team already approved, and only once you have explicitly set confirm_patch to allow it.
  • A Slack alert naming both the live and the expected revision, so a human can see exactly what changed without digging through the Argo CD UI.

Who it's for

  • Platform and SRE teams running Argo CD who need to know when an Application's source has been pointed somewhere other than the approved branch or tag.
  • Teams evaluating the Argo CD plugin who want a worked example of apps.Patch used as a governance remediation, distinct from this repo's existing Argo CD blueprints, which watch sync and health status rather than the spec's own source configuration.

Why orchestrate this with Kestra

Argo CD reconciles the cluster to whatever targetRevision is currently set; it has no policy engine comparing that value against an approved one, and no Slack integration of its own. Kestra keeps expected_target_revision and confirm_patch as flow inputs, turns a raw app get response into a policy decision, and keeps a full execution history of every drift this flow has seen and what it did about it.

Prerequisites

  • An Argo CD instance with API access and a token that can read and patch Applications.
  • An Application you can safely point at a different revision to test both the alert and the patch path.
  • A Slack incoming webhook URL.

A local Argo CD instance can be installed into a kind (Kubernetes-in-Docker) cluster via Argo CD's official install manifests for a fully local end-to-end test, no managed account required.

Secrets

  • ARGOCD_SERVER: the Argo CD API server URL used by check_app_spec and patch_target_revision. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_ARGOCD_SERVER.
  • ARGOCD_TOKEN: the Argo CD authentication token. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_ARGOCD_TOKEN.
  • SLACK_WEBHOOK_URL: used by all three Slack alert cases and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Default Purpose
argocd_application my-argocd-app Application to check
expected_target_revision main GitOps-approved branch, tag, or commit
confirm_patch false Authorizes this flow to patch the application itself

Outputs

  • {{ outputs.check_app_spec.rawOutput }}: the full argocd app get --output json response, as text.
  • {{ outputs.evaluate.values.live_target_revision }} / .severity: the application's live targetRevision, and ALIGNED, DRIFT_AUTO_PATCH, DRIFT_NEEDS_HUMAN, or UNREACHABLE.

Pitfalls

  • io.kestra.plugin.argocd.apps.Status's Output does not expose spec at all, only syncStatus, healthStatus, conditions, resources, and rawOutput; this is verified directly against the task's source, since neither its Javadoc examples nor its field list make that limitation obvious. evaluate works around it by parsing rawOutput itself with fromjson inside a jq filter.
  • This checks only spec.source.targetRevision for a single-source Application. A multi-source Application keeps its revisions under spec.sources[].targetRevision instead, which this blueprint does not read.
  • confirm_patch applies to the whole flow, not one specific drift; a scheduled run with confirm_patch: true will patch back any drift this flow finds on every run, so treat it as "this application's revision is fully policy-enforced," not a one-time approval.

Quick start

  1. Add the ARGOCD_SERVER, ARGOCD_TOKEN, and SLACK_WEBHOOK_URL secrets.
  2. Point argocd_application at a real Application and expected_target_revision at its current, correct revision; run manually and confirm log_aligned fires.
  3. Change the Application's targetRevision (via the Argo CD UI or CLI) and run again with confirm_patch: false; confirm alert_drift fires.
  4. Run again with confirm_patch: true; confirm patch_target_revision restores it and alert_auto_patched fires.
  5. Enable the hourly trigger once the inputs reflect a real application and policy.

How to extend

  • Extend the jq filter to also compare spec.source.repoURL and spec.source.path, so a redirected repository or path counts as drift too, not just the revision.
  • Loop over a list of tracked application names with io.kestra.plugin.core.flow.ForEach to run this policy check across an entire Argo CD project in one scheduled run.
  • Chain a lookup of the Git commit or PR that last touched the Application manifest to name the likely source of the drift in the Slack alert.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.