generated from coulomb/repo-seed
287 lines
10 KiB
Python
287 lines
10 KiB
Python
import unittest
|
|
|
|
from user_engine.adapters.local import InMemoryUserEngineStore, LocalAuthorizationCheckPort
|
|
from user_engine.domain import (
|
|
AccessMembershipRequirement,
|
|
AccessProfile,
|
|
AccessScopeType,
|
|
FactorVerification,
|
|
IdentityFactorType,
|
|
OnboardingTriggerType,
|
|
PreparedEntitlement,
|
|
PreparedEntitlementKind,
|
|
PreparedFactorRequirement,
|
|
WelcomeProtocol,
|
|
WelcomeProtocolStep,
|
|
)
|
|
from user_engine.service import UserEngineService
|
|
from user_engine.testing.fixtures import FixtureIdentityClaimsAdapter, human_actor_claims
|
|
from user_engine.ui import RegistrationAccessManagementUi, UiViewport
|
|
|
|
|
|
class RegistrationAccessUiTests(unittest.TestCase):
|
|
def test_information_architecture_and_api_contract_expose_expected_routes(self):
|
|
ui, _, _ = _ui()
|
|
|
|
ia = ui.information_architecture()
|
|
contract = ui.api_contract()
|
|
route_ids = {route.route_id for route in contract.routes}
|
|
|
|
self.assertIn("registration", ia.primary_navigation)
|
|
self.assertIn("prepared_account.review", route_ids)
|
|
self.assertIn("access_profile.select_hat", route_ids)
|
|
self.assertIn("admin.dashboard", route_ids)
|
|
self.assertIn("authorization decisions", contract.adapter_boundaries)
|
|
self.assertEqual(ia.breakpoints["mobile"]["columns"], 1)
|
|
self.assertEqual(ia.breakpoints["desktop"]["columns"], 2)
|
|
|
|
def test_self_service_registration_flow_requires_terms_and_redacts_factor_values(self):
|
|
ui, service, _ = _ui()
|
|
actor = _actor()
|
|
|
|
started = ui.start_registration(
|
|
actor,
|
|
required_factor_types=(IdentityFactorType.EMAIL,),
|
|
viewport=UiViewport.MOBILE,
|
|
correlation_id="corr-ui-start",
|
|
)
|
|
ui.attach_factor(
|
|
actor,
|
|
started.session.registration_id,
|
|
_verified_email(),
|
|
viewport=UiViewport.MOBILE,
|
|
correlation_id="corr-ui-factor",
|
|
)
|
|
blocked = ui.complete_registration(
|
|
actor,
|
|
started.session.registration_id,
|
|
terms_accepted=False,
|
|
viewport=UiViewport.MOBILE,
|
|
correlation_id="corr-ui-blocked",
|
|
)
|
|
completed = ui.complete_registration(
|
|
actor,
|
|
started.session.registration_id,
|
|
terms_accepted=True,
|
|
viewport=UiViewport.MOBILE,
|
|
correlation_id="corr-ui-complete",
|
|
)
|
|
html = ui.render_html(completed.screen)
|
|
|
|
self.assertIn("Terms and consent", blocked.screen.alerts[0])
|
|
self.assertEqual(completed.completion.netkingdom_id, completed.completion.user.user_id)
|
|
self.assertEqual(completed.screen.layout["min_touch_target"], 44)
|
|
self.assertIn("role='main'", html)
|
|
self.assertIn("data-viewport='mobile'", html)
|
|
self.assertNotIn("sample.user@example.test", html)
|
|
self.assertNotIn(
|
|
"sample.user@example.test",
|
|
repr([event.payload for event in service.outbox_events()]),
|
|
)
|
|
|
|
def test_prepared_rights_can_be_reviewed_accepted_or_dismissed(self):
|
|
ui, service, _ = _ui()
|
|
actor = _actor()
|
|
prepared = service.prepare_account(
|
|
actor,
|
|
tenant="tenant:coulomb",
|
|
required_factor_matches=(
|
|
PreparedFactorRequirement(
|
|
factor_type=IdentityFactorType.EMAIL,
|
|
normalized_value="sample.user@example.test",
|
|
),
|
|
),
|
|
entitlements=(
|
|
PreparedEntitlement(
|
|
kind=PreparedEntitlementKind.MEMBERSHIP,
|
|
tenant="tenant:coulomb",
|
|
scope_type="realm",
|
|
scope_id="realm:citadel",
|
|
role="member",
|
|
),
|
|
),
|
|
display_name="Prepared Member",
|
|
primary_email="sample.user@example.test",
|
|
correlation_id="corr-ui-prepare",
|
|
)
|
|
registration = _complete_registration(service, actor)
|
|
|
|
review = ui.prepared_rights_review(
|
|
actor,
|
|
registration.session.registration_id,
|
|
viewport=UiViewport.DESKTOP,
|
|
)
|
|
dismissed = ui.deny_prepared_claim(
|
|
prepared.prepared_account_id,
|
|
viewport=UiViewport.DESKTOP,
|
|
)
|
|
accepted = ui.accept_prepared_claim(
|
|
actor,
|
|
registration.session.registration_id,
|
|
prepared.prepared_account_id,
|
|
viewport=UiViewport.DESKTOP,
|
|
correlation_id="corr-ui-claim",
|
|
)
|
|
html = ui.render_html(review)
|
|
|
|
self.assertIn("denied_by_user", repr(dismissed))
|
|
self.assertEqual(accepted.claim.prepared_account.claimed_by_user_id, accepted.claim.user.user_id)
|
|
self.assertIn("Prepared Member", html)
|
|
self.assertIn("<redacted>", html)
|
|
self.assertNotIn("sample.user@example.test", html)
|
|
|
|
def test_hat_selection_view_selects_active_context_without_policy_details(self):
|
|
ui, service, store = _ui()
|
|
actor = _actor()
|
|
registration = _complete_registration(service, actor)
|
|
service.add_membership(
|
|
actor,
|
|
registration.user.user_id,
|
|
tenant="tenant:coulomb",
|
|
scope_type="realm",
|
|
scope_id="realm:citadel",
|
|
kind="operator",
|
|
correlation_id="corr-ui-membership",
|
|
)
|
|
profile = service.register_access_profile(
|
|
actor,
|
|
AccessProfile(
|
|
tenant="tenant:coulomb",
|
|
display_name="Realm Operator",
|
|
hat="operator",
|
|
scope_type=AccessScopeType.REALM,
|
|
scope_id="realm:citadel",
|
|
realm_id="realm:citadel",
|
|
service_id="app.demo",
|
|
membership_requirements=(
|
|
AccessMembershipRequirement(
|
|
scope_type="realm",
|
|
scope_id="realm:citadel",
|
|
kind="operator",
|
|
),
|
|
),
|
|
required_factor_types=(IdentityFactorType.EMAIL,),
|
|
claims={"internal_policy_hint": "do-not-render"},
|
|
),
|
|
correlation_id="corr-ui-profile",
|
|
)
|
|
|
|
before = ui.hat_selection_view(
|
|
actor,
|
|
registration.user.user_id,
|
|
tenant="tenant:coulomb",
|
|
viewport=UiViewport.DESKTOP,
|
|
)
|
|
selected = ui.select_hat(
|
|
actor,
|
|
registration.user.user_id,
|
|
profile.access_profile_id,
|
|
viewport=UiViewport.DESKTOP,
|
|
correlation_id="corr-ui-select-hat",
|
|
)
|
|
active = store.active_access_context(registration.user.user_id, "tenant:coulomb")
|
|
html = ui.render_html(selected)
|
|
|
|
self.assertIn("none", ui.render_html(before))
|
|
self.assertEqual(active.hat, "operator")
|
|
self.assertIn("Realm Operator", html)
|
|
self.assertNotIn("do-not-render", html)
|
|
|
|
def test_admin_dashboard_redacts_sensitive_setup_details(self):
|
|
ui, service, _ = _ui()
|
|
actor = _actor()
|
|
session = service.me(human_actor_claims(), correlation_id="corr-ui-me")
|
|
service.register_welcome_protocol(
|
|
session.actor,
|
|
WelcomeProtocol(
|
|
tenant="tenant:coulomb",
|
|
name="Blocked Welcome",
|
|
trigger_type=OnboardingTriggerType.MANUAL,
|
|
steps=(
|
|
WelcomeProtocolStep(
|
|
step_key="external",
|
|
title="External",
|
|
subsystem="crm",
|
|
requires_subsystem_callback=True,
|
|
),
|
|
),
|
|
),
|
|
correlation_id="corr-ui-protocol",
|
|
)
|
|
service.prepare_account(
|
|
actor,
|
|
tenant="tenant:coulomb",
|
|
required_factor_matches=(
|
|
PreparedFactorRequirement(
|
|
factor_type=IdentityFactorType.EMAIL,
|
|
normalized_value="sample.user@example.test",
|
|
),
|
|
),
|
|
entitlements=(
|
|
PreparedEntitlement(
|
|
kind=PreparedEntitlementKind.ONBOARDING_JOURNEY,
|
|
tenant="tenant:coulomb",
|
|
onboarding_journey="welcome-demo",
|
|
),
|
|
),
|
|
primary_email="sample.user@example.test",
|
|
correlation_id="corr-ui-prepare",
|
|
)
|
|
dashboard = ui.admin_dashboard(
|
|
actor,
|
|
tenant="tenant:coulomb",
|
|
viewport=UiViewport.DESKTOP,
|
|
)
|
|
html = ui.render_html(dashboard)
|
|
|
|
self.assertEqual(dashboard.layout["columns"], 2)
|
|
self.assertIn("Prepared Accounts", html)
|
|
self.assertIn("Onboarding", html)
|
|
self.assertNotIn("sample.user@example.test", html)
|
|
self.assertIn("role='navigation'", html)
|
|
self.assertIn("aria-label='Sections'", html)
|
|
|
|
|
|
def _ui():
|
|
store = InMemoryUserEngineStore()
|
|
service = UserEngineService(
|
|
store=store,
|
|
identity_adapter=FixtureIdentityClaimsAdapter(),
|
|
authorization=LocalAuthorizationCheckPort(),
|
|
)
|
|
return RegistrationAccessManagementUi(service), service, store
|
|
|
|
|
|
def _actor():
|
|
return FixtureIdentityClaimsAdapter().normalize(
|
|
human_actor_claims(subject="sample-user", tenant="tenant:coulomb")
|
|
)
|
|
|
|
|
|
def _verified_email() -> FactorVerification:
|
|
return FactorVerification(
|
|
factor_type=IdentityFactorType.EMAIL,
|
|
normalized_value="sample.user@example.test",
|
|
display_value="sample.user@example.test",
|
|
source_system="fixture-email",
|
|
)
|
|
|
|
|
|
def _complete_registration(service: UserEngineService, actor):
|
|
session = service.start_registration(actor, correlation_id="corr-ui-reg-start")
|
|
service.attach_registration_factor(
|
|
actor,
|
|
session.registration_id,
|
|
_verified_email(),
|
|
correlation_id="corr-ui-reg-factor",
|
|
)
|
|
return service.complete_registration(
|
|
actor,
|
|
session.registration_id,
|
|
correlation_id="corr-ui-reg-complete",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|