From cd8de4ff44badce9933f6fae07e228792e77351f Mon Sep 17 00:00:00 2001
From: Tim Jaacks <tim.jaacks@seco.com>
Date: Mon, 27 Mar 2023 15:51:06 +0200
Subject: [PATCH] .gitlab-ci: add analyze stage for limiting YAML script blocks

---
 .gitlab-ci.yml                     |  8 +++
 scripts/check_yaml_value_length.py | 91 ++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)
 create mode 100755 scripts/check_yaml_value_length.py

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9c2f0b9a..8f1f88ef 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -62,6 +62,14 @@ pylint:
     - cd scripts
     - pylint --rcfile=pylintrc *.py
 
+script_limit:
+  extends: .analyze
+  script:
+    - scripts/check_yaml_value_length.py *.yml --limit 800
+        --key script
+        --key before_script
+        --key after_script
+
 yamllint:
   extends: .analyze
   script:
diff --git a/scripts/check_yaml_value_length.py b/scripts/check_yaml_value_length.py
new file mode 100755
index 00000000..6e0e5338
--- /dev/null
+++ b/scripts/check_yaml_value_length.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+
+import argparse
+import glob
+import sys
+from collections import OrderedDict
+
+from ruamel.yaml import YAML, CommentedMap
+
+from colors import colors
+
+
+def check_value_length(filename: str, data: OrderedDict, keys: list[str], limit: int):
+    """Check if values of given YAML keys exceed a given limit.
+
+    Args:
+        filename: name of the file where data has been read from (used for debug output)
+        data: ordered dictionary containing YAML elements
+        keys: list of keys to check values of
+        limit: maximum number of allowed characters for any of the keys' values
+
+    Returns:
+        True if a limit exceedence has been found
+        False else
+    """
+
+    exceeded = False
+    for key, value in data.items():
+        if key in keys:
+            count = 0
+            for item in value:
+                count += len(item)
+            if count > limit:
+                exceeded = True
+                print(
+                    colors.fg.purple
+                    + filename
+                    + ":"
+                    + colors.fg.green
+                    + str(data[key].lc.line)
+                    + colors.reset
+                    + " value of '%s' exceeds character limit (%d > %d)"
+                    % (key, count, limit)
+                )
+        if type(value) is CommentedMap:
+            exceeded = check_value_length(filename, value, keys, limit) | exceeded
+    return exceeded
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+        "--key",
+        help="""YAML key to check (can be passed multiple times for multiple keys)""",
+        dest="key",
+        action="append",
+        required=True,
+    )
+    parser.add_argument(
+        "--limit",
+        help="""Character limit for given key(s)""",
+        dest="limit",
+        type=int,
+        required=True,
+    )
+    parser.add_argument(
+        "filename",
+        help="""File(s) to check""",
+        nargs="+",
+    )
+
+    args, _ = parser.parse_known_args()
+
+    files = []
+    for filename in args.filename:
+        for f in glob.glob(filename):
+            files.append(f)
+
+    exceeded = False
+    for f in files:
+        with open(f, "r", encoding="utf8") as fp:
+            yaml = YAML()
+            data = yaml.load(fp)
+            exceeded = check_value_length(f, data, args.key, args.limit) | exceeded
+
+    if exceeded:
+        sys.exit(1)
+
+
+if __name__ == "__main__":
+    main()
-- 
GitLab