Prepare isolated Firebase push configuration for pre-production

This commit is contained in:
2026-09-15 19:24:18 +02:00
parent e5fa427485
commit bb28e17220
16 changed files with 386 additions and 17 deletions
+60
View File
@@ -0,0 +1,60 @@
"""Offline credential checks inside the configured container; never sends a push."""
import argparse
import os
from pathlib import Path
import stat
from firebase_admin import credentials
from notifications import enabled
class PreflightError(Exception):
"""Only fixed diagnostic codes, never credential/SDK exception contents."""
def check(expected_service_account):
if not enabled():
raise PreflightError('push_disabled')
project = os.environ.get('FIREBASE_PROJECT_ID', '')
if not project:
raise PreflightError('project_missing')
path = Path(os.environ.get('GOOGLE_APPLICATION_CREDENTIALS', ''))
if str(path) != '/run/secrets/firebase-service-account.json':
raise PreflightError('container_path_mismatch')
try:
info = path.stat()
if not stat.S_ISREG(info.st_mode):
raise PreflightError('credential_not_a_file')
if info.st_mode & 0o077:
raise PreflightError('credential_permissions_too_broad')
if not os.statvfs(path).f_flag & os.ST_RDONLY:
raise PreflightError('credential_mount_not_read_only')
credential = credentials.Certificate(str(path))
except PreflightError:
raise
except Exception:
raise PreflightError('credential_missing_unreadable_or_invalid') from None
if credential.project_id != project:
raise PreflightError('credential_project_mismatch')
if credential.service_account_email != expected_service_account:
raise PreflightError('credential_service_account_mismatch')
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--expected-service-account', required=True,
help='Expected service-account email, not a token or key')
args = parser.parse_args()
try:
check(args.expected_service_account)
except PreflightError as error:
print('FAIL: ' + str(error))
return 1
print('PASS: push enabled; read-only credential; project and service account match. '
'No network request; IAM and delivery still require a smoke test.')
return 0
if __name__ == '__main__':
raise SystemExit(main())