Skip to content

Commit 8928a17

Browse files
committed
github actions: test on complete.
WIWT took agressive security recommendations from cluade
1 parent 78bf9d5 commit 8928a17

File tree

2 files changed

+692
-0
lines changed

2 files changed

+692
-0
lines changed
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
name: Validate Kernel Commits - Check (Secure)
2+
3+
on:
4+
workflow_call:
5+
# No inputs needed - uses github context from caller
6+
7+
permissions:
8+
contents: read
9+
# No pull-requests: write needed - we don't comment here
10+
11+
jobs:
12+
validate-kernel-commits-check:
13+
runs-on: ubuntu-latest
14+
timeout-minutes: 120
15+
16+
steps:
17+
- name: Validate and sanitize inputs
18+
id: validate_inputs
19+
env:
20+
BASE_REF: ${{ github.base_ref }}
21+
HEAD_REF: ${{ github.head_ref }}
22+
PR_NUMBER: ${{ github.event.pull_request.number }}
23+
PR_COMMITS: ${{ github.event.pull_request.commits }}
24+
run: |
25+
# Validate base branch name (alphanumeric, dots, slashes, dashes, underscores, curly braces)
26+
# Note: hyphen must be at end of character class or escaped to be literal
27+
if ! [[ "$BASE_REF" =~ ^[a-zA-Z0-9/_.{}-]+$ ]]; then
28+
echo "❌ Invalid base branch name: $BASE_REF"
29+
exit 1
30+
fi
31+
32+
# Validate head branch name
33+
if ! [[ "$HEAD_REF" =~ ^[a-zA-Z0-9/_.{}-]+$ ]]; then
34+
echo "❌ Invalid head branch name: $HEAD_REF"
35+
exit 1
36+
fi
37+
38+
# Validate length (prevent resource exhaustion)
39+
if [ ${#BASE_REF} -gt 255 ]; then
40+
echo "❌ Base branch name too long"
41+
exit 1
42+
fi
43+
44+
if [ ${#HEAD_REF} -gt 255 ]; then
45+
echo "❌ Head branch name too long"
46+
exit 1
47+
fi
48+
49+
# Validate PR number is numeric
50+
if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then
51+
echo "❌ Invalid PR number: $PR_NUMBER"
52+
exit 1
53+
fi
54+
55+
# Validate commits count is numeric
56+
if ! [[ "$PR_COMMITS" =~ ^[0-9]+$ ]]; then
57+
echo "❌ Invalid commits count: $PR_COMMITS"
58+
exit 1
59+
fi
60+
61+
# Pass validated values to environment
62+
echo "BASE_REF=$BASE_REF" >> "$GITHUB_ENV"
63+
echo "HEAD_REF=$HEAD_REF" >> "$GITHUB_ENV"
64+
echo "PR_NUMBER=$PR_NUMBER" >> "$GITHUB_ENV"
65+
echo "PR_COMMITS=$PR_COMMITS" >> "$GITHUB_ENV"
66+
67+
- name: Clone base branch
68+
env:
69+
BASE_CLONE_URL: ${{ github.event.pull_request.base.repo.clone_url }}
70+
run: |
71+
# Use environment variables to prevent injection
72+
git clone --depth=1 --no-checkout "$BASE_CLONE_URL" -b "$BASE_REF" .
73+
74+
- name: Fetch PR branch
75+
env:
76+
HEAD_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url }}
77+
run: |
78+
# Use environment variables to prevent command injection
79+
git fetch --depth=$((PR_COMMITS + 1)) "$HEAD_CLONE_URL" "$HEAD_REF"
80+
HEAD_SHA=$(git rev-parse FETCH_HEAD)
81+
82+
# Validate SHA format (40 hex characters)
83+
if ! [[ "$HEAD_SHA" =~ ^[0-9a-f]{40}$ ]]; then
84+
echo "❌ Invalid SHA format: $HEAD_SHA"
85+
exit 1
86+
fi
87+
88+
echo "HEAD_SHA=$HEAD_SHA" >> "$GITHUB_ENV"
89+
90+
- name: Verify PR branch isn't on stale base
91+
run: |
92+
if ! git merge-base --is-ancestor "$BASE_REF" "$HEAD_SHA"; then
93+
echo "❌ PR branch must be rebased onto latest base branch commit"
94+
exit 1
95+
fi
96+
97+
- name: Fetch upstream mainline branch
98+
run: |
99+
# Determine the kernel version tag, since it is the most recent common
100+
# ancestor between the base branch and the upstream mainline branch
101+
MAKEFILE=$(git show "$BASE_REF":Makefile)
102+
VERSION=$(grep -m1 -Po '(?<=^VERSION = )\d+' <<< "$MAKEFILE")
103+
PATCHLEVEL=$(grep -m1 -Po '(?<=^PATCHLEVEL = )\d+' <<< "$MAKEFILE")
104+
105+
# Validate VERSION and PATCHLEVEL are numeric
106+
if ! [[ "$VERSION" =~ ^[0-9]+$ ]] || ! [[ "$PATCHLEVEL" =~ ^[0-9]+$ ]]; then
107+
echo "❌ Invalid kernel version: $VERSION.$PATCHLEVEL"
108+
exit 1
109+
fi
110+
111+
# Fetch upstream mainline branch without tags, fetching only history
112+
# that is newer than this kernel version tag. This reduces the amount
113+
# of commits cloned knowing that there's no need to check any commits
114+
# for Fixes commits older than what the base branch already contains
115+
git fetch --no-tags --shallow-exclude="v$VERSION.$PATCHLEVEL" origin kernel-mainline
116+
MAINLINE_SHA=$(git rev-parse FETCH_HEAD)
117+
118+
# Validate SHA format
119+
if ! [[ "$MAINLINE_SHA" =~ ^[0-9a-f]{40}$ ]]; then
120+
echo "❌ Invalid mainline SHA format: $MAINLINE_SHA"
121+
exit 1
122+
fi
123+
124+
echo "MAINLINE_SHA=$MAINLINE_SHA" >> "$GITHUB_ENV"
125+
126+
- name: Checkout kernel-src-tree-tools
127+
uses: actions/checkout@v4
128+
with:
129+
repository: ctrliq/kernel-src-tree-tools
130+
ref: 'mainline'
131+
path: kernel-src-tree-tools
132+
133+
- name: Set up Python
134+
uses: actions/setup-python@v5
135+
with:
136+
python-version: '3.x'
137+
138+
- name: Run upstream fixes check
139+
id: check-kernel-commits
140+
working-directory: kernel-src-tree-tools
141+
run: |
142+
set +e # Don't exit on error, we want to capture the output
143+
set -o pipefail # Capture exit code from python script, not tee
144+
python3 check_kernel_commits.py \
145+
--repo .. \
146+
--pr_branch "$HEAD_SHA" \
147+
--base_branch "$BASE_REF" \
148+
--markdown \
149+
--upstream-ref "$MAINLINE_SHA" \
150+
--check-cves | tee ../ckc_result.txt
151+
EXIT_CODE=$?
152+
153+
# Check if the script failed
154+
if [ $EXIT_CODE -ne 0 ]; then
155+
echo "❌ Kernel commits check failed with exit code $EXIT_CODE"
156+
exit $EXIT_CODE
157+
fi
158+
159+
# Check for findings:
160+
# 1. Verify the success message exists
161+
# 2. If it exists, check if there are any OTHER lines (which would indicate issues)
162+
# 3. If success message doesn't exist, that's also a finding
163+
if grep -q "All referenced commits exist upstream and have no Fixes: tags." ../ckc_result.txt; then
164+
# Success message found, check if there are any other lines
165+
LINE_COUNT=$(wc -l < ../ckc_result.txt)
166+
if [ "$LINE_COUNT" -gt 1 ]; then
167+
echo "has_findings=true" >> $GITHUB_OUTPUT
168+
else
169+
echo "has_findings=false" >> $GITHUB_OUTPUT
170+
fi
171+
else
172+
# Success message not found, there must be findings
173+
echo "has_findings=true" >> $GITHUB_OUTPUT
174+
fi
175+
176+
set -e # Re-enable exit on error
177+
178+
- name: Install build dependencies for patchutils
179+
run: |
180+
sudo apt-get update
181+
sudo apt-get install -y build-essential autoconf automake libtool gnulib
182+
183+
- name: Clone and build custom patchutils
184+
run: |
185+
# Security: Pin to specific commit to prevent supply chain attacks
186+
EXPECTED_COMMIT="60a60b3909d0e29c0ff286f6a73de4168977b097"
187+
188+
# Clone repository
189+
git clone https://github.com/kerneltoast/patchutils.git
190+
cd patchutils
191+
192+
# Fetch the specific commit we want
193+
git fetch origin "$EXPECTED_COMMIT"
194+
git checkout "$EXPECTED_COMMIT"
195+
196+
# Verify we're on the expected commit
197+
ACTUAL_COMMIT=$(git rev-parse HEAD)
198+
if [ "$ACTUAL_COMMIT" != "$EXPECTED_COMMIT" ]; then
199+
echo "❌ Security: Commit mismatch!"
200+
echo "Expected: $EXPECTED_COMMIT"
201+
echo "Actual: $ACTUAL_COMMIT"
202+
exit 1
203+
fi
204+
205+
# Build patchutils
206+
./bootstrap
207+
./configure
208+
make -j$(nproc)
209+
210+
# Verify the binary was created
211+
if [ ! -x src/interdiff ]; then
212+
echo "❌ Failed to build interdiff binary"
213+
exit 1
214+
fi
215+
216+
- name: Run interdiff check
217+
id: interdiff
218+
working-directory: kernel-src-tree-tools
219+
run: |
220+
set +e # Don't exit on error, we want to capture the output
221+
set -o pipefail # Capture exit code from python script, not tee
222+
python3 run_interdiff.py \
223+
--repo .. \
224+
--pr_branch "$HEAD_SHA" \
225+
--base_branch "$BASE_REF" \
226+
--markdown \
227+
--interdiff ../patchutils/src/interdiff | tee ../interdiff_result.txt
228+
EXIT_CODE=$?
229+
230+
# Check if the script failed
231+
if [ $EXIT_CODE -ne 0 ]; then
232+
echo "❌ Interdiff check failed with exit code $EXIT_CODE"
233+
exit $EXIT_CODE
234+
fi
235+
236+
# Check for differences:
237+
# 1. Verify the success message exists
238+
# 2. If it exists, check if there are any OTHER lines (which would indicate differences)
239+
# 3. If success message doesn't exist, that's also a difference
240+
if grep -q "All backported commits match their upstream counterparts." ../interdiff_result.txt; then
241+
# Success message found, check if there are any other lines
242+
LINE_COUNT=$(wc -l < ../interdiff_result.txt)
243+
if [ "$LINE_COUNT" -gt 1 ]; then
244+
echo "has_differences=true" >> $GITHUB_OUTPUT
245+
else
246+
echo "has_differences=false" >> $GITHUB_OUTPUT
247+
fi
248+
else
249+
# Success message not found, there must be differences
250+
echo "has_differences=true" >> $GITHUB_OUTPUT
251+
fi
252+
253+
set -e # Re-enable exit on error
254+
255+
- name: Save PR metadata for comment workflow
256+
env:
257+
HEAD_REPO_FULL_NAME: ${{ github.event.pull_request.head.repo.full_name }}
258+
REPOSITORY: ${{ github.repository }}
259+
run: |
260+
mkdir -p pr_metadata
261+
262+
# Save validated metadata
263+
echo "$PR_NUMBER" > pr_metadata/pr_number.txt
264+
echo "$REPOSITORY" > pr_metadata/repository.txt
265+
echo "$BASE_REF" > pr_metadata/base_ref.txt
266+
echo "$HEAD_SHA" > pr_metadata/head_sha.txt
267+
echo "$HEAD_REPO_FULL_NAME" > pr_metadata/head_repo.txt
268+
269+
# Create a checksum of metadata for integrity verification
270+
(cd pr_metadata && sha256sum *.txt > checksums.txt)
271+
272+
- name: Upload check results
273+
uses: actions/upload-artifact@v4
274+
if: always() # Upload even if checks fail
275+
with:
276+
name: check-results
277+
path: |
278+
ckc_result.txt
279+
interdiff_result.txt
280+
pr_metadata/
281+
retention-days: 3 # Increased from 1 to prevent premature deletion

0 commit comments

Comments
 (0)