Files
aitbc/tests/contract_tests/test_dispute_auth.py
aitbc 494bd962b4
Some checks failed
Blockchain Synchronization Verification / sync-verification (push) Has been cancelled
CLI Tests / test-cli (push) Has been cancelled
Contract Performance Benchmarks / benchmark-gas-usage (push) Has been cancelled
Contract Performance Benchmarks / benchmark-execution-time (push) Has been cancelled
Contract Performance Benchmarks / benchmark-throughput (push) Has been cancelled
Coverage Phase 1 (70% Target) / test-coverage-70 (push) Has been cancelled
Coverage Phase 2 (85% Target) / test-coverage-85 (push) Has been cancelled
Cross-Chain Functionality Tests / test-cross-chain-sync (push) Has been cancelled
Cross-Chain Functionality Tests / test-cross-chain-transactions (push) Has been cancelled
Cross-Chain Functionality Tests / test-multi-chain-consensus (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Documentation Validation / validate-docs (push) Has been cancelled
Documentation Validation / validate-policies-strict (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Multi-Chain Island Architecture Tests / test-multi-chain-island (push) Has been cancelled
Multi-Node Blockchain Health Monitoring / health-check (push) Has been cancelled
Node Failover Simulation / failover-test (push) Has been cancelled
P2P Network Verification / p2p-verification (push) Has been cancelled
Package Tests / Python package - aitbc-agent-sdk (push) Has been cancelled
Package Tests / Python package - aitbc-core (push) Has been cancelled
Package Tests / Python package - aitbc-crypto (push) Has been cancelled
Package Tests / Python package - aitbc-sdk (push) Has been cancelled
Package Tests / JavaScript package - aitbc-sdk-js (push) Has been cancelled
Package Tests / JavaScript package - aitbc-token (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-contracts path:contracts]) (push) Has been cancelled
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Has been cancelled
Smart Contract Tests / test-foundry (push) Has been cancelled
Smart Contract Tests / lint-solidity (push) Has been cancelled
Smart Contract Tests / deploy-contracts (push) Has been cancelled
Staking Tests / test-staking-service (push) Has been cancelled
Contract Performance Benchmarks / compare-benchmarks (push) Has been cancelled
Cross-Chain Functionality Tests / aggregate-results (push) Has been cancelled
Staking Tests / test-staking-integration (push) Has been cancelled
Staking Tests / test-staking-contract (push) Has been cancelled
Staking Tests / run-staking-test-runner (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Successful in 3s
Cross-Node Transaction Testing / transaction-test (push) Successful in 3s
Add authentication to dispute endpoints and improve test coverage infrastructure
- Add get_authenticated_address() helper to extract wallet address from X-Wallet-Address header or JWT token
- Add authentication to dispute filing, evidence submission, verification, voting, and arbitrator authorization endpoints
- Replace hardcoded zero addresses with authenticated addresses from request headers
- Add DEV_MODE fallback for development without authentication
- Add --mock flag to experimental resource
2026-05-22 23:13:47 +02:00

208 lines
7.9 KiB
Python

"""
Negative authentication tests for dispute endpoints.
Tests for missing authentication, unauthorized access, and invalid tokens.
"""
import pytest
import os
from httpx import AsyncClient, ASGITransport
from fastapi import status
@pytest.mark.asyncio
class TestDisputeAuthentication:
"""Test authentication requirements for dispute endpoints"""
@pytest.fixture
async def client(self):
"""Create test client for blockchain node RPC"""
from apps.blockchain_node.src.aitbc_chain.rpc.router import router
from fastapi import FastAPI
app = FastAPI()
app.include_router(router, prefix="/rpc")
# Set DEV_MODE to false for production-like testing
original_dev_mode = os.getenv("DEV_MODE")
os.environ["DEV_MODE"] = "false"
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
# Restore original DEV_MODE
if original_dev_mode is None:
os.environ.pop("DEV_MODE", None)
else:
os.environ["DEV_MODE"] = original_dev_mode
async def test_file_dispute_missing_auth(self, client):
"""Test that filing a dispute without authentication returns 401"""
response = await client.post(
"/rpc/disputes/file",
json={
"agreement_id": "test_agreement_1",
"respondent": "0x1234567890123456789012345678901234567890",
"dispute_type": "payment_dispute",
"reason": "Test dispute",
"evidence_hash": "0xabcdef"
}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Authentication required" in response.json()["detail"]
async def test_file_dispute_with_invalid_wallet_address(self, client):
"""Test that filing a dispute with invalid wallet address format returns 401"""
response = await client.post(
"/rpc/disputes/file",
json={
"agreement_id": "test_agreement_1",
"respondent": "0x1234567890123456789012345678901234567890",
"dispute_type": "payment_dispute",
"reason": "Test dispute",
"evidence_hash": "0xabcdef"
},
headers={"X-Wallet-Address": "invalid_address_format"}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Invalid wallet address format" in response.json()["detail"]
async def test_submit_evidence_missing_auth(self, client):
"""Test that submitting evidence without authentication returns 401"""
response = await client.post(
"/rpc/disputes/evidence",
json={
"dispute_id": 1,
"evidence_type": "transaction_proof",
"evidence_data": "test_evidence_data"
}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Authentication required" in response.json()["detail"]
async def test_verify_evidence_missing_auth(self, client):
"""Test that verifying evidence without authentication returns 401"""
response = await client.post(
"/rpc/disputes/verify-evidence",
json={
"dispute_id": 1,
"evidence_id": 1,
"is_valid": True,
"verification_score": 95
}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Authentication required" in response.json()["detail"]
async def test_authorize_arbitrator_missing_auth(self, client):
"""Test that authorizing an arbitrator without authentication returns 401"""
response = await client.post(
"/rpc/disputes/arbitrators/authorize",
json={
"arbitrator": "0x1234567890123456789012345678901234567890",
"reputation_score": 85
}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Authentication required" in response.json()["detail"]
async def test_submit_vote_missing_auth(self, client):
"""Test that submitting a vote without authentication returns 401"""
response = await client.post(
"/rpc/disputes/vote",
json={
"dispute_id": 1,
"vote_in_favor_of_initiator": True,
"confidence": 90,
"reasoning": "Test reasoning"
}
)
assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert "Authentication required" in response.json()["detail"]
async def test_file_dispute_with_valid_wallet_address(self, client):
"""Test that filing a dispute with valid wallet address header succeeds (or returns expected error)"""
response = await client.post(
"/rpc/disputes/file",
json={
"agreement_id": "test_agreement_1",
"respondent": "0x1234567890123456789012345678901234567890",
"dispute_type": "payment_dispute",
"reason": "Test dispute",
"evidence_hash": "0xabcdef"
},
headers={"X-Wallet-Address": "0x1234567890123456789012345678901234567890"}
)
# Should not be 401 (authentication passed)
# May be 500 if dispute service is not available, which is acceptable
assert response.status_code != status.HTTP_401_UNAUTHORIZED
async def test_jwt_token_not_implemented(self, client):
"""Test that JWT token authentication returns 501 (not yet implemented)"""
response = await client.post(
"/rpc/disputes/file",
json={
"agreement_id": "test_agreement_1",
"respondent": "0x1234567890123456789012345678901234567890",
"dispute_type": "payment_dispute",
"reason": "Test dispute",
"evidence_hash": "0xabcdef"
},
headers={"Authorization": "Bearer test_token"}
)
assert response.status_code == status.HTTP_501_NOT_IMPLEMENTED
assert "JWT authentication not yet implemented" in response.json()["detail"]
@pytest.mark.asyncio
class TestDisputeAuthDevMode:
"""Test authentication behavior in development mode"""
@pytest.fixture
async def dev_client(self):
"""Create test client with DEV_MODE enabled"""
from apps.blockchain_node.src.aitbc_chain.rpc.router import router
from fastapi import FastAPI
app = FastAPI()
app.include_router(router, prefix="/rpc")
# Set DEV_MODE to true
original_dev_mode = os.getenv("DEV_MODE")
os.environ["DEV_MODE"] = "true"
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
# Restore original DEV_MODE
if original_dev_mode is None:
os.environ.pop("DEV_MODE", None)
else:
os.environ["DEV_MODE"] = original_dev_mode
async def test_file_dispute_dev_mode_fallback(self, dev_client):
"""Test that in dev mode, missing auth uses zero address fallback"""
response = await dev_client.post(
"/rpc/disputes/file",
json={
"agreement_id": "test_agreement_1",
"respondent": "0x1234567890123456789012345678901234567890",
"dispute_type": "payment_dispute",
"reason": "Test dispute",
"evidence_hash": "0xabcdef"
}
)
# In dev mode, should not return 401 (uses zero address fallback)
# May return 500 if dispute service is not available
assert response.status_code != status.HTTP_401_UNAUTHORIZED