Implement NetKingdom identity shell for coulomb.social (CSOC-WP-0002)
Django scaffold aligned with the business delivery lane: tenant-keyed Member model without passwords, identity app as sole OIDC/session boundary, dev-claims login, authenticated /app/ shell, ADR-0001, and tests. T01/T02/T05/T06 done; OIDC registration, real user-engine HTTP, flex-auth, and packaging remain open.
This commit is contained in:
parent
2ec7761504
commit
01da195c13
51 changed files with 2215 additions and 41 deletions
86
tests/test_shell.py
Normal file
86
tests/test_shell.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
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_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_establishes_member_and_shell(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"Ada Lovelace" in home.content
|
||||
assert b"sub-abc" in home.content
|
||||
|
||||
|
||||
@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",
|
||||
)
|
||||
# Use request factory via client session by posting twice
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue