#!/usr/bin/env bash # 源文件的权限位**政策**:不许比 0644 更严。 # # # 为什么要这条(一个实测出来的实例) # # 这台机器上写文件的工具**不理会 umask**(umask 是 022,但它建的仍是 0600)。 # 后果不是"本地难看",而是它会**进生产**:`deploy/redeploy-plugin.sh` 用 # `cp -a "$SRC/." "$STAGING/"` 打快照,`-a` 保留权限位 —— # 于是快照里 `src/paths.mjs`/`src/turn-cwd.mjs` 是 **0600**,而仓库是 0644。 # # 两头都不报警: # · `cmp` 只比**内容** ⇒ 报"逐字节相同"(实测就是这样); # · `check-deploy-drift.mjs` 只比**内容**、且只在脚本上判**可执行位**(`mode & 0o111`)。 # ⇒ "线上与仓库不一致"里,**只有权限位这一类**完全没有判据看着。 # # # 与漂移侧那条的分工(pi 评审 2026-09-15 §三 明确要求分开) # # · **本脚本 = 政策**:源文件不得比 0644 更严。它**不**看快照, # 所以"两边都是 0600"这种情况它能抓到,而漂移侧永远抓不到(两边一致 ⇒ 恒绿)。 # · **漂移侧 = 一致性**:部署副本的权限位 = 仓库那一份。 # 它抓不到"两边都错"。 # 两条别合成一条:合成的结果是"看起来覆盖了、其实只覆盖一半"。 # # # 为什么"更严"也算错 # # 这些文件是**源码**,要被构建/测试/部署以不同身份读(`install.sh` 会切身份做可写性判定, # 判据里还有以 nobody 跑的分支)。0600 在"跑的人恰好是属主"时不炸,一旦换身份就是 # EACCES —— 而那串报错看起来是**代码问题**。这条链一路上在消的就是这一类。 set -uo pipefail REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO" # 允许的最严权限:0644。比它更严(组/其他读位缺失)即判红。 # 例外:**可执行**脚本的 0755 不是"更严",它多了执行位、读位齐全,属正常。 fail=0 worst="" count=0 while IFS= read -r f; do [ -n "$f" ] || continue # 只判 git 已跟踪的文件(未跟踪的构建产物不在这条政策范围内) git ls-files --error-unmatch "$f" >/dev/null 2>&1 || continue [ -f "$f" ] || continue mode="$(stat -c '%a' "$f" 2>/dev/null)" || continue # 取八进制后三位 m="${mode: -3}" o="${m: -1}" # other 位 g="${m:1:1}" # group 位 # other 与 group 都必须有读位(4 及以上);否则这条政策判红 if [ "$(( o & 4 ))" -eq 0 ] || [ "$(( g & 4 ))" -eq 0 ]; then count=$((count + 1)) [ -z "$worst" ] && worst="$f" printf ' [FAIL] 权限过严:%s 是 %s(政策要求不严于 0644)\n' "$f" "$mode" >&2 fi done < <(git ls-files) if [ "$count" -gt 0 ]; then printf '\n 共 %d 个源文件比 0644 更严(首个:%s)。\n' "$count" "$worst" >&2 printf ' 药方:chmod 644 <文件>。原因:写文件的工具不理会 umask,而 `cp -a` 会把这个\n' >&2 printf ' 权限位带进生产快照,且 `cmp`/漂移判据都看不见它。\n' >&2 printf ' 这是**政策问题**(源文件应当可被构建/测试/部署以不同身份读),不是代码问题。\n' >&2 exit 1 fi printf ' 源文件权限政策:通过(没有任何已跟踪文件比 0644 更严)\n' exit 0