import logging
from pathlib import Path
from yr.cli.component.base import ComponentLauncher
logger = logging.getLogger(__name__)
class FaaSFrontendLauncher(ComponentLauncher):
def prestart_hook(self) -> None:
logger.info(f"{self.name}: prestart hook executing")
src = self.resolver.rendered_config["values"][self.name]["config_path"]
dest = Path(self.resolver.rendered_config[self.name]["env"]["INIT_ARGS_FILE_PATH"]).resolve()
self.patch_init_frontend_args(src, dest)
def patch_init_frontend_args(self, src: Path, dest: Path) -> None:
src = Path(src).resolve()
text = src.read_text()
config = self.resolver.rendered_config
values = config["values"]
faas_args = config[self.component_config.name]["args"]
faas_values = config["values"]["faas_frontend"]
etcd_addrs = config["function_proxy"]["args"]["etcd_address"]
etcd_addr = etcd_addrs.split(",")
etcd_addrs = '","'.join(etcd_addr)
ip_address = faas_values["ip"]
port = faas_values["port"]
etcd_auth_type = values["etcd"].get("auth_type", "Noauth")
etcd_table_prefix = values["etcd"].get("table_prefix", "")
ssl_enable = str(values["fs"]["tls"].get("enable", "false")).lower()
frontend_lease_bypass = str(faas_values.get("lease_bypass", False)).lower()
scc_enable = str(faas_values.get("scc_enable", "false")).lower()
ssl_base_path = values["fs"]["tls"].get("base_path", "")
scc_base_path = faas_args.get("scc_base_path", "")
etcd_ssl_base_path = values["etcd"]["auth"].get("base_path", "")
if etcd_auth_type == "TLS":
def safe_file_join(base_path, filename):
"""Safely join paths and prevent path traversal."""
if not filename:
return ""
if ".." in filename or filename.startswith("/"):
logger.warning(f"Potentially unsafe file name detected: {filename}")
return ""
import os
full_path = os.path.normpath(os.path.join(base_path, filename))
if not full_path.startswith(os.path.normpath(base_path)):
logger.warning(f"Path traversal attempt detected: {filename}")
return ""
return full_path
ca_file = values['etcd']['auth'].get('ca_file', '')
cert_file = values['etcd']['auth'].get('client_cert_file', '')
key_file = values['etcd']['auth'].get('client_key_file', '')
user_pass_phrase = values["etcd"]["auth"].get("pass_phrase", "")
etcd_ca = safe_file_join(etcd_ssl_base_path, ca_file)
etcd_cert = safe_file_join(etcd_ssl_base_path, cert_file)
etcd_key = safe_file_join(etcd_ssl_base_path, key_file)
pass_phrase = safe_file_join(etcd_ssl_base_path, user_pass_phrase) if user_pass_phrase else ""
else:
etcd_ca = ""
etcd_cert = ""
etcd_key = ""
pass_phrase = ""
replacements = {
"{etcdAddr}": etcd_addrs,
"{faas_frontend_http_ip}": ip_address,
"{faas_frontend_http_port}": str(port),
"{sslEnable}": ssl_enable,
"{frontend_lease_bypass}": frontend_lease_bypass,
"{sccEnable}": scc_enable,
"{etcdAuthType}": etcd_auth_type,
"{azPrefix}": etcd_table_prefix,
"{sslBasePath}": ssl_base_path,
"{sccBasePath}": scc_base_path,
"{etcdCAFile}": etcd_ca,
"{etcdCertFile}": etcd_cert,
"{etcdKeyFile}": etcd_key,
"{passphraseFile}": pass_phrase,
}
for placeholder, value in replacements.items():
text = text.replace(placeholder, value)
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_text(text)