Skip to content

Usage

Semantic validation rules are implemented as Python classes and placed in .py files located in the --rules path.

Rules can subclass RuleBase and return Violation objects, which enables richer terminal output (title, explanation, recommendation, references) in addition to the violation message.

from nac_validate import RuleBase, Violation
class Rule(RuleBase):
id = "101"
description = "Verify child naming restrictions"
severity = "HIGH"
title = "Forbidden child name"
explanation = "Child objects named 'FORBIDDEN' are not allowed."
recommendation = "Rename the child object to a compliant name."
references = ["https://example.com/naming-guidelines"]
@classmethod
def match(cls, data):
violations = []
try:
for child in data["root"]["children"]:
if child["name"] == "FORBIDDEN":
violations.append(
Violation(
message=f"root.children.name - {child['name']}",
path="root.children",
)
)
except KeyError:
pass
return violations

RuleBase requires id and description class attributes. severity (default HIGH), title, explanation, recommendation, affected_items_label (default Affected Items) and references are all optional. The match classmethod receives the merged YAML data and can optionally accept the Yamale schema as a second argument.

Violation is a dataclass with a required message field, and optional path and details fields.

The original, simpler style is still supported: a plain Rule class whose match classmethod returns a list of violation strings instead of Violation objects.

class Rule:
id = "101"
description = "Verify child naming restrictions"
severity = "HIGH"
@classmethod
def match(cls, data):
results = []
try:
for child in data["root"]["children"]:
if child["name"] == "FORBIDDEN":
results.append("root.children.name" + " - " + str(child["name"]))
except KeyError:
pass
return results

nac-validate uses distinct exit codes so CI pipelines can distinguish between failure types:

CodeMeaning
0Validation passed
1Semantic validation failed (rule violations)
2Syntax validation failed (YAML syntax or schema errors)
3Configuration error (e.g. missing schema, invalid rules)

The -f/--format option controls the output format (text or json). JSON output is useful for CI/CD integration:

Terminal window
nac-validate data/ -s schema.yaml -r rules/ --format json
{
"syntax_errors": [],
"semantic_errors": [
{
"rule_id": "301",
"description": "Verify Infra VLAN Is Defined When Referenced by AAEPs",
"errors": [
"apic.access_policies.aaeps[name=INFRA-AAEP].infra_vlan - AAEP 'INFRA-AAEP' has infra_vlan enabled but global infra_vlan is not defined"
]
}
]
}

The tool can be integrated via a pre-commit hook with the following config (.pre-commit-config.yaml), assuming the default values (.schema.yaml, .rules/) are appropriate:

repos:
- repo: https://github.com/netascode/nac-validate
rev: v2.0.0
hooks:
- id: nac-validate

In case the schema or validation rules are located somewhere else the required CLI arguments can be added like this:

repos:
- repo: https://github.com/netascode/nac-validate
rev: v2.0.0
hooks:
- id: nac-validate
args:
- '-s'
- 'my_schema.yaml'
- '-r'
- 'rules/'

Values can be encrypted using Ansible Vault. This requires Ansible (ansible-vault command) to be installed and the following two environment variables to be defined:

export ANSIBLE_VAULT_ID=dev
export ANSIBLE_VAULT_PASSWORD=Password123

ANSIBLE_VAULT_ID is optional, and if not defined will be omitted.

The !env YAML tag can be used to read values from environment variables.

root:
name: !env VAR_NAME