Files
maskanx_cm_backend/tests/test_campaign_operator_auth.py
T
AFFAANh 50345a1c89 feat(campaigns): require an operator identity to approve
approved_by was client-supplied, making approval forgeable ahead of
Phase 2 pushing real spend to Meta. Add a proportionate operator-token
check (no login system) via a new require_operator FastAPI dependency:
MASKANX_OPERATOR_TOKENS maps name:token pairs, and approve_campaign now
derives its actor solely from the resolved operator, never from the
client-supplied ActorPayload.actor. Unset env resolves to
"unauthenticated" so local dev and existing tests are not blocked;
set-but-unrecognised tokens 401. submit and reject remain
unauthenticated since neither authorises spend.

Updates test_submit_then_approve_moves_through_states to assert
approved_by == "unauthenticated" (env var unset in tests) instead of
the previously-trusted client actor, since a forged actor must now be
ignored.
2026-08-03 00:17:49 +05:30

61 lines
2.1 KiB
Python

# -*- coding: utf-8 -*-
"""Approve and launch must be attributable to a known operator."""
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from adclaw.app.routers import _operator
def _app():
from adclaw.app.routers import campaigns as campaigns_router
app = FastAPI()
app.include_router(campaigns_router.router, prefix="/api")
return app
def test_unset_env_allows_and_reports_unauthenticated(monkeypatch):
monkeypatch.delenv("MASKANX_OPERATOR_TOKENS", raising=False)
assert _operator.resolve_operator(None) == "unauthenticated"
def test_known_token_resolves_to_its_name(monkeypatch):
monkeypatch.setenv("MASKANX_OPERATOR_TOKENS", "owner:s3cr3t,ops:t0ken")
assert _operator.resolve_operator("s3cr3t") == "owner"
assert _operator.resolve_operator("t0ken") == "ops"
def test_unknown_token_is_rejected(monkeypatch):
monkeypatch.setenv("MASKANX_OPERATOR_TOKENS", "owner:s3cr3t")
with pytest.raises(_operator.OperatorAuthError):
_operator.resolve_operator("wrong")
def test_missing_header_is_rejected_when_configured(monkeypatch):
monkeypatch.setenv("MASKANX_OPERATOR_TOKENS", "owner:s3cr3t")
with pytest.raises(_operator.OperatorAuthError):
_operator.resolve_operator(None)
def test_malformed_config_entries_are_ignored(monkeypatch):
monkeypatch.setenv("MASKANX_OPERATOR_TOKENS", "bad,owner:s3cr3t,:empty,x:")
assert _operator.resolve_operator("s3cr3t") == "owner"
with pytest.raises(_operator.OperatorAuthError):
_operator.resolve_operator("empty")
def test_approve_uses_operator_identity_not_client_actor(monkeypatch):
"""The body's `actor` must never override the authenticated operator."""
monkeypatch.setenv("MASKANX_OPERATOR_TOKENS", "owner:s3cr3t")
client = TestClient(_app())
# Full flow is covered in test_campaign_api.py; here we assert the
# dependency is wired so a forged actor cannot win.
from adclaw.app.routers import campaigns as campaigns_router
import inspect
source = inspect.getsource(campaigns_router.approve_campaign)
assert "require_operator" in source
assert "payload.actor" not in source