Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion website/assets/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,24 @@ code, kbd, pre {
padding: 1em !important;
}

.hljs-red {
color: #ff5874;
}
.hljs-yellow {
color: #ecc48d;
}
.hljs-green {
color: #addb67;
}
.hljs-bash-prompt {
color: #dcdcaa;
font-weight: bold;
}

.doc pre.highlightjs {
font-size: .9rem;
padding-top: 0.75em;
padding-top: 0.3em;
padding-bottom: 0.5em;
}

.doc pre.highlightjs code {
Expand Down
29 changes: 28 additions & 1 deletion website/assets/js/vendor/highlight.pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,4 +488,31 @@ className:"number",variants:[{begin:e.C_NUMBER_RE+"[i]",relevance:1
},e.C_NUMBER_MODE]},{begin:/:=/},{className:"function",beginKeywords:"func",
end:"\\s*(\\{|$)",excludeEnd:!0,contains:[e.TITLE_MODE,{className:"params",
begin:/\(/,end:/\)/,endsParent:!0,keywords:n,illegal:/["']/}]}]}}})()
;hljs.registerLanguage("go",e)})();
;hljs.registerLanguage("go",e)})();/*! `rego` grammar compiled for Highlight.js 11.10.0 */
(()=>{var e=(()=>{"use strict";return e=>{const r=e.regex;return{case_insensitive:!1,keywords:{
keyword:["as","contains","default","else","every","if","in","import","package","not","some","with"],
literal:["false","true","null"],symbol:["data","input"],
built_in:["abs","all","and","any","array.concat","array.reverse","array.slice","assign","base64.decode","base64.encode","base64.is_valid","base64url.decode","base64url.encode","base64url.encode_no_pad","bits.and","bits.lsh","bits.negate","bits.or","bits.rsh","bits.xor","cast_array","cast_boolean","cast_null","cast_object","cast_set","cast_string","ceil","concat","count","crypto.hmac.equal","crypto.hmac.md5","crypto.hmac.sha1","crypto.hmac.sha256","crypto.hmac.sha512","crypto.md5","crypto.parse_private_keys","crypto.sha1","crypto.sha256","crypto.x509.parse_and_verify_certificates","crypto.x509.parse_and_verify_certificates_with_options","crypto.x509.parse_certificate_request","crypto.x509.parse_certificates","crypto.x509.parse_keypair","crypto.x509.parse_rsa_private_key","div","endswith","eq","equal","floor","format_int","glob.match","glob.quote_meta","graph.reachable","graph.reachable_paths","graphql.is_valid","graphql.parse","graphql.parse_and_verify","graphql.parse_query","graphql.parse_schema","graphql.schema_is_valid","gt","gte","hex.decode","hex.encode","http.send","indexof","indexof_n","internal.member_2","internal.member_3","internal.print","intersection","io.jwt.decode","io.jwt.decode_verify","io.jwt.encode_sign","io.jwt.encode_sign_raw","io.jwt.verify_es256","io.jwt.verify_es384","io.jwt.verify_es512","io.jwt.verify_hs256","io.jwt.verify_hs384","io.jwt.verify_hs512","io.jwt.verify_ps256","io.jwt.verify_ps384","io.jwt.verify_ps512","io.jwt.verify_rs256","io.jwt.verify_rs384","io.jwt.verify_rs512","is_array","is_boolean","is_null","is_number","is_object","is_set","is_string","json.filter","json.is_valid","json.marshal","json.marshal_with_options","json.match_schema","json.patch","json.remove","json.unmarshal","json.verify_schema","lower","lt","lte","max","min","minus","mul","neq","net.cidr_contains","net.cidr_contains_matches","net.cidr_expand","net.cidr_intersects","net.cidr_is_valid","net.cidr_merge","net.cidr_overlap","net.lookup_ip_addr","numbers.range","numbers.range_step","object.filter","object.get","object.keys","object.remove","object.subset","object.union","object.union_n","opa.runtime","or","plus","print","product","providers.aws.sign_req","rand.intn","re_match","regex.find_all_string_submatch_n","regex.find_n","regex.globs_match","regex.is_valid","regex.match","regex.replace","regex.split","regex.template_match","rego.metadata.chain","rego.metadata.rule","rego.parse_module","rem","replace","round","semver.compare","semver.is_valid","set_diff","sort","split","sprintf","startswith","strings.any_prefix_match","strings.any_suffix_match","strings.count","strings.render_template","strings.replace_n","strings.reverse","substring","sum","time.add_date","time.clock","time.date","time.diff","time.format","time.now_ns","time.parse_duration_ns","time.parse_ns","time.parse_rfc3339_ns","time.weekday","to_number","trace","trim","trim_left","trim_prefix","trim_right","trim_space","trim_suffix","type_name","union","units.parse","units.parse_bytes","upper","urlquery.decode","urlquery.decode_object","urlquery.encode","urlquery.encode_object","uuid.parse","uuid.rfc4122","walk","yaml.is_valid","yaml.marshal","yaml.unmarshal"]
},contains:[e.C_NUMBER_MODE,e.QUOTE_STRING_MODE,{match:/[{}[\]\\(\\),\\.]/,
className:"punctuation",relevance:0},{scope:"operator",
match:r.either("==","=","\\+","-","<=","<",">=",">","!=","\\|","\\*")},{
scope:"string",begin:"`",end:"`"},e.HASH_COMMENT_MODE,{begin:/import rego\.v1/,
keywords:"import",relevance:10}]}}})();hljs.registerLanguage("rego",e)})();

