CEL Entity Validation
CEL rules are used to validate the metadata and specifications of your entities against a set of predefined rules. This is ideal for enforcing naming conventions, mandatory fields, and architectural standards.
Concepts
The linter works by evaluating CEL (Common Expression Language) expressions against your entities. CEL is a powerful and efficient language designed for safety and performance.
Rule definition
A linting rule consists of:
- Name: A unique identifier for the rule (e.g.,
has-description). - Severity: How critical the violation is. Can be
error,warn, orinfo. - Condition: (Optional) A CEL expression that determines if the rule should be evaluated for a given entity. Use this to restrict rules to specific kinds or lifecycles.
- Check: The CEL expression that validates the entity. If it returns
false, the rule is considered violated. - Message: The message shown to the user when the rule is violated.
Tip
For a comprehensive list of CEL examples and how to use them with the swcat model, see the CEL Demo test file in the repository.
Configuration
Linter rules are configured in a lint.yml file located in your data root directory.
The file has the following sections:
celRules: A list of CEL-based rules.customRules: A list of rules that invoke registered Go functions for complex validation.reportedGroups: (Optional) A list of group names (e.g.team-alphaormy-namespace/team-beta). If set, the global lint findings page will only show these groups as individual cards. All other groups will be grouped under an "Others" section. This is useful for focusing on your own teams in a large catalog with many external owners.
Example lint.yml
reportedGroups:
- team-alpha
- team-beta
- external/partner-team
celRules:
- name: has-description
severity: warn
check: 'metadata.description != ""'
message: "The entity should have a non-empty description for better documentation."
- name: has-docs-link
severity: info
# CEL 'exists' macro to check for a specific link type
check: 'metadata.links.exists(l, l.type == "docs")'
message: "Consider adding a link of type 'docs' for detailed documentation."
- name: api-has-provider
severity: error
condition: 'kind == "api"'
# Inverse relationships are also available!
check: 'size(spec.providers) > 0'
message: "The API must have at least one provider component."
- name: domain-has-org
severity: error
condition: 'kind == "domain"'
check: '"company/org" in metadata.labels'
message: "The Domain must have a 'company/org' label to indicate ownership."
Viewing Findings
When an entity violates a rule, swcat displays the findings in three ways:
- Global Lint Findings Page: Click the "Bug" icon in the top navigation bar to see a report of all findings in the catalog, grouped by Owner and System.
- Entity Detail Page: A small indicator icon (yellow exclamation mark) appears in the top toolbar next to the entity's kind. The detailed findings are shown in a foldable section at the bottom of the page.
- Search: You can find all entities with linting violations using the
lintsearch property.
Searching for violations
You can use the lint attribute in your search queries:
lint:error: Find all entities with at least one "error" severity violation.lint:warn: Find all entities with at least one "warn" severity violation.lint:has-description: Find all entities that violate thehas-descriptionrule.
Example: kind:API AND lint:error
The Entity Model
When writing CEL expressions, you have access to the entity's fields as defined in the catalog.proto Protobuf definition.
The following variables are available in the CEL environment:
kind: The entity's kind (string).metadata: The entity's metadata (e.g.,metadata.name,metadata.labels).spec: The entity's specification (e.g.,spec.type,spec.owner). For kind-specific rules,specis automatically cast to the correct type (e.g.,ApiSpecfor API entities).
Inverse Relationships
Unlike the static YAML files, the model seen by the linter includes inverse relationships that are automatically populated by swcat:
ComponentSpec:dependents(entities that depend on this component),subcomponents.ApiSpec:providers(components that provide this API),consumers(components that consume this API).ResourceSpec:dependents.SystemSpec:components,apis,resources.DomainSpec:systems.GroupSpec:children.
These fields allow you to write powerful rules that enforce architectural standards across your catalog.