Roadie Backstage Entity Validator

Published on June 29th, 2022

Introduction

Roadie provides many additional utilities to make your experience with Backstage smoother. One of these is the Backstage Entity Validator . With this validator you can confirm that the entity descriptor files you are creating for Backstage conform to the schema and can be ingested by Backstage. The validator does not check the validity of entity references such as the "owner" field.

The Entity Validator is enabled automatically when you install the Roadie GitHub app to your GitHub organization. The validator automatically checks your pull requests and validates Backstage files included in them. The GitHub app check files with .yml or .yaml type and that have an apiVersion containing a string backstage.io, thus indicating that it is a Backstage descriptor file.

Configuration

The validator reads a .roadierc configuration file (YAML format) to control its behaviour. It looks for this file in two places, in order:

  1. Org-level config: {your-org}/.github/.roadierc — applies to all repositories in your GitHub organization. The Roadie GitHub app must be installed on the .github repo for this to work. If the app isn't installed there or the file doesn't exist, it is silently ignored.
  2. Repo-level config: .roadierc in the root of the repository being validated — takes precedence over org-level config for repo-specific overrides.

Available options

yaml
validator:
  disabled: true
  exclude:
    - "catalog-*.yaml"
  validationSchemaUrl: "https://example.com/schemas/entity-validation.json"
OptionDescription
validator.disabledSet to true to skip validation entirely for this repo (or org-wide if set in .github).
validator.excludeGlob patterns for files to skip. Org and repo exclude lists are merged together.
validator.validationSchemaUrlURL to a custom JSON Schema used to validate entity. Useful for enforcing naming conventions or custom annotation rules.

Precedence rules

When both org-level and repo-level configs exist, they are merged as follows:

FieldBehaviour
disabledRepo overrides org. Setting disabled: false in a repo runs validation even if the org config disables it.
excludeBoth lists are concatenated — org excludes and repo excludes both apply.
validationSchemaUrlRepo overrides org. If the repo specifies a different URL, it wins.

Examples

Disable validation for all repositories in your org:

yaml
# {your-org}/.github/.roadierc
validator:
  disabled: true

Use a custom annotation schema org-wide, but allow a specific repo to override it:

yaml
# {your-org}/.github/.roadierc
validator:
  validationSchemaUrl: "https://raw.githubusercontent.com/my-org/.github/main/schemas/entity-validation.json"
yaml
# my-special-repo/.roadierc
validator:
  validationSchemaUrl: "https://raw.githubusercontent.com/my-org/.github/main/schemas/strict-validation.json"

Testing a custom schema before rolling it out org-wide

Because a repo-level .roadierc overrides the org-level one, you can safely trial a new schema in a single repository without affecting anyone else:

  1. Add the schema file to your .github repo (or any public URL) and merge it to the default branch.
  2. In a test repository, add a .roadierc that points to the new schema URL:
yaml
# my-test-repo/.roadierc
validator:
  validationSchemaUrl: "https://raw.githubusercontent.com/my-org/.github/main/schemas/entity-validation-candidate.json"
  1. Open a pull request in that repo with entity files that should pass, and others that should fail. Verify the check results match your expectations.
  2. Once you're happy, move the validationSchemaUrl into {your-org}/.github/.roadierc to apply it across the org, and remove the repo-level .roadierc.

Custom schema example

The validationSchemaUrl must point to a JSON Schema (draft-07) file. The schema is run against the entire entity object, so you can add extra constraints on any field — metadata.name, metadata.labels, spec.owner, metadata.annotations, etc.

Important: the custom schema is purely additive. It runs on top of Backstage's built-in structural validation (required fields, valid kind, correct spec shape for each kind). It cannot relax or remove those built-in rules — it can only add stricter ones.

The following example enforces two org-specific rules on top of the standard Backstage validation:

  1. metadata.name must be lowercase kebab-case with an optional team prefix separated by a dot (e.g. payments.checkout-service)
  2. All annotation keys must be prefixed with either backstage.io/ or my-org.com/
json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://raw.githubusercontent.com/my-org/.github/main/schemas/entity-validation.json",
  "type": "object",
  "properties": {
    "metadata": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^([a-z0-9]+\\.)?[a-z0-9][a-z0-9-]*[a-z0-9]$",
          "description": "Entity names must be lowercase kebab-case, optionally prefixed with a team name and dot (e.g. payments.checkout-service)"
        },
        "annotations": {
          "type": "object",
          "patternProperties": {
            "^(backstage\\.io|my-org\\.com)/": {
              "type": "string"
            }
          },
          "additionalProperties": false
        }
      }
    }
  }
}

With this schema in place, a PR containing the following would fail validation because the name uses uppercase and the annotation key is not from an allowed domain:

yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: MyCheckoutService
  annotations:
    internal/owner: payments-team
spec:
  type: service
  lifecycle: production
  owner: group:payments

Schemas

The validator is based on the published Backstage schemas which can be referred to in the Backstage docs along with two additional Kinds - Repository and Product. A list of Kinds available in Roadie can be found here.

Further reading

  1. The Backstage Entity Validator repository .
  2. Backstage Entity Schemas