Add account recovery, visible access records and shared sign-out handoff
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m21s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
This commit is contained in:
tegwick 2026-09-12 10:34:44 +02:00
parent 7330c25d80
commit e54b6ee970
5 changed files with 169 additions and 13 deletions

View file

@ -0,0 +1,48 @@
import unittest
import test_portal_navigation
from test_web import invoke
class AccountRecoveryTests(unittest.TestCase):
setUp = test_portal_navigation.PortalNavigationTests.setUp
get = test_portal_navigation.PortalNavigationTests.get
def test_recovery_is_public_and_never_trusts_query_identity(self):
response, body = invoke(self.app, '/access-recovery', query='username=forged&code=private&next=https://evil.example')
self.assertEqual('200 OK', response['status'])
for marker in [b'forged', b'private', b'evil.example']:
self.assertNotIn(marker, body)
self.assertIn(b'/logout', body)
self.assertNotIn('Location', response['headers'])
def test_signed_in_recovery_has_verified_identity_and_access_link(self):
response, body = self.get('/access-recovery')
self.assertEqual('200 OK', response['status'])
self.assertIn(b'/onboarding', body)
self.assertIn(b'This portal is signed in as', body)
_, body = self.get('/onboarding')
self.assertIn(b'Current identity', body)
self.assertIn(b'Workload access', body)
self.assertIn(b'No workload-specific access is recorded', body)
def test_shared_logout_clears_portal_then_uses_provider_confirmation(self):
response, _ = invoke(self.app, '/logout', method='POST', cookie='ue_session=operator', form={'csrf_token':'wrong','scope':'shared'})
self.assertEqual('403 Forbidden', response['status'])
self.assertIsNotNone(self.oidc.claims('operator'))
response, _ = invoke(self.app, '/logout', method='POST', cookie='ue_session=operator', form={'csrf_token':'operator-csrf','scope':'shared','return':'https://evil.example'})
self.assertEqual('https://kc.example/account/logout', response['headers']['Location'])
self.assertIsNone(self.oidc.claims('operator'))
self.assertIsNotNone(self.oidc.claims('member'))
_, body = invoke(self.app, '/logged-out')
self.assertIn(b'https://kc.example/account/logout',body)
def test_failed_callback_has_clean_recovery_and_no_loop(self):
response, _ = invoke(self.app, '/oidc/callback', query='error=access_denied&state=private&code=private')
self.assertEqual('/access-recovery', response['headers']['Location'])
def test_account_workload_list_is_scoped_to_current_user(self):
from user_engine.domain import Membership
session = self.app.service.me(self.oidc.claims('operator'), correlation_id='synthetic')
for user, scope, label in [(session.user.user_id,'service','own-workload'),('someone-else','service','private-workload')]:
self.app.service.store.save_membership(Membership(membership_id=label, user_id=user, tenant='tenant:platform:root', scope_type=scope, scope_id=label, kind='user'))
_, body = self.get('/onboarding')
self.assertIn(b'own-workload', body)
self.assertNotIn(b'private-workload', body)