61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""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())
|