> For the complete documentation index, see [llms.txt](https://docs-lunar.earthly.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs-lunar.earthly.dev/configuration/lunar-config/policies.md).

# policies

Define the policies section of lunar-config.yml — rules that Lunar evaluates against components to enforce standards and check health.

* `lunar-config.yml -> policies`
* Type: `array`
* Form:

  ```yaml
  policies:
    - <policy-object>
    - <policy-object>
    - ...
  ```

Policies are used to define the rules that Lunar uses to evaluate the health of components.

Example policies definition:

{% code title="lunar-config.yml" %}

```yaml
policies:
  - uses: github://third-party/some-policy@v1
    on: [my-domain]
    enforcement: block-pr
  - uses: ./security-scanning
    on: [my-domain, another-domain]
    runs_on: [default-branch]
    enforcement: score
  - name: Collect code coverage information
    runPython: |
      from lunar_policy import Check, Path
      with Check("codecov-check", "Verify code coverage was collected") as check:
          check.assert_true(Path(".codecov.was_run"), "Code coverage data should be collected")
    on: [another-domain]
  - name: Should have unit tests
    mainPython: ./unit-tests.py
    on: [another-domain]
    enforcement: block-pr-and-release
```

{% endcode %}

## Policy

* `lunar-config.yml -> policies.<policy-index>`
* Type: `object`
* Forms:
  * Uses form:

    ```yaml
    name: <policy-name>
    uses: <policy-string>
    include: <include-array>
    exclude: <exclude-array>
    with:
      <input-name>: <input-value>
      ...
    on: <domain-array>
    runs_on: <runs-on-array>
    enforcement: <enforcement-level>
    initiative: <initiative-name>
    meta:
      <meta-key>: <meta-value>
      ...
    failureText: <failure-text-template>
    image: <docker-image>
    ```
  * Run form:

    ```yaml
    name: <policy-name>
    description: <policy-description>
    run<language>: <code-string>
    on: <domain-array>
    runs_on: <runs-on-array>
    enforcement: <enforcement-level>
    initiative: <initiative-name>
    image: <docker-image>
    ```
  * Main form:

    ```yaml
    name: <policy-name>
    description: <policy-description>
    main<language>: <main-file-path>
    on: <domain-array>
    runs_on: <runs-on-array>
    enforcement: <enforcement-level>
    initiative: <initiative-name>
    image: <docker-image>
    ```

Policies are used to define the rules that Lunar uses to evaluate the health of components. Policies are associated with domains and are automatically inherited by child domains.

### `name`

* `lunar-config.yml -> policies.<policy-index>.name`
* Type: `string`
* Required for Run and Main policy forms, Optional for Uses policy form

The `name` field is used to specify the name of the policy. If a name is not provided in the case of a policy plugin, the name from the policy plugin is used. The name must be unique within the configuration.

### `uses`

* `lunar-config.yml -> policies.<policy-index>.uses`
* Type `string`
* Forms
  * GitHub form: `github://<owner>/<repo>@<version>`
  * GitLab form: `gitlab://<host>/<namespace>/<project>@<version>`
  * Local form: `./<path-to-policy>`
* Required in Uses policy form

The `uses` field is used to import an external (plugin) policy from a GitHub or GitLab repository, or from a local file. The GitLab form requires an explicit host, including for `gitlab.com`. The policy is then associated with a domain. Browse the [100+ available guardrails](https://earthly.dev/lunar/guardrails/) to find policies for your standards.

### `with`

* `lunar-config.yml -> policies.<policy-index>.with`
* Type: `object`
* Optional

The `with` field specifies the inputs to pass to the policy plugin. The inputs are defined in the policy's configuration file. Input values are available to policy scripts via the `variable_or_default` function from the `lunar_policy` SDK.

Plugin authors can also reference inputs in their plugin YAML definitions using the `${{ inputs.NAME }}` syntax. This allows plugins to expose configurable fields as explicit settings. See [policy plugins](/plugin-sdks/plugins/policy-plugins.md#inputs) for details.

### `include`

* `lunar-config.yml -> policies.<policy-index>.include`
* Type: `array`
* Optional

The `include` field specifies which sub-policies to include from an imported policy plugin. When a policy is imported via `uses`, it may define (or import) multiple sub-policies. Use `include` to control which of those sub-policies are used.

If neither `include` nor `exclude` is specified, all sub-policies are included by default.

### `exclude`

* `lunar-config.yml -> policies.<policy-index>.exclude`
* Type: `array`
* Optional

The `exclude` field specifies which sub-policies to exclude from an imported policy plugin. Use `exclude` when you want to include most sub-policies but skip a few specific ones.

If neither `include` nor `exclude` is specified, all sub-policies are included by default.

For example, if a policy called `security` includes sub-policies named `vulnerability-scan`, `license-check`, and `dependency-audit`:

{% code title="lunar-config.yml" %}

```yaml
policies:
  # Include only the vulnerability-scan sub-policy
  - uses: ./dir/security
    include: [vulnerability-scan]

  # Include all except license-check
  - uses: ./dir/security
    exclude: [license-check]

  # Include vulnerability-scan and license-check only
  - uses: ./dir/security
    include: [vulnerability-scan, license-check]
```

{% endcode %}

### `description`

* `lunar-config.yml -> policies.<policy-index>.description`
* Type: `string`
* Optional

The `description` field is used to specify a description of the policy. If a description is not provided in the case of a policy plugin, the description from the policy plugin is used.

### `run<language>`

* `lunar-config.yml -> policies.<policy-index>.run<language>`
* Type: `string`
* Required in Run policy form

Defines the command to execute when the policy is invoked. Only `Python` is supported. So `runPython` is the only valid field.

Running Python supports [installing dependencies](/plugin-sdks/python-sdk/dependencies.md).

#### `runPython`

* `lunar-config.yml -> policies.<policy-index>.runPython`
* Type: `string`

The `runPython` field specifies the python policy script to run. Running Python supports [installing dependencies](/plugin-sdks/python-sdk/dependencies.md).

### `main<language>`

* `lunar-config.yml -> policies.<policy-index>.main<language>`
* Type: `string`
* Required in Main policy form

Defines the main file path used to execute when the policy is invoked. Only `Python` is supported. So `mainPython` is the only valid field.

The file path is relative to the directory of the configuration file that declares it.

Running Python supports [installing dependencies](/plugin-sdks/python-sdk/dependencies.md).

#### `mainPython`

* `lunar-config.yml -> policies.<policy-index>.mainPython`
* Type: `string`

The `mainPython` field specifies the path to the python main file to run. Running Python supports [installing dependencies](/plugin-sdks/python-sdk/dependencies.md).

### `on`

* `lunar-config.yml -> policies.<policy-index>.on`
* Type: `array`
* Required

The `on` field specifies the tags that the policy should be associated with. The policy will apply when the component has one or more of the specified tags.

For detailed documentation on tag matching syntax, including domain/component targeting, expressions, and cross-references to other collectors or policies, see [Tag Matching with `on`](/configuration/lunar-config/on.md).

### `runs_on`

* `lunar-config.yml -> policies.<policy-index>.runs_on`
* Type: `array`
* Default: `[prs, default-branch]`

Specifies the contexts in which the policy should run. The available values are:

* `prs` - the policy will run on pull requests
* `default-branch` - the policy will run on the default branch

By default, policies run in both contexts. To restrict a policy to only run on pull requests, use `runs_on: [prs]`. To restrict a policy to only run on the default branch, use `runs_on: [default-branch]`.

### `enforcement`

* `lunar-config.yml -> policies.<policy-index>.enforcement`
* Type: `string`. One of `draft`, `score`, `report-pr`, `block-pr`, `block-release`, `block-pr-and-release`
* Optional - defaults to `report-pr`

The `enforcement` field specifies the enforcement level of the policy. It determines how the policy affects the component.

The following enforcement levels are supported:

* `draft` - the policy is still under development and does not affect the score, and is not enforced or shown to application teams
* `score` - the checks under this policy contribute to the score of the component and are not reported in PRs. They still run on pull requests, subject to [`runs_on`](#runs_on), with their results visible on the pull request's dashboard — which makes `score` the level to trial a guardrail at, including one that only does anything in a PR, before application teams see it
* `report-pr` - the checks under this policy report the results in PRs, but do not block them
* `block-pr` - the checks under this policy block PRs from being merged
* `block-release` - the checks under this policy block releases, but not PRs. This level may be useful for checks that don't necessarily run in PRs due to performance reasons, but are nevertheless important to gate the release process.
* `block-pr-and-release` - the checks under this policy block both PRs and releases

{% hint style="info" %}
When `block-release` or `block-pr-and-release` levels are used, the Lunar CLI command `lunar policy ok-release <component> <git_sha>` will return a non-zero exit code of `1` if the associated policy is failing for the given component. This command may be used in CD or release pipelines to prevent a deployment to production, or a release package to be published.

When `block-pr` or `block-pr-and-release` levels are used, the Lunar CLI command `lunar policy ok-pr <component> <git_sha>` will return a non-zero exit code of `1` if the associated policy is failing for the given component. This command may be used wherever needed to block PR merges or prevent PR deployment pipelines to staging environments.
{% endhint %}

{% hint style="info" %}
**On GitLab Ultimate, a `block-pr` policy blocks the merge request directly** — Lunar reports the result as a status check that GitLab enforces, with a comment-driven override for authorized engineers. See the [merge gate](/install/git-platforms/gitlab.md#merge-gate). On GitLab Free and Premium, and on GitHub unless you mark Lunar's check required in branch protection, blocking is enforced through the `ok-pr` command above.
{% endhint %}

### `initiative`

* `lunar-config.yml -> policies.<policy-index>.initiative`
* Type: `string`
* Optional - defaults to `default`

The `initiative` field specifies the initiative that the policy belongs to. Initiatives are used to group related policies together for easier management and reporting. If not specified, the policy will be associated with the built-in "default" initiative.

For information on how to configure initiatives, see [initiatives](/configuration/lunar-config/initiatives.md).

### `meta`

* `lunar-config.yml -> policies.<policy-index>.meta`
* Type: `object` of `string` to `string`
* Optional

The `meta` field attaches your own key/value annotations to a policy. Lunar stores them and exposes them through the [SQL API](/sql-api/views/policies.md) so you can select checks by an identifier of your own, such as the control a policy enforces in your compliance framework:

{% code title="lunar-config.yml" %}

```yaml
policies:
  - uses: github://earthly/lunar-lib/policies/terraform@v1
    name: ebs-volume-enc
    include: [aws-ebs-volume-encryption]
    enforcement: block-pr
    meta:
      enforce_control: CONTROL123
```

{% endcode %}

```sql
SELECT cl.*
FROM checks_latest AS cl
JOIN policies AS p ON cl.policy_id = p.id
WHERE p.meta->>'enforce_control' = 'CONTROL123';
```

Keys and values are free-form; Lunar does not validate them against a schema. Two things to know before you pick a naming convention:

* **`meta` is never shown to a human.** It does not appear in pull request comments or in the dashboards. To put a control ID in front of a developer, render it with [`failureText`](#failuretext).
* **`meta` applies to every sub-policy in the entry it is written on.** A plugin bundles many sub-policies, and `include`/`exclude` select which ones run — but they all share the entry's `meta`. To map sub-policies to different values, import the plugin once per sub-policy, as the example above does with `include: [aws-ebs-volume-encryption]`.

`meta` is not a replacement for [initiatives](/configuration/lunar-config/initiatives.md). An initiative groups policies for reporting and can cover many controls; `meta` is a flat tagging dimension that sits alongside it.

### `failureText`

* `lunar-config.yml -> policies.<policy-index>.failureText`
* Type: `string`, a [Go text/template](https://pkg.go.dev/text/template)
* Optional - defaults to the built-in list of failing assertion messages

The `failureText` field replaces what a failing check writes into the pull request comment, so you can wrap a plugin's wording in your own prose and links without forking the policy:

{% code title="lunar-config.yml" %}

```yaml
policies:
  - uses: github://earthly/lunar-lib/policies/terraform@v1
    name: ebs-volume-enc
    include: [aws-ebs-volume-encryption]
    enforcement: block-pr
    meta:
      enforce_control: CONTROL123
    failureText: |
      Enforces control [{{ .meta.enforce_control }}](https://intranet.example.com/controls/{{ .meta.enforce_control }}):
      {{ .check.failure }}
```

{% endcode %}

The comment then reads:

```markdown
* ❌ `ebs-volume-enc.aws-ebs-volume-encryption` - EBS volumes must be encrypted at rest
  Enforces control [CONTROL123](https://intranet.example.com/controls/CONTROL123):
  * volume vol-a is unencrypted
  * volume vol-b is unencrypted
```

The template renders as Markdown, so links, emphasis, and lists all work. Three namespaces are available:

| Reference                                                | What it renders                                                                                            |
| -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `{{ .check.failure }}`                                   | Every failing assertion as one bullet list, the same block Lunar writes by default. Position it as a unit. |
| `{{ range .check.failure_msgs }}{{ .message }}{{ end }}` | The failing assertions one at a time, for full control of the layout. Ordered as the policy asserted them  |
| `{{ .check.name }}`                                      | The check's name, qualified by its policy                                                                  |
| `{{ .meta.<key> }}`                                      | A value from the policy's [`meta`](#meta)                                                                  |
| `{{ .policy.name }}`, `{{ .policy.description }}`        | The policy's own name and description                                                                      |

{% hint style="warning" %}
**Setting `failureText` replaces the assertion messages; it does not add to them.** A template that references neither `{{ .check.failure }}` nor `{{ .check.failure_msgs }}` produces a comment that says the check failed without saying why. Include one of them unless you mean to drop the detail.
{% endhint %}

Two details worth knowing when you write one:

* **Hyphenated `meta` keys need `index`.** Go reads the hyphen in `{{ .meta.enforce-control }}` as subtraction, so a key like `enforce-control` has to be written `{{ index .meta "enforce-control" }}`. Underscored keys avoid it. Hyphens are fine on the SQL side either way.
* **A broken template falls back to the default.** An unknown key renders as empty text, and a template that fails to parse leaves the built-in assertion list in place. A typo costs you your wording, never the reason the check failed.

Like `meta`, `failureText` applies to every sub-policy in the entry it is written on.

### `image`

* `lunar-config.yml -> policies.<policy-index>.image`
* Type: `string`
* Optional

The `image` field specifies the Docker image to use when running the policy. When set, the policy runs inside a container instead of natively on the host.

Use the special value `native` to explicitly run the policy without a container, even when a default image has been configured.

Example:

{% code title="lunar-config.yml" %}

```yaml
policies:
  # Run in a container
  - uses: ./my-policy
    image: earthly/lunar-scripts:1.0.0
    on: [my-tag]

  # Run natively (override any default image)
  - mainPython: ./local-policy.py
    image: native
    on: [my-tag]
```

{% endcode %}

For more information about default images and container execution, see [Images](/configuration/lunar-config/images.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs-lunar.earthly.dev/configuration/lunar-config/policies.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
