GitOps Guardrails
Tool-agnostic GitOps best practices over normalized .cd.gitops: automated sync (prune + self-heal), source/destination allow-lists, and adoption coverage to flag components that should be on GitOps but aren't. Works for any GitOps collector (argocd today, flux later).
gitops to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/gitops@v1.0.5
Included Guardrails
This policy includes 4 guardrails that enforce standards for your deployment and infrastructure.
sync-policy
Requires Applications to use an automated sync policy with prune and self-heal enabled. Drift between Git and the cluster is corrected automatically instead of accumulating silently.
source-repo-allowlist
Requires each Application's manifest source repository to be within a configured allow-list of trusted repositories. Prevents deployments from unreviewed or untrusted Git sources.
destination-allowlist
Requires each Application's destination namespace and cluster to be within a configured allow-list. Stops Applications from targeting clusters or namespaces they should not deploy to.
gitops-managed
Coverage check: requires every component this policy targets (optionally narrowed to a tag) to actually be deployed by an ArgoCD Application — i.e. to have resolved .cd.gitops data, whether parsed locally or pushed by the argocd-deployment-tracking collector from a separate GitOps repo. Surfaces components that should be on GitOps but haven't been migrated. Unlike the other checks, absence of GitOps data is a failure here, not a skip — that's the whole point.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
allowed_source_repos
|
Required | — | Comma-separated allow-list of permitted Application source repoURLs for source-repo-allowlist. Required when that check is enabled (errors if empty). |
allowed_destinations
|
Required | — | Comma-separated allow-list of permitted destinations for destination-allowlist. Each entry is `namespace` (allowed on any cluster) or `cluster/namespace` (pinned to one cluster — the cluster segment matches the Application destination's registered name or its server URL). Required when that check is enabled (errors if empty). |
expected_tag
|
Required | — | For gitops-managed — only enforce coverage on components whose catalog tags (.catalog.entity.tags, e.g. from a Backstage catalog-info.yaml) include this value. Empty enforces on every component the policy targets (via on:). |
Documentation
View on GitHubGitOps Guardrails
Tool-agnostic GitOps continuous-delivery best practices, for any GitOps tool.
Overview
This policy holds the GitOps checks that aren't tied to a specific tool — they read the normalized .cd.gitops paths, so they work for any GitOps collector (ArgoCD today, Flux later). It enforces automated sync with prune and self-heal, source-repo and destination allow-lists, and GitOps adoption coverage. Because the argocd-deployment-tracking collector pushes .cd.gitops onto a source component from a separate GitOps repo, these guardrails apply on the service repo, not just the GitOps repo. The config checks skip cleanly when a component has no GitOps data; the gitops-managed coverage check inverts that, failing components that should be on GitOps but aren't. Pair it with the argocd policy for ArgoCD-specific checks (CRD validation, AppProject hygiene).
Policies
This plugin provides the following guardrails (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
sync-policy |
Requires automated sync with prune and self-heal | Application sync policy is manual or missing prune/self-heal |
source-repo-allowlist |
Requires the manifest source repo to be allow-listed | Application source repoURL is not in the allow-list |
destination-allowlist |
Requires the destination namespace/cluster to be allow-listed | Application targets a namespace or cluster outside the allow-list |
gitops-managed |
Requires targeted components to actually be GitOps-managed (coverage) | A component that should be on GitOps has no resolved .cd.gitops data |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.cd.gitops |
object | argocd collector (presence = GitOps-managed; read by gitops-managed) |
.cd.gitops.applications[] |
array | argocd collector |
.cd.gitops.applications[].sync_policy |
object | argocd collector |
.cd.gitops.applications[].destination |
object | argocd collector |
.cd.gitops.applications[].source_ref |
object | argocd collector |
.catalog.entity.tags[] |
array | catalog collector (only when gitops-managed uses expected_tag) |
Note: Ensure the argocd collector is configured before enabling this policy. The gitops-managed check decides which components are "expected on GitOps" two ways: deploy it on: the tag/domain that must be GitOps-managed (e.g. on: [production]) and leave expected_tag empty, or set expected_tag to a catalog tag and the check only enforces on components whose .catalog.entity.tags carry it (populated by a catalog cataloger, e.g. from a Backstage catalog-info.yaml).
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/argocd@v1.0.0
on: [gitops]
policies:
# Tool-agnostic GitOps checks
- uses: github://earthly/lunar-lib/policies/gitops@v1.0.0
on: [gitops]
enforcement: report-pr
# include: [sync-policy, gitops-managed] # Only run specific checks
# with:
# allowed_source_repos: "https://github.com/org/gitops.git"
# allowed_destinations: "payments,checkout"
# expected_tag: "should-be-gitops"
# ArgoCD-specific checks (recommended alongside)
- uses: github://earthly/lunar-lib/policies/argocd@v1.0.0
on: [gitops]
enforcement: report-pr
Examples
Passing Example
An Application with automated sync, an allow-listed source, and an allowed destination:
{
"cd": {
"gitops": {
"applications": [
{
"name": "payment-api",
"path": "apps/payment-api.yaml",
"sync_policy": {"automated": true, "prune": true, "self_heal": true},
"destination": {"server": "https://kubernetes.default.svc", "namespace": "payments"},
"source_ref": {"repoURL": "https://github.com/org/gitops.git"}
}
]
}
}
}
Failing Example
An Application with manual sync and no prune/self-heal:
{
"cd": {
"gitops": {
"applications": [
{
"name": "my-app",
"path": "apps/my-app.yaml",
"sync_policy": {"automated": false, "prune": false, "self_heal": false},
"destination": {"server": "https://kubernetes.default.svc", "namespace": "payments"},
"source_ref": {"repoURL": "https://github.com/org/gitops.git"}
}
]
}
}
}
Failure message: apps/my-app.yaml: Application 'my-app' should use an automated sync policy with prune and self-heal
Coverage Failure (gitops-managed)
A component the org expects on GitOps, with no resolved .cd.gitops — nothing parsed locally and nothing pushed by argocd-deployment-tracking from the GitOps repo:
{
"vcs": { "provider": "github" }
}
Failure message: Component is expected to be GitOps-managed but no GitOps Application deploys it (.cd.gitops not found). Migrate it to GitOps or exclude it from this policy's scope.
Remediation
When this policy fails, resolve it by:
- For
sync-policyfailures: Enable automated sync withprune: trueandselfHeal: true(spec.syncPolicy.automatedin ArgoCD). - For
source-repo-allowlistfailures: Point the Application's sourcerepoURLat an allow-listed repository, or add the repository toallowed_source_repos. - For
destination-allowlistfailures: Set the destination to an allow-listed namespace/cluster, or extendallowed_destinations. - For
gitops-managedfailures: Either migrate the component to GitOps (create an Application that deploys it, soargocd-deployment-trackingresolves and stamps.cd.gitops), or narrow the policy's scope (on:targeting, orexpected_tag) so it isn't expected on GitOps. This check converges onceargocd-deployment-trackinghas processed the GitOps repo and pushed the link.
Consumers who want any of these surfaced without blocking can pin enforcement: report-pr at config time.
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.