Skip to content

✨ org-accounts-auth-context: スイッチ式認証 (X-Organization-Id ヘッダで組織コンテキスト操作) - #58

Merged
turtton merged 2 commits into
mainfrom
org-accounts-auth-context
Sep 2, 2026
Merged

turtton merged 2 commits into
mainfrom
org-accounts-auth-context

Conversation

@turtton

@turtton turtton commented Sep 2, 2026

Copy link
Copy Markdown
Member

org-accounts-auth-context: スイッチ式認証

認証済み個人がログインしたまま、リクエストヘッダ X-Organization-Id で
組織コンテキストを指定して操作できるようにする (issue #57)。

実装内容

  • コンテキスト解決: 認証後 middleware (server/src/api/organization_context.rs) が
    X-Organization-Id (org nanoid) を解決 — org 存在確認 (404) →
    要求者の個人 AccountId で organization_members の active membership 検証 (403) →
    OrganizationContext { org_account_id, role } を request extension に格納
  • 後方互換: ヘッダなしは None が格納され、既存の個人経路に一切の挙動変化なし
  • SessionContext 拡張: org_context: Option<OrganizationContext> を追加し、
    GET /api/v1/me/session-context で返却
  • Profile 作成: POST /api/v1/profiles を新設。組織コンテキストでは
    org AccountId を所有者として作成。1 org : 1 Profile 制約維持 (2件目は 422)
  • Profile 更新: PATCH /api/v1/accounts/{account_id} は
    個人経路では従来どおり Keto account_edit、組織コンテキストでは
    解決済み org AccountId と対象 AccountId の一致で認可
    (Member 以上の membership は middleware で検証済み)
  • メンバー管理 API: foundation の Owner/Admin ロール判定をそのまま維持
  • CORS / OpenAPI: x-organization-id を許可ヘッダに追加し、
    対象操作に header contract を記載。openapi.json 再生成

検証

  • cargo fmt --check / cargo check --workspace / cargo clippy --workspace -- -D warnings: 緑
  • cargo test --workspace: 446 passed, 0 failed (実 PostgreSQL + 実 Axum router)
  • 追加テスト: コンテキスト未指定 (個人据え置き) / 所属 org / 非所属 (403) /
    非存在 org (404) / org Profile 作成 (org AccountId 所有) / 2件目拒否 (422) /
    org コンテキストでの Profile 更新許可

Closes #57

…解決 + SessionContext 拡張 + 組織 Profile 操作

- 認証後 middleware で X-Organization-Id を組織コンテキストに解決
  (org 存在確認 404 → メンバーシップ検証 403 → org AccountId + OrgRole)
- SessionContext に org_context を追加し GET /api/v1/me/session-context で返却
- POST /api/v1/profiles を追加し組織コンテキスト主体で Profile 作成
  (1 org : 1 Profile 制約維持、2件目は 422)
- PATCH /api/v1/accounts/{id} は個人経路 Keto account_edit 据え置き、
  組織コンテキストでは org AccountId 一致で認可 (Member 以上は検証済み)
- CORS / utoipa に X-Organization-Id を反映、openapi.json 再生成
- コンテキスト未指定は既存挙動のまま (後方互換)
@turtton turtton added the intent-target intent-cli workflow label label Sep 2, 2026
@codecov

codecov Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 91.81495% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.95%. Comparing base (d01d424) to head (9c935d1).

Files with missing lines Patch % Lines
server/src/main.rs 0.00% 7 Missing ⚠️
server/src/route/account/client.rs 75.00% 5 Missing ⚠️
server/src/route/me.rs 86.48% 5 Missing ⚠️
application/src/service/profile.rs 92.45% 4 Missing ⚠️
application/src/permission.rs 80.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #58      +/-   ##
==========================================
+ Coverage   75.64%   75.95%   +0.31%     
==========================================
  Files         209      211       +2     
  Lines       24496    24601     +105     
==========================================
+ Hits        18529    18686     +157     
+ Misses       5967     5915      -52     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@turtton

turtton commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

Review: request-update (org-accounts-auth-context)

packet (.intent-cli/issues/org-accounts-auth-context/) の acceptance criteria は全て実装・テスト済みで、後方互換・既存 surface への影響なしを確認しました。ただし 1 件、修正必須の contract finding があります。

[Blocker] 新 API surface が内部 BIGINT id を nanoid として露出している (ADR 0007 §4 違反)

foundation (PR #56) で確定した API 契約 —「org / account_id / invited_by 等の外部表現は全て nanoid 経由で、内部 BIGINT id は API surface に露出しない」(ADR 0007 §4、「アクセス制御・表現の確定細部」) に対し、本 PR の新規レスポンス 2 箇所が内部 id の文字列を返しています:

  1. server/src/route/me.rs get_session_context —
    org_account_id: AsRef::<i64>::as_ref(&context.org_account_id).to_string()
    により OrganizationContextResponse.org_account_id が内部 BIGINT id になります。
    X-Organization-Id ヘッダは nanoid 前提 (resolve_organization_context → find_by_nanoid) なので、
    response で返した値を次回リクエストにそのまま使うと 404 になり、round-trip が成立しません。

  2. application/src/service/profile.rs create_organization_profile —
    let account_nanoid = AsRef::<i64>::as_ref(profile.account_id()).to_string();
    により ProfileDto.account_nanoid (名前は nanoid) に内部 BIGINT id が格納され、
    ProfileResponse.account_id としてそのまま露出します。Dto フィールド名と中身の不整合は
    将来の consumer (AP actor URL 構築等、nanoid 前提の経路) でのバグの温床になります。

期待する修復:

  • resolve_organization_context (server/src/api/mod.rs) は org の Account projection を既に握っているので、OrganizationContext { org_account_id, org_account_nanoid, role } に nanoid を載せるのが最小の拡張です。
  • get_session_context の response と create_organization_profile の ProfileDto::new 呼び出しで nanoid を返す。
  • テスト更新:
    • client_tests.rs::get_session_context_with_member_header_returns_organization_context の assertion を fixture.organization.nanoid().as_ref() 比較に更新 (現状は内部 id でロックインされている)。
    • create_profile_with_organization_context_uses_organization_account_id に response body の account_id == org nanoid assertion を追加。

照合済みの acceptance criteria (修正は finding 部分のみで OK)

  • コンテキスト未指定は現行動作 (middleware で None 解決、legacy update_account_detail は Keto 経路不変、既存 me_tests 維持、CI 全緑) ✓
  • ヘッダ指定時: org 存在確認 (404) → Active メンバーシップ検証 (403) を middleware で解決。route テストで両 status 検証済み ✓
  • SessionContext に org_context: Option<OrganizationContext> 拡張 + GET /api/v1/me/session-context ✓
  • 組織コンテキストの Profile 更新は membership 判定 (Active member) で許可、Keto account_edit 非適用 (empty-Keto mock 下で更新 200 を検証) ✓
  • 組織 Profile 作成は org AccountId 所有、2 個目は 422 (1 org : 1 Profile 制約維持、migration 変更なし) ✓
  • メンバー管理 API は foundation の OrgRole 判定を流用 (変更なし) ✓
  • 単体/ハンドラテストで未指定・所属・非所属 (403)・非存在 (404) の 4 経路を検証 ✓
  • 既存 surface への影響なし: kernel 非変更 (find_by_auth_id 不変、caller 側で kind filter) ✓
  • scope 遵守: Out-of-scope (メンバー管理・移管・Drive・Ratcap・Keto namespace・AP 連合) に踏み込みなし ✓

@turtton turtton added the intent-pr-request-update intent-cli workflow label label Sep 2, 2026
…は組織 nanoid を返す

レビュー指摘 (ADR 0007 §4: 外部表現は nanoid、内部 BIGINT id を露出しない) 対応。
- OrganizationContext に org_account_nanoid を追加し resolve_organization_context で格納
- get_session_context と create_organization_profile の応答で nanoid を返却 (round-trip 成立)
- 対応テストを nanoid 比較に更新 + Profile 作成応答に nanoid assertion 追加
@turtton turtton added intent-pr-update-in-progress intent-cli workflow label intent-pr-rereview-ready intent-cli workflow label intent-pr-approved intent-cli workflow label and removed intent-pr-request-update intent-cli workflow label intent-pr-update-in-progress intent-cli workflow label intent-pr-rereview-ready intent-cli workflow label labels Sep 2, 2026

@turtton turtton left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve (rereview) — semantic review verdict

前ラウンド request-update (#issuecomment-5512883839: 内部 BIGINT id / nanoid 露出, ADR 0007 §4 違反) への repair を検証。

改善確認

  1. OrganizationContextResponse.org_account_id / ProfileResponse.account_id が org nanoid を返す — OrganizationContext.org_account_nanoid を新設し resolve_organization_context で organization.nanoid() から設定、me.rs / profile.rs の応答がこれを利用。
  2. X-Organization-Id round-trip 成立 — 解決入口 (find_by_nanoid(header)) と応答の nanoid が同一値のため、応答の org_account_id を次リクエストのヘッダにそのまま投入可能。
  3. テストが nanoid 比較に更新 — client_tests.rs の session-context assertion と create_profile_with_organization_context_uses_organization_account_id が fixture.organization.nanoid() 比較。
  4. 前回照合済み AC 1-8 に回帰なし — repair 差分は指摘範囲の 5 ファイルに限定 (session_context.rs / api/mod.rs / me.rs / profile.rs / client_tests.rs)、CI 全 12 件 green。

ADR 0007 §4 (全て nanoid 経由・内部 id 非露出) に整合。残課題なし。closeout へ進む。

@turtton
turtton merged commit c33fe53 into main Sep 2, 2026
12 checks passed
@turtton
turtton deleted the org-accounts-auth-context branch September 2, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

intent-pr-approved intent-cli workflow label intent-target intent-cli workflow label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

org-accounts-auth-context: スイッチ式認証 — 個人 identity のまま組織コンテキストを指定して操作

1 participant