# 接続と身元 (Atasira への接続) 本章は、認可された atasino メンバーの代理として Atasira BFF に接続し、その身元(RBAC)を得るまでを扱う。**PAT を持たなければ Atasira では何もできない** — 本章は他章すべての前提条件である。 - **Base URL**: `$ATASIRA_BFF_URL`。既定は本番 `https://atasira.atasino.biz`。社内からローカル BFF を使う場合は `http://localhost:18908`。 - **認証**: PAT(Personal Access Token)。HTTP ヘッダ `Authorization: Bearer atspat_...`。 ## 1. 誰が接続できるか — allowlist ゲート付き OAuth Atasira の console は **OAuth 専用**(Google / GitHub)でローカルパスワードは存在しない。ログインは次の 2 つを **両方**満たす必要がある: 1. **Workspace/org メンバーシップ** — Google の場合、ID トークンの `hd` claim が allowlist ドメイン(`ATASIRA_ALLOWED_GOOGLE_HD`、既定 `atasino.com,atasino.co.jp`)のいずれかで、かつ email 自身のドメインと一致すること。 2. **admin 管理の allowlist** — 有効な atasino.com/co.jp の身元でも、admin が事前に `users` の ACTIVE 行を作成していない email は `403 user_not_provisioned` で拒否される。本番に自己サインアップ経路は無い。 admin がメンバーを招待する(admin 専用、`require_role("admin")`): ```bash curl -sS -X POST "$ATASIRA_BFF_URL/api/v1/users/invite" \ -H "Content-Type: application/json" \ -b "atasira_access=<admin cookie>" \ -d '{"email": "[email protected]", "role": "viewer", "display_name": "Person Name"}' # -> {"id": "...", "email": "...", "role": "viewer", "status": "invited", "temporary_password": null, "message": "..."} ``` `role` は `admin` / `operator` / `viewer` のいずれか(省略時 `viewer`)。パスワードは決して発行されない(`temporary_password` は常に `null`)。本人の初回 Google/GitHub ログインで OAuth 身元がこの行に紐付く。 ## 2. RBAC — 2 層モデル Atasira の権限は **2 層**で構成される。両方が各操作の可否を決める。 ### (A) アカウント role(`User.role`、招待時に設定・admin が `PATCH /api/v1/users/{user_id}` で変更可) | role | 見える/できる範囲 | |------|-------------------| | `admin` | 全コントロールプレーン操作: ユーザー招待/一覧/更新/削除、box draft の承認/却下/pending 一覧、全 Box を **assignment 無しで** view/instruct((B) を完全バイパス)、box 制御 | | `operator` | box/task の運用(pause/resume/kill・escalation 対応)+ viewer 相当。ユーザー管理・draft 承認は**不可** | | `viewer`(既定) | 自分に見える Box 一覧の閲覧、box draft 起票(常に pending_approval)、自分の PAT 管理。特定 Box の instruct/view は (B) の assignment が無ければ**不可** | 強制は `require_role(*roles)` 依存で行われる。 ### (B) Box 個別 assignment role(`role_in_box`、`box_user_assignments`) | role_in_box | view | instruct | 他者への権限付与 | |-------------|------|----------|------------------| | `primary`(owner) | ✅ | ✅ | `secondary`/`observer` の付与・剥奪可(`primary` の付替えは admin のみ) | | `secondary` | ✅ | ✅ | 不可 | | `observer` | ✅ | 不可(読取専用) | 不可 | 強制は `require_box_access` / `check_box_access`(instruct = `primary`/`secondary`、view = 全 3 role)。**`admin` アカウント role はこの表を完全にバイパス**する。 assignment 管理は `POST` / `DELETE /api/v1/boxes/{box_id}/user-assignments`。admin または当該 Box の `primary` が呼べるが、非 admin(Box primary)が付与/剥奪できるのは `secondary`/`observer` のみ。 > **頻出の落とし穴**: draft 承認は起票者を自動 assign **しない**。承認後、admin(または Box primary)が別途 `user-assignments` を呼ばないと、viewer 起票者は自分の Box を instruct/view できない(`02-box-lifecycle.md`)。 ## 3. PAT 発行 — 「エージェントがこのユーザーとして動く」仕組み MCP クライアント(非ブラウザ)は httpOnly cookie を使えないため、メンバー本人が **PAT** を発行し、エージェントはそれで認証する。これが「エージェントを特定 atasino メンバーに紐付ける」正確な仕組みである。 ```bash curl -sS -X POST "$ATASIRA_BFF_URL/api/v1/users/me/tokens" \ -H "Content-Type: application/json" \ -b "atasira_access=<自分のログイン cookie>" \ -d '{"name": "my-mcp-client", "expires_in_days": 90}' # -> {"id": "...", "name": "...", "token": "atspat_...", "token_prefix": "...", "created_at": ..., "expires_at": ...} ``` console UI の **`/tokens`** ページ(self-service)でも作成/一覧/失効ができる(curl 不要)。 - **平文トークン(`atspat_` + 48 hex 文字)はこの作成応答でのみ返る。** DB は `SHA-256(token)` のみ保存する。再取得は不可 — 紛失時は再発行。 - 一覧(prefix のみ): `GET /api/v1/users/me/tokens` - 失効(即時・soft、以後の全認証でチェック): `DELETE /api/v1/users/me/tokens/{token_id}` - 上限: 1 ユーザー **50 個**の有効 PAT。超過は `409` — 未使用トークンを先に失効する。 ### 身元モデル: PAT は本人の権限をそのまま持ち出す(超えられない) BFF の `get_current_user()` は `atspat_` prefix を検出して PAT 認証に回し、SHA-256 hash で照合、`revoked`/期限切れなら 401、所有 `User` 行をロードして、cookie/JWT セッションと**同一形状**の dict(`id`/`username`/`role`/`display_name`/`email`/`tenant_id`)を返す。以降の全認可(`require_role` / `require_box_access`)はこの dict しか見ない。 したがって: - **PAT 駆動のエージェントは、トークンを発行した人間の account role と box assignment を、リクエスト毎にライブ評価してそのまま持つ。人間の権限を決して超えられない。** - トークン失効・role 降格・assignment 剥奪は、次のリクエストから即座に効く(キャッシュ無し)。 - PAT に「なりすまし用の別権限」は無い。admin scope を PAT に付与する経路も存在しない。 実務上の帰結: - Box draft を作らせたい → 発行ユーザーは最低 `viewer`(draft 起票に role gate は無い)。 - 特定 Box を instruct/view させたい → 発行ユーザーにその Box の assignment(または admin role)が必要。 - draft を承認・他ユーザー管理させたい → 発行ユーザーが `admin`。 ## 4. `atasira` MCP クライアントのセットアップ `atasira-mcp` は BFF HTTP API への薄い stdio ラッパー(`src/mcp_server/`, FastMCP)。ローカル LLM 推論はせず GPU/Docker 不要。`uv` + repo checkout があれば任意のマシンで動く。 **env**: | env | 意味 | 既定 | |-----|------|------| | `ATASIRA_BFF_URL` | BFF base URL | `https://atasira.atasino.biz`(ローカル: `http://localhost:18908`) | | `ATASIRA_PAT` | 発行した PAT(`atspat_...`) | (必須) | **登録コマンド**: ```bash claude mcp add atasira \ --env ATASIRA_BFF_URL=https://atasira.atasino.biz \ --env ATASIRA_PAT=atspat_xxxxxxxx \ -- uv run --directory /path/to/Atasira atasira-mcp ``` `/path/to/Atasira` は接続元マシンの Atasira repo checkout 位置に読み替える。`atspat_xxxxxxxx` は実 PAT に置き換える(ハードコードのリテラルは禁止 — §6)。 **`.mcp.json` に直接書く場合**(PAT は env 展開で参照し平文を残さない): ```json { "mcpServers": { "atasira": { "command": "uv", "args": ["run", "--directory", "/path/to/Atasira", "atasira-mcp"], "env": { "ATASIRA_BFF_URL": "https://atasira.atasino.biz", "ATASIRA_PAT": "${ATASIRA_PAT}" } } } } ``` 登録後に使える 8 ツールの詳細は `03-mcp-tools.md`。 ## 5. 疎通確認(smoke test) Claude Code 再起動後、MCP ツール `atasira_list_boxes` を呼ぶ。生 API での代替確認: ```bash curl -sS "$ATASIRA_BFF_URL/api/v1/boxes" -H "Authorization: Bearer $ATASIRA_PAT" ``` | 結果 | 意味 | |------|------| | `200` + `boxes` 配列(空でも可) | 疎通 OK | | `401` | PAT が無効/失効/typo/期限切れ → 再発行 | | 空配列(非 admin) | 正常。まだどの Box にも assignment が無いだけ(§2(B) の付与を admin に依頼) | ## 6. secret 取扱いルール(必須) - 平文 PAT(`atspat_...`)は作成応答で**一度だけ**返る。DB は SHA-256 hash のみ。再取得不可。 - **受領した瞬間に 1Password へ保存する。** `/1password-one-shot` または `/op-sa-write`(Service Account token、`env -u` scrub、ambient token 漏洩防止)のパターンを使い、平文を shell 履歴・chat・ファイルに残さない。 - 平文 PAT を repo ファイル・`.mcp.json`・commit・ログ・scrollback に**絶対に**書かない。`.mcp.json` では env 展開 `${ATASIRA_PAT}` のみを使う(§4)。 - 上限 409 到達時・不要時は `DELETE /api/v1/users/me/tokens/{token_id}` で即失効する。 - admin cookie/PAT(invite/approve/pending/cross-user assignment に必要)は個人 PAT より強力。admin タスク用の短命 PAT を都度発行し作業後に失効する運用を推奨。 - 本書中の例トークン(`atspat_xxxxxxxx` 等)はすべてプレースホルダで実在 secret ではない。