Skip to content

Commit fef8d10

Browse files
committed
add soup approval (verification) workflow
1 parent deb309c commit fef8d10

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
name: SOUP - Approval (Verification)
2+
on:
3+
workflow_call:
4+
5+
jobs:
6+
verify-and-update-approval:
7+
if: github.event.review.state == 'approved'
8+
runs-on: [self-hosted, Linux]
9+
steps:
10+
- uses: QuickBirdEng/actions/checkout-ssh@main
11+
with:
12+
ssh-private-key: ${{ secrets.CI_SSH_PRIVATE_KEY_FOR_GITHUB_PRIVATE_REPOS }}
13+
- name: Checkout pull request branch
14+
shell: bash
15+
run: |
16+
BASE_BRANCH="${{ github.event.pull_request.base.ref }}"
17+
HEAD_BRANCH="${{ github.event.pull_request.head.ref }}"
18+
19+
echo "Base branch: $BASE_BRANCH"
20+
echo "Head branch: $HEAD_BRANCH"
21+
22+
git fetch origin "$BASE_BRANCH":"refs/remotes/origin/$BASE_BRANCH" --depth=1 --force
23+
git fetch origin "$HEAD_BRANCH":"refs/remotes/origin/$HEAD_BRANCH" --depth=1 --force
24+
25+
git checkout -B "$HEAD_BRANCH" "origin/$HEAD_BRANCH"
26+
27+
git pull --rebase
28+
echo "BASE_BRANCH=$BASE_BRANCH" >> "$GITHUB_ENV"
29+
- name: Fetch changed SOUP files
30+
id: fetch-soup-files
31+
shell: bash
32+
run: |
33+
JSON_FILES=$(git diff --name-only --diff-filter=AM "origin/$BASE_BRANCH" -- soups/**/*.json || true)
34+
if [ -z "$JSON_FILES" ]; then
35+
echo "::error::No JSON files changed in this PR"
36+
exit 1
37+
fi
38+
39+
echo "Found JSON files in PR: $JSON_FILES"
40+
{
41+
echo "SOUP_FILES<<EOF"
42+
echo "$JSON_FILES"
43+
echo "EOF"
44+
} >> "$GITHUB_ENV"
45+
- name: Verification - Requirements
46+
run: |
47+
STATUS=0
48+
49+
MAGENTA="\033[95m"
50+
CYAN="\033[96m"
51+
RESET="\033[0m"
52+
53+
echo -e "${MAGENTA}Requirements:${RESET}"
54+
55+
FIRST=0
56+
57+
for FILE in $SOUP_FILES; do
58+
if [ $FIRST -eq 0 ]; then
59+
jq -r '
60+
.requirements
61+
| to_entries[]
62+
| "\(.key): \(.value.description)"
63+
' "$FILE" | sort -u | while IFS= read -r line; do
64+
echo -e "${CYAN}${line}${RESET}"
65+
done
66+
FIRST=1
67+
fi
68+
69+
INVALID=$(jq -r '
70+
.requirements
71+
| to_entries
72+
| map(
73+
select(
74+
(.value.fulfilled != true)
75+
and
76+
((.value.reason_if_requirement_not_fulfilled | tostring) == "")
77+
)
78+
)
79+
| .[].key
80+
' "$FILE")
81+
82+
if [ -n "$INVALID" ]; then
83+
INVALID_LIST=$(echo "$INVALID" | tr '\n' ',' | sed 's/,$//')
84+
echo "::error::❌ $FILE -> $INVALID_LIST"
85+
STATUS=1
86+
else
87+
echo "✅ $FILE -> All requirements are either fulfilled or there is a valid reason if not fulfilled."
88+
fi
89+
done
90+
91+
if [ $STATUS -ne 0 ]; then
92+
echo "::error::⚠️ One or more files have invalid requirement statuses. See above for details."
93+
exit $STATUS
94+
else
95+
echo "All changed files have valid requirement statuses."
96+
fi
97+
- name: Verification - Version (Vulnerability)
98+
shell: bash
99+
run: |
100+
SUCCESS_FILES=()
101+
FAILED_FILES=()
102+
STATUS=1
103+
104+
for FILE in $SOUP_FILES; do
105+
CONDITION=$(jq -r '.metadata.approval.condition // empty' "$FILE")
106+
VERSION=$(jq -r '.metadata.input_version // empty' "$FILE")
107+
108+
if [ -z "$CONDITION" ]; then
109+
echo "No condition set in $FILE, skipping version check"
110+
SUCCESS_FILES+=("$FILE")
111+
continue
112+
fi
113+
114+
CONDITION_STRIPPED=$(echo "$CONDITION" | sed 's/-.*//')
115+
echo "Checking condition in $FILE: required version >= $CONDITION (stripped: $CONDITION_STRIPPED), provided $VERSION"
116+
117+
if [[ "$CONDITION_STRIPPED" =~ ^[0-9]+(\.[0-9]+){1,2}$ ]]; then
118+
greater=$(printf "%s\n%s\n" "$CONDITION_STRIPPED" "$VERSION" | sort -V | tail -n1)
119+
if [ "$greater" == "$VERSION" ]; then
120+
STATUS=0
121+
fi
122+
123+
elif [[ "$CONDITION_STRIPPED" =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
124+
if (( $(echo "$VERSION > $CONDITION_STRIPPED" | bc -l) )); then
125+
STATUS=0
126+
fi
127+
128+
else
129+
STATUS=1
130+
fi
131+
132+
if [ "$STATUS" -eq 0 ]; then
133+
echo "✅ Version check passed for $FILE"
134+
SUCCESS_FILES+=("$FILE")
135+
else
136+
echo "❌ Version check FAILED for $FILE"
137+
FAILED_FILES+=("$FIULE")
138+
fi
139+
140+
done
141+
142+
echo "✅ Passed files (${#SUCCESS_FILES[@]}): ${SUCCESS_FILES[*]:-None}"
143+
echo "❌ Failed files (${#FAILED_FILES[@]}): ${FAILED_FILES[*]:-None}"
144+
145+
if [ ${#FAILED_FILES[@]} -ne 0 ]; then
146+
echo "::error::❌ One or more SOUPs did not meet the version condition."
147+
echo "::error::❌ Failed files: ${FAILED_FILES[*]:-None}"
148+
exit 1
149+
fi
150+
- name: Update approval information
151+
shell: bash
152+
env:
153+
ALLOWED_APPROVERS: ${{ vars.SOUP_APPROVERS }}
154+
run: |
155+
APPROVED_BY="${{ github.event.review.user.login }}"
156+
157+
if [ -n "$ALLOWED_APPROVERS" ]; then
158+
echo "Checking if $APPROVED_BY is in allowed approvers list..."
159+
160+
IFS=',' read -ra APPROVER_LIST <<< "$ALLOWED_APPROVERS"
161+
APPROVER_FOUND=false
162+
163+
for approver in "${APPROVER_LIST[@]}"; do
164+
if [ "$(echo "$approver" | xargs)" = "$APPROVED_BY" ]; then
165+
APPROVER_FOUND=true
166+
break
167+
fi
168+
done
169+
170+
if [ "$APPROVER_FOUND" = false ]; then
171+
echo "❌ $APPROVED_BY is not in the allowed approvers list: $ALLOWED_APPROVERS"
172+
echo "Approval will not be recorded."
173+
exit 0
174+
fi
175+
176+
echo "✅ $APPROVED_BY is authorized to approve soups"
177+
else
178+
echo "⚠️ No ALLOWED_APPROVERS configured - allowing all approvals"
179+
fi
180+
181+
APPROVED_ON=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
182+
183+
for FILE in $JSON_FILES; do
184+
if [ ! -f "$FILE" ]; then
185+
echo "File $FILE not found, skipping"
186+
continue
187+
fi
188+
189+
jq --arg approved_by "$APPROVED_BY" --arg approved_on "$APPROVED_ON" \
190+
'.metadata.approval.by = $approved_by | .metadata.approval.date = $approved_on' \
191+
"$FILE" > "${FILE}.tmp" && mv "${FILE}.tmp" "$FILE"
192+
193+
echo "Updated approval info in $FILE"
194+
done
195+
196+
- name: Commit approval updates
197+
shell: bash
198+
run: |
199+
git config --local user.email "soup-approver@quickbird.io"
200+
git config --local user.name "SOUP Approver"
201+
202+
if git diff --quiet; then
203+
echo "No changes to commit"
204+
exit 0
205+
fi
206+
207+
git add soups/*.json
208+
git commit -m "Update approval information: approved by ${{ github.event.review.user.login }}"
209+
git push origin HEAD

0 commit comments

Comments
 (0)