Files
pingu-concerts/app/tests/test_push_preflight.py
T

76 lines
3.7 KiB
Python

"""Synthetic offline checks; no key files or Firebase requests are needed."""
import os
import stat
from types import SimpleNamespace
import unittest
from unittest.mock import patch
import push_preflight
class PushPreflightTests(unittest.TestCase):
account = 'metalcircle-push-preprod@metalcircle-30d9b.iam.gserviceaccount.com'
def setUp(self):
env = patch.dict(os.environ, {
'PUSH_ENABLED': 'true', 'FIREBASE_PROJECT_ID': 'metalcircle-30d9b',
'GOOGLE_APPLICATION_CREDENTIALS': '/run/secrets/firebase-service-account.json',
})
env.start()
self.addCleanup(env.stop)
for target, value in (
('push_preflight.Path.stat', SimpleNamespace(st_mode=stat.S_IFREG | 0o600)),
('push_preflight.os.statvfs', SimpleNamespace(f_flag=os.ST_RDONLY)),
('push_preflight.credentials.Certificate', SimpleNamespace(
project_id='metalcircle-30d9b', service_account_email=self.account)),
):
mock = patch(target, return_value=value)
mock.start()
self.addCleanup(mock.stop)
def test_expected_read_only_preprod_credential_passes(self):
push_preflight.check(self.account)
def test_rejects_local_account_even_in_the_same_project(self):
with patch('push_preflight.credentials.Certificate', return_value=SimpleNamespace(
project_id='metalcircle-30d9b',
service_account_email='metalcircle-push-local@metalcircle-30d9b.iam.gserviceaccount.com',
)):
with self.assertRaisesRegex(push_preflight.PreflightError, '^credential_service_account_mismatch$'):
push_preflight.check(self.account)
def test_rejects_wrong_project(self):
with patch.dict(os.environ, {'FIREBASE_PROJECT_ID': 'wrong-project'}):
with self.assertRaisesRegex(push_preflight.PreflightError, '^credential_project_mismatch$'):
push_preflight.check(self.account)
def test_rejects_missing_config_or_disabled_push(self):
for values, code in (
({'PUSH_ENABLED': 'false'}, 'push_disabled'),
({'FIREBASE_PROJECT_ID': ''}, 'project_missing'),
({'GOOGLE_APPLICATION_CREDENTIALS': '/app/key.json'}, 'container_path_mismatch'),
):
with self.subTest(code=code), patch.dict(os.environ, values):
with self.assertRaisesRegex(push_preflight.PreflightError, '^' + code + '$'):
push_preflight.check(self.account)
def test_rejects_broad_permissions_and_directory_mounts(self):
for mode, code in (
(stat.S_IFREG | 0o644, 'credential_permissions_too_broad'),
(stat.S_IFDIR | 0o700, 'credential_not_a_file'),
):
with self.subTest(mode=mode), patch('push_preflight.Path.stat', return_value=SimpleNamespace(st_mode=mode)):
with self.assertRaisesRegex(push_preflight.PreflightError, '^' + code + '$'):
push_preflight.check(self.account)
def test_rejects_writable_mount(self):
with patch('push_preflight.os.statvfs', return_value=SimpleNamespace(f_flag=0)):
with self.assertRaisesRegex(push_preflight.PreflightError, '^credential_mount_not_read_only$'):
push_preflight.check(self.account)
def test_invalid_or_unreadable_credential_error_never_exposes_details(self):
for target in ('push_preflight.Path.stat', 'push_preflight.credentials.Certificate'):
with self.subTest(target=target), patch(target, side_effect=ValueError('sensitive SDK details')):
with self.assertRaisesRegex(push_preflight.PreflightError, '^credential_missing_unreadable_or_invalid$'):
push_preflight.check(self.account)