From 70efcd55f2b1dcdd83b7b857dc8dc31260a50362 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Wed, 29 Jul 2026 09:12:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(role):=20=E6=AA=A2=E6=9F=A5=E8=85=B3?= =?UTF-8?q?=E6=9C=AC=E8=87=AA=E8=A1=8C=E8=BC=89=E5=85=A5=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=AD=A3=20cron=20=E7=92=B0=E5=A2=83?= =?UTF-8?q?=E5=8F=96=E4=B8=8D=E5=88=B0=E8=AE=8A=E6=95=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 晨間狀態檢查在 cron 下實際不會運作:cron 沒有互動 shell 的環境變數, 而 ~/.bashrc 多數在非互動時提早 return,導致範例腳本永遠拿不到 GITEA_TOKEN 而安靜結束,功能等於無效。 - examples/check-gitea-prs.sh 新增 load_env_var():依序從 ~/.roles/.env、 ~/.bashrc、~/.profile 只抽取所需變數的那一行並 eval 該行賦值, 不要求使用者把權杖複製到新檔案,也不必寫進 crontab - role skill 補設定來源說明:非機密放 ~/.roles/.env(權限 600), 權杖留在原本位置不要複製副本 - 版號 0.0.4 → 0.0.5 驗證:以 env -i 模擬 cron 環境(完全無環境變數)執行,成功取得設定並列出 待合併 PR;確認輸出無疑似權杖字串、.env 不含權杖。 Co-Authored-By: Claude Opus 5 (1M context) --- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 2 +- plugin.json | 2 +- scripts/role/examples/check-gitea-prs.sh | 29 +++++++++++++++++++++++- skills/role/SKILL.md | 9 +++++++- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index c117489..473aeac 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-generic", - "version": "0.0.4", + "version": "0.0.5", "description": "JSC 跨 AI 助理共用規範 plugin(Claude Code / Codex / Antigravity / OpenCode)。所有 skills 以 SKILL.md 為共通標準,於 Claude Code 以 /jsc-generic: 前綴呼叫。", "skills": "./skills", "author": { diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index dad4d42..233800c 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-generic", - "version": "0.0.4", + "version": "0.0.5", "description": "JSC 跨 AI 助理共用規範 plugin。所有 skills 以 SKILL.md 為共通標準。", "skills": "./skills" } diff --git a/plugin.json b/plugin.json index 6caffc8..6117410 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-generic", - "version": "0.0.4", + "version": "0.0.5", "description": "JSC 跨 AI 助理共用規範 plugin。所有 skills 以 SKILL.md 為共通標準;於 Antigravity 以 /jsc-generic: 前綴呼叫。", "skills": "./skills/" } diff --git a/scripts/role/examples/check-gitea-prs.sh b/scripts/role/examples/check-gitea-prs.sh index 8d8c452..96b18f7 100755 --- a/scripts/role/examples/check-gitea-prs.sh +++ b/scripts/role/examples/check-gitea-prs.sh @@ -8,17 +8,44 @@ # cp check-gitea-prs.sh ~/.roles/YUI01.checks/ # chmod +x ~/.roles/YUI01.checks/check-gitea-prs.sh # -# 設定(環境變數,需寫進 crontab 或 ~/.roles 的環境,cron 沒有互動 shell 的變數): +# 設定(環境變數): # GITEA_HOST Gitea 站台,例如 https://gitea.example.com # GITEA_TOKEN 存取權杖(本腳本不會輸出它;晨間檢查寫入記憶前仍會再遮蔽一次) # GITEA_REPOS 逗號分隔的 owner/repo 清單,例如 plugins/generic,plugins/code # +# cron 沒有互動 shell 的環境變數,且 ~/.bashrc 多數在非互動時會提早 return, +# 因此本腳本會依序從 ~/.roles/.env、~/.bashrc、~/.profile **只抽取所需變數的那一行**, +# 不要求使用者把權杖複製到新檔案,也不必寫進 crontab。 +# 建議把非機密設定(HOST/REPOS)放 ~/.roles/.env,權杖留在原本的位置。 +# # 慣例:**沒有需要回報的事情就不要輸出任何內容**。晨間檢查只在有輸出時才寫記憶, # 靜默即代表「一切正常,不必打擾使用者」。 # ============================================================================== set -u +# 從使用者既有的設定檔補齊未設定的變數。只取用「NAME=」開頭的那一行並 eval 該行賦值, +# 風險等同使用者自己 source 這些檔案;不會讀取或輸出其他內容。 +load_env_var() { + local name="$1" file line current + eval "current=\${$name:-}" + [ -n "$current" ] && return 0 + for file in "$HOME/.roles/.env" "$HOME/.bashrc" "$HOME/.profile"; do + [ -f "$file" ] || continue + line="$(grep -m1 -E "^[[:space:]]*(export[[:space:]]+)?${name}=" "$file" 2>/dev/null)" || true + [ -n "$line" ] || continue + eval "$(printf '%s' "$line" | sed -E 's/^[[:space:]]*export[[:space:]]+//')" 2>/dev/null || continue + export "$name" + eval "current=\${$name:-}" + [ -n "$current" ] && return 0 + done + return 0 +} + +load_env_var GITEA_HOST +load_env_var GITEA_TOKEN +load_env_var GITEA_REPOS + HOST="${GITEA_HOST:-}" TOKEN="${GITEA_TOKEN:-}" REPOS="${GITEA_REPOS:-}" diff --git a/skills/role/SKILL.md b/skills/role/SKILL.md index c5617b9..a576c04 100644 --- a/skills/role/SKILL.md +++ b/skills/role/SKILL.md @@ -256,7 +256,14 @@ chmod +x ~/.roles/<角色 ID>.checks/check-gitea-prs.sh | 遮蔽 | 腳本輸出視為外部資料,寫入記憶前一律經 `transcript.js redact` 遮蔽憑證與個資 | | 記憶分類 | 寫成 `daily` 低優先度記憶,會依遺忘規則自然淘汰,不會長期堆積 | -**安全須知**:這個機制會以使用者身分執行 `.checks/` 內的腳本,等同於自己寫的 cron job。只放自己看得懂的腳本,不要放來源不明的檔案。cron 沒有互動 shell 的環境變數,腳本需要的設定要自己在腳本內處理或寫進 crontab。 +**cron 沒有互動 shell 的環境變數**,而 `~/.bashrc` 多數在非互動時會提早 return,因此檢查腳本不能假設變數已存在。範例腳本的做法是依序從 `~/.roles/.env`、`~/.bashrc`、`~/.profile` **只抽取所需變數的那一行**,讓使用者不必把權杖複製到新檔案、也不必寫進 crontab: + +| 設定 | 建議放置位置 | +| --- | --- | +| 非機密(站台網址、repo 清單等) | `~/.roles/.env`(權限設 `600`) | +| 權杖與密碼 | **留在原本的位置**,例如 `~/.bashrc`;不要複製出副本 | + +**安全須知**:這個機制會以使用者身分執行 `.checks/` 內的腳本,等同於自己寫的 cron job。只放自己看得懂的腳本,不要放來源不明的檔案。腳本輸出寫入記憶前雖然會經 `redact` 遮蔽,但仍不應在腳本中主動印出憑證。 ### 額度控制策略