Files
govoplan/tools/release/release-console.py

68 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Start the local GovOPlaN release console."""
from __future__ import annotations
import argparse
import ipaddress
from pathlib import Path
import secrets
import sys
from govoplan_release.workspace import DEFAULT_WORKSPACE_ROOT
def loopback_host(value: str) -> str:
try:
address = ipaddress.ip_address(value)
except ValueError as exc:
raise argparse.ArgumentTypeError(
"release console host must be a numeric loopback address"
) from exc
if not address.is_loopback:
raise argparse.ArgumentTypeError(
"release console refuses non-loopback hosts without an authenticated "
"TLS deployment boundary"
)
return value
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--host",
type=loopback_host,
default="127.0.0.1",
help="Numeric loopback bind address. Defaults to 127.0.0.1.",
)
parser.add_argument("--port", type=int, default=8765, help="Bind port. Defaults to 8765.")
parser.add_argument("--workspace-root", type=Path, default=DEFAULT_WORKSPACE_ROOT)
args = parser.parse_args()
try:
import uvicorn
except ImportError:
print("uvicorn is required. Install the meta development environment with `pip install -r requirements-dev.txt`.", file=sys.stderr)
return 2
from server.app import create_app
workspace_root = args.workspace_root.expanduser().resolve()
token = secrets.token_urlsafe(24)
app = create_app(workspace_root=workspace_root, token=token)
display_host = f"[{args.host}]" if ":" in args.host else args.host
url = f"http://{display_host}:{args.port}/"
# URL fragments are never sent in HTTP requests. The WebUI transfers
# this one-time bootstrap token to sessionStorage and clears the hash.
url = f"{url}#token={token}"
print("GovOPlaN release console")
print(f" workspace: {workspace_root}")
print(f" url: {url}")
print(" mode: local release dashboard; mutating actions require explicit confirmation")
uvicorn.run(app, host=args.host, port=args.port, log_level="info")
return 0
if __name__ == "__main__":
raise SystemExit(main())