Hamburger Cross Icon
Backstage Guardrails - System Domain Valid

System Domain Valid

backstage.system-domain-valid

Follows spec.system to its System in the Backstage catalog and on to that System's domain, and fails at the first broken step: the System does not exist, it belongs to no domain, or its domain does not exist. Each failure names the System. One check for what system-exists, system-domain-set and system-domain-exists report separately. Fails if the catalog file is missing, like system-set. Skips when no spec.system is declared (system-set reports that), when the collector has no backstage_url, or when a lookup errored.

backstage domain system referential integrity catalog transitive domain assignment

Compatible Integrations

This guardrail works with the following integrations. Click to see how to use System Domain Valid with each collector.

Enable This Guardrail

Add the parent policy to your lunar-config.yml to enable this guardrail.

📄 lunar-config.yml
policies:
  - uses: github://earthly/lunar-lib/policies/backstage@v1.0.5
    include: [system-domain-valid]
    # with: ...

How This Guardrail Works

This guardrail is part of the Backstage Guardrails policy. It evaluates data collected by integrations and produces a pass/fail check with actionable feedback.

When enabled, this check runs automatically on every PR and in AI coding workflows, providing real-time enforcement of your engineering standards.

Learn How Lunar Works →
1
↓ Integrations Gather Data
Collectors extract metadata from code, CI pipelines, tool outputs, and scans
2
{ } Centralized as JSON
All data merged into each component's unified metadata document
3
✓ This Guardrail Checks Current
System Domain Valid runs and provides pass/fail feedback

Configuration Options

These inputs can be configured in your lunar-config.yml to customize how the parent policy (and this guardrail) behaves.

Input Required Default Description
skip_when_no_catalog_info Optional false Skip every check in this policy on a component with no catalog-info.yaml, instead of failing it. Set to `"true"` when only some repositories in scope are registered in Backstage, so importing the policy broadly does not turn the rest red. One switch for the whole family, and the only place their missing-file behaviour is described. With the default (`"false"`) a missing catalog file fails `catalog-info-exists`, `catalog-info-valid`, `owner-set`, `lifecycle-set`, `system-set` and `system-domain-valid`; fails `required-annotations`, `required-tag-patterns`, `required-link-types`, `dependencies-documented`, `allowed-types` and `allowed-lifecycles` when those are configured; passes the two `disallowed-*` deny-checks, since nothing forbidden can be present without a file; and skips the other referential-integrity checks, which have nothing to cross-check. With `"true"` every check skips instead — the `disallowed-*` pair included, so a component that is not in the catalog reports no green passes it did not earn. Only the file's absence is affected: a component that has a catalog-info.yaml is held to every check either way.
required_annotations Required — Annotation keys that must be present (and non-empty) in catalog-info.yaml `metadata.annotations`. Two forms are accepted. Comma-separated keys (presence-only, unchanged), e.g. `backstage.io/source-location,pagerduty.com/integration-key`. Or a YAML list, where each entry is either a bare key (presence-only) or a mapping with a `key` and optional value constraints: `type` (string|integer|number|boolean, default string), `min`/`max` (integer/number bounds), `min_length`/`max_length` (string length), `pattern` (full-match regex), and `enum` (allowed values). For example, a `key: example.com/service-tier` with `type: integer`, `min: 0`, `max: 5` requires that annotation to parse as an integer in 0–5. Annotation values are strings in Backstage, so `type` validates that the value *parses* as the declared type (`"2"` satisfies `integer`, `"2.5"` does not). `enum` inherits `type`: its entries are coerced to the declared type before comparison, so `type: integer` with `enum: [1,2,3]` compares integers while the default `type: string` compares strings. Constraints must match the declared type (`min`/`max` for integer/number; `min_length`/`max_length`/`pattern` for string). A value that violates a constraint fails the check; a malformed constraint (unknown type, min greater than max, invalid regex, a constraint on the wrong type, or an enum entry not of the declared type) makes it error. Empty (the default) disables the check.
required_tag_patterns Required — Comma-separated list of glob patterns; the component's `metadata.tags` must include at least one tag matching each pattern. Example: `location/*,runs-on/*`. Matching is case-insensitive. Empty (the default) disables the `required-tag-patterns` check.
required_link_types Required — Comma-separated list of link types; catalog-info.yaml `metadata.links` must include an entry whose `type` is each of them. Example: `runbook,dashboard`. Matching is exact and case-sensitive, and only the `type` is compared, not the link's title or URL. Empty (the default) disables the `required-link-types` check.
disallowed_annotations Required — Comma-separated list of annotation keys that must NOT be present in catalog-info.yaml `metadata.annotations`. Example: `backstage.io/skip-checks`. Empty (the default) disables the `disallowed-annotations` check.
disallowed_tag_patterns Required — Comma-separated list of glob patterns; the component's `metadata.tags` must NOT include any tag matching these patterns. Example: `deprecated/*,internal-only`. Matching is case-insensitive. Empty (the default) disables the `disallowed-tag-patterns` check.
require_dependencies Optional false Set to `"true"` to enforce `dependencies-documented`. Off by default, so importing the whole policy doesn't fail every component that declares no dependencies.
dependencies_annotation Required — Annotation key that also counts as declared dependencies when its value is a non-empty comma-separated list, for catalogs that record dependencies there instead of in `spec.dependsOn`. Example: `example.com/dependencies`. Empty (the default) checks `spec.dependsOn` only.
allowed_types Required — Comma-separated list of allowed `spec.type` values. Example: `service,website,library`. Matching is exact and case-sensitive, and applies to the primary entity whatever its kind, so an `API` entity's type (e.g. `openapi`) needs listing too. Empty (the default) disables the `allowed-types` check.
allowed_lifecycles Required — Comma-separated list of allowed `spec.lifecycle` values. Example: `production,experimental,deprecated`. Matching is exact and case-sensitive. Empty (the default) disables the `allowed-lifecycles` check.
Backstage Guardrails

Backstage Guardrails

This guardrail is part of the Backstage Guardrails policy, which includes 19 guardrails for repository and ownership.

View Policy

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 300+ built-in guardrails.

Works with any process
check AI agent rules & prompt files
check Post-mortem action items
check Security & compliance policies
check Testing & quality requirements
Auto-ID My Guardrails
Paste your AGENTS.md or manual process doc and get guardrails in minutes
Book a Demo