mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-05-19 12:25:13 +02:00
Adds `no-auth-svc`, a lightweight IAM service that permits all access unconditionally — no database, no bootstrap, no signing keys. Deploy it in place of `iam-svc` for development, demos, and single-user setups where authentication overhead is unwanted. The gateway no longer hard-codes a 401 on missing credentials. Instead it asks the IAM regime via a new `authenticate-anonymous` operation whether token-free access is allowed. This keeps the gateway regime-agnostic: `iam-svc` rejects anonymous auth (preserving existing security), while `no-auth-svc` grants it with a configurable default user and workspace. Includes a tech spec (docs/tech-specs/no-auth-regime.md) and tests that pin the safety boundary — malformed tokens never fall through to the anonymous path, and a contract test ensures the full iam-svc always rejects `authenticate-anonymous`.
44 lines
1.2 KiB
Python
44 lines
1.2 KiB
Python
"""
|
|
Contract test: the full iam-svc MUST reject authenticate-anonymous.
|
|
|
|
This is a safety pin — if someone accidentally adds anonymous access
|
|
to the production IAM handler, this test catches it.
|
|
"""
|
|
|
|
import asyncio
|
|
from unittest.mock import Mock, AsyncMock
|
|
|
|
import pytest
|
|
|
|
from trustgraph.iam.service.iam import IamService
|
|
|
|
|
|
def _make_request(**kwargs):
|
|
req = Mock()
|
|
for k, v in kwargs.items():
|
|
setattr(req, k, v)
|
|
return req
|
|
|
|
|
|
class TestIamRejectsAnonymous:
|
|
|
|
@pytest.fixture
|
|
def handler(self):
|
|
svc = object.__new__(IamService)
|
|
svc.table_store = Mock(spec=[])
|
|
svc.bootstrap_mode = "token"
|
|
svc.bootstrap_token = "tok"
|
|
svc._on_workspace_created = None
|
|
svc._on_workspace_deleted = None
|
|
svc._signing_key = None
|
|
svc._signing_key_lock = asyncio.Lock()
|
|
return svc
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_authenticate_anonymous_returns_auth_failed(self, handler):
|
|
resp = await handler.handle(
|
|
_make_request(operation="authenticate-anonymous")
|
|
)
|
|
assert resp.error is not None
|
|
assert resp.error.type == "auth-failed"
|
|
assert "anonymous" in resp.error.message.lower()
|