/*! Custom highlight Pack for Conforma output. Simulate
* how it looks in the terminal with the ansi text color. */
(function () {
'use strict';
hljs.registerLanguage('ec', function statusHighlight() {
return {
name: 'Conforma output',
case_insensitive: false,
contains: [
{ begin: /✕ \[Violation\]/, className: 'red' },
{ begin: /› \[Warning\]/, className: 'yellow' },
{ begin: /✓ \[Success\]/, className: 'green' },
{ begin: /^\$/, className: 'bash-prompt' },
]
};
});
})();
330 changes: 330 additions & 0 deletions website/content/posts/01-validate-input-basics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
---
title: Validating arbitary data
date: 2026-01-13T00:30:43-05:00
author: Simon Baird
---
In this tutorial we'll introduce some basic Conforma concepts
and work through some examples of applying policies against some arbitrary
input data.

## ec validate input

Conforma can perform policy checks on arbitrary data with `ec
validate input`. Let's try an example.


A simple data file:

```yaml
# file: input.yaml

animals:
- name: Charlie
species: dog
- name: Luna
species: cat
```


A minimal Conforma policy defined in Rego:

```rego
# file: no-cats/main.rego

package main

# METADATA
# title: No cats
# description: Disallow felines.
# custom:
# short_name: no_cats
# solution: Please ensure no cats are
# present in the animal list.
#
deny contains result if {
some animal in input.animals
animal.species == "cat"
result := {"code": "main.no_cats", "msg": "No cats allowed!"}
}
```

To use that, Conforma needs a policy file specifying a policy source:

```yaml
# file: policy.yaml

sources:
- policy:
- ./no-cats
```


Now we can run Conforma like this:

```ec
$ ec validate input --file input.yaml --policy policy.yaml
Success: false
Result: FAILURE
Violations: 1, Warnings: 0, Successes: 0
Input File: input.yaml

Results:
✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: No cats allowed!

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/
Error: success criteria not met

```


## Using --info for more detailed output

The metadata associated with the policy rule is important for
Conforma. Adding the `--info` flag will use the metadata to show more
verbose/user-friendly output:

```ec
$ ec validate input --file input.yaml --policy policy.yaml --info
Success: false
Result: FAILURE
Violations: 1, Warnings: 0, Successes: 0
Input File: input.yaml

Results:
✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: No cats allowed!
Title: No cats
Description: Disallow felines. To exclude this rule add "main.no_cats" to the `exclude` section of the policy configuration.
Solution: Please ensure no cats are present in the animal list.

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/
Error: success criteria not met

```


## Using --show-successes to show passing checks

Let's "fix" the violation and run it again:

```ec
$ sed -i "s/cat/rabbit/" input.yaml

```

```yaml
# file: input.yaml

animals:
- name: Charlie
species: dog
- name: Luna
species: rabbit
```

```ec
$ ec validate input --file input.yaml --policy policy.yaml --info
Success: true
Result: SUCCESS
Violations: 0, Warnings: 0, Successes: 1
Input File: input.yaml


```


By default there's not much output on success, but we can add
the `--show-successes` flag to change that:

```ec
$ ec validate input --file input.yaml --policy policy.yaml --info --show-successes
Success: true
Result: SUCCESS
Violations: 0, Warnings: 0, Successes: 1
Input File: input.yaml

Results:
✓ [Success] main.no_cats
FilePath: input.yaml
Title: No cats
Description: Disallow felines.


```


(Turn rabbits back into cats for the next step):

```ec
$ sed -i "s/rabbit/cat/" input.yaml

```


