Publish curated ITWorx-ModelForge source from 990401737f96c8d46a9f7b0d84994516cadcb6a0

This commit is contained in:
Public Source Publisher committed 2026-09-30 09:23:17 +00:00
1 parent 7082ab955a
commit 848f0d8f8a
434 files changed
+67298 -4315

No files matched your search

+252
View File
@@ -0,0 +1,252 @@
"""Read-only, bounded audit timeline query contract regressions."""
from __future__ import annotations
import hashlib
import json
from collections.abc import Iterator
from datetime import UTC, datetime, timedelta
import pytest
from fastapi.testclient import TestClient
from pydantic import SecretStr
from sqlalchemy import create_engine, func, select
from sqlalchemy.orm import Session
from sqlalchemy.pool import StaticPool
from modelforge_api.db import get_session
from modelforge_api.main import app
from modelforge_api.persistence.models import AuditEvent, Base
from modelforge_api.services.audit import AuditContext, AuditWriter
from modelforge_api.settings import Settings, get_settings
TIMELINE_PATH = "/api/v1/admin/audit/events"
ADMIN_CREDENTIAL = "audit-timeline-test-admin"
@pytest.fixture
def session() -> Iterator[Session]:
engine = create_engine(
"sqlite+pysqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(engine)
with Session(engine) as value:
yield value
engine.dispose()
@pytest.fixture(autouse=True)
def clean_overrides() -> Iterator[None]:
yield
app.dependency_overrides.clear()
def _client(session: Session, role: str = "admin") -> tuple[TestClient, dict[str, str]]:
app.dependency_overrides[get_session] = lambda: session
if role == "admin":
settings = Settings(_env_file=None, operator_api_key=SecretStr(ADMIN_CREDENTIAL)) # type: ignore[call-arg]
token = ADMIN_CREDENTIAL
else:
token = "mfop_" + "A" * 43
identities = [
{
"credential_id": f"audit-{role}",
"subject": f"audit-{role}",
"role": role,
"token_sha256": hashlib.sha256(token.encode()).hexdigest(),
"expires_at": (datetime.now(UTC) + timedelta(hours=1)).isoformat(),
}
]
settings = Settings(
_env_file=None,
operator_identities=SecretStr(json.dumps(identities)),
) # type: ignore[call-arg]
app.dependency_overrides[get_settings] = lambda: settings
return TestClient(app), {"X-ModelForge-Admin-Token": token}
def _append(
session: Session,
*,
principal: str = "alice",
action: str = "MODEL_UPDATED",
resource_type: str = "model",
resource_id: str = "model-1",
outcome: str = "success",
correlation_id: str = "correlation-1",
details: dict[str, object] | None = None,
) -> AuditEvent:
event = AuditWriter(
session,
context=AuditContext("operator", principal, correlation_id),
).write(
action,
resource_type,
resource_id,
details or {"changed_fields": ["display_name"]},
outcome=outcome,
)
session.commit()
return event
@pytest.mark.parametrize("role", ["viewer", "operator"])
def test_timeline_requires_admin_human_authentication(session: Session, role: str) -> None:
client, headers = _client(session, role)
assert client.get(TIMELINE_PATH).status_code == 401
assert client.get(TIMELINE_PATH, headers=headers).status_code == 403
assert (
client.get(
TIMELINE_PATH,
headers={"Authorization": "Bearer mfsvc_project-scoped"},
).status_code
== 401
)
assert (
client.get(
TIMELINE_PATH,
headers={"Authorization": "Bearer mfnode_node-scoped"},
).status_code
== 401
)
def test_timeline_applies_typed_filters_and_omits_untrusted_details(session: Session) -> None:
_append(
session,
principal="alice-operator",
action="NODE_ENROLLMENT_COMPLETED",
resource_type="compute_node",
resource_id="gpu_node-node-42",
outcome="failure",
correlation_id="corr-audit-42",
details={
"access_token": "mfpw_NEVER_RETURN_THIS",
"nested": {"api-key": "NEVER_RETURN_THIS_EITHER", "changed": True},
"comment": "authorization: Bearer mfpw_NEVER_RETURN_THIS",
"operator_note": "opaque-credential-value-do-not-return-7f93",
},
)
_append(
session,
principal="bob-operator",
action="NODE_ENROLLMENT_COMPLETED",
resource_type="compute_node",
resource_id="gpu_node-node-43",
outcome="success",
correlation_id="corr-audit-43",
)
client, headers = _client(session)
moment = datetime.now(UTC)
response = client.get(
TIMELINE_PATH,
headers=headers,
params={
"principal": "alice",
"action": "enrollment",
"resource": "node-42",
"outcome": "failure",
"correlation_id": "corr-audit-42",
"occurred_after": (moment - timedelta(minutes=1)).isoformat(),
"occurred_before": (moment + timedelta(minutes=1)).isoformat(),
"limit": 10,
},
)
assert response.status_code == 200
payload = response.json()
assert len(payload["events"]) == 1
assert payload["events"][0]["actor_id"] == "alice-operator"
assert payload["events"][0]["action"] == "NODE_ENROLLMENT_COMPLETED"
assert "details" not in payload["events"][0]
for secret_like in (
"NEVER_RETURN_THIS",
"NEVER_RETURN_THIS_EITHER",
"opaque-credential-value-do-not-return-7f93",
):
assert secret_like not in response.text
def test_timeline_cursor_pages_stably_when_new_events_are_appended(session: Session) -> None:
seeded = [_append(session, principal=f"operator-{index}") for index in range(3)]
client, headers = _client(session)
first = client.get(TIMELINE_PATH, headers=headers, params={"limit": 2})
assert first.status_code == 200
first_payload = first.json()
assert [item["sequence"] for item in first_payload["events"]] == [
seeded[2].sequence,
seeded[1].sequence,
]
cursor = first_payload["next_cursor"]
assert isinstance(cursor, str) and cursor
_append(session, principal="operator-new")
second = client.get(
TIMELINE_PATH,
headers=headers,
params={"limit": 2, "cursor": cursor},
)
assert second.status_code == 200
second_payload = second.json()
assert [item["sequence"] for item in second_payload["events"]] == [seeded[0].sequence]
assert second_payload["next_cursor"] is None
assert not (
{item["id"] for item in first_payload["events"]}
& {item["id"] for item in second_payload["events"]}
)
mismatched_filters = client.get(
TIMELINE_PATH,
headers=headers,
params={"limit": 2, "cursor": cursor, "principal": "another-principal"},
)
assert mismatched_filters.status_code == 422
@pytest.mark.parametrize(
"params",
[
{"limit": 101},
{"cursor": "not-a-valid-cursor"},
{"principal": "p" * 256},
{"action": "a" * 129},
{"resource": "r" * 129},
{"outcome": "o" * 33},
{"correlation_id": "c" * 65},
{"occurred_after": "2026-01-01T00:00:00Z"},
{"occurred_after": "not-a-time", "occurred_before": "2026-01-02T00:00:00Z"},
{
"occurred_after": "2024-01-01T00:00:00Z",
"occurred_before": "2026-01-01T00:00:00Z",
},
{
"occurred_after": "2026-02-01T00:00:00Z",
"occurred_before": "2026-01-01T00:00:00Z",
},
{"unexpected_filter": "not-accepted"},
],
)
def test_timeline_rejects_malformed_or_unbounded_query_input(
session: Session, params: dict[str, str | int]
) -> None:
client, headers = _client(session)
response = client.get(TIMELINE_PATH, headers=headers, params=params)
assert response.status_code == 422
def test_timeline_returns_a_typed_empty_page_and_does_not_append_audit_events(
session: Session,
) -> None:
client, headers = _client(session)
response = client.get(TIMELINE_PATH, headers=headers)
assert response.status_code == 200
assert response.json() == {"events": [], "next_cursor": None, "limit": 50}
assert session.scalar(select(func.count()).select_from(AuditEvent)) == 0