b80e40e7e9
The PERMISSIONS matrix only listed the POST /api/acks entry (parse-999 ingest). The GET list + detail endpoints for 999 / TA1 / 277CA acks were missing, so the matrix_gate (default-deny) returned 403 to every authenticated role, breaking the 999 ACKs / TA1 / 277CA inbox pages. Add the three GET entries as ALL_ROLES — they're read-only metadata surfaces that every authenticated operator needs to see. Add a regression test that logs in as admin via the public route and exercises the matrix; the existing test_existing_endpoints_require_auth suite only checks the unauthenticated 401 path, which is why this slipped through. Fixes the live-verification 'Couldn't load ACKs from the backend / forbidden' error reported against the UI.
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
"""Regression: GET /api/acks, /api/ta1-acks, /api/277ca-acks must be reachable
|
|
for an authenticated admin. The PERMISSIONS matrix only listed the
|
|
``POST /api/acks`` (parse-999) entry, so the GET list/detail endpoints
|
|
returned 403 to admins and broke the Inbox / 999 ACKs pages on the UI.
|
|
|
|
This test exercises the matrix via the public login route — not by
|
|
flipping ``AUTH_DISABLED`` — so a missing ``("GET", "/api/<kind>-acks"):
|
|
ALL_ROLES`` entry would surface as 403.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy import delete
|
|
|
|
from cyclone.api import app
|
|
from cyclone.auth import users
|
|
from cyclone.db import Session as DbSession
|
|
from cyclone.db import SessionLocal, User
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clear(monkeypatch):
|
|
monkeypatch.setattr("cyclone.auth.deps.AUTH_DISABLED", False)
|
|
with SessionLocal()() as db:
|
|
db.execute(delete(DbSession))
|
|
db.execute(delete(User))
|
|
db.commit()
|
|
yield
|
|
with SessionLocal()() as db:
|
|
db.execute(delete(DbSession))
|
|
db.execute(delete(User))
|
|
db.commit()
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_client(client):
|
|
with SessionLocal()() as db:
|
|
users.create(db, username="admin", password="adminpassword1", role="admin")
|
|
resp = client.post(
|
|
"/api/auth/login",
|
|
json={"username": "admin", "password": "adminpassword1"},
|
|
)
|
|
assert resp.status_code == 200
|
|
return client
|
|
|
|
|
|
@pytest.mark.parametrize("path", [
|
|
"/api/acks",
|
|
"/api/acks/0",
|
|
"/api/ta1-acks",
|
|
"/api/ta1-acks/0",
|
|
"/api/277ca-acks",
|
|
"/api/277ca-acks/0",
|
|
])
|
|
def test_admin_can_list_and_detail_all_ack_kinds(admin_client, path):
|
|
resp = admin_client.get(path, headers={"Accept": "application/json"})
|
|
# 200 for the list endpoint (empty rows is fine), 404 for the detail
|
|
# of a non-existent id (the gate must let the request through).
|
|
assert resp.status_code in (200, 404), (
|
|
f"{path} returned {resp.status_code}: {resp.text}"
|
|
)
|
|
assert resp.status_code != 403, (
|
|
f"{path} returned 403 — PERMISSIONS matrix is missing a GET entry"
|
|
) |