## Warnings

We can use "warn" to produce a warning instead of a violation:

(Append to the existing file...)

```rego
# file: no-cats/main.rego

# METADATA
# title: Charlie warning
# description: Charlie is a troublemaker!
# custom:
# short_name: charlie_watch
# solution: Keep a close eye on Charlie.
#
warn contains result if {
some animal in input.animals
animal.name == "Charlie"
result := {"code": "main.charlie_watch", "msg": "Charlie is here"}
}
```

```ec
$ ec validate input --file input.yaml --policy policy.yaml --info --show-successes
Success: false
Result: FAILURE
Violations: 1, Warnings: 1, Successes: 0
Input File: input.yaml

Results:
✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: No cats allowed!
Title: No cats
Description: Disallow felines. To exclude this rule add "main.no_cats" to the `exclude` section of the policy configuration.
Solution: Please ensure no cats are present in the animal list.

› [Warning] main.charlie_watch
FilePath: input.yaml
Reason: Charlie is here
Title: Charlie warning
Description: Charlie is a troublemaker!
Solution: Keep a close eye on Charlie.

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/
Error: success criteria not met

```

Warnings are considered non-blocking.


## Adding more detail to the violation reason

```rego
# file: no-cats/main.rego

deny contains result if {
some animal in input.animals
animal.species == "cat"
result := {"code": "main.no_cats", "msg": sprintf("A cat named %s was found!", [animal.name])}
}
```
```ec
$ ec validate input --file input.yaml --policy policy.yaml
Success: false
Result: FAILURE
Violations: 1, Warnings: 1, Successes: 0
Input File: input.yaml

Results:
✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: A cat named Luna was found!

› [Warning] main.charlie_watch
FilePath: input.yaml
Reason: Charlie is here

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/
Error: success criteria not met

```


If there are multiple cats, we now get multiple different violations:

```yaml
# file: input.yaml

animals:
- name: Charlie
species: dog
- name: Luna
species: cat
- name: Fluffy
species: cat
```

```ec
$ ec validate input --file input.yaml --policy policy.yaml
Success: false
Result: FAILURE
Violations: 2, Warnings: 1, Successes: 0
Input File: input.yaml

Results:
✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: A cat named Fluffy was found!

✕ [Violation] main.no_cats
FilePath: input.yaml
Reason: A cat named Luna was found!

› [Warning] main.charlie_watch
FilePath: input.yaml
Reason: Charlie is here

For more information about policy issues, see the policy documentation: https://conforma.dev/docs/policy/
Error: success criteria not met

```


## Machine readable output

Text output is the default, but you can also output json or yaml,
which includes some additional information.

```ec
$ ec validate input --file input.yaml --policy policy.yaml --info --output json
{"success":false,"filepaths":[{"filepath":"input.yaml","violations":[{"msg":"A cat named Fluffy was found!","metadata":{"code":"main.no_cats","description":"Disallow felines. To exclude this rule add \"main.no_cats\" to the `exclude` section of the policy configuration.","solution":"Please ensure no cats are present in the animal list.","title":"No cats"}},{"msg":"A cat named Luna was found!","metadata":{"code":"main.no_cats","description":"Disallow felines. To exclude this rule add \"main.no_cats\" to the `exclude` section of the policy configuration.","solution":"Please ensure no cats are present in the animal list.","title":"No cats"}}],"warnings":[{"msg":"Charlie is here","metadata":{"code":"main.charlie_watch","description":"Charlie is a troublemaker!","solution":"Keep a close eye on Charlie.","title":"Charlie warning"}}],"successes":null,"success":false,"success-count":0}],"policy":{"sources":[{"policy":["./no-cats"]}]},"ec-version":"v0.8.79","effective-time":"2026-01-13T05:30:43.860003948Z"}
Error: success criteria not met

```


## Strict vs non-strict

By default we produce a non-zero exit code if there are any
violations, which is useful to interrupt a script or a CI task. You can change
that behavior if you need to with --strict=false:

```ec
$ ec validate input --file input.yaml --policy policy.yaml > output.txt; echo "Exit code: $?"; head -3 output.txt
Error: success criteria not met
Exit code: 1
Success: false
Result: FAILURE
Violations: 2, Warnings: 1, Successes: 0

```

```ec
$ ec validate input --file input.yaml --policy policy.yaml --strict=false > output.txt; echo "Exit code: $?"; head -3 output.txt
Exit code: 0
Success: false
Result: FAILURE
Violations: 2, Warnings: 1, Successes: 0

```