Skip to content

Commit 34188be

Browse files
authored
Merge branch 'main' of https://github.com/ClickHouse/clickhouse-docs into security109
2 parents 9834ab8 + 4cb9236 commit 34188be

File tree

1,793 files changed

+15316
-9332
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,793 files changed

+15316
-9332
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
* @ClickHouse/docs
2-
/docs/integrations/ @ClickHouse/integrations @ClickHouse/docs
2+
/docs/integrations/data-ingestion/clickpipes/ @ClickHouse/clickpipes @ClickHouse/docs
3+
/docs/integrations/ @ClickHouse/integrations-ecosystem @ClickHouse/docs

.github/workflows/check-build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ jobs:
2727
if: matrix.check_type == 'kbcheck'
2828
run: |
2929
curl -Ls https://astral.sh/uv/install.sh | sh
30-
uv python install 3.12
30+
uv clean
31+
uv python install 3.12 --verbose
3132
- name: Setup md-lint environment
3233
if: matrix.check_type == 'md-lint'
3334
uses: actions/setup-node@v3
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
name: CLA Approval Handler
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
permissions: write-all
8+
9+
jobs:
10+
process-cla-comment:
11+
runs-on: ubuntu-latest
12+
if: github.event_name == 'issue_comment' && github.actor != 'workflow-authentication-public[bot]'
13+
14+
steps:
15+
- name: Generate Token
16+
id: generate-token
17+
continue-on-error: true
18+
uses: actions/create-github-app-token@v1
19+
with:
20+
app-id: "${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}"
21+
private-key: "${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}"
22+
23+
- name: Process CLA Agreement Comment
24+
id: process-comment
25+
uses: actions/github-script@v7
26+
with:
27+
github-token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
28+
script: |
29+
// Only process comments on pull requests
30+
if (!context.payload.issue.pull_request) {
31+
console.log('Comment is not on a pull request, skipping...');
32+
return;
33+
}
34+
35+
const prNumber = context.payload.issue.number;
36+
const commentBody = context.payload.comment.body;
37+
const commenter = context.payload.comment.user.login;
38+
39+
console.log(`Processing comment on PR #${prNumber} from ${commenter}`);
40+
41+
// Check if this is a CLA agreement comment
42+
const isClaAgreement = commentBody.includes('I agree to the Trademark License Addendum') &&
43+
commentBody.includes('CLA-SIGNATURE:');
44+
45+
if (!isClaAgreement) {
46+
console.log('Comment is not a CLA agreement, skipping...');
47+
return;
48+
}
49+
50+
console.log('Found CLA agreement comment, validating...');
51+
52+
// Extract the signature from the comment
53+
const signatureMatch = commentBody.match(/CLA-SIGNATURE:\s*(\S+)/);
54+
if (!signatureMatch) {
55+
console.log('CLA signature format is invalid');
56+
return;
57+
}
58+
59+
const signatureUser = signatureMatch[1];
60+
61+
// Get PR details to verify the commenter is the PR author
62+
const { data: pr } = await github.rest.pulls.get({
63+
owner: context.repo.owner,
64+
repo: context.repo.repo,
65+
pull_number: prNumber
66+
});
67+
68+
const prAuthor = pr.user.login;
69+
console.log(`PR author: ${prAuthor}, commenter: ${commenter}, signature: ${signatureUser}`);
70+
71+
// If someone other than PR author is trying to sign, silently ignore
72+
if (commenter !== prAuthor) {
73+
console.log(`Comment with CLA text from ${commenter} (not PR author ${prAuthor}), ignoring silently`);
74+
return;
75+
}
76+
77+
// If PR author is signing but signature doesn't match their username, silently ignore
78+
if (signatureUser !== commenter) {
79+
console.log(`PR author ${commenter} used incorrect signature '${signatureUser}', ignoring silently`);
80+
return;
81+
}
82+
83+
// Check if PR has trademark-addendum-required label
84+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
85+
owner: context.repo.owner,
86+
repo: context.repo.repo,
87+
issue_number: prNumber
88+
});
89+
90+
const hasTrademarkRequired = labels.some(label => label.name === 'trademark-addendum-required');
91+
const hasTrademarkSigned = labels.some(label => label.name === 'trademark-addendum-signed');
92+
93+
if (!hasTrademarkRequired) {
94+
console.log('PR does not have trademark-addendum-required label, skipping...');
95+
return;
96+
}
97+
98+
if (hasTrademarkSigned) {
99+
console.log('PR already has trademark-addendum-signed label, skipping...');
100+
return;
101+
}
102+
103+
console.log('Valid CLA agreement from PR author, processing...');
104+
105+
// Remove blocking labels
106+
try {
107+
await github.rest.issues.removeLabel({
108+
owner: context.repo.owner,
109+
repo: context.repo.repo,
110+
issue_number: prNumber,
111+
name: 'trademark-addendum-required'
112+
});
113+
console.log('Removed trademark-addendum-required label');
114+
} catch (e) {
115+
console.log('trademark-addendum-required label not found or already removed');
116+
}
117+
118+
try {
119+
await github.rest.issues.removeLabel({
120+
owner: context.repo.owner,
121+
repo: context.repo.repo,
122+
issue_number: prNumber,
123+
name: 'integrations-with-image-change'
124+
});
125+
console.log('Removed integrations-with-image-change label');
126+
} catch (e) {
127+
console.log('integrations-with-image-change label not found or already removed');
128+
}
129+
130+
// Add trademark-addendum-signed label
131+
await github.rest.issues.addLabels({
132+
owner: context.repo.owner,
133+
repo: context.repo.repo,
134+
issue_number: prNumber,
135+
labels: ['trademark-addendum-signed']
136+
});
137+
138+
console.log('Added trademark-addendum-signed label successfully');
139+
140+
// Store signature details for the next step
141+
core.setOutput('pr_number', prNumber);
142+
core.setOutput('pr_author', prAuthor);
143+
core.setOutput('approved_by', prAuthor);
144+
core.setOutput('pr_head_sha', pr.head.sha);
145+
core.setOutput('pr_head_ref', pr.head.ref);
146+
core.setOutput('pr_head_repo_full_name', pr.head.repo.full_name);
147+
core.setOutput('is_fork', pr.head.repo.full_name !== context.repo.owner + '/' + context.repo.repo);
148+
149+
// Add confirmation comment
150+
const confirmationBody = [
151+
'## Trademark license agreement confirmed ✅',
152+
'',
153+
`The trademark license agreement has been confirmed for @${prAuthor}.`,
154+
'',
155+
'**Status:** Confirmed',
156+
`**Date:** ${new Date().toISOString()}`,
157+
'**Method:** Self-signed agreement via comment',
158+
'',
159+
'This PR is now unblocked and can proceed with normal review.'
160+
].join('\n');
161+
162+
await github.rest.issues.createComment({
163+
owner: context.repo.owner,
164+
repo: context.repo.repo,
165+
issue_number: prNumber,
166+
body: confirmationBody
167+
});
168+
169+
console.log(`✅ CLA agreement processed successfully for ${prAuthor}`);
170+
171+
- name: Check out repository
172+
if: success() && steps.process-comment.outputs.pr_number != ''
173+
uses: actions/checkout@v4
174+
with:
175+
fetch-depth: 0
176+
# For forked PRs, we need to fetch from the fork and checkout the SHA
177+
# For non-fork PRs, we can checkout the branch directly
178+
ref: ${{ steps.process-comment.outputs.is_fork == 'true' && steps.process-comment.outputs.pr_head_sha || steps.process-comment.outputs.pr_head_ref }}
179+
token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
180+
181+
- name: Record signature to file
182+
id: record-signature
183+
if: success() && steps.process-comment.outputs.pr_number != ''
184+
run: |
185+
set -e
186+
187+
echo "=== Recording signature immediately after label addition ==="
188+
189+
# Debug: Check current working directory and branch
190+
echo "=== Debug Info ==="
191+
pwd
192+
echo "Current branch: $(git branch --show-current)"
193+
echo "Git remote: $(git remote -v)"
194+
ls -la contribute/ 2>/dev/null || echo "contribute/ directory does not exist"
195+
196+
# Get signature details
197+
USERNAME="${{ steps.process-comment.outputs.pr_author }}"
198+
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
199+
PR_NUMBER="${{ steps.process-comment.outputs.pr_number }}"
200+
APPROVED_BY="${{ steps.process-comment.outputs.approved_by }}"
201+
202+
echo "Recording signature for PR #$PR_NUMBER"
203+
echo " Username: $USERNAME"
204+
echo " Approved by: $APPROVED_BY"
205+
echo " Date: $DATE"
206+
207+
# Ensure contribute directory exists
208+
mkdir -p contribute
209+
210+
# Signature file
211+
SIGNATURES_FILE="contribute/trade-addendum-signatures.json"
212+
213+
# Create or read existing signatures file
214+
if [ ! -f "$SIGNATURES_FILE" ]; then
215+
echo '{"signatures": []}' > "$SIGNATURES_FILE"
216+
echo "Created new signatures file"
217+
fi
218+
219+
# Check if signature already exists
220+
EXISTING=$(jq --arg user "$USERNAME" --arg pr "$PR_NUMBER" '.signatures[] | select(.username == $user and .pr_number == ($pr | tonumber))' "$SIGNATURES_FILE" 2>/dev/null || echo "")
221+
222+
if [ -z "$EXISTING" ]; then
223+
# Add new signature
224+
echo "Adding signature to file..."
225+
jq --arg user "$USERNAME" \
226+
--arg date "$DATE" \
227+
--arg pr "$PR_NUMBER" \
228+
--arg approved_by "$APPROVED_BY" \
229+
'.signatures += [{
230+
"username": $user,
231+
"date": $date,
232+
"pr_number": ($pr | tonumber),
233+
"approved_by": $approved_by
234+
}]' "$SIGNATURES_FILE" > tmp.json && mv tmp.json "$SIGNATURES_FILE"
235+
236+
echo "✅ Added signature for $USERNAME"
237+
echo "File contents after update:"
238+
cat "$SIGNATURES_FILE"
239+
else
240+
echo "ℹ️ Signature already exists for $USERNAME on PR #$PR_NUMBER"
241+
fi
242+
243+
# Configure git
244+
git config user.name "github-actions[bot]"
245+
git config user.email "github-actions[bot]@users.noreply.github.com"
246+
247+
# Debug: Check git status
248+
echo "=== Git status ==="
249+
git status
250+
251+
echo "=== Git diff ==="
252+
git diff "$SIGNATURES_FILE"
253+
254+
# Add the file to git and commit
255+
git add "$SIGNATURES_FILE"
256+
257+
# Store signature in ClickHouse
258+
echo "Storing signature in ClickHouse..."
259+
260+
# Format date for ClickHouse DateTime (YYYY-MM-DD HH:MM:SS)
261+
CH_DATE=$(date -u +"%Y-%m-%d %H:%M:%S")
262+
263+
# Prepare SQL INSERT query
264+
SQL_QUERY="INSERT INTO docs_trademark_agreements.signatures (date, user_name, pr_number) VALUES ('$CH_DATE', '$USERNAME', $PR_NUMBER)"
265+
266+
echo "Executing SQL: $SQL_QUERY"
267+
268+
# Send to ClickHouse
269+
RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/ch_response.txt \
270+
-X POST \
271+
-H "x-clickhouse-user: docs_feedback" \
272+
-H "x-clickhouse-key: " \
273+
-H "Content-Type: text/plain" \
274+
-d "$SQL_QUERY" \
275+
"https://sql-clickhouse.clickhouse.com")
276+
277+
HTTP_CODE="${RESPONSE: -3}"
278+
RESPONSE_BODY=$(cat /tmp/ch_response.txt)
279+
280+
if [ "$HTTP_CODE" = "200" ]; then
281+
echo "✅ Signature stored successfully in ClickHouse"
282+
else
283+
echo "❌ Failed to store signature in ClickHouse"
284+
echo "HTTP Code: $HTTP_CODE"
285+
echo "Response: $RESPONSE_BODY"
286+
# Don't exit 1 here - we don't want to fail the workflow if ClickHouse is down
287+
echo "⚠️ Continuing workflow despite ClickHouse error"
288+
fi

0 commit comments

Comments
 (0)