fix: close task 3 resolution findings
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
from fastapi.testclient import TestClient
|
||||
import pytest
|
||||
from sqlalchemy import select
|
||||
|
||||
from central.app.blocked_products import upsert_blocker
|
||||
from central.app.blocker_resolution import resolve_blocker_with_context, validate_resolution_input
|
||||
from central.app.main import create_app
|
||||
from central.app.models import AdminUser, AuditEvent, FiscalContextEntry, Job, Installation
|
||||
from central.app.models import AdminUser, Agent, AuditEvent, BlockedProduct, FiscalContextEntry, Job, Installation, Tenant
|
||||
from central.tests.test_control_plane import seed, setup_db
|
||||
|
||||
|
||||
@@ -106,6 +107,78 @@ def test_resolve_blocker_with_context_persists_one_context_row_job_and_sanitized
|
||||
assert session.query(FiscalContextEntry).count() == 1
|
||||
|
||||
|
||||
def test_legacy_blocker_without_installation_fails_closed_without_job_or_audit():
|
||||
session_factory = setup_db()
|
||||
blocker_id, admin_id, _ = _seed_blocker(session_factory)
|
||||
|
||||
with session_factory() as session:
|
||||
blocker = session.get(BlockedProduct, blocker_id)
|
||||
blocker.installation_id = None
|
||||
session.commit()
|
||||
admin = session.get(AdminUser, admin_id)
|
||||
|
||||
with pytest.raises(LookupError, match="installation"):
|
||||
resolve_blocker_with_context(session, blocker_id, admin, {"scope": "PRODUCT", "scope_key": "P-001", "key": "product_role", "value": "RESALE", "reason": "reviewed"})
|
||||
|
||||
assert session.query(FiscalContextEntry).count() == 0
|
||||
assert session.query(Job).count() == 0
|
||||
assert session.query(AuditEvent).count() == 0
|
||||
|
||||
|
||||
def test_cross_tenant_installation_pointer_fails_before_mutation():
|
||||
session_factory = setup_db()
|
||||
blocker_id, admin_id, _ = _seed_blocker(session_factory)
|
||||
|
||||
with session_factory() as session:
|
||||
blocker = session.get(BlockedProduct, blocker_id)
|
||||
other_tenant = Tenant(name="Other Client")
|
||||
session.add(other_tenant)
|
||||
session.flush()
|
||||
other_agent = Agent(tenant_id=other_tenant.id, name="other-agent", token_hash="other-agent-token".ljust(64, "x"))
|
||||
session.add(other_agent)
|
||||
session.flush()
|
||||
other_installation = Installation(agent_id=other_agent.id, tenant_id=other_tenant.id, installation_id="22222222-2222-4222-8222-222222222222", company_code="OTHER-COMPANY")
|
||||
session.add(other_installation)
|
||||
session.flush()
|
||||
blocker.installation_id = other_installation.id
|
||||
session.commit()
|
||||
admin = session.get(AdminUser, admin_id)
|
||||
|
||||
with pytest.raises(LookupError, match="tenant"):
|
||||
resolve_blocker_with_context(session, blocker_id, admin, {"scope": "PRODUCT", "scope_key": "P-001", "key": "product_role", "value": "RESALE", "reason": "reviewed"})
|
||||
|
||||
assert session.query(FiscalContextEntry).count() == 0
|
||||
assert session.query(Job).count() == 0
|
||||
assert session.query(AuditEvent).count() == 0
|
||||
|
||||
|
||||
def test_resolution_input_rejects_oversized_and_non_string_fields_cleanly():
|
||||
base = {"scope": "PRODUCT", "scope_key": "P-001", "key": "service_cfop", "value": "5102", "reason": "reviewed"}
|
||||
for field, value in (("value", "v" * 513), ("reason", "r" * 2001), ("reason", 123)):
|
||||
payload = {**base, field: value}
|
||||
normalized, error = validate_resolution_input(payload)
|
||||
assert normalized is None
|
||||
assert error
|
||||
|
||||
|
||||
def test_boundary_length_audit_keeps_required_fields_instead_of_truncating_context():
|
||||
session_factory = setup_db()
|
||||
blocker_id, admin_id, _ = _seed_blocker(session_factory)
|
||||
|
||||
with session_factory() as session:
|
||||
admin = session.get(AdminUser, admin_id)
|
||||
result = resolve_blocker_with_context(
|
||||
session,
|
||||
blocker_id,
|
||||
admin,
|
||||
{"scope": "PRODUCT", "scope_key": "P-001", "key": "service_cfop", "value": "v" * 512, "reason": "r" * 2000},
|
||||
)
|
||||
audit = session.get(AuditEvent, result["audit_id"])
|
||||
required = {"admin_user_id", "tenant_id", "client", "company_key", "installation_id", "product_code", "blocker_id", "key", "scope", "scope_key", "value", "reason", "before", "after", "reprocess_job_id", "request_ip"}
|
||||
assert required <= audit.context.keys()
|
||||
assert "truncated" not in audit.context
|
||||
|
||||
|
||||
def test_human_resolution_detail_requires_auth_csrf_and_renders_safe_form():
|
||||
session_factory = setup_db()
|
||||
blocker_id, _, _ = _seed_blocker(session_factory)
|
||||
@@ -127,6 +200,14 @@ def test_human_resolution_detail_requires_auth_csrf_and_renders_safe_form():
|
||||
)
|
||||
assert missing_csrf.status_code == 403
|
||||
|
||||
success = client.post(
|
||||
f"/blockers/{blocker_id}/resolve-context",
|
||||
data={"csrf_token": client.cookies.get("gti_csrf"), "scope": "PRODUCT", "scope_key": "P-001", "key": "product_role", "value": "RESALE", "reason": "reviewed"},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert success.status_code == 303
|
||||
assert success.headers["location"] == f"/blockers/{blocker_id}"
|
||||
|
||||
|
||||
def test_human_and_json_resolution_routes_use_the_same_validated_workflow():
|
||||
session_factory = setup_db()
|
||||
|
||||
Reference in New Issue
Block a user