From 14abc16b2d1febc199c00d23cf160cb2962c7532 Mon Sep 17 00:00:00 2001
From: Nick Barry <nbarry10@unl.edu>
Date: Fri, 26 Jul 2024 13:15:40 -0500
Subject: [PATCH 1/4] add script that can check file extensions and content
 changes to determine if we need to review the merge request or not

---
 merge-request-check/merge_review_check.sh | 141 ++++++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 merge-request-check/merge_review_check.sh

diff --git a/merge-request-check/merge_review_check.sh b/merge-request-check/merge_review_check.sh
new file mode 100644
index 0000000..35570d2
--- /dev/null
+++ b/merge-request-check/merge_review_check.sh
@@ -0,0 +1,141 @@
+#!/bin/bash
+
+# Script to check changed file extensions and for code in changed lines of files
+
+# Define variables for testing only (these are passed in via GitLab CI)
+#CI_COMMIT_BEFORE_SHA=""
+#CI_COMMIT_SHA=""
+
+# Function to check for ASP.NET controls and directives
+check_aspx() {
+    local content="$1"
+
+    # Check for ASP.NET server controls and directives (matches <asp:, <%@ Page, <%@ Control, etc.)
+    if echo "$content" | grep -qE '<asp:|<%|%>'; then
+        return 0  # ASP.NET control or directive found
+    fi
+
+    return 1  # No ASP.NET control or directive found
+}
+
+# Function to check for PHP code and Blade directives
+check_php_blade() {
+    local content="$1"
+
+    # Check for PHP code (matches <?php ... ?> and <?= ... ?>)
+    if echo "$content" | grep -qE '<\?php|<\?='; then
+        return 0  # PHP code found
+    fi
+
+    # Check for Blade directives (matches {{ ... }}, {!! ... !!}, @if, @foreach, etc.)
+    if echo "$content" | grep -qE '{{.*}}|{!!.*!!}|@\w+'; then
+        return 0  # Blade directive found
+    fi
+
+    return 1  # No PHP code or Blade directive found
+}
+
+# Flag to track if code was found
+code_found=0
+
+# Loop through each changed file in the commit
+tempfile=$(mktemp)
+git diff --name-only $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA > "$tempfile"
+while read -r file; do
+    case "$file" in
+        *.html)
+            echo "OK: HTML file change - $file"
+            ;;
+        *.js)
+            echo "OK: JS file change - $file"
+            ;;
+        *.css)
+            echo "OK: CSS file change - $file"
+            ;;
+        *.pdf)
+            echo "OK: PDF file change - $file"
+            ;;
+        *.doc)
+            echo "OK: DOC file change - $file"
+            ;;
+        *.docx)
+            echo "OK: DOCX file change - $file"
+            ;;
+        *.png)
+            echo "OK: PNG file change - $file"
+            ;;
+        *.jpg)
+            echo "OK: JPG file change - $file"
+            ;;
+        *.gif)
+            echo "OK: GIF file change - $file"
+            ;;
+        *.svg)
+            echo "OK: SVG file change - $file"
+            ;;
+        *.ico)
+            echo "OK: ICO file change - $file"
+            ;;
+        *.md)
+            echo "OK: MD file change - $file"
+            ;;
+        *.csproj)
+            echo "OK: CSPROJ file change - $file"
+            ;;
+        *.sln)
+            echo "OK: SLN file change - $file"
+            ;;
+        *.aspx)
+            # need to look for code within the HTML
+            echo "CHECKING: ASPX file - $file"
+
+            while IFS= read -r line; do
+                if [[ $line == \+\ * ]]; then
+                    # Extract added lines, ignoring leading '+'
+                    content=$(echo "$line" | cut -c2-)
+
+                    # Check for ASP.NET code and elements
+                    if check_aspx "$content"; then
+                        trimmed=$(echo "$content" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+                        echo "FAIL: Found ASP.NET code or elements in $file: $trimmed"
+                        code_found=1  # Set flag indicating code was found
+                    fi
+                fi
+            done < <(git diff $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA -- "$file")
+            ;;
+        *.blade.php)
+            # need to look for code within the HTML
+            echo "CHECKING: BLADE.PHP file - $file"
+
+            while IFS= read -r line; do
+                if [[ $line == \+\ * ]]; then
+                    # Extract added lines, ignoring leading '+'
+                    content=$(echo "$line" | cut -c2-)
+
+                    # Check for PHP code and blade directives
+                    if check_php_blade "$content"; then
+                        trimmed=$(echo "$content" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
+                        echo "FAIL: Found PHP code or Blade directives in $file: $trimmed"
+                        code_found=1  # Set flag indicating code was found
+                    fi
+                fi
+            done < <(git diff $CI_COMMIT_BEFORE_SHA..$CI_COMMIT_SHA -- "$file")
+            ;;
+        *)
+            # All other files fail for manual review
+            echo "FAIL: File type needs reviewed - $file"
+            code_found=1  # Set flag indicating code could be present
+            ;;
+    esac
+done < "$tempfile"
+
+rm "$tempfile"
+
+# Fail the GitLab CI job if code was found
+if [ $code_found -eq 1 ]; then
+    echo "Job failed. Files found that need to be reviewed. Please contact ITS-ADS to request a review of this deployment."
+    exit 1  # Exit with non-zero status to indicate failure
+else
+    echo "Job succeeded. No files that need to be reviewed."
+    exit 0  # Exit with zero status to indicate success
+fi
\ No newline at end of file
-- 
GitLab


