Some checks are pending
CI / Integration (mcr.microsoft.com/mssql/server:2017-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2019-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2022-latest) (push) Blocked by required conditions
CI / Integration (mcr.microsoft.com/mssql/server:2025-latest) (push) Blocked by required conditions
deploy hub / deploy (push) Successful in 24s
CI / Build og unit tests (push) Successful in 56s
deploy community / deploy (push) Successful in 1s
CI / MSI-installer (push) Successful in 33s
- deploy-community.yml: bygger og starter webstedet ved push (som hubben), bundet til DMZ-adressen. Springes over, indtil COMMUNITY_PORT er sat. Feedet læses skrivebeskyttet fra hubbens feed-mappe; download-links går til hub.sqlinsight.seosoft.dk/updates/ (ny indstilling DownloadUrl). - deploy-forum.yml (manuel): kører discourse_docker-launcheren i en helper-container med /var/discourse og docker.sock fra værten. app.yml er en skabelon, som render.py udfylder fra secrets. - Discourse uden egen TLS: lytter på DMZ-adressen, tvinger https-links og tager klient-IP fra X-Forwarded-For fra proxyen (ellers rammer rate limiting alle brugere samlet). - Caddy-opsætningen er fjernet; docs/community.md beskriver secrets og proxy-opsætning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3EExwndy8Z22EK2Qpt6BK
65 lines
2.3 KiB
Python
Executable file
65 lines
2.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Fills in deploy/forum/app.yml from environment variables and writes the result (mode 600).
|
|
|
|
render.py <template> <output>
|
|
|
|
Required: FORUM_BIND FORUM_PORT KNOWN_PROXY FORUM_ADMIN_EMAIL FORUM_SMTP_ADDRESS FORUM_SMTP_USER FORUM_SMTP_PASSWORD
|
|
Optional: FORUM_HOSTNAME (forum.sqlinsight.seosoft.dk), FORUM_SMTP_PORT (587), FORUM_NOTIFICATION_EMAIL (FORUM_SMTP_USER),
|
|
FORUM_WORKERS (4), FORUM_DB_SHARED_BUFFERS (512MB)
|
|
"""
|
|
import ipaddress
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
DEFAULTS = {
|
|
"FORUM_HOSTNAME": "forum.sqlinsight.seosoft.dk",
|
|
"FORUM_SMTP_PORT": "587",
|
|
"FORUM_WORKERS": "4",
|
|
"FORUM_DB_SHARED_BUFFERS": "512MB",
|
|
}
|
|
# Values that end up unquoted in YAML or in nginx/docker syntax must look exactly like this.
|
|
FORMATS = {
|
|
"FORUM_PORT": r"\d{1,5}",
|
|
"FORUM_SMTP_PORT": r"\d{1,5}",
|
|
"FORUM_WORKERS": r"\d{1,2}",
|
|
"FORUM_DB_SHARED_BUFFERS": r"\d+[MG]B",
|
|
"FORUM_HOSTNAME": r"[a-z0-9.-]+",
|
|
}
|
|
|
|
|
|
def value(name):
|
|
v = os.environ.get(name) or DEFAULTS.get(name)
|
|
if name == "FORUM_NOTIFICATION_EMAIL" and not v:
|
|
v = os.environ.get("FORUM_SMTP_USER")
|
|
if not v:
|
|
sys.exit(f"ERROR: {name} is not set")
|
|
if "\n" in v or "{{" in v:
|
|
sys.exit(f"ERROR: {name} contains a line break or {{{{")
|
|
if name in FORMATS and not re.fullmatch(FORMATS[name], v):
|
|
sys.exit(f"ERROR: {name} has an unexpected format")
|
|
if name in ("FORUM_BIND", "KNOWN_PROXY"):
|
|
try:
|
|
ipaddress.ip_network(v, strict=False) if name == "KNOWN_PROXY" else ipaddress.ip_address(v)
|
|
except ValueError:
|
|
sys.exit(f"ERROR: {name} is not an IP address" + (" or network" if name == "KNOWN_PROXY" else ""))
|
|
# All free-text values sit in single-quoted YAML strings.
|
|
return v.replace("'", "''")
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 3:
|
|
sys.exit(__doc__)
|
|
template, output = sys.argv[1], sys.argv[2]
|
|
with open(template, encoding="utf-8") as f:
|
|
text = f.read()
|
|
names = sorted(set(re.findall(r"\{\{([A-Z_]+)\}\}", text)))
|
|
text = re.sub(r"\{\{([A-Z_]+)\}\}", lambda m: value(m.group(1)), text)
|
|
fd = os.open(output, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
|
|
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
|
f.write(text)
|
|
print(f"{output}: {len(names)} values filled in")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|