メインコンテンツへ

認可モデル

Astar の認可は、Discord のようなロール/権限モデルを土台にしつつ、どこでチェックするかについては 2026-07-01 に大きな再設計(primitives-only 認可)を経ています。このページは現行モデルの考え方を説明します。個々のツール・エンドポイントの認可要件の網羅表は生成ドキュメントに譲ります。

土台: ロールと権限ルール

権限の割り当て自体は Discord ライク なロールモデルです。

PermissionRule:
  resource: ResourceType (TABLE, DOCUMENT, WORKSPACE, ...)
  action: Action (VIEW, CREATE, UPDATE, DELETE, ...)
  scope: Scope (WORKSPACE, SPECIFIC_RESOURCE)
  effect: Effect (ALLOW, DENY)

DynamicRole:
  name: "プロジェクトマネージャー"
  permissions: [PermissionRule, ...]
  position: 1  # 優先順位

メンバーにロールを割り当て、ロールに権限ルールを紐付ける、という一般的な形です。AI も人間と同じ権限系に従います — AI メンバーやサービスアカウントにもロールを割り当てます。ここまでは従来通りです。

primitives-only 認可(2026-07-01)

再設計されたのは「この権限ルールをどの層でチェックするか」です。

以前は pack apply・template apply・import・export のような「機能単位の操作」ごとに、@AuthorizesInBody という compound マーカーや、node.view.all のような capability-wide ゲートで個別に認可する設計でした。施主はこれを明確に拒否しました:

「何のためのnodeなんだよ。packってなんだよ。ゴミ」— pack は node の集合にすぎない。node であるなら、他の node と同じように per-resource に認可すべき。

この一言で、機能単位の認可という概念そのものが撤去されました。

現行原理: 認可は、リソースプリミティブ(record / document / table property / dataset / tag / template / share link / screen placement / embedding など)の**唯一の gated プリミティブメソッド(membrane)**の上にのみ存在します。プリミティブより上の層(adapter・orchestrator・feature service・tool body)は認可ゲートを一切宣言しません。

プリミティブ vs オーケストレータ

種別定義ゲート
プリミティブ (membrane)単一リソース型のインスタンスを識別子で指定して生成/変更/削除/読み取りする最下層のサービスメソッド。他のプリミティブを呼ばないcanAccessResource / canAccessRecord / canAccessDataset などの @PreAuthorize を1つだけ持つ
オーケストレータ2つ以上のプリミティブ(または他のオーケストレータ)を合成する feature service / tool body認可ゲートを一切持たない(isAuthenticated() のみ)

pack_form_apply を例にすると、以前は hasPermissionRule('node.view.all') という「pack を触れる人は全nodeを読める」という all-or-nothing なゲートを1つ持っていました。これは per-folder の粒度の権限付与を無視してしまう欠陥でした。現行設計では pack_form_apply 自体はゲートを持たない thin orchestrator になり、内部で呼ぶ recordService.list(table READ プリミティブ)と storageAwareDocumentService.createDocument(node CREATE プリミティブ)がそれぞれ per-resource に認可します。読めない table があれば読み取りの時点で、書けない folder があれば作成の時点で、自動的に弾かれます。pack という認可単位そのものが存在しなくなったのがポイントです。

同じロジックが template apply・import・export・resource-set apply にも当てはまります。これらは「既存リソースを読み、node/table/record を生成するオーケストレータ」という同じ形なので、認可は各プリミティブに transitive に効きます。

読み取り (list/tree) の認可

単一リソースの読み取りは canAccessResource(id, 'NODE', 'view') のような1本の SpEL 式で表現できますが、一覧・ツリー取得は複数行を返すため単一式に収まりません。この場合はプリミティブの list メソッドが内部で AuthorizationService.filterAccessibleResourceIds を呼び、アクセス可能な id だけを返します。これは「機能特別扱いの body 認可」ではなく、list プリミティブの内在的契約として扱われます。

deny の表現: 403 と 404 の使い分け

ゲートプリミティブは deny を false で返すだけで、ResourceNotFoundException を throw しません。HTTP としての表現は handler 層で一元化されています。

  • GET(読み取り) → 404(情報秘匿。「存在するが権限が無い」と教えない)
  • 非GET(書き込み) → 403@PreAuthorize の権限判定失敗)
  • クロステナントのリソースは常に「存在しない」扱い(マルチテナンシーと RLS 参照)

AI エージェントも同じ認可を通る

MCP 経由でツールを呼ぶ AI エージェント(内製・BYO 問わず)も、REST API を叩く人間のユーザーも、CustomMethodSecurityExpressionRoot 上の同じプリミティブゲートを通ります。AI メンバーはサービスアカウント(スコープ付きトークン)として同一の権限系に乗り、ロールを割り当てられます。astar CLI も同じツール定義・同じ認可経路です。

深掘り資料

このページはモデルの「考え方」に絞っています。個々のツール・エンドポイントの認可要件を1つずつ確認したい場合は、以下の生成ドキュメントを参照してください(ハンド編集禁止・アノテーションから自動生成)。

  • docs/authorization/tool-access-catalog.md — 全 MCP ツールの capability / gate SpEL / 例外理由の一覧
  • docs/authorization/membrane-migration-ledger.md — primitives-only 移行前の調査記録(P-0 inventory)。移行の経緯を追いたいときの一次資料
  • docs/designs/2026-07-01-authorization-primitives-only.md — 本ページの元になった詳細設計。BUCKET A/B(principal の有無によるゲート回避の要否)や migration phase の全量はここにあります