- Docs
- Guides
Writing Rules
Turn a standard, policy, pattern or principle into a machine-checkable rule — choose the scope, match the right elements, assert on properties, evidence or decisions, and dry-run before a board adopts it.
#Start from the Statement
A rule makes an artefact's statement checkable. Write the statement first, for people; then ask which fact in the derived model or the imported evidence would show it is met. If no such fact exists, the artefact is still valuable without a rule — boards cite it, reviews link to it — it simply is not evaluated.
#Choose the Kind of Fact
| The statement is about… | Use | Example |
|---|---|---|
| A property Archigov normalises (region, TLS, public access, tags) | A property assertion | Production resources run in UK regions |
| A configuration Defender or Azure Policy already assesses | An evidence assertion (op: evidence) | Storage accounts do not allow public blob access |
| Whether a decision exists for a kind of application | hasDecision | Applications running Azure SQL have a data-store decision |
| Whether deployed resources match an accepted decision | decisionConstraint | Deployed databases are those the decision allowed |
| Ownership or sprawl at application level | hasOwnerTag, maxResourcesOfType | Every application has an owner |
Important
Do not rebuild a security-posture check as a property rule when Defender or Azure Policy already assesses it. Assert on the imported evidence instead. Your rule then rests on the same result your cloud security team sees, and no evidence is reported as a finding rather than silently passing.
#Examples
#A Property Rule
Production resources must be in UK regions:
{
"scope": "resource",
"match": { "where": [ { "path": "tags.env", "op": "eq", "value": "prod" } ] },
"assert": { "path": "location", "op": "in", "value": ["uksouth", "ukwest"] }
}#An Evidence Rule
Storage accounts pass Defender's public-access assessment:
{
"scope": "resource",
"match": { "type": "Microsoft.Storage/storageAccounts" },
"assert": { "op": "evidence", "source": "defender", "control": "storage-public-access", "state": "pass" }
}Omit source to accept evidence from any source.
#A Decision Rule Pair
Applications running Azure SQL need an accepted data-store decision:
{ "scope": "application", "assert": { "op": "hasDecision", "topic": "data-store", "type": "Microsoft.Sql" } }…and their databases must be the types that decision allows:
{
"scope": "resource",
"match": { "typeIn": ["Microsoft.Sql/servers", "Microsoft.DBforPostgreSQL/flexibleServers", "Microsoft.DocumentDB/databaseAccounts"] },
"assert": { "op": "decisionConstraint", "topic": "data-store" }
}The decision supplies the allowed types in its checkable constraint. When an application has no accepted decision on the topic, the constraint rule skips it — the hasDecision rule reports the gap instead.
#A Technology-radar Rule
Retired OS versions are a decision about technology, so a rule may read derived properties directly:
{
"scope": "resource",
"match": { "type": "Microsoft.Compute/virtualMachines" },
"assert": { "path": "props.osSku", "op": "notIn", "value": ["2012-R2-Datacenter", "2012-Datacenter", "2008-R2-SP1"] }
}#Critical Applications Only
Any rule can be narrowed by the application's criticality with app.* paths in match.where, at either scope. Critical applications need an accepted hosting decision:
{
"scope": "application",
"match": { "where": [ { "path": "app.criticality", "op": "eq", "value": "critical" } ] },
"assert": { "op": "hasDecision", "topic": "hosting" }
}An unclassified application does not match critical, so check the Business Services page for applications nobody has classified yet.
#Validate, Then Dry-run
In the artefact editor:
- Save the draft. The rule is validated: an unknown operator, a missing field or an invalid regular expression is reported in place.
- Dry run evaluates the draft rule against the current model and evidence without storing anything, and shows what it would find — its blast radius.
- Pre-review the artefact, then submit it. The board adopts it; only then is it evaluated in every run.
With Rule Drafting enabled, an author can generate a rule from the statement. The draft comes back already validated and dry-run, and the author decides whether to keep it.
#Severity and Enforcement
Findings carry the artefact's severity. Policies carry an enforcement level — mandatory or recommended — that tells boards how to treat exceptions. Neither changes how the rule is evaluated.
#Common Mistakes
- Asserting on the wrong path. A rule sees
name,type,location,tags.<key>,props.<key>and the owning application's classification asapp.*. Prefer the normalised properties (props.publicAccess,props.minTlsVersion,props.httpsOnly,props.osSku) — raw ARM property names differ between resource types and API versions. - Forgetting the match. A resource rule without
matchapplies to every resource. - Treating
missingas safe.missingpasses when the property is absent; prefer evidence when absence means unknown.
The full grammar is in the Rule DSL reference.
Something unclear or out of date? Write to hello@archigov.com or open an issue on GitHub.