import pytest from django.urls import reverse from coulomb_social.apps.identity.services import establish_session from coulomb_social.apps.identity.user_engine import IdentityClaims from coulomb_social.apps.members.models import Member, User @pytest.mark.django_db def test_healthz(client): r = client.get("/healthz") assert r.status_code == 200 assert r.json()["status"] == "ok" @pytest.mark.django_db def test_landing_public(client): r = client.get(reverse("core:landing")) assert r.status_code == 200 assert b"Sign in" in r.content @pytest.mark.django_db def test_registration_link_uses_only_configured_destination(client, settings): settings.NETKINGDOM_REGISTRATION_URL = ( "https://users.coulomb.social/register?client_id=coulomb-social" ) r = client.get(reverse("identity:register") + "?next=https://evil.example") assert r.status_code == 302 assert r["Location"] == settings.NETKINGDOM_REGISTRATION_URL @pytest.mark.django_db def test_app_home_requires_login(client): r = client.get(reverse("core:app_home")) assert r.status_code == 302 assert reverse("identity:login") in r["Location"] @pytest.mark.django_db def test_dev_login_lands_on_app_home_not_principal_dump(client, settings): settings.DEBUG = True settings.OIDC_ENABLED = False r = client.post( reverse("identity:dev_login"), { "subject": "sub-abc", "issuer": "https://local.dev/issuer", "name": "Ada Lovelace", "email": "ada@example.com", "preferred_username": "ada", }, ) assert r.status_code == 302 assert reverse("core:app_home") in r["Location"] member = Member.objects.get(subject="sub-abc") assert member.tenant_id == settings.DEFAULT_TENANT_ID assert member.display_name == "Ada Lovelace" assert member.user_engine_user_id assert member.user.has_usable_password() is False home = client.get(reverse("core:app_home")) assert home.status_code == 200 assert b"Spaces" in home.content assert b"No spaces yet" in home.content # Principal dump moved off the home body assert b"user-engine id" not in home.content assert b"sub-abc" not in home.content # Profile chrome shows display name assert b"Ada Lovelace" in home.content assert b"Session details" in home.content @pytest.mark.django_db def test_account_session_shows_principal_diagnostics(client, settings): settings.DEBUG = True settings.OIDC_ENABLED = False client.post( reverse("identity:dev_login"), { "subject": "sub-diag", "issuer": "https://local.dev/issuer", "name": "Diag User", "email": "diag@example.com", }, ) r = client.get(reverse("core:account_session")) assert r.status_code == 200 assert b"Session details" in r.content assert b"sub-diag" in r.content assert b"Diag User" in r.content assert b"user-engine id" in r.content assert b"Tenant" in r.content assert b"Roles" in r.content assert b"Groups" in r.content @pytest.mark.django_db def test_account_session_requires_login(client): r = client.get(reverse("core:account_session")) assert r.status_code == 302 assert reverse("identity:login") in r["Location"] @pytest.mark.django_db def test_establish_session_idempotent(client, settings): claims = IdentityClaims( issuer="https://id.example", subject="same-sub", email="x@example.com", name="Once", ) settings.DEBUG = True settings.OIDC_ENABLED = False client.post( reverse("identity:dev_login"), {"subject": "same-sub", "issuer": "https://id.example", "name": "Once"}, ) client.post( reverse("identity:dev_login"), {"subject": "same-sub", "issuer": "https://id.example", "name": "Once"}, ) assert Member.objects.filter(subject="same-sub").count() == 1 assert User.objects.count() == 1 @pytest.mark.django_db def test_no_password_columns_on_member(): field_names = {f.name for f in Member._meta.fields} assert "password" not in field_names