mirror of
https://github.com/langgenius/dify.git
synced 2026-04-03 06:33:16 +00:00
Compare commits
6 Commits
codex-add-
...
chore/depe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
457914ea84 | ||
|
|
2cb4d9f59d | ||
|
|
0eb233eb46 | ||
|
|
54e11c1a7e | ||
|
|
49f4ed5cd6 | ||
|
|
1b71dbed69 |
282
.github/workflows/dependabot-alert-to-feishu.yml
vendored
Normal file
282
.github/workflows/dependabot-alert-to-feishu.yml
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
name: Dependabot Alert to Feishu
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 2 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: read
|
||||
|
||||
jobs:
|
||||
notify-feishu:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate webhook secret
|
||||
env:
|
||||
FEISHU_WEBHOOK: ${{ secrets.FEISHU_WEBHOOK }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -z "${FEISHU_WEBHOOK:-}" ]; then
|
||||
echo "FEISHU_WEBHOOK secret is not configured."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Notify Feishu from event or API polling
|
||||
env:
|
||||
FEISHU_WEBHOOK: ${{ secrets.FEISHU_WEBHOOK }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
MAX_ITEMS="${MAX_ITEMS:-10}"
|
||||
SUMMARY_MAX_LEN="${SUMMARY_MAX_LEN:-140}"
|
||||
|
||||
build_payload() {
|
||||
local alerts_json="$1"
|
||||
local alert_count critical_count high_count header_template
|
||||
local summary_line summary_line_2 summary_line_3 generated_at
|
||||
local stats_elements visible_items hidden_count table_rows_data
|
||||
|
||||
alert_count="$(echo "${alerts_json}" | jq 'length')"
|
||||
critical_count="$(echo "${alerts_json}" | jq '[.[] | select((.security_advisory.severity // "") == "critical")] | length')"
|
||||
high_count="$(echo "${alerts_json}" | jq '[.[] | select((.security_advisory.severity // "") == "high")] | length')"
|
||||
|
||||
header_template="orange"
|
||||
if [ "${critical_count}" -gt 0 ]; then
|
||||
header_template="red"
|
||||
fi
|
||||
|
||||
summary_line="🚨 嗨,这里是您的 EE&CE 企业级🐮🐴在线打工播报员~"
|
||||
summary_line_2="当前系统雷达已锁定一批**高风险依赖告警**,建议优先处理,不然它们可能比 KPI 先“爆炸”💥"
|
||||
summary_line_3=$'📌 已为您智能筛选:\n仅展示 **未分配负责人的 High / Critical 告警**\n(也就是说——没人背锅,但锅已经烧起来了🔥)\n\n请尽快认领处理,拯救系统于水火之中 🙏'
|
||||
generated_at="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
||||
|
||||
stats_elements="$(jq -n \
|
||||
--argjson total "${alert_count}" \
|
||||
--argjson critical "${critical_count}" \
|
||||
--argjson high "${high_count}" '
|
||||
[
|
||||
{
|
||||
tag: "column_set",
|
||||
flex_mode: "trisect",
|
||||
horizontal_spacing: "small",
|
||||
columns: [
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**待处理告警**\n" + ($total|tostring)}]
|
||||
},
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**🔴 严重风险**\n" + ($critical|tostring)}]
|
||||
},
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**🟠 高风险**\n" + ($high|tostring)}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]')"
|
||||
|
||||
if [ "${alert_count}" -eq 0 ]; then
|
||||
jq -n \
|
||||
--arg title "Dependabot Security Alerts" \
|
||||
--arg subtitle "${REPOSITORY}" \
|
||||
--arg summary "🚨 嗨,这里是您的 EE&CE 企业级🐮🐴在线打工播报员~" \
|
||||
--arg summary2 "当前没有待处理的高风险依赖告警,继续保持,今天可以安心下班。" \
|
||||
--arg summary3 $'📌 已为您智能筛选:\n仅展示 **未分配负责人的 High / Critical 告警**\n(当前结果为空,系统暂时平稳)' \
|
||||
--arg generatedAt "${generated_at}" '
|
||||
{
|
||||
msg_type: "interactive",
|
||||
card: {
|
||||
schema: "2.0",
|
||||
config: {wide_screen_mode: true},
|
||||
header: {
|
||||
template: "green",
|
||||
title: {tag: "plain_text", content: $title},
|
||||
subtitle: {tag: "plain_text", content: $subtitle}
|
||||
},
|
||||
body: {
|
||||
elements: [
|
||||
{tag: "markdown", content: $summary},
|
||||
{tag: "markdown", content: $summary2},
|
||||
{tag: "markdown", content: $summary3},
|
||||
{
|
||||
tag: "column_set",
|
||||
flex_mode: "trisect",
|
||||
horizontal_spacing: "small",
|
||||
columns: [
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**待处理告警**\n0"}]
|
||||
},
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**🔴 严重风险**\n0"}]
|
||||
},
|
||||
{
|
||||
tag: "column",
|
||||
width: "weighted",
|
||||
weight: 1,
|
||||
padding: "8px",
|
||||
background_style: "grey",
|
||||
elements: [{tag: "markdown", content: "**🟠 高风险**\n0"}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
tag: "div",
|
||||
text: {
|
||||
tag: "plain_text",
|
||||
content: ("通知时间:" + $generatedAt),
|
||||
text_color: "grey",
|
||||
text_align: "right"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}'
|
||||
return 0
|
||||
fi
|
||||
|
||||
visible_items="$(echo "${alerts_json}" | jq --argjson max "${MAX_ITEMS}" '.[:$max]')"
|
||||
hidden_count="$(echo "${alerts_json}" | jq --argjson max "${MAX_ITEMS}" 'if length > $max then length - $max else 0 end')"
|
||||
|
||||
table_rows_data="$(echo "${visible_items}" | jq -c \
|
||||
--argjson maxLen "${SUMMARY_MAX_LEN}" '
|
||||
map(
|
||||
. as $a |
|
||||
($a.number // "unknown") as $number |
|
||||
($a.security_advisory.severity // "unknown") as $severity |
|
||||
($a.dependency.package.name // "unknown") as $package |
|
||||
($a.security_advisory.summary // "N/A") as $summary |
|
||||
($a.html_url // "") as $url |
|
||||
(
|
||||
if ($summary | length) > $maxLen
|
||||
then ($summary[0:$maxLen] + "...")
|
||||
else $summary
|
||||
end
|
||||
) as $summaryShort |
|
||||
{
|
||||
level: (if $severity == "critical" then "🔴 critical" else "🟠 high" end),
|
||||
alert_id: ("#" + ($number|tostring)),
|
||||
package: ("`" + $package + "`"),
|
||||
details: ($summaryShort + "\n[View alert](" + $url + ")")
|
||||
}
|
||||
)')"
|
||||
|
||||
jq -n \
|
||||
--arg title "Dependabot Security Alerts" \
|
||||
--arg subtitle "${REPOSITORY}" \
|
||||
--arg summary "${summary_line}" \
|
||||
--arg summary2 "${summary_line_2}" \
|
||||
--arg summary3 "${summary_line_3}" \
|
||||
--arg generatedAt "${generated_at}" \
|
||||
--arg headerTemplate "${header_template}" \
|
||||
--argjson stats "${stats_elements}" \
|
||||
--argjson tableRows "${table_rows_data}" \
|
||||
--argjson hidden "${hidden_count}" '
|
||||
{
|
||||
msg_type: "interactive",
|
||||
card: {
|
||||
schema: "2.0",
|
||||
config: {wide_screen_mode: true},
|
||||
header: {
|
||||
template: $headerTemplate,
|
||||
title: {tag: "plain_text", content: $title},
|
||||
subtitle: {tag: "plain_text", content: $subtitle}
|
||||
},
|
||||
body: {
|
||||
elements:
|
||||
(
|
||||
[
|
||||
{tag: "markdown", content: $summary},
|
||||
{tag: "markdown", content: $summary2},
|
||||
{tag: "markdown", content: $summary3},
|
||||
{tag: "hr"},
|
||||
$stats[0],
|
||||
{tag: "hr"},
|
||||
{
|
||||
tag: "table",
|
||||
page_size: 10,
|
||||
row_height: "auto",
|
||||
header_style: {
|
||||
text_align: "left",
|
||||
text_size: "normal",
|
||||
text_color: "grey",
|
||||
bold: true,
|
||||
lines: 1
|
||||
},
|
||||
columns: [
|
||||
{name: "level", display_name: "Level", data_type: "text", width: "120px"},
|
||||
{name: "alert_id", display_name: "ID", data_type: "text", width: "90px"},
|
||||
{name: "package", display_name: "Package", data_type: "lark_md", width: "140px"},
|
||||
{name: "details", display_name: "Summary / Link", data_type: "lark_md", width: "auto"}
|
||||
],
|
||||
rows: $tableRows
|
||||
}
|
||||
]
|
||||
+ (
|
||||
if $hidden > 0
|
||||
then [
|
||||
{tag: "hr"},
|
||||
{tag: "markdown", content: ("还有 " + ($hidden|tostring) + " 条告警未展示,请点击仓库安全页查看全部。")}
|
||||
]
|
||||
else []
|
||||
end
|
||||
)
|
||||
+ [
|
||||
{
|
||||
tag: "div",
|
||||
text: {
|
||||
tag: "plain_text",
|
||||
content: ("通知时间:" + $generatedAt),
|
||||
text_color: "grey",
|
||||
text_align: "right"
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}'
|
||||
}
|
||||
|
||||
api_url="https://api.github.com/repos/${REPOSITORY}/dependabot/alerts?state=open&severity=high,critical&assignee=none&per_page=100"
|
||||
alerts_json="$(curl -sS -f -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
"$api_url")"
|
||||
|
||||
filtered_json="$(echo "${alerts_json}" | jq '[.[] | select(((.security_advisory.severity // "") == "high" or (.security_advisory.severity // "") == "critical") and ((.assignees | length) == 0))]')"
|
||||
alert_count="$(echo "${filtered_json}" | jq 'length')"
|
||||
echo "Filtered dependabot alerts count: ${alert_count}"
|
||||
|
||||
payload="$(build_payload "${filtered_json}")"
|
||||
curl -sS -f -X POST "${FEISHU_WEBHOOK}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "${payload}"
|
||||
Reference in New Issue
Block a user