yaml_path_equals
Query a structured document with a JSONPath expression and assert every match deep-equals the supplied value.
Semantics:
- Multiple matches — every match must equal the expected value.
- Zero matches — counts as a violation (the key the rule is enforcing doesn’t exist).
- Unparseable files — one violation per file (not silently skipped).
XML mapping applies to every XML surface: xml_path_*, json_schema_passes format: xml, and the xml: extract used by cross_file / file_graph / registry_paths_resolve. XML is mapped to the queryable tree with the xmltodict-style convention so the JSONPath reads like the XML — the document is { <root-element>: … } ($.Project…, $.project…); attributes are @name keys (['@Version'], in bracket notation, since .@Version is not valid JSONPath); a leaf element collapses to its text (<TargetFramework>net8.0</TargetFramework> → "net8.0"); namespaces flatten to the local name (Maven’s default pom.xml namespace just works). Two properties of XML’s data model to keep in mind:
- Every XML leaf value is a string. Quote expected values (
equals: "4.0.0", notequals: 4.0.0), reach for*_path_matches, and in ajson_schema_passesschema type XML fields asstringwith apattern—type: integer/boolean/numberalways fail against XML (every leaf is a string);type: array/objectadditionally depend on cardinality (next point). - Cardinality is data-dependent. A single
<dependency>is an object (a string for a leaf element); two or more become an array. A[*]wildcard therefore does not normalize cardinality —dependency[*]reads nothing for one element but every element for many, and a leaf query flips the same way (an attribute such as MSBuild’sCondition=also turns a would-be leaf string into a{ "@Condition": …, "#text": … }object). When a rule must handle both one and many, use recursive descent:$.Project.ItemGroup.ProjectReference..['@Include']reads the@Includeof one or many. Scope the..under a parent element so it does not over-match a same-named key elsewhere.
Full rationale and edge cases: docs/design/v0.10/xml_path.md.
Options
Section titled “Options”| Option | Type | Required | Default | Description |
|---|---|---|---|---|
equals | any value | yes | Expected value. Any JSON type (string, number, boolean, null, array, object). | |
if_present | boolean | false | When true, a query returning zero matches is silently OK - only real matches that fail the op produce violations. | |
path | string | yes | JSONPath expression rooted at $. Supports dot-access ($.foo.bar), array index ($.deps[0]), wildcards ($.deps[*]), filters, and every other RFC 9535 construct. |
Plus the common paths, level, id, and when fields. This table is generated from the JSON Schema; option types and defaults are authoritative.
Example
Section titled “Example”A workflow that sets contents permission to write
Section titled “A workflow that sets contents permission to write”The rule fires on this repository:
.github/.github/workflows/.github/workflows/bad.yml.github/workflows/ci.ymlname: Badon: pushpermissions: contents: writejobs: test: runs-on: ubuntu-latest steps: - run: echo hiname: CIon: pushpermissions: contents: readjobs: test: runs-on: ubuntu-latest steps: - run: echo hiWith this .alint.yml:
version: 1rules: - id: workflow-contents-read kind: yaml_path_equals paths: ".github/workflows/*.yml" path: "$.permissions.contents" equals: "read" level: erroralint check reports:
--- .github/workflows/bad.yml -------------------------------------------------- x error workflow-contents-read value at path does not equal expected: expected "read", got "write"
Summary (1 violation): x 1 error 0 passing * 1 failingEvery workflow sets contents permission to read
Section titled “Every workflow sets contents permission to read”This repository is compliant:
.github/.github/workflows/.github/workflows/ci.yml.github/workflows/release.ymlname: CIon: pushpermissions: contents: readjobs: build: runs-on: ubuntu-latest steps: - run: echo hiname: Releaseon: pushpermissions: contents: readjobs: release: runs-on: ubuntu-latest steps: - run: echo hiWith this .alint.yml:
version: 1rules: - id: workflow-default-permissions kind: yaml_path_equals paths: ".github/workflows/*.yml" path: "$.permissions.contents" equals: "read" level: erroralint check reports:
v All 1 rule(s) passed.