From 35a541de0d0309602c43c46ef42ee4aea40b30a8 Mon Sep 17 00:00:00 2001
From: Alan Nelson <alan.nelson@nebraska.edu>
Date: Mon, 19 Aug 2024 17:28:09 -0500
Subject: [PATCH 2/4] Integrate new bash script into approval check flow

---
 merge-request-check/Dockerfile            |  3 +++
 merge-request-check/approval_check.py     | 17 +++++++++++++++--
 merge-request-check/merge_review_check.sh |  3 +++
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/merge-request-check/Dockerfile b/merge-request-check/Dockerfile
index a1cae24..c42327b 100644
--- a/merge-request-check/Dockerfile
+++ b/merge-request-check/Dockerfile
@@ -14,9 +14,12 @@ LABEL org.label-schema.build-date=$BUILD_DATE \
 RUN mkdir /code
 WORKDIR /code
 
+RUN apk add --no-cache bash git
+
 COPY requirements.txt ./
 RUN pip install --no-cache-dir -r requirements.txt
 
 COPY approval_check.py ./
+COPY merge_review_check.sh ./
 
 CMD ["python", "approval_check.py"]
diff --git a/merge-request-check/approval_check.py b/merge-request-check/approval_check.py
index 628158d..45e7019 100644
--- a/merge-request-check/approval_check.py
+++ b/merge-request-check/approval_check.py
@@ -1,5 +1,6 @@
 import os
 import requests
+import subprocess
 import sys
 
 '''
@@ -18,11 +19,23 @@ response = requests.post('https://its-lampprod1-whm.unl.edu/merge_auth_check.php
     'user': os.environ.get('GITLAB_USER_LOGIN')
 })
 
-if (response.status_code == 200):
+if response.status_code == 200:
     # Merge is allowed, print response and exit cleanly (status 0)
     print(response.content.decode('utf-8'))
     exit(0)
+elif response.status_code == 403:
+    # Merge is not allowed, run further checks to see if a review is needed.
+    result = subprocess.run(['bash', '/code/merge_review_check.sh'], capture_output=True, text=True)
+
+    # Print output from additional checks script
+    print(result.stdout)
+    print(result.stderr, file=sys.stderr)
+
+    # Exit using the exit code form the check script
+    exit(result.returncode)
 else:
-    # Merge is not allowed, print response and exit with an error (status 1)
+    # API call failed. Server may be down, or other setup failure. Exit with an error (status 1)
+    print('Merge request approval check API call failed')
+    print(f'API Call Status Code: {response.status_code}')
     print(response.content.decode('utf-8'), file=sys.stderr)
     exit(1)
diff --git a/merge-request-check/merge_review_check.sh b/merge-request-check/merge_review_check.sh
index 35570d2..b92f5f5 100644
--- a/merge-request-check/merge_review_check.sh
+++ b/merge-request-check/merge_review_check.sh
@@ -6,6 +6,9 @@
 #CI_COMMIT_BEFORE_SHA=""
 #CI_COMMIT_SHA=""
 
+# If any commands in this scprt fail, exit with a non-zero exit code
+set -e
+
 # Function to check for ASP.NET controls and directives
 check_aspx() {
     local content="$1"
-- 
GitLab


From fc1316685bc85bd57e6bab33df43a3fc88a9a47b Mon Sep 17 00:00:00 2001
From: Alan Nelson <alan.nelson@nebraska.edu>
Date: Mon, 19 Aug 2024 17:35:08 -0500
Subject: [PATCH 3/4] Update requirements file

---
 merge-request-check/requirements.txt | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/merge-request-check/requirements.txt b/merge-request-check/requirements.txt
index e20605c..05cabde 100644
--- a/merge-request-check/requirements.txt
+++ b/merge-request-check/requirements.txt
@@ -1 +1,6 @@
-requests==2.22.0
\ No newline at end of file
+certifi==2024.7.4
+chardet==3.0.4
+charset-normalizer==3.3.2
+idna==2.8
+requests==2.32.3
+urllib3==2.2.2
-- 
GitLab


From cc53a1e9d2123bfa91f833c0343f8ab32980b85d Mon Sep 17 00:00:00 2001
From: Alan Nelson <alan.nelson@nebraska.edu>
Date: Wed, 21 Aug 2024 11:13:12 -0500
Subject: [PATCH 4/4] Use alternate SHA for MR pipelines

---
 merge-request-check/merge_review_check.sh | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/merge-request-check/merge_review_check.sh b/merge-request-check/merge_review_check.sh
index b92f5f5..016b541 100644
--- a/merge-request-check/merge_review_check.sh
+++ b/merge-request-check/merge_review_check.sh
@@ -6,6 +6,12 @@
 #CI_COMMIT_BEFORE_SHA=""
 #CI_COMMIT_SHA=""
 
+# For merge request pipelines, the before SHA is all 0s.
+# Replace with a MR specific variable for these pipelines.
+if [[ $CI_PIPELINE_SOURCE = 'merge_request_event' ]]; then
+	CI_COMMIT_BEFORE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
+fi
+
 # If any commands in this scprt fail, exit with a non-zero exit code
 set -e
 
-- 
GitLab