@cocorograph/hub-agent 0.5.24 → 0.5.26
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/package.json
CHANGED
package/scripts/install.sh
CHANGED
|
@@ -214,6 +214,183 @@ ensure_npm_user_prefix() {
|
|
|
214
214
|
done
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
# =============================================================================
|
|
218
|
+
# Node TLS 環境の自動修復
|
|
219
|
+
#
|
|
220
|
+
# 背景: npm install で `UNABLE_TO_GET_ISSUER_CERT_LOCALLY` が出る環境がある。
|
|
221
|
+
# 原因は「node は OS の信頼ストアを使わず、自分にコンパイル時に焼き込まれた
|
|
222
|
+
# CA リストだけで TLS 検証する」設計にある:
|
|
223
|
+
#
|
|
224
|
+
# - curl は macOS Keychain (or /etc/ssl/certs) を使う → 通る
|
|
225
|
+
# - node はバンドル CA のみ → 通らない
|
|
226
|
+
#
|
|
227
|
+
# テナント環境では以下のいずれかで MITM 的な証明書差し替えが起きうる:
|
|
228
|
+
# - ウィルス対策ソフト (Sophos / Trend Micro / Norton / Symantec / Kaspersky 等)
|
|
229
|
+
# - 企業の SSL インスペクション proxy (ZScaler / Cloudflare WARP for Teams 等)
|
|
230
|
+
# - VPN クライアントによるトラフィック検査
|
|
231
|
+
# - 広告ブロッカー (NextDNS / AdGuard / 1.1.1.1 等)
|
|
232
|
+
# - 親会社配布のセキュリティアプリ
|
|
233
|
+
#
|
|
234
|
+
# どれもユーザー操作なしには検出しにくく、ユーザー自身も気づいていないことが多い。
|
|
235
|
+
#
|
|
236
|
+
# 対処: ユーザーが既に OS で信頼している CA バンドルを node にも渡せば、curl と
|
|
237
|
+
# node の信頼ストアの乖離が解消する。`NODE_EXTRA_CA_CERTS` 環境変数を使えば
|
|
238
|
+
# node のバンドル CA に「追加で」信頼する証明書を渡せる (バンドル CA を置き換える
|
|
239
|
+
# わけではないので、通常環境への副作用はない)。
|
|
240
|
+
#
|
|
241
|
+
# 1. pre-flight check で node の TLS が通るかテスト
|
|
242
|
+
# 2. 失敗時のみ、OS の信頼ストアを PEM に書き出して NODE_EXTRA_CA_CERTS にセット
|
|
243
|
+
# 3. シェル profile (.zprofile / .bash_profile) にも追記して永続化
|
|
244
|
+
# 4. 再テスト → ダメなら明確な日本語エラーガイドで終了
|
|
245
|
+
# =============================================================================
|
|
246
|
+
|
|
247
|
+
# node 側 TLS で npm registry に到達できるかテスト。成功で 0、失敗で 1。
|
|
248
|
+
# stderr の最後の行を grep 用に echo するので、呼び出し側で原因種別を判定できる。
|
|
249
|
+
_test_node_tls() {
|
|
250
|
+
if ! present node; then
|
|
251
|
+
return 1
|
|
252
|
+
fi
|
|
253
|
+
# node -e で出る ERR_TLS_CERT_ALTNAME_INVALID 等の他種別エラーは別途扱う必要が
|
|
254
|
+
# あるため戻り値だけで判定。stdout/stderr は呼び出し側で破棄してよい。
|
|
255
|
+
node -e "require('https').get('https://registry.npmjs.org/', r => { process.exit(r.statusCode >= 400 ? 1 : 0); }).on('error', e => { console.error(e.code || e.message); process.exit(1); });" 2>&1
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
# OS の信頼ストア (system / login keychain or /etc/ssl/certs) を PEM に書き出す。
|
|
259
|
+
# 返り値: 成功なら 0 + ファイルパスを stdout に echo / 失敗なら 1。
|
|
260
|
+
_export_os_ca_bundle() {
|
|
261
|
+
local out_pem="$HOME/.hub-agent-ca.pem"
|
|
262
|
+
case "$(uname -s)" in
|
|
263
|
+
Darwin)
|
|
264
|
+
# System.keychain には企業配布 CA や手動追加 CA、SystemRootCertificates.keychain
|
|
265
|
+
# には Apple 配布の標準 root CA が入っている。両方をマージ。
|
|
266
|
+
# `-p` で PEM 形式、`-a` で全件出力。pemcat に近い操作。
|
|
267
|
+
{
|
|
268
|
+
security find-certificate -a -p /Library/Keychains/System.keychain 2>/dev/null || true
|
|
269
|
+
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain 2>/dev/null || true
|
|
270
|
+
} > "$out_pem"
|
|
271
|
+
;;
|
|
272
|
+
Linux)
|
|
273
|
+
# Debian/Ubuntu 系
|
|
274
|
+
if [[ -r /etc/ssl/certs/ca-certificates.crt ]]; then
|
|
275
|
+
cp /etc/ssl/certs/ca-certificates.crt "$out_pem"
|
|
276
|
+
# RHEL/CentOS/Fedora 系
|
|
277
|
+
elif [[ -r /etc/pki/tls/certs/ca-bundle.crt ]]; then
|
|
278
|
+
cp /etc/pki/tls/certs/ca-bundle.crt "$out_pem"
|
|
279
|
+
# SUSE 系
|
|
280
|
+
elif [[ -r /var/lib/ca-certificates/ca-bundle.pem ]]; then
|
|
281
|
+
cp /var/lib/ca-certificates/ca-bundle.pem "$out_pem"
|
|
282
|
+
else
|
|
283
|
+
return 1
|
|
284
|
+
fi
|
|
285
|
+
;;
|
|
286
|
+
*)
|
|
287
|
+
return 1
|
|
288
|
+
;;
|
|
289
|
+
esac
|
|
290
|
+
if [[ ! -s "$out_pem" ]]; then
|
|
291
|
+
rm -f "$out_pem"
|
|
292
|
+
return 1
|
|
293
|
+
fi
|
|
294
|
+
echo "$out_pem"
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# シェル profile に `export NODE_EXTRA_CA_CERTS=...` を追記する。
|
|
298
|
+
# 既に同じパス指定の export 行があればスキップ (idempotent)。
|
|
299
|
+
_persist_node_extra_ca_certs() {
|
|
300
|
+
local ca_path="$1"
|
|
301
|
+
local snippet="export NODE_EXTRA_CA_CERTS=\"$ca_path\""
|
|
302
|
+
local marker="# >>> hub-agent: NODE_EXTRA_CA_CERTS (TLS fallback) >>>"
|
|
303
|
+
local end_marker="# <<< hub-agent: NODE_EXTRA_CA_CERTS <<<"
|
|
304
|
+
local target
|
|
305
|
+
for target in "$HOME/.zprofile" "$HOME/.bash_profile"; do
|
|
306
|
+
[[ -e "$target" ]] || touch "$target"
|
|
307
|
+
if grep -Fq "$snippet" "$target" 2>/dev/null; then
|
|
308
|
+
continue
|
|
309
|
+
fi
|
|
310
|
+
{
|
|
311
|
+
printf '\n%s\n' "$marker"
|
|
312
|
+
printf '%s\n' "$snippet"
|
|
313
|
+
printf '%s\n' "$end_marker"
|
|
314
|
+
} >> "$target"
|
|
315
|
+
color_ok "$target に NODE_EXTRA_CA_CERTS を追記"
|
|
316
|
+
done
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# 「UNABLE_TO_GET_ISSUER_CERT_LOCALLY が出た時に何を確認すべきか」のガイド表示。
|
|
320
|
+
# フォールバックも効かなかった最終手段ケース用。
|
|
321
|
+
_print_tls_failure_guidance() {
|
|
322
|
+
# ヘッダーだけ printf で色付け。本文は cat <<EOF で複数行を読みやすく出す。
|
|
323
|
+
printf '\n\033[1;31m✗ node の TLS 検証が修復できませんでした。\033[0m\n'
|
|
324
|
+
cat <<EOF
|
|
325
|
+
|
|
326
|
+
curl は通るのに node だけ落ちる場合、お使いの Mac/PC に
|
|
327
|
+
HTTPS 通信を検査しているソフトが入っている可能性が高いです。
|
|
328
|
+
典型例:
|
|
329
|
+
- ウィルス対策ソフト (Sophos / Norton / Trend Micro / Symantec 等)
|
|
330
|
+
- 親会社配布のセキュリティアプリ
|
|
331
|
+
- SSL インスペクション機能つきの VPN クライアント
|
|
332
|
+
- 広告ブロッカー (NextDNS / 1.1.1.1 for Families / AdGuard 等)
|
|
333
|
+
|
|
334
|
+
以下のコマンドで「実際の証明書発行者」が見えます。
|
|
335
|
+
ここに表示される \`issuer\` が \`Let's Encrypt\` や \`DigiCert\` ではなく、
|
|
336
|
+
特定のソフト名 (ZScaler / Cocorograph / 製品名 等) なら、それが原因です:
|
|
337
|
+
|
|
338
|
+
node -e 'const t=require("tls");const s=t.connect(443,"registry.npmjs.org",{servername:"registry.npmjs.org",rejectUnauthorized:false},()=>{let c=s.getPeerCertificate(true);while(c&&Object.keys(c).length){console.log("issuer:",JSON.stringify(c.issuer));if(!c.issuerCertificate||c.issuerCertificate===c)break;c=c.issuerCertificate;}s.end();});'
|
|
339
|
+
|
|
340
|
+
暫定的に install を進めたい場合(自分の環境を信頼している前提):
|
|
341
|
+
|
|
342
|
+
npm install -g $PACKAGE_NAME --strict-ssl=false
|
|
343
|
+
npm install -g $CLAUDE_CODE_PACKAGE --strict-ssl=false
|
|
344
|
+
hub-agent enroll <token> --hub-url <hub-url>
|
|
345
|
+
hub-agent install-service
|
|
346
|
+
|
|
347
|
+
詳細サポートは Hub の cockpit チャネルへ。
|
|
348
|
+
|
|
349
|
+
EOF
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# pre-flight TLS 検査 + 自動 fallback の本体。
|
|
353
|
+
# main() から ensure_npm_user_prefix の直後で呼ぶ想定。
|
|
354
|
+
ensure_node_tls_works() {
|
|
355
|
+
# Linux の中には node を持たない経路 (本スクリプトより前に node が入る) もあるので
|
|
356
|
+
# node が無ければスキップ (後段の ensure_global_install で別エラーになる)。
|
|
357
|
+
present node || return 0
|
|
358
|
+
|
|
359
|
+
color_step "node の TLS 検証を pre-flight check"
|
|
360
|
+
|
|
361
|
+
# ステップ 0: brew link 直後はシェル command hash に古い node/npm パスが残る
|
|
362
|
+
# ことがあるので、念のためクリアしてから検査する。
|
|
363
|
+
hash -r 2>/dev/null || true
|
|
364
|
+
|
|
365
|
+
if _test_node_tls >/dev/null 2>&1; then
|
|
366
|
+
color_ok "node TLS 検証 OK (registry.npmjs.org に到達可能)"
|
|
367
|
+
return 0
|
|
368
|
+
fi
|
|
369
|
+
|
|
370
|
+
color_warn "node TLS 検証失敗 → OS 信頼ストアから CA をエクスポートして再試行"
|
|
371
|
+
|
|
372
|
+
local ca_pem
|
|
373
|
+
if ! ca_pem=$(_export_os_ca_bundle); then
|
|
374
|
+
color_err "OS の信頼ストア (macOS Keychain / Linux ca-certificates) からの CA エクスポートに失敗"
|
|
375
|
+
_print_tls_failure_guidance
|
|
376
|
+
exit 1
|
|
377
|
+
fi
|
|
378
|
+
color_ok "$ca_pem に OS 信頼ストアの CA を書き出し ($(wc -l < "$ca_pem" | tr -d ' ') 行)"
|
|
379
|
+
|
|
380
|
+
export NODE_EXTRA_CA_CERTS="$ca_pem"
|
|
381
|
+
_persist_node_extra_ca_certs "$ca_pem"
|
|
382
|
+
|
|
383
|
+
# 再テスト
|
|
384
|
+
if _test_node_tls >/dev/null 2>&1; then
|
|
385
|
+
color_ok "node TLS 検証 OK (NODE_EXTRA_CA_CERTS=$ca_pem 経由)"
|
|
386
|
+
return 0
|
|
387
|
+
fi
|
|
388
|
+
|
|
389
|
+
color_err "OS 信頼ストアを渡しても node TLS 検証が通りません"
|
|
390
|
+
_print_tls_failure_guidance
|
|
391
|
+
exit 1
|
|
392
|
+
}
|
|
393
|
+
|
|
217
394
|
ensure_pkg() {
|
|
218
395
|
local cmd="$1"
|
|
219
396
|
local brew_pkg="$2"
|
|
@@ -371,6 +548,11 @@ main() {
|
|
|
371
548
|
ensure_pkg tmux tmux tmux
|
|
372
549
|
ensure_node_version
|
|
373
550
|
ensure_npm_user_prefix
|
|
551
|
+
# ensure_node_version 直後だと brew link でシェルの command hash がズレている
|
|
552
|
+
# 場合があるため、prefix 設定後にまとめて TLS pre-flight check + 自動 fallback
|
|
553
|
+
# を行う。失敗時はガイダンス付きで exit するので、後段の npm install で TLS
|
|
554
|
+
# エラーを再度浴びる経路はカットされる。
|
|
555
|
+
ensure_node_tls_works
|
|
374
556
|
ensure_global_install
|
|
375
557
|
ensure_claude_code
|
|
376
558
|
do_enroll
|
package/src/service-install.mjs
CHANGED
|
@@ -41,11 +41,43 @@ async function readTemplate(name) {
|
|
|
41
41
|
return fs.readFile(p, "utf-8")
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
function escapeXmlText(s) {
|
|
45
|
+
// plist の <string> 中身を埋めるための最小エスケープ。
|
|
46
|
+
// パスに XML 特殊文字が入っているケースは現実にはほぼ無いが、念のため。
|
|
47
|
+
return String(s)
|
|
48
|
+
.replaceAll("&", "&")
|
|
49
|
+
.replaceAll("<", "<")
|
|
50
|
+
.replaceAll(">", ">")
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
function expandTemplate(text, hubAgentBin) {
|
|
54
|
+
// hub-agent デーモンの runtime 環境に必須な追加 env を、各プラットフォームの
|
|
55
|
+
// 起動ファイル形式 (plist / systemd) に合わせて差し込むためのプレースホルダ展開。
|
|
56
|
+
//
|
|
57
|
+
// NODE_EXTRA_CA_CERTS: install.sh の TLS pre-flight で OS Keychain → PEM
|
|
58
|
+
// エクスポート経由で設定された場合 (e.g. MITM 環境)、シェル profile の export
|
|
59
|
+
// だけだと launchd / systemd には届かない。install-service 実行時の env に
|
|
60
|
+
// 残っている値を plist/unit に永続化する。未 set なら関連行を空に置換するので
|
|
61
|
+
// 通常環境への副作用はゼロ。
|
|
62
|
+
const nodeExtraCa = process.env.NODE_EXTRA_CA_CERTS || ""
|
|
63
|
+
let plistEntry = ""
|
|
64
|
+
let systemdLine = ""
|
|
65
|
+
if (nodeExtraCa) {
|
|
66
|
+
// plist 側: EnvironmentVariables dict の inside に <key>...</key><string>...</string>
|
|
67
|
+
// 2 行を追加 (インデント 4 スペースは既存 PATH/HOME と揃える)。末尾に \n を付けて
|
|
68
|
+
// テンプレートの "__...__\n" を綺麗に消費する。
|
|
69
|
+
plistEntry =
|
|
70
|
+
` <key>NODE_EXTRA_CA_CERTS</key>\n` +
|
|
71
|
+
` <string>${escapeXmlText(nodeExtraCa)}</string>\n`
|
|
72
|
+
// systemd 側: Environment=KEY=VALUE の 1 行。末尾 \n でテンプレ "__...__\n" を吸収。
|
|
73
|
+
systemdLine = `Environment=NODE_EXTRA_CA_CERTS=${nodeExtraCa}\n`
|
|
74
|
+
}
|
|
45
75
|
return text
|
|
46
76
|
.replaceAll("__HUB_AGENT_BIN__", hubAgentBin)
|
|
47
77
|
.replaceAll("__HOME__", os.homedir())
|
|
48
78
|
.replaceAll("__PATH__", process.env.PATH || "/usr/local/bin:/usr/bin:/bin")
|
|
79
|
+
.replaceAll("__NODE_EXTRA_CA_CERTS_PLIST_ENTRY__", plistEntry)
|
|
80
|
+
.replaceAll("__NODE_EXTRA_CA_CERTS_SYSTEMD_LINE__", systemdLine)
|
|
49
81
|
}
|
|
50
82
|
|
|
51
83
|
async function ensureDir(p) {
|
|
@@ -31,13 +31,21 @@
|
|
|
31
31
|
<key>WorkingDirectory</key>
|
|
32
32
|
<string>__HOME__</string>
|
|
33
33
|
|
|
34
|
+
<!--
|
|
35
|
+
EnvironmentVariables は launchd 起動時の env を完全に置き換える (ログイン
|
|
36
|
+
シェルや .zprofile の export を継承しない)。シェル profile に export した
|
|
37
|
+
cert 系 env 等を agent デーモンに届けるには plist に明示する必要がある。
|
|
38
|
+
下の placeholder 行は install-service 実行時に expandTemplate() が「env が
|
|
39
|
+
set されていれば NODE_EXTRA_CA_CERTS entry に、未 set なら空文字列に」展開する。
|
|
40
|
+
未 set 時は当該行ごと消えるので、通常環境への副作用はゼロ。
|
|
41
|
+
-->
|
|
34
42
|
<key>EnvironmentVariables</key>
|
|
35
43
|
<dict>
|
|
36
44
|
<key>PATH</key>
|
|
37
45
|
<string>__PATH__</string>
|
|
38
46
|
<key>HOME</key>
|
|
39
47
|
<string>__HOME__</string>
|
|
40
|
-
</dict>
|
|
48
|
+
__NODE_EXTRA_CA_CERTS_PLIST_ENTRY__ </dict>
|
|
41
49
|
|
|
42
50
|
<!-- KeepAlive で過剰再起動した時に 10 秒スロットルする -->
|
|
43
51
|
<key>ThrottleInterval</key>
|
|
@@ -5,9 +5,14 @@ Wants=network-online.target
|
|
|
5
5
|
|
|
6
6
|
[Service]
|
|
7
7
|
Type=simple
|
|
8
|
+
# Environment は systemd ユニット起動時の env を明示指定する (ログインシェルや
|
|
9
|
+
# .bashrc / .profile の export を継承しないため、agent デーモンに必要な env は
|
|
10
|
+
# ここに書く必要がある)。下の placeholder 行は install-service 実行時に
|
|
11
|
+
# expandTemplate() が「env が set されていれば Environment=NODE_EXTRA_CA_CERTS=...
|
|
12
|
+
# 行に、未 set なら空文字列に」展開する。
|
|
8
13
|
Environment=PATH=__PATH__
|
|
9
14
|
Environment=HOME=__HOME__
|
|
10
|
-
|
|
15
|
+
__NODE_EXTRA_CA_CERTS_SYSTEMD_LINE__WorkingDirectory=__HOME__
|
|
11
16
|
ExecStart=__HUB_AGENT_BIN__ start
|
|
12
17
|
Restart=always
|
|
13
18
|
RestartSec=10
|