hgserver/pash/pash.py (75 lines of code) (raw):

#!/var/hg/venv_pash/bin/python -u # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import json import logging import os import sys from datetime import datetime from pathlib import Path import hg_helper from hgmolib import ldap_helper AUTOLAND_USER = "bind-autoland@mozilla.com" LANDING_WORKER_USER = "lando_landing_worker@mozilla.com" LANDING_WORKER_USER_2 = "lando_landing_worker_2@mozilla.com" LANDING_WORKER_USER_DEV = "lando_landing_worker_dev@mozilla.com" PASH_JSON = Path("/etc/mercurial/pash.json") def source_environment(path: Path): """Source a file with environment variables. Parsed environment variables are added to ``os.environ`` as a side-effect. """ if not path.is_file(): return # Open in text mode because environment variables are not bytes in Python # 3. with path.open("r") as fh: for line in fh: line = line.strip() if not line or line.startswith("#"): continue # Valid formats: # key=value # key="value" if "=" not in line: continue key, value = line.split("=", 1) key = key.strip() value = value.strip() if value.startswith('"') and value.endswith('"'): value = value[1:-1] os.environ[key] = value def touch_hg_access_date(user): # Run ldap access date toucher, silently fail and log if we're unable to write try: settings = ldap_helper.get_ldap_settings() ldap_helper.update_access_date( user, "hgAccessDate", datetime.utcnow().strftime("%Y%m%d%H%M%S.%fZ"), settings["url"], settings["write_url"], ) except Exception: logging.basicConfig(filename="/var/log/pash.log", level=logging.DEBUG) logging.exception("Failed to update LDAP attributes for %s" % user) def process_login(user): try: # Validate user input. hg_helper.is_valid_user(user) except ValueError as err: sys.stderr.write(str(err)) sys.exit(0) with PASH_JSON.open("rb") as fh: pash_settings = json.load(fh) touch_hg_access_date(user) # landing_users are both autoland-transplant and Lando landing worker # users that push on behalf of other users. landing_users = ( pash_settings.get("autoland_user", AUTOLAND_USER), pash_settings.get("landing_worker_user", LANDING_WORKER_USER), pash_settings.get("landing_worker_user_2", LANDING_WORKER_USER_2), pash_settings.get("landing_worker_user_dev", LANDING_WORKER_USER_DEV), ) # Touch the initiator of the autoland request, if required. if user in landing_users: request_user = os.environ.get("AUTOLAND_REQUEST_USER") if request_user: touch_hg_access_date(request_user) else: if "AUTOLAND_REQUEST_USER" in os.environ: del os.environ["AUTOLAND_REQUEST_USER"] hg_helper.serve( cname=pash_settings["hostname"], user=user, enable_repo_config=pash_settings.get("repo_config", False), enable_repo_group=pash_settings.get("repo_group", False), enable_user_repos=pash_settings.get("user_repos", False), ) sys.exit(0) if __name__ == "__main__": # /etc/environment contains important environment variables needed for # the execution of some functionality (like hooks making HTTP requests # and needing to pick up http_proxy and kin). This file is normally sourced # by login shells. But we are the login process and a shell is never # invoked. There are ways to get sshd to source a file with environment # variables by using PAM. But this feels complicated and requires mucking # about with system auth settings. It is relatively easy to source the file # from Python. So we do that. source_environment(Path("/etc/environment")) process_login(os.environ.get("USER"))