Skip to content

MEDIUM-tier OAuth: verified-owner elevation + claim-by-name (VPS / sos_mcp_sse) - #189

Open
servathadi wants to merge 2 commits into
mainfrom
feat/medium-oauth-verified-owner
Open

MEDIUM-tier OAuth: verified-owner elevation + claim-by-name (VPS / sos_mcp_sse)#189
servathadi wants to merge 2 commits into
mainfrom
feat/medium-oauth-verified-owner

Conversation

@servathadi

Copy link
Copy Markdown
Collaborator

SENSITIVE AUTH — REPORT-ONLY. Built in an ISOLATED worktree; the live
/home/mumega/sos-public-kernel file is UNTOUCHED, no service restart. Gate before flip.

VPS-Python half of the MEDIUM-tier identity model (spec §2.3–2.4). Pairs with
Mumega-com/mumega-com PR #222 (worker + inkwell-api half).

What this does

  • §2.3 _elevate_verified_owner_if_eligible — after _require_auth, re-resolve
    a worker_oauth customer via inkwell-api resolve-owner (server-side, BY SUB) and
    elevate IN-PLACE to scope="tenant"/role=highest when sub_matched + owner/
    editor membership. Unknown/unverified/low-role/error → customer wall UNCHANGED
    (fail-closed). Wired into both /mcp (Streamable HTTP) and /sse transports.
    list_projects/sign_in prefer cached owner_memberships (OAuth
    /connections/lookup misses — token is internal-hash). Gated behind
    SOS_SECURITY_MODE (default medium; low disables elevation entirely).
  • §2.4 _handle_claim (claim tool) — RLS-FIRST via _peer_tenant_meta + HMAC
    tenant-slug compare; qNFT read ONLY after RLS passes (closes BLOCK-3 — qNFT
    presence is never an authz input). Novel name that passes RLS but has no qNFT →
    qnft_required River-gate; physically NO mint call. Owner-only (single-sourced
    with as_agent, WARN-B); customer/tenant-agent forbidden.

Tests

12 unit tests (elevation gate + claim ordering) re-verifying all 4 closures. All pass.

Adversarial pass (kasra-review, parallel gate)

BLOCK-2/3/4 + novel-name-no-mint GREEN. WARN-C = flip gate: nginx :6070 X-
scrub + loopback bind must land + forged-header test (e) pass before live elevation.
*

🤖 Generated with Claude Code

servathadi and others added 2 commits June 11, 2026 22:15
…side)

§2.3 _elevate_verified_owner_if_eligible: after _require_auth, re-resolve a
worker_oauth customer via inkwell-api resolve-owner (server-side, by sub) and
elevate IN-PLACE to scope="tenant"/role=highest when sub_matched + owner/editor
membership. Unknown/unverified/low-role/error → customer wall UNCHANGED
(fail-closed). Wired into both /mcp Streamable HTTP and /sse transports.
list_projects/sign_in prefer cached owner_memberships (OAuth /connections/lookup
misses — token is internal-hash). Gated behind SOS_SECURITY_MODE (default medium).

§2.4 _handle_claim ("claim" tool): RLS-FIRST via _peer_tenant_meta + HMAC
tenant-slug compare, qNFT read ONLY after RLS passes (closes BLOCK-3 — qNFT
presence is never an authz input). Novel name that passes RLS but has no qNFT →
qnft_required River-gate; physically NO mint call. Owner/editor tenant scope
only; customer/tenant-agent forbidden (mirrors as_agent).

12 unit tests (elevation gate + claim ordering, all 4 closures re-verified).
REPORT-ONLY: built in an isolated worktree; the live /home/mumega/sos-public-
kernel file is UNTOUCHED, no service restart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ingle source)

_handle_claim previously admitted {owner,admin,editor} but delegates the bind to
_handle_as_agent, whose tenant-scope gate is owner-ONLY — an editor/admin session
would pass claim then be bounced by as_agent (fail-closed but drift-prone). Make
claim's tenant role gate identical (owner-only) so the two predicates can't drift
open independently; widening tenant-claim authority is now a single-point change
in _handle_as_agent. Scope elevation (§2.3) still grants tenant scope to
owner/admin/editor for general tool access — only the claim/as_agent primitive is
owner-gated (intentional layer separation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant