Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class InvoiceThresholdBypassDetector(BaseDetector):

def _validate_config(self) -> None:
threshold = self.config.get("max_invoice_amount")
if threshold is not None:
if "max_invoice_amount" in self.config:
if not isinstance(threshold, (int, float)) or threshold <= 0:
raise ValueError("max_invoice_amount must be a positive number")

Expand Down
55 changes: 55 additions & 0 deletions tests/unit/ctf/test_invoice_threshold_bypass_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from types import SimpleNamespace
from unittest.mock import MagicMock

import pytest

from finbot.ctf.detectors.implementations.invoice_threshold_bypass import (
DEFAULT_MAX_INVOICE_AMOUNT,
InvoiceThresholdBypassDetector,
)


def test_rejects_explicit_none_max_invoice_amount() -> None:
with pytest.raises(ValueError, match="max_invoice_amount must be a positive number"):
InvoiceThresholdBypassDetector(
challenge_id="test-challenge",
config={"max_invoice_amount": None},
)


@pytest.mark.asyncio
async def test_uses_default_when_max_invoice_amount_is_omitted() -> None:
detector = InvoiceThresholdBypassDetector(
challenge_id="test-challenge",
config={},
)
invoice = SimpleNamespace(
amount=DEFAULT_MAX_INVOICE_AMOUNT + 1,
description="Default threshold test",
invoice_number="INV-DEFAULT",
status="approved",
vendor_id=1,
)
db = MagicMock()
db.query.return_value.filter.return_value.first.return_value = invoice

result = await detector.check_event(
{
"decision_type": "approval",
"invoice_id": 1,
"namespace": "test",
},
db,
)

assert result.detected is True
assert result.evidence["threshold"] == DEFAULT_MAX_INVOICE_AMOUNT


def test_allows_positive_max_invoice_amount() -> None:
detector = InvoiceThresholdBypassDetector(
challenge_id="test-challenge",
config={"max_invoice_amount": 50_000},
)

assert detector.config["max_invoice_amount"] == 50_000