diff --git a/services/crud_helper.py b/services/crud_helper.py index 49d1c914..2c7f3d41 100644 --- a/services/crud_helper.py +++ b/services/crud_helper.py @@ -43,7 +43,7 @@ def model_adder(session, table, model, user=None, **kwargs): if kwargs: md.update(kwargs) - if user: + if isinstance(user, dict): # TODO: see note in "AuditMixin" md["created_by_id"] = user["sub"] md["created_by_name"] = user["name"] @@ -115,14 +115,14 @@ def model_patcher( else: setattr(item, key, value) - if user: + if isinstance(user, dict): item.updated_by_id = user["sub"] item.updated_by_name = user["name"] session.commit() session.refresh(item) - if user: + if isinstance(user, dict): resource_type = _resource_type_for_item(model, item) if resource_type: label = _resource_label(item) diff --git a/services/observation_helper.py b/services/observation_helper.py index f99241db..4e1cab5e 100644 --- a/services/observation_helper.py +++ b/services/observation_helper.py @@ -326,7 +326,7 @@ def observation_model_patcher( for key, value in payload.model_dump(exclude_unset=True).items(): setattr(observation, key, value) - if user: + if isinstance(user, dict): observation.updated_by_id = user["sub"] observation.updated_by_name = user["name"] diff --git a/tests/test_contact.py b/tests/test_contact.py index 2076168a..c4cb4392 100644 --- a/tests/test_contact.py +++ b/tests/test_contact.py @@ -1117,3 +1117,29 @@ def test_delete_address_404_not_found(second_address): # assert response.status_code == 404 # data = response.json() # assert data["detail"] == f"ThingContactAssociation with ID {bad_id} not found." + + +# REGRESSION: isinstance(user, dict) guard in model_patcher ==================== +# When AUTHENTIK_DISABLE_AUTHENTICATION=1 the auth dependency returns True +# instead of a claims dict. Before the fix, model_patcher did user["sub"] on +# True, which raised TypeError and produced a 500 with no CORS headers. +# This test overrides the editor dependency with the boolean True (same as the +# live dev environment does) to confirm the patch still returns 200. + + +def test_patch_contact_with_bool_user(contact): + """PATCH returns 200 when the auth dependency yields True (not a dict).""" + app.dependency_overrides[amp_editor_function] = override_authentication( + default=True + ) + try: + payload = {"name": "Bool User Patch"} + response = client.patch(f"/contact/{contact.id}", json=payload) + assert response.status_code == 200 + assert response.json()["name"] == payload["name"] + finally: + # Restore the dict-user override so subsequent tests are unaffected. + app.dependency_overrides[amp_editor_function] = override_authentication( + default={"name": "foobar", "sub": "1234567890"} + ) + cleanup_patch_test(Contact, payload, contact) diff --git a/transfers/seed.py b/transfers/seed.py index f3cf741b..bbe2c188 100644 --- a/transfers/seed.py +++ b/transfers/seed.py @@ -460,4 +460,4 @@ def seed_all(n: int = 5, skip_if_exists: bool = False): if __name__ == "__main__": - seed_all(5) + seed_all(5, skip_if_exists=True)