PinVault/tests.py
Jarian Cottingham 606b7c71c2 fix: add API key auth, PIN rate limiting, configurable NAS, bootstrap fix (#1,#3,#6,#7)
Require Bearer token on all API endpoints (PINVAULT_API_KEY env).
Rate limit PIN access to 5 attempts per 15min lockout per PIN.
Make NAS_BACKUP_DIR configurable via PINVAULT_NAS_BACKUP_DIR.
Replace bootstrap() sys.exit(1) with graceful False return.
Add tests for rate limiting and auth.
2026-07-04 04:54:33 +00:00

59 lines
1.9 KiB
Python

import os
import sys
import unittest
from unittest import mock
sys.path.insert(0, os.path.dirname(__file__))
class TestPinVaultSecurity(unittest.TestCase):
def test_api_key_required(self):
import app
self.assertTrue(hasattr(app, 'require_api_key'))
self.assertTrue(len(app.API_KEY) >= 32)
def test_rate_limit_exists(self):
import app
self.assertTrue(hasattr(app, '_check_pin_rate_limit'))
self.assertEqual(app._PIN_MAX_ATTEMPTS, 5)
self.assertEqual(app._PIN_LOCKOUT_SECONDS, 900)
def test_rate_limit_blocks_after_max(self):
import app
app._pin_attempt_locks.clear()
for i in range(app._PIN_MAX_ATTEMPTS):
allowed, _ = app._check_pin_rate_limit(999)
self.assertTrue(allowed, f"Attempt {i+1} should be allowed")
allowed, remaining = app._check_pin_rate_limit(999)
self.assertFalse(allowed, "Should be locked out after max attempts")
self.assertGreater(remaining, 0)
app._pin_attempt_locks.clear()
def test_rate_limit_resets_on_success(self):
import app
app._pin_attempt_locks.clear()
for i in range(3):
app._check_pin_rate_limit(999)
app._reset_pin_rate_limit(999)
allowed, _ = app._check_pin_rate_limit(999)
self.assertTrue(allowed, "Should allow after reset")
app._pin_attempt_locks.clear()
def test_nas_backup_configurable(self):
import app
self.assertEqual(app.NAS_BACKUP_DIR, os.environ.get("PINVAULT_NAS_BACKUP_DIR", ""))
def test_bootstrap_returns_bool(self):
import app
self.assertIsInstance(app._bootstrap_ok, bool)
def test_no_sys_exit_in_bootstrap(self):
import inspect, app
src = inspect.getsource(app.bootstrap)
self.assertNotIn("sys.exit", src, "bootstrap must not call sys.exit")
if __name__ == "__main__":
unittest.main()