@@ -10,7 +10,7 @@ permissions:
1010
1111on :
1212 push :
13- branches : [ main, feature/spz-v2-profile-core, feature/spz-gatekeeper-2.0.2-r1, feature/spz-gatekeeper-2.0.2-r2, feature/spz-gatekeeper-2.0.2-r3, feature/spz-gatekeeper-2.0.2-r4, feature/spz-gatekeeper-2.0.2-r5, feature/spz-gatekeeper-2.0.2-r6, feature/spz-gatekeeper-2.0.4-r7, feature/spz-gatekeeper-2.0.5.1, fix/pages-deploy-on-tag ]
13+ branches : [ main, feature/spz-v2-profile-core, feature/spz-gatekeeper-2.0.2-r1, feature/spz-gatekeeper-2.0.2-r2, feature/spz-gatekeeper-2.0.2-r3, feature/spz-gatekeeper-2.0.2-r4, feature/spz-gatekeeper-2.0.2-r5, feature/spz-gatekeeper-2.0.2-r6, feature/spz-gatekeeper-2.0.4-r7, feature/spz-gatekeeper-2.0.5.1, fix/pages-deploy-on-tag, feature/spz-gatekeeper-encoding-defense ]
1414 pull_request :
1515 branches : [ main ]
1616 workflow_dispatch :
@@ -226,6 +226,113 @@ jobs:
226226 - name : Scan GitHub Actions workflows
227227 run : zizmor --format plain --min-severity medium .github/workflows/
228228
229+ # 乱码防护(移植自 TDAI 1.0 pr-ci.yml encoding-defense job,L1-L5 五层)
230+ # 适配:门卫源码含合法中文注释,L5 从"禁止非 ASCII"改为"乱码特征检测";
231+ # 检测目标 = U+FFFD 替换符、无效 UTF-8、意外 BOM、.sh CRLF、编码绕过模式。
232+ encoding-defense :
233+ name : Encoding Defense (L1-L5)
234+ runs-on : ubuntu-latest
235+ timeout-minutes : 5
236+ steps :
237+ - name : Checkout
238+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
239+ with :
240+ persist-credentials : false
241+
242+ - name : L5 - Detect garbled Unicode (U+FFFD / invalid UTF-8) in source
243+ # TDAI L5 扫描非 ASCII 字符;门卫源码含中文注释(合法),故改为检测乱码特征:
244+ # U+FFFD (EF BF BD) 替换符 = 编码损坏的直接证据;无效 UTF-8 序列同样拦截。
245+ # 排除 .spz 二进制数据文件(压缩内容天然含任意字节)。
246+ run : |
247+ echo "── Layer 5: mojibake scan in source files ──"
248+ violations=0
249+ while IFS= read -r -d '' f; do
250+ if ! python3 -c "open('$f','rb').read().decode('utf-8')" 2>/dev/null; then
251+ echo " INVALID UTF-8: $f"
252+ violations=$((violations + 1))
253+ continue
254+ fi
255+ if grep -q $'\xef\xbf\xbd' "$f" 2>/dev/null; then
256+ echo " U+FFFD (mojibake): $f"
257+ violations=$((violations + 1))
258+ fi
259+ done < <(find . \
260+ -path './.git' -prune -o \
261+ -path './build' -prune -o \
262+ -path './build-*' -prune -o \
263+ -type f \( -name '*.cc' -o -name '*.h' -o -name '*.js' -o -name '*.html' \
264+ -o -name '*.sh' -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' \
265+ -o -name '*.cmake' -o -name 'CMakeLists.txt' \) \
266+ -print0 2>/dev/null)
267+ if [ "$violations" -gt 0 ]; then echo "FAIL: $violations file(s) with encoding errors"; exit 1; fi
268+ echo "OK: $violations encoding violations (0 = clean)"
269+
270+ - name : L4 - Verify .gitattributes encoding config
271+ run : |
272+ echo "── Layer 4: git pipeline encoding config ──"
273+ fails=0
274+ if [ -f .gitattributes ]; then
275+ if grep -q "eol=lf" .gitattributes 2>/dev/null; then
276+ echo " .gitattributes declares eol=lf rules"
277+ else
278+ echo " WARN: .gitattributes exists but no eol=lf"
279+ fails=$((fails + 1))
280+ fi
281+ else
282+ echo " WARN: no .gitattributes found"
283+ fails=$((fails + 1))
284+ fi
285+ ENC=$(git config --local core.autocrlf 2>/dev/null || echo "unset")
286+ echo " core.autocrlf: $ENC"
287+ if [ "$fails" -gt 0 ]; then echo "WARN: $fails pipeline encoding issue(s) (non-fatal)"; fi
288+ echo "OK: pipeline encoding check"
289+
290+ - name : L3 - Detect shell encoding bypass patterns
291+ run : |
292+ echo "── Layer 3: shell encoding bypass scan ──"
293+ fails=0
294+ while IFS= read -r -d '' f; do
295+ if grep -q 'iconv.*UTF-16\|sed.*s/BOM\|dos2unix\|recode' "$f" 2>/dev/null; then
296+ echo " SUSPICIOUS: $f may bypass encoding"
297+ fails=$((fails + 1))
298+ fi
299+ done < <(find . -path './.git' -prune -o -name '*.sh' -print 2>/dev/null | tr '\n' '\0')
300+ if [ "$fails" -gt 0 ]; then echo "WARN: $fails shell file(s) with bypass patterns (non-fatal)"; fi
301+ echo "OK: shell encoding bypass check"
302+
303+ - name : L2 - Detect CRLF in shell scripts
304+ run : |
305+ echo "── Layer 2: CRLF scan in .sh ──"
306+ fails=0
307+ while IFS= read -r -d '' f; do
308+ if grep -lU $'\r' "$f" 2>/dev/null | grep -q .; then
309+ echo " CRLF: $f"
310+ fails=$((fails + 1))
311+ fi
312+ done < <(find . -path './.git' -prune -o -name '*.sh' -print 2>/dev/null | tr '\n' '\0')
313+ if [ "$fails" -gt 0 ]; then echo "FAIL: $fails .sh file(s) with CRLF"; exit 1; fi
314+ echo "OK: all .sh use LF"
315+
316+ - name : L1 - Detect unexpected UTF-8 BOM in text sources
317+ run : |
318+ echo "── Layer 1: UTF-8 BOM scan ──"
319+ fails=0
320+ while IFS= read -r -d '' f; do
321+ header=$(od -A n -t x1 -N 3 "$f" 2>/dev/null | tr -d ' \n')
322+ if [ "$header" = "efbbbf" ]; then
323+ echo " UNEXPECTED BOM: $f"
324+ fails=$((fails + 1))
325+ fi
326+ done < <(find . \
327+ -path './.git' -prune -o \
328+ -path './build' -prune -o \
329+ -path './build-*' -prune -o \
330+ -type f \( -name '*.cc' -o -name '*.h' -o -name '*.js' -o -name '*.html' \
331+ -o -name '*.sh' -o -name '*.yml' -o -name '*.yaml' -o -name '*.md' \) \
332+ -print0 2>/dev/null)
333+ if [ "$fails" -gt 0 ]; then echo "FAIL: $fails file(s) with unexpected BOM"; exit 1; fi
334+ echo "OK: no unexpected BOM"
335+
229336 wasm :
230337 runs-on : ubuntu-latest
231338 timeout-minutes : 30
0 commit comments