create-dwy 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/bin/index.js +0 -0
- package/package.json +3 -2
- package/src/searchable-select.js +419 -0
- package/src/sync-all.js +11 -7
- package/src/sync.js +38 -32
- package/templates/ai-tools/CHANGELOG.md +76 -0
- package/templates/ai-tools/VERSION +1 -0
- package/templates/ai-tools/hook-manifests/hooks.json +7 -0
- package/templates/ai-tools/hooks/Git/pre-git-commit-ai-signature-check.sh +57 -0
- package/templates/ai-tools/rules/Android/dwy-android-core.md +215 -4
- package/templates/ai-tools/rules/Docker/dwy-docker.md +52 -1
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +50 -1
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-design.md +139 -0
- package/templates/ai-tools/rules/HarmonyOS/dwy-harmony-pitfalls.md +72 -0
- package/templates/ai-tools/rules/iOS/dwy-ios-pitfalls.md +7 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-git-commit.md +9 -6
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/SKILL.md +511 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-data.md +126 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-network.md +88 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-runtime.md +195 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/security-doc-search.md +179 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_base.sh +39 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_capacity.sh +278 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_db.sh +147 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_docker.sh +230 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_env.sh +64 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_https.sh +60 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_logs.sh +209 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_nginx.sh +100 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_resilience.sh +157 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_secrets.sh +265 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_services.sh +94 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_ssh.sh +56 -0
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/run_all.sh +105 -0
- package/templates/ai-tools/skills//345/205/203/345/267/245/345/205/267/dwy-shared/SKILL.md +22 -1
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/SKILL.md +1 -1
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/references/checks-runtime.md +2 -2
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_docker.sh +3 -3
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_secrets.sh +1 -1
- package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-first/SKILL.md +176 -0
- package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-deploy-first/references/chapter-01-mirrors.md +112 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 凭证强度审计 (只读, 全脱敏)
|
|
3
|
+
#
|
|
4
|
+
# 检查范围 (5 类):
|
|
5
|
+
# 1. .env 文件: PASSWORD/SECRET/TOKEN/KEY/AK/SK 字段
|
|
6
|
+
# 2. docker 容器内联 env (Config.Env)
|
|
7
|
+
# 3. Redis 容器 --requirepass 启动参数
|
|
8
|
+
# 4. Postgres 容器 POSTGRES_PASSWORD
|
|
9
|
+
# 5. SSH 私钥 类型 + 位数 (~/.ssh/id_*)
|
|
10
|
+
#
|
|
11
|
+
# 强制脱敏: 只输出派生指标 (len/classes/strength), 永不输出明文
|
|
12
|
+
# 字典词: 内置 ~30 个最常见弱口令
|
|
13
|
+
|
|
14
|
+
TARGET="$1"; shift
|
|
15
|
+
SSH_OPTS=("$@")
|
|
16
|
+
|
|
17
|
+
ssh "${SSH_OPTS[@]}" "${TARGET}" bash -s <<'REMOTE'
|
|
18
|
+
# ---------- 强度评估函数 ----------
|
|
19
|
+
# 输入: 一个秘密字符串(从 stdin)
|
|
20
|
+
# 输出: "len=N classes=K strength=STRONG/MEDIUM/WEAK reason=xxx"
|
|
21
|
+
# 不打印明文, 不写文件
|
|
22
|
+
strength_of() {
|
|
23
|
+
local val
|
|
24
|
+
IFS= read -r val
|
|
25
|
+
local len=${#val}
|
|
26
|
+
|
|
27
|
+
# 字典词内置(精简, 30 个最常见弱口令; 大小写不敏感子串匹配)
|
|
28
|
+
local weak_dict='password|passwd|123456|123123|qwerty|abc123|admin|administrator|root|test|demo|guest|user|welcome|letmein|changeme|secret|default|temp|public|private|master|sample|example|prod|dev|staging|backup|hello|monkey'
|
|
29
|
+
local is_dict=0
|
|
30
|
+
echo "$val" | grep -qiE "($weak_dict)" && is_dict=1
|
|
31
|
+
|
|
32
|
+
# 字符类
|
|
33
|
+
local has_upper=0 has_lower=0 has_digit=0 has_symbol=0
|
|
34
|
+
[[ "$val" =~ [A-Z] ]] && has_upper=1
|
|
35
|
+
[[ "$val" =~ [a-z] ]] && has_lower=1
|
|
36
|
+
[[ "$val" =~ [0-9] ]] && has_digit=1
|
|
37
|
+
[[ "$val" =~ [^a-zA-Z0-9] ]] && has_symbol=1
|
|
38
|
+
local classes=$(( has_upper + has_lower + has_digit + has_symbol ))
|
|
39
|
+
|
|
40
|
+
# 评级
|
|
41
|
+
local strength reason
|
|
42
|
+
if [[ "$len" -lt 8 ]]; then strength="WEAK"; reason="len<8"
|
|
43
|
+
elif [[ "$is_dict" == "1" ]]; then strength="WEAK"; reason="dict_match"
|
|
44
|
+
elif [[ "$len" -lt 16 ]]; then strength="MEDIUM"; reason="len<16"
|
|
45
|
+
elif [[ "$classes" -lt 3 ]]; then strength="MEDIUM"; reason="classes<3"
|
|
46
|
+
else strength="STRONG"; reason="ok"
|
|
47
|
+
fi
|
|
48
|
+
printf "len=%d classes=%d strength=%s reason=%s" "$len" "$classes" "$strength" "$reason"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# 排除明显是"数值/枚举配置参数"而非凭证的 key 名
|
|
52
|
+
# (子串匹配 TOKEN/KEY 会误命中 ACCESS_TOKEN_EXPIRE_MINUTES / KEY_TIMEOUT 这种)
|
|
53
|
+
is_config_not_secret() {
|
|
54
|
+
local key="$1"
|
|
55
|
+
echo "$key" | grep -qiE '(EXPIRE|EXPIRY|TTL|TIMEOUT|SECONDS|MINUTES|HOURS|DAYS|COUNT|LIMIT|RETRY|MAX|MIN|SIZE|LENGTH|INTERVAL|DELAY|ENABLED|DISABLED|MODE|TYPE|VERSION|PORT|HOST|URL|PATH|FILE|DIR)$|_(EXPIRE|TTL|TIMEOUT|SECONDS|MINUTES|HOURS|DAYS|COUNT|LIMIT|MAX|MIN|SIZE|MODE|TYPE)_'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# 包装: 给定 key+value, 加上"高敏字段长度门槛 32"判定
|
|
59
|
+
evaluate_secret() {
|
|
60
|
+
local key="$1"
|
|
61
|
+
local val="$2"
|
|
62
|
+
[[ -z "$val" ]] && { echo " (空值)"; return; }
|
|
63
|
+
|
|
64
|
+
# 判定是否真凭证字段 (key 名含 PASSWORD/SECRET/ACCESS_KEY_SECRET 等明确含义的)
|
|
65
|
+
# 这类即使值是纯数字短串(如某些服务默认密码 123456) 也必须评估为 WEAK 而非 SKIP
|
|
66
|
+
local is_true_credential=0
|
|
67
|
+
echo "$key" | grep -qiE '(PASSWORD|PASSWD|SECRET|PRIVATE[_-]?KEY|ACCESS[_-]?KEY[_-]?SECRET|_SK$|^SK_)' && is_true_credential=1
|
|
68
|
+
|
|
69
|
+
# Bug fix 1: 跳过明显是配置参数的 key (含 EXPIRE/TTL/TIMEOUT/MAX/MIN 等)
|
|
70
|
+
# 但真凭证字段不跳过
|
|
71
|
+
if [[ "$is_true_credential" == "0" ]] && is_config_not_secret "$key"; then
|
|
72
|
+
printf " %-30s [i] SKIP: 看起来是配置参数(非凭证), key 名含 EXPIRE/TTL/TIMEOUT/MAX 等\n" "$key"
|
|
73
|
+
return
|
|
74
|
+
fi
|
|
75
|
+
# Bug fix 1.b: 纯数字短值(像 30 / 86400 这种 TTL/expire) 跳过
|
|
76
|
+
# 但真凭证字段不跳过 (服务默认密码 123456 / Redis 默认 123 这种弱密码必须报)
|
|
77
|
+
if [[ "$is_true_credential" == "0" ]] && [[ "$val" =~ ^[0-9]+$ ]] && [[ ${#val} -lt 10 ]]; then
|
|
78
|
+
printf " %-30s [i] SKIP: 纯数字短值(看起来是配置参数, len=%d)\n" "$key" "${#val}"
|
|
79
|
+
return
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# 是否高敏字段
|
|
83
|
+
local high_sens=0
|
|
84
|
+
echo "$key" | grep -qiE 'SECRET|JWT|TOKEN|API[_-]?KEY|ACCESS[_-]?KEY[_-]?SECRET|PRIVATE[_-]?KEY|_AK$|_SK$|^AK_|^SK_' && high_sens=1
|
|
85
|
+
|
|
86
|
+
local result
|
|
87
|
+
result=$(printf '%s\n' "$val" | strength_of)
|
|
88
|
+
local len=$(echo "$result" | grep -oE 'len=[0-9]+' | cut -d= -f2)
|
|
89
|
+
local classes=$(echo "$result" | grep -oE 'classes=[0-9]+' | cut -d= -f2)
|
|
90
|
+
local strength=$(echo "$result" | grep -oE 'strength=[A-Z]+' | cut -d= -f2)
|
|
91
|
+
|
|
92
|
+
# Bug fix 2: 长度 >= 24 即视为 STRONG (即使 classes 少, 熵足够)
|
|
93
|
+
# 例如 48 字符 base64 / 64 字符 hex 即使只 2 类, 熵 >= 192 bits 远超 128 bits 安全门槛
|
|
94
|
+
if [[ "$strength" != "WEAK" && "$len" -ge 24 ]]; then
|
|
95
|
+
strength="STRONG"
|
|
96
|
+
result="${result/strength=MEDIUM/strength=STRONG}"
|
|
97
|
+
result="${result/reason=classes<3/reason=long_enough}"
|
|
98
|
+
result="${result/reason=len<16/reason=long_enough}"
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
printf " %-30s %s" "$key" "$result"
|
|
102
|
+
# 严重级标记
|
|
103
|
+
if [[ "$strength" == "WEAK" ]]; then
|
|
104
|
+
printf " [!!!] CRITICAL: 弱凭证, 必须立即轮换\n"
|
|
105
|
+
elif [[ "$high_sens" == "1" && "$len" -lt 32 ]]; then
|
|
106
|
+
printf " [!!] HIGH: 高敏字段建议 >= 32 字符随机串\n"
|
|
107
|
+
elif [[ "$strength" == "MEDIUM" ]]; then
|
|
108
|
+
printf " [!] MEDIUM: 建议加长至 16+ 且 3 类字符\n"
|
|
109
|
+
else
|
|
110
|
+
printf " [OK]\n"
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# ---------- 1. .env 文件扫描 ----------
|
|
115
|
+
echo "########## 1. .env 文件凭证强度 ##########"
|
|
116
|
+
ENV_FILES=$(sudo -n find /home /opt /srv /root -maxdepth 6 -type f \
|
|
117
|
+
\( -name ".env" -o -name ".env.*" -o -name "*.env" \) 2>/dev/null \
|
|
118
|
+
| grep -vE '\.example|\.template|\.sample|\.bak|\.old|node_modules' \
|
|
119
|
+
| sort -u | head -20)
|
|
120
|
+
[[ -z "$ENV_FILES" ]] && ENV_FILES=$(find /home /opt /srv /root -maxdepth 6 -type f \
|
|
121
|
+
\( -name ".env" -o -name ".env.*" -o -name "*.env" \) 2>/dev/null \
|
|
122
|
+
| grep -vE '\.example|\.template|\.sample|\.bak|\.old|node_modules' \
|
|
123
|
+
| sort -u | head -20)
|
|
124
|
+
|
|
125
|
+
if [[ -z "$ENV_FILES" ]]; then
|
|
126
|
+
echo "[i] 未找到 .env 文件"
|
|
127
|
+
else
|
|
128
|
+
for f in $ENV_FILES; do
|
|
129
|
+
echo ""
|
|
130
|
+
echo "[$f]"
|
|
131
|
+
# 只挑密码类字段, 解析 KEY=VALUE
|
|
132
|
+
if ! sudo -n cat "$f" 2>/dev/null | head -1 >/dev/null && ! cat "$f" 2>/dev/null | head -1 >/dev/null; then
|
|
133
|
+
echo " [i] 不可读"
|
|
134
|
+
continue
|
|
135
|
+
fi
|
|
136
|
+
(sudo -n cat "$f" 2>/dev/null || cat "$f" 2>/dev/null) \
|
|
137
|
+
| grep -E '^[[:space:]]*[A-Z][A-Z0-9_]*[[:space:]]*=' \
|
|
138
|
+
| grep -iE '(PASSWORD|PASSWD|SECRET|TOKEN|API[_-]?KEY|ACCESS[_-]?KEY|PRIVATE[_-]?KEY|_AK|_SK|^AK_|^SK_)' \
|
|
139
|
+
| while IFS='=' read -r key val; do
|
|
140
|
+
key=$(echo "$key" | tr -d ' \t')
|
|
141
|
+
# 去引号 + 行尾注释
|
|
142
|
+
val=$(echo "$val" | sed -E 's/^[[:space:]]*//; s/[[:space:]]*#.*$//; s/^"//; s/"$//; s/^'\''//; s/'\''$//')
|
|
143
|
+
evaluate_secret "$key" "$val"
|
|
144
|
+
done
|
|
145
|
+
done
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# ---------- 2. docker 容器内联 env ----------
|
|
149
|
+
echo ""
|
|
150
|
+
echo "########## 2. Docker 容器内联 env 凭证强度 ##########"
|
|
151
|
+
if command -v docker >/dev/null 2>&1; then
|
|
152
|
+
for c in $(docker ps -q 2>/dev/null); do
|
|
153
|
+
name=$(docker inspect -f '{{.Name}}' "$c" 2>/dev/null | sed 's|^/||')
|
|
154
|
+
echo ""
|
|
155
|
+
echo "[$name]"
|
|
156
|
+
docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' "$c" 2>/dev/null \
|
|
157
|
+
| grep -iE '(PASSWORD|PASSWD|SECRET|TOKEN|API[_-]?KEY|ACCESS[_-]?KEY|PRIVATE[_-]?KEY|_AK=|_SK=|^AK_|^SK_)' \
|
|
158
|
+
| while IFS='=' read -r key val; do
|
|
159
|
+
key=$(echo "$key" | tr -d ' \t')
|
|
160
|
+
evaluate_secret "$key" "$val"
|
|
161
|
+
done
|
|
162
|
+
done
|
|
163
|
+
else
|
|
164
|
+
echo "[i] Docker 未安装"
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# ---------- 3. Redis requirepass (从启动参数提取) ----------
|
|
168
|
+
echo ""
|
|
169
|
+
echo "########## 3. Redis --requirepass 强度 ##########"
|
|
170
|
+
if command -v docker >/dev/null 2>&1; then
|
|
171
|
+
REDIS_FOUND=0
|
|
172
|
+
for c in $(docker ps -q 2>/dev/null); do
|
|
173
|
+
image=$(docker inspect -f '{{.Config.Image}}' "$c" 2>/dev/null)
|
|
174
|
+
if echo "$image" | grep -qi "redis"; then
|
|
175
|
+
REDIS_FOUND=1
|
|
176
|
+
name=$(docker inspect -f '{{.Name}}' "$c" 2>/dev/null | sed 's|^/||')
|
|
177
|
+
echo ""
|
|
178
|
+
echo "[$name]"
|
|
179
|
+
args=$(docker inspect -f '{{range .Args}}{{.}} {{end}}' "$c" 2>/dev/null)
|
|
180
|
+
pass=$(echo "$args" | grep -oE -- '--requirepass [^ ]+' | head -1 | awk '{print $2}')
|
|
181
|
+
if [[ -n "$pass" ]]; then
|
|
182
|
+
evaluate_secret "REDIS_PASSWORD(--requirepass)" "$pass"
|
|
183
|
+
else
|
|
184
|
+
echo " [!!!] CRITICAL: Redis 未设置 --requirepass"
|
|
185
|
+
fi
|
|
186
|
+
fi
|
|
187
|
+
done
|
|
188
|
+
[[ "$REDIS_FOUND" == "0" ]] && echo "[i] 未发现 Redis 容器"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# ---------- 4. Postgres POSTGRES_PASSWORD (容器 env, 已在 2 覆盖, 此处单独 highlight) ----------
|
|
192
|
+
echo ""
|
|
193
|
+
echo "########## 4. Postgres POSTGRES_PASSWORD 强度 ##########"
|
|
194
|
+
if command -v docker >/dev/null 2>&1; then
|
|
195
|
+
PG_FOUND=0
|
|
196
|
+
for c in $(docker ps -q 2>/dev/null); do
|
|
197
|
+
image=$(docker inspect -f '{{.Config.Image}}' "$c" 2>/dev/null)
|
|
198
|
+
if echo "$image" | grep -qi "postgres"; then
|
|
199
|
+
PG_FOUND=1
|
|
200
|
+
name=$(docker inspect -f '{{.Name}}' "$c" 2>/dev/null | sed 's|^/||')
|
|
201
|
+
echo ""
|
|
202
|
+
echo "[$name]"
|
|
203
|
+
pass=$(docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' "$c" 2>/dev/null \
|
|
204
|
+
| grep '^POSTGRES_PASSWORD=' | head -1 | cut -d= -f2-)
|
|
205
|
+
if [[ -n "$pass" ]]; then
|
|
206
|
+
evaluate_secret "POSTGRES_PASSWORD" "$pass"
|
|
207
|
+
else
|
|
208
|
+
echo " [!!!] CRITICAL: 未取得 POSTGRES_PASSWORD (是否 secrets 挂载或 trust 认证?)"
|
|
209
|
+
fi
|
|
210
|
+
fi
|
|
211
|
+
done
|
|
212
|
+
[[ "$PG_FOUND" == "0" ]] && echo "[i] 未发现 Postgres 容器"
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# ---------- 5. SSH 私钥强度 ----------
|
|
216
|
+
echo ""
|
|
217
|
+
echo "########## 5. SSH 私钥类型 / 位数 ##########"
|
|
218
|
+
# 当前用户 + root 的 ~/.ssh/ (Bug fix 3: 去重, root 用户登录时 $HOME=/root 会重复)
|
|
219
|
+
SSH_DIRS=$(printf '%s\n' "$HOME/.ssh" /root/.ssh /home/*/.ssh 2>/dev/null | sort -u)
|
|
220
|
+
for ssh_dir in $SSH_DIRS; do
|
|
221
|
+
[[ -d "$ssh_dir" ]] || continue
|
|
222
|
+
for kf in "$ssh_dir"/id_rsa "$ssh_dir"/id_ed25519 "$ssh_dir"/id_ecdsa "$ssh_dir"/id_dsa; do
|
|
223
|
+
[[ -f "$kf" ]] || continue
|
|
224
|
+
info=$(ssh-keygen -l -f "$kf" 2>/dev/null || sudo -n ssh-keygen -l -f "$kf" 2>/dev/null)
|
|
225
|
+
if [[ -z "$info" ]]; then
|
|
226
|
+
echo " $kf [i] 无法读取(权限?)"
|
|
227
|
+
continue
|
|
228
|
+
fi
|
|
229
|
+
bits=$(echo "$info" | awk '{print $1}')
|
|
230
|
+
type=$(echo "$info" | grep -oE '\([A-Z0-9]+\)$' | tr -d '()')
|
|
231
|
+
perm=$(stat -c '%a' "$kf" 2>/dev/null)
|
|
232
|
+
|
|
233
|
+
case "$type" in
|
|
234
|
+
ED25519)
|
|
235
|
+
printf " %-40s type=%-8s bits=%-4s perm=%s [OK]\n" "$kf" "$type" "$bits" "$perm" ;;
|
|
236
|
+
RSA)
|
|
237
|
+
if [[ "$bits" -ge 4096 ]]; then mark="[OK]"
|
|
238
|
+
elif [[ "$bits" -ge 3072 ]]; then mark="[OK] (建议升 ed25519)"
|
|
239
|
+
elif [[ "$bits" -ge 2048 ]]; then mark="[!] MEDIUM: RSA-${bits} 可接受但建议升 ed25519 或 RSA-4096"
|
|
240
|
+
else mark="[!!!] CRITICAL: RSA-${bits} 已不安全, 立即轮换"
|
|
241
|
+
fi
|
|
242
|
+
printf " %-40s type=%-8s bits=%-4s perm=%s %s\n" "$kf" "$type" "$bits" "$perm" "$mark" ;;
|
|
243
|
+
ECDSA)
|
|
244
|
+
printf " %-40s type=%-8s bits=%-4s perm=%s [!] MEDIUM: ECDSA 存疑(NIST 曲线), 建议 ed25519\n" "$kf" "$type" "$bits" "$perm" ;;
|
|
245
|
+
DSA)
|
|
246
|
+
printf " %-40s type=%-8s bits=%-4s perm=%s [!!!] CRITICAL: DSA 已废弃, 立即轮换\n" "$kf" "$type" "$bits" "$perm" ;;
|
|
247
|
+
*)
|
|
248
|
+
printf " %-40s type=%-8s bits=%-4s perm=%s\n" "$kf" "$type" "$bits" "$perm" ;;
|
|
249
|
+
esac
|
|
250
|
+
|
|
251
|
+
# 权限检查
|
|
252
|
+
if [[ -n "$perm" && "$perm" != "600" && "$perm" != "400" ]]; then
|
|
253
|
+
echo " [!!] HIGH: 私钥权限 $perm 过宽, 应 600"
|
|
254
|
+
fi
|
|
255
|
+
done
|
|
256
|
+
done
|
|
257
|
+
|
|
258
|
+
echo ""
|
|
259
|
+
echo "########## 凭证强度汇总 ##########"
|
|
260
|
+
echo "[i] 修复指引:"
|
|
261
|
+
echo " - WEAK 密码: 立即轮换 (建议 >= 16 字符 + 三类字符的强密码)"
|
|
262
|
+
echo " - 高敏字段 (JWT/SECRET/AK/SK): >= 32 字符随机串"
|
|
263
|
+
echo " - 生成命令: openssl rand -base64 24 | tr -d '=+/' | cut -c1-20"
|
|
264
|
+
echo " - 高敏: openssl rand -hex 32 (生成 64 字符 hex token)"
|
|
265
|
+
REMOTE
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 依赖服务连通性 / 防火墙
|
|
3
|
+
TARGET="$1"; shift
|
|
4
|
+
SSH_OPTS=("$@")
|
|
5
|
+
|
|
6
|
+
ssh "${SSH_OPTS[@]}" "${TARGET}" bash -s <<'REMOTE'
|
|
7
|
+
echo "--- 防火墙状态 ---"
|
|
8
|
+
if command -v ufw >/dev/null 2>&1; then
|
|
9
|
+
echo "[ufw]"
|
|
10
|
+
sudo -n ufw status verbose 2>/dev/null || echo " [!] 需 sudo 查看 ufw"
|
|
11
|
+
fi
|
|
12
|
+
if command -v firewall-cmd >/dev/null 2>&1; then
|
|
13
|
+
echo "[firewalld]"
|
|
14
|
+
sudo -n firewall-cmd --state 2>/dev/null
|
|
15
|
+
sudo -n firewall-cmd --list-all 2>/dev/null
|
|
16
|
+
fi
|
|
17
|
+
echo "[iptables]"
|
|
18
|
+
sudo -n iptables -L INPUT -n --line-numbers 2>/dev/null | head -20 || echo " [i] 无法读取 iptables"
|
|
19
|
+
|
|
20
|
+
echo ""
|
|
21
|
+
echo "--- 监听端口 (按地址分组) ---"
|
|
22
|
+
(ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null) | awk 'NR>1 {print $4}' | awk -F: '{
|
|
23
|
+
port=$NF;
|
|
24
|
+
ip=substr($0,1,length($0)-length(port)-1);
|
|
25
|
+
if (ip=="0.0.0.0" || ip=="*" || ip=="[::]") public[port]++;
|
|
26
|
+
else if (ip=="127.0.0.1" || ip=="[::1]") loop[port]++;
|
|
27
|
+
else internal[port]++;
|
|
28
|
+
}
|
|
29
|
+
END {
|
|
30
|
+
print "公网监听 (0.0.0.0 / *):"
|
|
31
|
+
for (p in public) print " " p
|
|
32
|
+
print "内网监听 (具体 IP):"
|
|
33
|
+
for (p in internal) print " " p
|
|
34
|
+
print "回环监听 (127.0.0.1):"
|
|
35
|
+
for (p in loop) print " " p
|
|
36
|
+
}'
|
|
37
|
+
|
|
38
|
+
echo ""
|
|
39
|
+
echo "--- 系统负载与内存 ---"
|
|
40
|
+
uptime
|
|
41
|
+
free -h 2>/dev/null | head -3
|
|
42
|
+
|
|
43
|
+
echo ""
|
|
44
|
+
echo "--- 磁盘 ---"
|
|
45
|
+
df -h | grep -vE "tmpfs|udev" | head -10
|
|
46
|
+
|
|
47
|
+
echo ""
|
|
48
|
+
echo "--- 已安装的 Web 应用进程 (常见) ---"
|
|
49
|
+
ps -eo user,pid,%cpu,%mem,cmd --sort=-%mem 2>/dev/null \
|
|
50
|
+
| grep -E "(nginx|node|python|uvicorn|gunicorn|java|php-fpm|redis-server|postgres|mysql|mongod)" \
|
|
51
|
+
| grep -v grep | head -20
|
|
52
|
+
|
|
53
|
+
echo ""
|
|
54
|
+
echo "--- 应用健康检查端点 (经本地 nginx 回环 + --resolve, 避免 hairpin NAT) ---"
|
|
55
|
+
NGINX_DUMP=$(sudo -n nginx -T 2>/dev/null || nginx -T 2>/dev/null || true)
|
|
56
|
+
# 只取真实 server_name 指令行(行首仅空白 + 关键字), 去行内注释, 拆多域名, 过滤 _ / 通配 / 空 / 非法 token
|
|
57
|
+
# 旧实现用 awk '/server_name/' 会误匹配注释行里的 server_name 文字, 产出 _) 1. :80 等垃圾域名
|
|
58
|
+
DOMAINS=$(echo "$NGINX_DUMP" \
|
|
59
|
+
| grep -E '^[[:space:]]*server_name[[:space:]]' \
|
|
60
|
+
| sed -E 's/#.*$//; s/^[[:space:]]*server_name[[:space:]]+//; s/;.*$//' \
|
|
61
|
+
| tr ' ' '\n' \
|
|
62
|
+
| grep -E '^[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?$' \
|
|
63
|
+
| grep -v '^_$' \
|
|
64
|
+
| sort -u | head -5)
|
|
65
|
+
[[ -z "$DOMAINS" ]] && DOMAINS="localhost"
|
|
66
|
+
# 是否启用 https(443 在监听); 公网域名从本机直连会触发 hairpin NAT 返回 000,
|
|
67
|
+
# 用 --resolve 把域名钉到回环, 既走本地 nginx 又匹配 SNI 证书, 才是白盒正解
|
|
68
|
+
HAS_HTTPS=$( (ss -tln 2>/dev/null || netstat -tln 2>/dev/null) | grep -qE ':443[[:space:]]' && echo yes || echo no )
|
|
69
|
+
for D in $DOMAINS; do
|
|
70
|
+
for path in "/api/health" "/health" "/healthz" "/_health" "/status"; do
|
|
71
|
+
if [[ "$HAS_HTTPS" == "yes" ]]; then
|
|
72
|
+
code=$(curl -k -sS -o /dev/null -w "%{http_code}" --max-time 3 --resolve "$D:443:127.0.0.1" "https://$D$path" 2>/dev/null || echo "000")
|
|
73
|
+
scheme="https"
|
|
74
|
+
else
|
|
75
|
+
code=$(curl -sS -o /dev/null -w "%{http_code}" --max-time 3 --resolve "$D:80:127.0.0.1" "http://$D$path" 2>/dev/null || echo "000")
|
|
76
|
+
scheme="http"
|
|
77
|
+
fi
|
|
78
|
+
[[ "$code" != "404" && "$code" != "000" ]] && printf " %s://%s%s -> %s\n" "$scheme" "$D" "$path" "$code"
|
|
79
|
+
done
|
|
80
|
+
done
|
|
81
|
+
|
|
82
|
+
echo ""
|
|
83
|
+
echo "--- 系统更新提示 ---"
|
|
84
|
+
if command -v apt >/dev/null 2>&1; then
|
|
85
|
+
sudo -n apt list --upgradable 2>/dev/null | head -10 || echo " [i] 无法检查 apt 更新"
|
|
86
|
+
elif command -v yum >/dev/null 2>&1; then
|
|
87
|
+
sudo -n yum check-update 2>/dev/null | head -10 || echo " [i] 无法检查 yum 更新"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
echo ""
|
|
91
|
+
echo "--- 内核/系统启动时间 ---"
|
|
92
|
+
who -b 2>/dev/null
|
|
93
|
+
echo "kernel: $(uname -r)"
|
|
94
|
+
REMOTE
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# SSH 安全检查 (只读)
|
|
3
|
+
TARGET="$1"; shift
|
|
4
|
+
SSH_OPTS=("$@")
|
|
5
|
+
|
|
6
|
+
ssh "${SSH_OPTS[@]}" "${TARGET}" bash -s <<'REMOTE'
|
|
7
|
+
echo "--- /etc/ssh/sshd_config (filtered key directives) ---"
|
|
8
|
+
SSHD_CONF="/etc/ssh/sshd_config"
|
|
9
|
+
SSHD_DIR="/etc/ssh/sshd_config.d"
|
|
10
|
+
if [[ -r "$SSHD_CONF" ]]; then
|
|
11
|
+
grep -Ei "^[[:space:]]*(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|PermitEmptyPasswords|Port|Protocol|MaxAuthTries|LoginGraceTime|AllowUsers|AllowGroups|DenyUsers|DenyGroups|ChallengeResponseAuthentication|UsePAM|X11Forwarding|ClientAliveInterval|ClientAliveCountMax|LogLevel|Banner)" "$SSHD_CONF" 2>/dev/null
|
|
12
|
+
if [[ -d "$SSHD_DIR" ]]; then
|
|
13
|
+
echo "--- $SSHD_DIR/*.conf ---"
|
|
14
|
+
grep -EiH "^[[:space:]]*(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|PermitEmptyPasswords|Port|Protocol|MaxAuthTries)" "$SSHD_DIR"/*.conf 2>/dev/null
|
|
15
|
+
fi
|
|
16
|
+
else
|
|
17
|
+
echo "[!] $SSHD_CONF 不可读 (需要 sudo)"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo ""
|
|
21
|
+
echo "--- effective sshd config (sshd -T, 需 sudo) ---"
|
|
22
|
+
sudo -n sshd -T 2>/dev/null | grep -Ei "^(permitrootlogin|passwordauthentication|pubkeyauthentication|permitemptypasswords|port|protocol|maxauthtries|logingracetime|allowusers|allowgroups|x11forwarding|loglevel)" || echo "[i] 无法读取 effective config (需要 sudo 或 sshd -T 不可用)"
|
|
23
|
+
|
|
24
|
+
echo ""
|
|
25
|
+
echo "--- ssh process & version ---"
|
|
26
|
+
sshd -V 2>&1 | head -2 || ssh -V 2>&1
|
|
27
|
+
|
|
28
|
+
echo ""
|
|
29
|
+
echo "--- recent failed logins (last 20) ---"
|
|
30
|
+
sudo -n journalctl _COMM=sshd --since "7 days ago" 2>/dev/null | grep -Ei "failed|invalid" | tail -20 \
|
|
31
|
+
|| sudo -n grep -Ei "failed|invalid" /var/log/auth.log 2>/dev/null | tail -20 \
|
|
32
|
+
|| echo "[i] 无法读取认证日志 (需要 sudo)"
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo "--- fail2ban status ---"
|
|
36
|
+
if command -v fail2ban-client >/dev/null 2>&1; then
|
|
37
|
+
sudo -n fail2ban-client status 2>/dev/null || echo "[i] fail2ban 已安装,但需要 sudo 查看状态"
|
|
38
|
+
else
|
|
39
|
+
echo "[!] fail2ban 未安装"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo ""
|
|
43
|
+
echo "--- authorized_keys 概览 (当前用户) ---"
|
|
44
|
+
if [[ -r ~/.ssh/authorized_keys ]]; then
|
|
45
|
+
awk '{print " key: " $1 " " substr($2,1,16) "... " $3}' ~/.ssh/authorized_keys
|
|
46
|
+
echo " total: $(wc -l < ~/.ssh/authorized_keys) keys"
|
|
47
|
+
else
|
|
48
|
+
echo "[i] 当前用户无 authorized_keys"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo ""
|
|
52
|
+
echo "--- /root/.ssh/authorized_keys (需 sudo) ---"
|
|
53
|
+
sudo -n test -f /root/.ssh/authorized_keys 2>/dev/null && \
|
|
54
|
+
echo " [!] root 用户存在 authorized_keys, 共 $(sudo -n wc -l < /root/.ssh/authorized_keys 2>/dev/null) 行" \
|
|
55
|
+
|| echo "[i] 无 root authorized_keys 或无 sudo 权限"
|
|
56
|
+
REMOTE
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# uc-deploy-audit: 一键全量巡检(subagent 不可用时的串行/并行退化方案)
|
|
3
|
+
#
|
|
4
|
+
# 优先做法是让 Claude 用 subagent 并行派遣多个 Agent 跑各类 check_xxx.sh
|
|
5
|
+
# (见 SKILL.md Step 4)。本脚本仅作为本地一键回退使用。
|
|
6
|
+
#
|
|
7
|
+
# 用法:
|
|
8
|
+
# ./run_all.sh <user>@<host> [-p <port>] [-i <key>] [--serial]
|
|
9
|
+
#
|
|
10
|
+
# 默认 8 路并行。--serial 强制串行。
|
|
11
|
+
|
|
12
|
+
set -uo pipefail
|
|
13
|
+
|
|
14
|
+
if [[ $# -lt 1 ]]; then
|
|
15
|
+
echo "Usage: $0 <user>@<host|alias> [-p <port>] [-i <key>] [--serial]" >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
TARGET="$1"; shift
|
|
20
|
+
SSH_OPTS=(-o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=accept-new)
|
|
21
|
+
PARALLEL=true
|
|
22
|
+
|
|
23
|
+
while [[ $# -gt 0 ]]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
-p) SSH_OPTS+=(-p "$2"); shift 2;;
|
|
26
|
+
-i) SSH_OPTS+=(-i "$2"); shift 2;;
|
|
27
|
+
--serial) PARALLEL=false; shift;;
|
|
28
|
+
*) echo "Unknown arg: $1" >&2; exit 1;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
33
|
+
TMP_DIR=$(mktemp -d -t uc-audit-XXXXXX)
|
|
34
|
+
trap 'rm -rf "$TMP_DIR"' EXIT
|
|
35
|
+
|
|
36
|
+
# 检查项: <section_name>:<script_name>
|
|
37
|
+
SECTIONS=(
|
|
38
|
+
"BASE_INFO:check_base.sh"
|
|
39
|
+
"SSH:check_ssh.sh"
|
|
40
|
+
"NGINX:check_nginx.sh"
|
|
41
|
+
"DB:check_db.sh"
|
|
42
|
+
"HTTPS:check_https.sh"
|
|
43
|
+
"ENV:check_env.sh"
|
|
44
|
+
"DOCKER:check_docker.sh"
|
|
45
|
+
"SERVICES:check_services.sh"
|
|
46
|
+
"RESILIENCE:check_resilience.sh"
|
|
47
|
+
"LOGS:check_logs.sh"
|
|
48
|
+
"CAPACITY:check_capacity.sh"
|
|
49
|
+
"SECRETS:check_secrets.sh"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
echo "========================================"
|
|
53
|
+
echo " uc-deploy-audit | target: ${TARGET}"
|
|
54
|
+
echo " timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
55
|
+
echo " mode: $([ "$PARALLEL" = true ] && echo "parallel (${#SECTIONS[@]} workers)" || echo 'serial')"
|
|
56
|
+
echo "========================================"
|
|
57
|
+
|
|
58
|
+
run_section() {
|
|
59
|
+
local name="$1"
|
|
60
|
+
local script="$2"
|
|
61
|
+
local out_file="${TMP_DIR}/${name}.out"
|
|
62
|
+
{
|
|
63
|
+
echo "########## SECTION: ${name} ##########"
|
|
64
|
+
bash "${SCRIPT_DIR}/${script}" "${TARGET}" "${SSH_OPTS[@]}" 2>&1 \
|
|
65
|
+
|| echo "[!] ${name} 部分失败"
|
|
66
|
+
echo "########## END: ${name} ##########"
|
|
67
|
+
} > "$out_file" 2>&1
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if [[ "$PARALLEL" == "true" ]]; then
|
|
71
|
+
# 并行:所有 section 后台启动
|
|
72
|
+
pids=()
|
|
73
|
+
for entry in "${SECTIONS[@]}"; do
|
|
74
|
+
name="${entry%%:*}"
|
|
75
|
+
script="${entry##*:}"
|
|
76
|
+
run_section "$name" "$script" &
|
|
77
|
+
pids+=($!)
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
# 等所有完成
|
|
81
|
+
for pid in "${pids[@]}"; do
|
|
82
|
+
wait "$pid"
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
# 按顺序输出结果(保证报告分类有序)
|
|
86
|
+
for entry in "${SECTIONS[@]}"; do
|
|
87
|
+
name="${entry%%:*}"
|
|
88
|
+
echo ""
|
|
89
|
+
cat "${TMP_DIR}/${name}.out"
|
|
90
|
+
done
|
|
91
|
+
else
|
|
92
|
+
# 串行
|
|
93
|
+
for entry in "${SECTIONS[@]}"; do
|
|
94
|
+
name="${entry%%:*}"
|
|
95
|
+
script="${entry##*:}"
|
|
96
|
+
echo ""
|
|
97
|
+
run_section "$name" "$script"
|
|
98
|
+
cat "${TMP_DIR}/${name}.out"
|
|
99
|
+
done
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
echo ""
|
|
103
|
+
echo "========================================"
|
|
104
|
+
echo " 巡检数据采集完成,请由 Claude 分析生成报告"
|
|
105
|
+
echo "========================================"
|
|
@@ -153,10 +153,31 @@ git -C "$REPO_PATH" mv <仓库内相对路径> <new-相对路径>
|
|
|
153
153
|
|
|
154
154
|
**冲突处理**:目标已存在 → AskUserQuestion 让用户选「覆盖 / 改名 / 取消」。
|
|
155
155
|
|
|
156
|
+
### 步骤 6.5:bump ai-tools 内部版本 + CHANGELOG(强制)
|
|
157
|
+
|
|
158
|
+
凡改动 `$REPO_PATH/dwy-cli/templates/ai-tools/` 下任意内容,**必须**同批更新:
|
|
159
|
+
|
|
160
|
+
| 文件 | 动作 |
|
|
161
|
+
| ---- | ---- |
|
|
162
|
+
| `dwy-cli/templates/ai-tools/VERSION` | 按 `CHANGELOG.md` 内维护约定 bump(MAJOR / MINOR / PATCH) |
|
|
163
|
+
| `dwy-cli/templates/ai-tools/CHANGELOG.md` | 顶部追加 `## x.y.z — YYYY-MM-DD` 段 + Added/Changed/Fixed/Removed |
|
|
164
|
+
|
|
165
|
+
约定全文见:`$REPO_PATH/dwy-cli/templates/ai-tools/CHANGELOG.md`「维护约定」。
|
|
166
|
+
|
|
167
|
+
- 新增 skill/rule/hook/command 或新增强制约束 → 至少 **MINOR**
|
|
168
|
+
- 仅修正文案 / 链接 / 不改强制语义 → **PATCH**
|
|
169
|
+
- 破坏同步结构 / 删除广泛依赖项且无迁移 → **MAJOR**
|
|
170
|
+
|
|
171
|
+
**禁止**只提交模板文件而不改 `VERSION` + `CHANGELOG.md`。
|
|
172
|
+
|
|
156
173
|
### 步骤 7:staged + 显示 diff
|
|
157
174
|
|
|
158
175
|
```bash
|
|
159
176
|
git -C "$REPO_PATH" add <精准路径>
|
|
177
|
+
# 务必包含 VERSION 与 CHANGELOG
|
|
178
|
+
git -C "$REPO_PATH" add \
|
|
179
|
+
"$REPO_PATH/dwy-cli/templates/ai-tools/VERSION" \
|
|
180
|
+
"$REPO_PATH/dwy-cli/templates/ai-tools/CHANGELOG.md"
|
|
160
181
|
git -C "$REPO_PATH" status --short
|
|
161
182
|
git -C "$REPO_PATH" diff --cached --stat
|
|
162
183
|
```
|
|
@@ -170,7 +191,7 @@ git -C "$REPO_PATH" diff --cached --stat
|
|
|
170
191
|
按项目 `CLAUDE.md` 中 Git Commit Scope 规范:
|
|
171
192
|
- scope: `cli`
|
|
172
193
|
- type: `feat`(新模板)/ `fix`(修复模板)/ `docs`(仅文档)
|
|
173
|
-
- subject: 中文动宾短语 ≤72
|
|
194
|
+
- subject: 中文动宾短语 ≤72 字符;可附 ai-tools 版本号(如 `ai-tools 0.2.0`)
|
|
174
195
|
- **禁** AI 署名 / Co-Authored-By trailer
|
|
175
196
|
|
|
176
197
|
模板:
|
|
@@ -464,7 +464,7 @@ bash {scripts}/check_db.sh <target> [ssh_opts...]
|
|
|
464
464
|
|
|
465
465
|
根据本次失败项归纳的可执行后续动作:
|
|
466
466
|
|
|
467
|
-
- 镜像版本不固定 (4.6) → 跑 `/dwy-docker
|
|
467
|
+
- 镜像版本不固定 (4.6) → 跑 `/dwy-docker` 选 N-1 minor
|
|
468
468
|
- daemon 未配 registry-mirrors (4.6) → 跑 `/dwy-mirror-source` 写国内源
|
|
469
469
|
- 容器资源偏离推荐 (4.10) → 改 `docker-compose.prod.yml` 的 mem_limit/maxmemory
|
|
470
470
|
- ...
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
## 4.6 Docker 安全 — `{scripts}/check_docker.sh`
|
|
12
12
|
|
|
13
13
|
> **跨 skill 联动**:本节发现的镜像版本/镜像源问题,只**报告**不修复。具体修复路径:
|
|
14
|
-
> - 镜像 tag 不固定 / `:latest` / 浮动 tag → 引导用户跑 `/dwy-docker
|
|
14
|
+
> - 镜像 tag 不固定 / `:latest` / 浮动 tag → 引导用户跑 `/dwy-docker`(走 query_dockerhub.py 选 N-1 minor)
|
|
15
15
|
> - daemon 未配 registry-mirrors / 容器用境外 registry → 引导用户跑 `/dwy-mirror-source`(写阿里云/中科大/daocloud)
|
|
16
16
|
|
|
17
17
|
| 检查项 | 期望值 | 严重级 |
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
|
|
108
108
|
## 4.10 硬件识别与资源推荐 — `{scripts}/check_capacity.sh`
|
|
109
109
|
|
|
110
|
-
> 脚本只输出 raw(硬件规格 + 当前容器 mem_limit + Postgres/Redis 启动参数 + compose 资源声明);主 Claude 用下表生成 "推荐 vs 当前" 对比报告。详细推荐规则与配比公式参考 `dwy-docker
|
|
110
|
+
> 脚本只输出 raw(硬件规格 + 当前容器 mem_limit + Postgres/Redis 启动参数 + compose 资源声明);主 Claude 用下表生成 "推荐 vs 当前" 对比报告。详细推荐规则与配比公式参考 `dwy-docker` skill 第二部分。
|
|
111
111
|
|
|
112
112
|
**容器资源推荐分级表(按宿主总内存)**
|
|
113
113
|
|
package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_docker.sh
CHANGED
|
@@ -43,7 +43,7 @@ docker ps --format "{{.Names}}|{{.Ports}}" 2>/dev/null | while IFS='|' read -r n
|
|
|
43
43
|
done
|
|
44
44
|
|
|
45
45
|
echo ""
|
|
46
|
-
echo "--- 镜像 tag 分级检查 (生产期望: 固定到具体 patch, 跑 /dwy-docker
|
|
46
|
+
echo "--- 镜像 tag 分级检查 (生产期望: 固定到具体 patch, 跑 /dwy-docker 选 N-1 minor) ---"
|
|
47
47
|
# 浮动 tag 黑名单 (无版本号或仅描述类的)
|
|
48
48
|
FLOATING_TAGS='^(latest|stable|mainline|edge|current|alpine|slim|bookworm|bullseye|buster|jammy|focal|noble|nightly)$'
|
|
49
49
|
docker ps --format "{{.Names}}|{{.Image}}" 2>/dev/null | while IFS='|' read -r name image; do
|
|
@@ -87,7 +87,7 @@ docker ps --format "{{.Names}}|{{.Image}}" 2>/dev/null | while IFS='|' read -r n
|
|
|
87
87
|
fi
|
|
88
88
|
done
|
|
89
89
|
echo ""
|
|
90
|
-
echo "[i] 修复:对每条 [!!!] / [!!] / [!] 的镜像,跑 /dwy-docker
|
|
90
|
+
echo "[i] 修复:对每条 [!!!] / [!!] / [!] 的镜像,跑 /dwy-docker 用 query_dockerhub.py 拿 N-1 minor 推荐版本"
|
|
91
91
|
|
|
92
92
|
echo ""
|
|
93
93
|
echo "--- 容器是否以 root 运行 ---"
|
|
@@ -255,5 +255,5 @@ echo ""
|
|
|
255
255
|
echo "[i] 修复路径:"
|
|
256
256
|
echo " 1. docker.io 加速 → /dwy-mirror-source 自动配 daemon registry-mirrors"
|
|
257
257
|
echo " 2. gcr/ghcr/k8s → 把 image 改 <registry>.m.daocloud.io 前缀, 见 dwy-mirror-source 镜像替换表"
|
|
258
|
-
echo " 3. 镜像版本不固定 → /dwy-docker
|
|
258
|
+
echo " 3. 镜像版本不固定 → /dwy-docker 选 N-1 minor 重新固定"
|
|
259
259
|
REMOTE
|
package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_secrets.sh
CHANGED
|
@@ -320,7 +320,7 @@ done
|
|
|
320
320
|
echo ""
|
|
321
321
|
echo "########## 凭证强度汇总 ##########"
|
|
322
322
|
echo "[i] 修复指引:"
|
|
323
|
-
echo " - WEAK 密码: 立即轮换
|
|
323
|
+
echo " - WEAK 密码: 立即轮换 (建议 >= 16 字符 + 三类字符的强密码)"
|
|
324
324
|
echo " - 高敏字段 (JWT/SECRET/AK/SK): >= 32 字符随机串"
|
|
325
325
|
echo " - 生成命令: openssl rand -base64 24 | tr -d '=+/' | cut -c1-20"
|
|
326
326
|
echo " - 高敏: openssl rand -hex 32 (生成 64 字符 hex token)"
|