Skip to content

Commit

Permalink
Merge pull request #1 from nicholasmhughes/add-yaml-value-regex
Browse files Browse the repository at this point in the history
Add yaml value regex hook
  • Loading branch information
nicholasmhughes authored Mar 16, 2022
2 parents a24b57f + 836bb60 commit 321bd88
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 2 deletions.
8 changes: 8 additions & 0 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@
always_run: True
types:
- yaml
- id: valueregex
name: valueregex
description: Disallows the use of certain YAML values based on a regex.
entry: valueregex
language: python
always_run: False
types:
- yaml
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ Add this to your `.pre-commit-config.yaml`
```yaml
repos:
- repo: https://github.com/eitrtechnologies/pre-commit-yamlpolicy
rev: v1.1.0 # Use the ref you want to point to
rev: v1.2.0 # Use the ref you want to point to
hooks:
- id: bannedk8skinds
- id: disallowunquoted
- id: valueregex
args: [--jmespath, '*.matchers[].match', --regex, '\([^ ]|[^ ]\)']
```
### Hooks Available
Expand All @@ -33,3 +35,14 @@ Deny commits where certain YAML values are found but not quoted.
Defaults to `on,off,yes,no,y,n`.
- `--case-sensitive` - Flag to turn off case insensitivity when searching for
values. Operation defaults to ignore case.

#### `valueregex`
Deny commits where certain YAML values are found and match a given regex. A
JMESPath query is used in conjunction with a regular expression to match string
values in YAML.
- `--jmespath` - [JMESPath expression](https://jmespath.org/) which returns
the values to run a regex against. *REQUIRED*
- `--regex` - Regex which will cause the hook to fail if it matches any of the
values returned by the JMESPath query. *REQUIRED*
- `--allow-multiple-documents` - Allow YAML files which use the
[multi-document syntax](http://www.yaml.org/spec/1.2/spec.html#YAML)
4 changes: 3 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = yamlpolicy
version = 1.0.0
version = 1.2.0
description = Allows an organization to specify YAML usage policy.
long_description = file: README.md
long_description_content_type = text/markdown
Expand All @@ -23,13 +23,15 @@ classifiers =
[options]
packages = find:
install_requires =
jmespath>=1.0.0
ruamel.yaml>=0.16.12
python_requires = >=3.7.1

[options.entry_points]
console_scripts =
bannedk8skinds = bannedk8skinds.bannedk8skinds:main
disallowunquoted = disallowunquoted.disallowunquoted:main
valueregex = valueregex.valueregex:main

[options.packages.find]
exclude =
Expand Down
Empty file added valueregex/__init__.py
Empty file.
75 changes: 75 additions & 0 deletions valueregex/valueregex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import argparse
import re
from typing import List, Optional, Sequence

import jmespath
import ruamel.yaml

yaml = ruamel.yaml.YAML(typ="safe")


def main(argv: Optional[Sequence[str]] = None) -> int:
parser: argparse.ArgumentParser = argparse.ArgumentParser(add_help=False)
required: argparse.ArgumentGroup = parser.add_argument_group("required arguments")
optional: argparse.ArgumentGroup = parser.add_argument_group("optional arguments")
optional.add_argument(
"-h",
"--help",
action="help",
default=argparse.SUPPRESS,
help="show this help message and exit",
)
optional.add_argument(
"-m",
"--multi",
"--allow-multiple-documents",
action="store_true",
)
required.add_argument(
"-r",
"--regex",
required=True,
)
required.add_argument(
"-j",
"--jmespath",
required=True,
)
required.add_argument("filenames", nargs="*", help="Filenames to check.")
args: argparse.Namespace = parser.parse_args(argv)

regex: re.Pattern = re.compile(args.regex)
search: str = args.jmespath

retval: int = 0
for filename in args.filenames:
try:
with open(filename, encoding="UTF-8") as f:
if args.multi:
docs = yaml.load_all(f)
else:
docs = [yaml.load(f)]
for doc in docs:
for val in jmespath.search(search, doc) or []:
match: re.Match = regex.search(val)
if match:
print(
f'{filename}: Restricted value found for JMESPath "{search}" = {match.group(0).rstrip()}'
)
retval = 1
except ruamel.yaml.YAMLError as exc:
print(exc)
retval = 1
except jmespath.exceptions.ParseError as exc:
print(exc)
retval = 1
except TypeError:
print(
"JMESPath expression returned non-string values. Ensure your expression returns a flat list of strings."
)
retval = 1
return retval


if __name__ == "__main__":
exit(main())

0 comments on commit 321bd88

Please sign in to comment.