Files
claude-code/CLAUDE.md
T
claude 6514747b4e
Helm Chart Release / release-chart (push) Failing after 9s
Build Session Image / build-push (push) Successful in 2m9s
feat: リポジトリ URL バリデーションを緩和しエラー文言を具体化 (v2.1.263-e)
claude@host:path のような SSH ユーザー違いの URL が「形式が不正」で弾かれ
原因が分かりにくかった。Gitea/GitHub の SSH ユーザーは常に git。

- REPO_RE を ssh://<user>@host/… / <user>@host:path / host:path も受理するよう緩和
  (// 始まりは拒否、ホスト allowlist は全形式に適用)
- URL 形式エラーで受理形式と「SSH ユーザーは常に git」を明記、
  ホスト不許可で許可済み一覧を併記
- UI のリポジトリ URL 入力欄にヒントを追加、README に URL 形式表を追加
2026-09-09 11:41:41 +09:00

166 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md — claude-code Helm Chart
> **共通ルール(要約)** — 詳細は `P:\Claude\CLAUDE.md`(全体共通)と `P:\Claude\HelmChart\CLAUDE.md`(Helm チャート共通: リリースフロー・ワークフロー・Gitea Secrets)を参照。
> 作業前に pull / 機能変更時は README 更新 / 作業単位ごとに commit → push まで / コミットに AI クレジットを付けない / pull で入った変更を revert しない / Helm はローカル実行不可(Python のみ可)。
## リポジトリ概要
Alpine Linux ベースの軽量コンテナで **Claude Code をリモート実行** するための Helm チャート。
ブラウザ(PC / スマートフォン)からアクセスし、**セッションごとに独立した使い捨て Pod** で
Git リポジトリ(GitHub / Gitea など互換 Git 全般)をチェックアウト・編集・検証・プッシュする。
一定時間アイドルなセッション Pod は自動破棄される。Raspberry Pi などの ARM ベアメタル運用を想定。
- **Gitea リポジトリ**: `ssh://git@192.168.9.65/helmchart/claude-code`
- **Helm リポジトリ**: `https://git.cafepieters.com/api/packages/helmchart/helm`
- **セッションイメージ**: `git.cafepieters.com/helmchart/claude-code/session:<appVersion>`(CI で publish)
> **注意**: セッション Pod は Gitea からリポジトリ単体を clone するため、`P:\Claude` の上位階層 CLAUDE.md は届かない。各リポジトリの CLAUDE.md 先頭に「共通ルール(要約)」を置く理由はこれ。
## アーキテクチャ(要点)
| コンポーネント | 実体 | 役割 |
|---|---|---|
| `gateway` | `nginxinc/nginx-unprivileged:alpine` | 単一入口。認証(token/basic/forward)、WebSocket リバースプロキシ、アクティビティ計測 |
| `manager` | `python:3.x-alpine`(標準ライブラリのみ) | セッション CRUD API、Web UI、アイドル/寿命回収ループ。in-cluster SA で K8s API を直接操作 |
| `session` | Alpine + node + git + ttyd + claude-code | セッションごとに作られる使い捨て Pod。`git clone` → `claude`(ttyd) → `claude-verify`/`claude-push` |
| `reaper` CronJob | `manager` イメージ `--reap-once` | manager 障害時の保険となる孤児掃除 |
- 制御プレーンはリリース NS、セッション Pod は専用 NS(`sessionsNamespace.name`)に分離。
- manager の RBAC はセッション NS の `pods` / `services` に限定した Role のみ(ClusterRole 不使用)。
- セッション Pod は **API サーバー到達不可**(`automountServiceAccountToken: false`)、
非 root / `readOnlyRootFilesystem` / drop ALL caps / seccomp RuntimeDefault、
egress は DNS + git ホスト + `api.anthropic.com` のみ(NetworkPolicy)。
- ファイル実体は `files/`(`.Files.Get` で ConfigMap 化): `manager.py` / `session-entrypoint.sh`
/ `gateway.conf.template` / `gateway-entrypoint.sh` / `Dockerfile.session`。
## README 更新時の追加事項
- values の新設キー、挙動変更、セキュリティ影響は README の該当セクションと values リファレンス表へ反映する。
- 手動リリース(`-a` 等)時は対応する `CHANGELOG-<version>.md` を追加し、README の「バージョン履歴」にも 1 行追加する(このリポジトリの慣行)。
## リリースフロー(組織ルールとの差分)
- **バージョン番号**: `Chart.yaml` の `version` / `appVersion` は
**主アプリ = Claude Code CLI(`@anthropic-ai/claude-code` の npm 最新版)と同一**にする。
- **ワークフロー(3 本)**
- `helm-release.yaml` — `main` への push で発火。`helm lint` の後、`Chart.yaml` の version が
未リリース(Gitea リリース・Package Registry 双方に存在しない)なら タグ + Gitea リリース +
チャート publish。リリース済みなら lint のみで終了(再 publish しない)。
- `image-update-and-release.yaml` — 毎週月曜 3:00 JST。npm の Claude Code 最新版と
base image(nginx / python)の最新 Alpine タグを確認。Claude Code 更新時は
`values.yaml` / `Chart.yaml` / README 履歴を更新しコミット → タグ + リリース + publish。
base image のみ更新時は `values.yaml` を更新してコミットのみ(**リリースなし**)。
- `session-image.yaml` — `files/Dockerfile.session` 等の変更、または上記による `Chart.yaml`
更新で発火。セッションイメージを `linux/amd64,linux/arm64` でビルドして
Gitea Container Registry(`helmchart/claude-code/session:<appVersion>` + `latest`)へ push。
- **手動リリース(臨時)**: 例 `2.1.259` → `2.1.259-a` → `2.1.259-b`。
## 改修履歴
### リポジトリ URL バリデーション緩和 + エラーメッセージ具体化(2026-09-09, v2.1.263-e)
**症状**: `claude@192.168.9.65:...`(SSH ユーザーをアカウント名にした URL)が
`リポジトリ URL の形式が不正です` で弾かれ、原因が分かりにくい。Gitea/GitHub の SSH
ユーザーは常に `git`。
**修正内容**: `manager.py` の `REPO_RE` を `ssh://<user>@host/…` / `<user>@host:path` /
`host:path` も受理するよう緩和(`//` 始まりは拒否、ホスト allowlist は全形式に適用)。
URL 形式エラーで受理形式と「SSH ユーザーは常に `git`」を明記、ホスト不許可で許可済み
一覧を併記。UI 入力欄にヒント追加。README の git セクションに URL 形式表を追加。
**対象ファイル**: `files/manager.py`, `README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-e.md`
### 失敗セッションの調査性改善(終了 Pod の保持 + ログ API + UI)(2026-09-08, v2.1.263-d)
**症状**: セッション Pod がブート失敗で `Failed` になると reaper が即削除し、`kubectl logs` で
死因を追えない。UI では「開く」で 502 になるだけ。
**修正内容**:
- `session.reaper.terminatedRetentionSeconds`(既定 900)を追加。終了済み Pod を
`finishedAt` からこの秒数は残す。`manager.py` の `reap_once` と reaper CronJob の両方が尊重。
- `GET /api/sessions/<id>/log`(`k8s_text` で pods/log を text 取得。追加 RBAC 不要)。
- UI: 「ログ」ボタン、状態の色分け、`Failed` 行に reason/exitCode/message 併記、
`Running` 以外は「開く」非表示。
- `session-entrypoint.sh`: URL スキームと identity 型の不一致を警告。`git clone` を
`--progress ... 2>&1` にして git/ssh 出力を Pod ログへ。
**対象ファイル**: `files/manager.py`, `files/session-entrypoint.sh`, `values.yaml`,
`values.schema.json`, `templates/deployment.yaml`, `templates/cronjob-reaper.yaml`,
`README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-d.md`
### gateway nginx クラッシュループ修正(location 正規表現のクォート)(2026-09-08, v2.1.263-c)
**症状**: gateway コンテナが起動直後に
`nginx: [emerg] pcre2_compile() failed: missing closing parenthesis in "^/s/(?<sid>[a-f0-9]"`
で終了し、CrashLoopBackOff。
**原因**: `files/gateway.conf.template` の
`location ~ ^/s/(?<sid>[a-f0-9]{10})(?<rest>/.*)?$ { ... }` で、正規表現中の `{10}` の
`{` `}` を nginx の設定パーサーがブロック区切りと解釈し、`location` の regex が
`^/s/(?<sid>[a-f0-9]` で切れていた(nginx は `{` `}` `;` を含む正規表現のクォートを必須とする)。
**修正内容**: `location ~ "^/s/(?<sid>[a-f0-9]{10})(?<rest>/.*)?$" { ... }` と
正規表現全体をダブルクォートで囲んだ。envsubst の対象は `${...}` の 6 変数のみで
`{10}` には影響しないことを確認済み。
**対象ファイル**: `files/gateway.conf.template`, `README.md`, `Chart.yaml`, `CHANGELOG-2.1.263-c.md`
### 認証情報の credentials モード + トークン自動リフレッシュ(2026-09-08, v2.1.263-b)
**背景**: サブスクリプションのアクセストークンは定期的に失効・ローテーションする。単発
トークン注入では失効のたびに `helm upgrade` が必要だった。
**症状**: あわせて、一部の Helm バージョンで `values.schema.json` の
`$schema: https://json-schema.org/draft-07/schema#` が
`no schema with key or ref ...` エラーになる不具合。
**修正内容**:
- `anthropic.authMode: credentials`(新既定): `~/.claude/.credentials.json` 全体を Secret に
格納 →(a)セッション Pod にファイルとしてマウントし `$HOME/.claude` へコピー、セッション内
`claude` が `refreshToken` で自己更新。(b)`anthropic.refresher` CronJob
(`files/token-refresher.py`、専用 SA + `resourceNames` 限定 Role で該当 Secret の get/patch のみ)
がクラスタ内で `accessToken` を定期更新し Secret を書き戻す。`tokenUrl` / `clientId` は
Claude Code CLI の非公式値で values 上書き可。
- `manager.py` の `build_pod`: credentials モードは `envFrom` を使わずファイルマウント +
`SEED_CREDENTIALS_FILE` env。apiKey/oauth は従来どおり `envFrom`。
- Secret に `helm.sh/resource-policy: keep`(credentials 時)。
- `values.schema.json` の `$schema` 行を削除(他チャートと同じ。Helm は draft-07 で検証)。
**対象ファイル**: `values.yaml`, `values.schema.json`, `templates/secret-anthropic.yaml`,
`templates/deployment.yaml`, `templates/configmap-manager.yaml`, `templates/token-refresher.yaml`(新規),
`templates/NOTES.txt`, `files/manager.py`, `files/session-entrypoint.sh`,
`files/token-refresher.py`(新規), `examples/loadbalancer-oauth.values.yaml`, `README.md`,
`Chart.yaml`, `CHANGELOG-2.1.263-b.md`
### Service の LoadBalancer 対応 + サブスクリプション認証手順の明文化(2026-09-08, v2.1.263-a)
**背景**: Ingress を張らずに、ローカルネットワークの LB(kube-vip 等)から払い出した IP で
管理画面へアクセスしたい、という運用要望。あわせて「Claude の API 課金を使わず、ローカルの
Claude Code と同様にサブスクリプションで使いたい」という確認があった。
**修正内容**:
- `templates/service.yaml` を書き換え、`service.type: LoadBalancer` を既定化。
`service.annotations`(kube-vip の `kube-vip.io/loadbalancerIPs` / `vipHost` 等)、
`loadBalancerIP` / `loadBalancerClass` / `loadBalancerSourceRanges` /
`externalTrafficPolicy` / `nodePort` / `labels` を追加。Ingress 機能は変更なし(併用可)。
- `values.yaml` の `service:` ブロック拡張、`values.schema.json` に対応プロパティ追加。
- `templates/NOTES.txt` に LoadBalancer の EXTERNAL-IP 案内を追加。
- `examples/loadbalancer-oauth.values.yaml` を追加(Ingress 無効 + LB + source range +
`authMode: oauth`)。
- README に「Claude 認証(API 課金なし / サブスクリプション)」「管理画面へのアクセス
(LoadBalancer / Ingress)」セクションを追加。サブスクリプション認証は
`claude setup-token` → `anthropic.authMode: oauth`(`CLAUDE_CODE_OAUTH_TOKEN` を
セッション Pod に注入)で、ローカル実行の Claude Code と同一挙動。
**対象ファイル**: `templates/service.yaml`, `values.yaml`, `values.schema.json`,
`templates/NOTES.txt`, `examples/loadbalancer-oauth.values.yaml`, `README.md`, `Chart.yaml`,
`CHANGELOG-2.1.263-a.md`
### 初版(2026-09-03, v2.1.259)
チャート新規作成。gateway + manager + 使い捨て session Pod + reaper CronJob の構成で、
ブラウザからの Claude Code リモート実行、GitHub/Gitea 両対応、アイドル自動破棄、
NetworkPolicy / RBAC 最小化 / restricted PodSecurity を実装。
**対象ファイル**: 全ファイル(初期コミット)