about summary refs log tree commit diff
diff options
context:
space:
mode:
authorClaude2026-08-31 00:00:00 +0000
committerFrederick Muriuki Muriithi2026-08-31 13:23:46 -0500
commit0eb06200d7c4e24e63bf730be29609bd4c7269c8 (patch)
treecd22bcf784ca22a27c5304ff82ab4bbd9bfca53a
parent8979be2b4576a33cb70db84340345e3408c0005d (diff)
downloadgn-integration-tests-0eb06200d7c4e24e63bf730be29609bd4c7269c8.tar.gz
test(gn3/case-attr): level 5 — data-curator approve/reject
Add fixtures and tests for approve/reject access control using a
systemwide-data-curator token.

conftest.py:
- data_curator_oauth2_credentials: reads role "systemwide-data-curator"
  from GN_TEST_USERS_FILE; skips if absent.
- data_curator_token: requests scope "profile group resource role user".

tests/test_gn3_case_attr_access.py:
- test_data_curator_can_approve_returns_200_or_201: parametrized over
  flat (/case-attribute/…) and v1 endpoints; asserts 200 or 201 (either
  proves the auth check passed).
- test_data_curator_can_reject_returns_200_or_201: same for reject
  paths.

Reviewed-By: Frederick M. Muriithi <fredmanglis@gmail.com>
-rw-r--r--conftest.py51
-rw-r--r--tests/test_gn3_case_attr_access.py54
2 files changed, 105 insertions, 0 deletions
diff --git a/conftest.py b/conftest.py
index 250f72d..26931fc 100644
--- a/conftest.py
+++ b/conftest.py
@@ -204,3 +204,54 @@ def basic_access_token(gn_auth_url, basic_oauth2_credentials, http):
     data = resp.json()
     assert "access_token" in data
     return data["access_token"]
+
+
+@pytest.fixture(scope="session")
+def data_curator_oauth2_credentials():
+    """Return (email, password, client_id, client_secret) for the systemwide-data-curator user.
+
+    Requires GN_TEST_USERS_FILE + GN_TEST_CLIENT_FILE (set by the CI
+    auth-flow job).  Skips if not available or if the role is absent.
+    """
+    users_file = os.environ.get("GN_TEST_USERS_FILE")
+    client_file = os.environ.get("GN_TEST_CLIENT_FILE")
+    if not (users_file and client_file):
+        pytest.skip(
+            "Set GN_TEST_USERS_FILE and GN_TEST_CLIENT_FILE to run "
+            "auth-flow tests that require the systemwide-data-curator user."
+        )
+    users_data = _read_json_file(users_file)
+    client_data = _read_json_file(client_file)
+    curator = _user_by_role(users_data, "systemwide-data-curator")
+    if curator is None:
+        pytest.fail(
+            f"No user with role='systemwide-data-curator' found in {users_file}"
+        )
+    return (
+        curator["email"],
+        curator["password"],
+        client_data["client"]["client_id"],
+        client_data["client"]["client_secret"],
+    )
+
+
+@pytest.fixture(scope="session")
+def data_curator_token(gn_auth_url, data_curator_oauth2_credentials, http):
+    """Bearer token for the systemwide-data-curator test user."""
+    email, password, client_id, client_secret = data_curator_oauth2_credentials
+    resp = http.post(
+        f"{gn_auth_url}/auth/token",
+        json={
+            "grant_type": "password",
+            "username": email,
+            "password": password,
+            "scope": "profile group resource role user",
+            "client_id": client_id,
+            "client_secret": client_secret,
+        },
+        timeout=30,
+    )
+    assert resp.status_code == 200, f"Data-curator token request failed: {resp.text}"
+    data = resp.json()
+    assert "access_token" in data
+    return data["access_token"]
diff --git a/tests/test_gn3_case_attr_access.py b/tests/test_gn3_case_attr_access.py
index 92d97e2..0e7706a 100644
--- a/tests/test_gn3_case_attr_access.py
+++ b/tests/test_gn3_case_attr_access.py
@@ -248,3 +248,57 @@ def test_resource_owner_can_edit_returns_201(
         f"If 401: likely the __population_privileges__ bug (resource_privs always empty). "
         f"Body: {resp.text[:300]}"
     )
+
+
+# ---------------------------------------------------------------------------
+# Level 5: approve/reject with systemwide-data-curator privilege
+# ---------------------------------------------------------------------------
+
+@pytest.mark.case_attr_access
+@pytest.mark.auth_flow
+@pytest.mark.parametrize("path", [
+    f"/case-attribute/{_INBREDSET_ID}/approve/{_CHANGE_ID}",
+    f"/v1/species/{_SPECIES_ID}/populations/{_INBREDSET_ID}/case-attributes/diffs/{_CHANGE_ID}/approve",
+])
+def test_data_curator_can_approve_returns_200_or_201(
+        gn3_url, http, data_curator_token, path):
+    """A systemwide-data-curator must be allowed to approve diffs (200/201).
+
+    The endpoint returns 201 when the change is successfully applied and 200
+    when there is no matching pending diff.  Either response proves the auth
+    check passed.
+    """
+    resp = http.post(
+        f"{gn3_url}{path}",
+        headers={"Authorization": f"Bearer {data_curator_token}"},
+        timeout=30,
+    )
+    assert resp.status_code in (200, 201), (
+        f"Expected 200 or 201 for systemwide-data-curator POST {path!r}, "
+        f"got {resp.status_code}. Body: {resp.text[:300]}"
+    )
+
+
+@pytest.mark.case_attr_access
+@pytest.mark.auth_flow
+@pytest.mark.parametrize("path", [
+    f"/case-attribute/{_INBREDSET_ID}/reject/{_CHANGE_ID}",
+    f"/v1/species/{_SPECIES_ID}/populations/{_INBREDSET_ID}/case-attributes/diffs/{_CHANGE_ID}/reject",
+])
+def test_data_curator_can_reject_returns_200_or_201(
+        gn3_url, http, data_curator_token, path):
+    """A systemwide-data-curator must be allowed to reject diffs (200/201).
+
+    The endpoint returns 201 when the change is successfully rejected and 200
+    when there is no matching pending diff.  Either response proves the auth
+    check passed.
+    """
+    resp = http.post(
+        f"{gn3_url}{path}",
+        headers={"Authorization": f"Bearer {data_curator_token}"},
+        timeout=30,
+    )
+    assert resp.status_code in (200, 201), (
+        f"Expected 200 or 201 for systemwide-data-curator POST {path!r}, "
+        f"got {resp.status_code}. Body: {resp.text[:300]}"
+    )