Skip to content

Commit 321bd88

Browse files
Merge pull request #1 from nicholasmhughes/add-yaml-value-regex
Add yaml value regex hook
2 parents a24b57f + 836bb60 commit 321bd88

5 files changed

Lines changed: 100 additions & 2 deletions

File tree

.pre-commit-hooks.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,11 @@
1616
always_run: True
1717
types:
1818
- yaml
19+
- id: valueregex
20+
name: valueregex
21+
description: Disallows the use of certain YAML values based on a regex.
22+
entry: valueregex
23+
language: python
24+
always_run: False
25+
types:
26+
- yaml

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ Add this to your `.pre-commit-config.yaml`
1111
```yaml
1212
repos:
1313
- repo: https://github.com/eitrtechnologies/pre-commit-yamlpolicy
14-
rev: v1.1.0 # Use the ref you want to point to
14+
rev: v1.2.0 # Use the ref you want to point to
1515
hooks:
1616
- id: bannedk8skinds
1717
- id: disallowunquoted
18+
- id: valueregex
19+
args: [--jmespath, '*.matchers[].match', --regex, '\([^ ]|[^ ]\)']
1820
```
1921
2022
### Hooks Available
@@ -33,3 +35,14 @@ Deny commits where certain YAML values are found but not quoted.
3335
Defaults to `on,off,yes,no,y,n`.
3436
- `--case-sensitive` - Flag to turn off case insensitivity when searching for
3537
values. Operation defaults to ignore case.
38+
39+
#### `valueregex`
40+
Deny commits where certain YAML values are found and match a given regex. A
41+
JMESPath query is used in conjunction with a regular expression to match string
42+
values in YAML.
43+
- `--jmespath` - [JMESPath expression](https://jmespath.org/) which returns
44+
the values to run a regex against. *REQUIRED*
45+
- `--regex` - Regex which will cause the hook to fail if it matches any of the
46+
values returned by the JMESPath query. *REQUIRED*
47+
- `--allow-multiple-documents` - Allow YAML files which use the
48+
[multi-document syntax](http://www.yaml.org/spec/1.2/spec.html#YAML)

setup.cfg

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = yamlpolicy
3-
version = 1.0.0
3+
version = 1.2.0
44
description = Allows an organization to specify YAML usage policy.
55
long_description = file: README.md
66
long_description_content_type = text/markdown
@@ -23,13 +23,15 @@ classifiers =
2323
[options]
2424
packages = find:
2525
install_requires =
26+
jmespath>=1.0.0
2627
ruamel.yaml>=0.16.12
2728
python_requires = >=3.7.1
2829

2930
[options.entry_points]
3031
console_scripts =
3132
bannedk8skinds = bannedk8skinds.bannedk8skinds:main
3233
disallowunquoted = disallowunquoted.disallowunquoted:main
34+
valueregex = valueregex.valueregex:main
3335

3436
[options.packages.find]
3537
exclude =

valueregex/__init__.py

Whitespace-only changes.

valueregex/valueregex.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import argparse
2+
import re
3+
from typing import List, Optional, Sequence
4+
5+
import jmespath
6+
import ruamel.yaml
7+
8+
yaml = ruamel.yaml.YAML(typ="safe")
9+
10+
11+
def main(argv: Optional[Sequence[str]] = None) -> int:
12+
parser: argparse.ArgumentParser = argparse.ArgumentParser(add_help=False)
13+
required: argparse.ArgumentGroup = parser.add_argument_group("required arguments")
14+
optional: argparse.ArgumentGroup = parser.add_argument_group("optional arguments")
15+
optional.add_argument(
16+
"-h",
17+
"--help",
18+
action="help",
19+
default=argparse.SUPPRESS,
20+
help="show this help message and exit",
21+
)
22+
optional.add_argument(
23+
"-m",
24+
"--multi",
25+
"--allow-multiple-documents",
26+
action="store_true",
27+
)
28+
required.add_argument(
29+
"-r",
30+
"--regex",
31+
required=True,
32+
)
33+
required.add_argument(
34+
"-j",
35+
"--jmespath",
36+
required=True,
37+
)
38+
required.add_argument("filenames", nargs="*", help="Filenames to check.")
39+
args: argparse.Namespace = parser.parse_args(argv)
40+
41+
regex: re.Pattern = re.compile(args.regex)
42+
search: str = args.jmespath
43+
44+
retval: int = 0
45+
for filename in args.filenames:
46+
try:
47+
with open(filename, encoding="UTF-8") as f:
48+
if args.multi:
49+
docs = yaml.load_all(f)
50+
else:
51+
docs = [yaml.load(f)]
52+
for doc in docs:
53+
for val in jmespath.search(search, doc) or []:
54+
match: re.Match = regex.search(val)
55+
if match:
56+
print(
57+
f'{filename}: Restricted value found for JMESPath "{search}" = {match.group(0).rstrip()}'
58+
)
59+
retval = 1
60+
except ruamel.yaml.YAMLError as exc:
61+
print(exc)
62+
retval = 1
63+
except jmespath.exceptions.ParseError as exc:
64+
print(exc)
65+
retval = 1
66+
except TypeError:
67+
print(
68+
"JMESPath expression returned non-string values. Ensure your expression returns a flat list of strings."
69+
)
70+
retval = 1
71+
return retval
72+
73+
74+
if __name__ == "__main__":
75+
exit(main())

0 commit comments

Comments
 (0)